Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App recoil refactoring #760

Draft
wants to merge 11 commits into
base: v1.3.5-release
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ services:
volumes:
- ./docs:/docs
ports:
- "127.0.0.1:8001:8001"
- 8001:8001

postgres:
container_name: postgres
Expand Down
1 change: 1 addition & 0 deletions frontend/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = {
parserOptions: {
project: './tsconfig.json',
},
ignorePatterns: ['*.test.tsx'],
rules: {
'prettier/prettier': ['error'],
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
Expand Down
36 changes: 33 additions & 3 deletions frontend/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
VersionType,
} from '../components/Search/types';
import messageDisplayData from '../components/Messaging/messageDisplayData';
import { AppPage } from './types';
import { AppPage, CSSinJS } from './types';

export type NotificationType = 'success' | 'info' | 'warning' | 'error';

Expand Down Expand Up @@ -66,6 +66,36 @@ export async function showNotice(
}
}

const bodySider = {
padding: '12px 12px 12px 12px',
width: '384px',
marginRight: '2px',
};

const bodySiderDark = {
background: 'rgba(255, 255, 255, 0.1)',
};
const bodySiderLight = {
background: 'rgba(255, 255, 255, 0.9)',
boxShadow: '2px 0 4px 0 rgba(0, 0, 0, 0.2)',
};

// Provides appropriate styling based on current theme
export function getStyle(isDark: boolean): CSSinJS {
const colorsToUse = isDark ? bodySiderDark : bodySiderLight;
const styles: CSSinJS = {
bodySider: {
...bodySider,
...colorsToUse,
},
bodyContent: { padding: '12px 12px', margin: 0 },
messageAddIcon: { color: '#90EE90' },
messageRemoveIcon: { color: '#ff0000' },
};

return styles;
}

export async function showError(
msgApi: MessageInstance,
errorMsg: React.ReactNode | string
Expand Down Expand Up @@ -233,8 +263,8 @@ export const getUrlFromSearch = (search: ActiveSearchQuery): string => {
Object.keys(newSearch.activeFacets).length > 0
) {
// Convert array values to string if they are of size 1
const facetsToStringify: { [x: string]: string[] | string } = newSearch.activeFacets;
Object.keys(search.activeFacets).forEach((key) => {
const facetsToStringify: { [x: string]: string[] | string } = { ...newSearch.activeFacets };
Object.keys(newSearch.activeFacets).forEach((key) => {
if (newSearch.activeFacets[key].length === 1) {
facetsToStringify[key] = (newSearch.activeFacets[key][0] as unknown) as string;
}
Expand Down
96 changes: 53 additions & 43 deletions frontend/src/components/App/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { getSearchFromUrl } from '../../common/utils';
import customRender from '../../test/custom-render';
import { ActiveSearchQuery } from '../Search/types';
import App from './App';
import { activeSearch, submitKeywordSearch } from '../../test/jestTestFunctions';
import {
activeSearch,
printElementContents,
RecoilWrapper,
submitKeywordSearch,
} from '../../test/jestTestFunctions';
import { userCartAtom } from './recoil/atoms';

const user = userEvent.setup();

Expand All @@ -32,7 +38,9 @@ describe('test main components', () => {
});

it('renders App component with undefined search query', async () => {
customRender(<App searchQuery={(undefined as unknown) as ActiveSearchQuery} />);
customRender(<App searchQuery={(undefined as unknown) as ActiveSearchQuery} />, {
usesRecoil: true,
});

// Check applicable components render
const navComponent = await screen.findByTestId('nav-bar');
Expand Down Expand Up @@ -255,6 +263,7 @@ describe('test main components', () => {

describe('User cart', () => {
it('handles authenticated user adding and removing items from cart', async () => {
RecoilWrapper.modifyAtomValue(userCartAtom.key, []);
customRender(<App searchQuery={activeSearch} />);

// Wait for components to rerender
Expand Down Expand Up @@ -287,16 +296,6 @@ describe('User cart', () => {
// Wait for components to rerender
await screen.findByTestId('main-query-string-label');

// Check first row has add button and click it
const addBtn = await screen.findByTestId('row-1-add-to-cart');
expect(addBtn).toBeTruthy();

await userEvent.click(addBtn);

// Check 'Added items(s) to the cart' message appears
const addText = await screen.findByText('Added item(s) to your cart');
expect(addText).toBeTruthy();

// Check applicable components render
const rightMenuComponent = await screen.findByTestId('right-menu');
expect(rightMenuComponent).toBeTruthy();
Expand All @@ -315,14 +314,14 @@ describe('User cart', () => {

const numDatasetsField = await within(cartSummary).findByText('Total Number of Datasets:');
const numFilesText = await within(cartSummary).findByText('Total Number of Files:');
expect(numDatasetsField.textContent).toEqual('Total Number of Datasets: 1');
expect(numFilesText.textContent).toEqual('Total Number of Files: 2');
expect(numDatasetsField.textContent).toEqual('Total Number of Datasets: 3');
expect(numFilesText.textContent).toEqual('Total Number of Files: 8');
const numSelectedDatasetsField = await within(cartSummary).findByText(
'Selected Number of Datasets:'
);
const numSelectedFilesText = await within(cartSummary).findByText('Selected Number of Files:');
expect(numSelectedDatasetsField.textContent).toEqual('Selected Number of Datasets: 1');
expect(numSelectedFilesText.textContent).toEqual('Selected Number of Files: 2');
expect(numSelectedDatasetsField.textContent).toEqual('Selected Number of Datasets: 0');
expect(numSelectedFilesText.textContent).toEqual('Selected Number of Files: 0');

// Check "Remove All Items" button renders with cart > 0 items and click it
const clearCartBtn = await screen.findByTestId('clear-cart-button');
Expand All @@ -346,7 +345,8 @@ describe('User cart', () => {

it('handles anonymous user adding and removing items from cart', async () => {
// Render component as anonymous
customRender(<App searchQuery={activeSearch} />, {}, false);
RecoilWrapper.modifyAtomValue(userCartAtom.key, []);
customRender(<App searchQuery={activeSearch} />, { authenticated: false });

// Wait for components to rerender
await screen.findByTestId('main-query-string-label');
Expand All @@ -365,21 +365,11 @@ describe('User cart', () => {
});

it('displays anonymous user"s number of files in the cart summary and handles clearing the cart', async () => {
customRender(<App searchQuery={activeSearch} />, {}, false);
customRender(<App searchQuery={activeSearch} />, { usesRecoil: true, authenticated: false });

// Wait for components to rerender
await screen.findByTestId('main-query-string-label');

// Check first row has add button and click it
const addBtn = await screen.findByTestId('row-1-add-to-cart');
expect(addBtn).toBeTruthy();

await userEvent.click(addBtn);

// Check 'Added items(s) to the cart' message appears
const addText = await screen.findByText('Added item(s) to your cart');
expect(addText).toBeTruthy();

// Check applicable components render
const rightMenuComponent = await screen.findByTestId('right-menu');
expect(rightMenuComponent).toBeTruthy();
Expand All @@ -400,15 +390,15 @@ describe('User cart', () => {

const numDatasetsField = await within(cartSummary).findByText('Total Number of Datasets:');
const numFilesText = await within(cartSummary).findByText('Total Number of Files:');
expect(numDatasetsField.textContent).toEqual('Total Number of Datasets: 1');
expect(numFilesText.textContent).toEqual('Total Number of Files: 2');
expect(numDatasetsField.textContent).toEqual('Total Number of Datasets: 3');
expect(numFilesText.textContent).toEqual('Total Number of Files: 8');

const numSelectedDatasetsField = await within(cartSummary).findByText(
'Selected Number of Datasets:'
);
const numSelectedFilesText = await within(cartSummary).findByText('Selected Number of Files:');
expect(numSelectedDatasetsField.textContent).toEqual('Selected Number of Datasets: 1');
expect(numSelectedFilesText.textContent).toEqual('Selected Number of Files: 2');
expect(numSelectedDatasetsField.textContent).toEqual('Selected Number of Datasets: 0');
expect(numSelectedFilesText.textContent).toEqual('Selected Number of Files: 0');

// Check "Remove All Items" button renders with cart > 0 items and click it
const clearCartBtn = await screen.findByTestId('clear-cart-button');
Expand All @@ -432,10 +422,13 @@ describe('User cart', () => {
});

it('resets cart totals and selections to 0 when all items are removed', async () => {
RecoilWrapper.modifyAtomValue(userCartAtom.key, []);
customRender(<App searchQuery={activeSearch} />);

// Wait for components to rerender
await screen.findByTestId('main-query-string-label');
await screen.findByText('results found for', { exact: false });

printElementContents();

// Check first row has add button and click it
const addBtn = await screen.findByTestId('row-1-add-to-cart');
Expand Down Expand Up @@ -509,7 +502,10 @@ describe('Error handling', () => {
);

customRender(<App searchQuery={activeSearch} />, {
token: 'token',
usesRecoil: true,
options: {
token: 'token',
},
});

// Check applicable components render
Expand All @@ -525,7 +521,10 @@ describe('Error handling', () => {
describe('User search library', () => {
it('handles authenticated user saving and applying searches', async () => {
customRender(<App searchQuery={activeSearch} />, {
token: 'token',
usesRecoil: true,
options: {
token: 'token',
},
});

// Wait for components to rerender
Expand Down Expand Up @@ -570,7 +569,10 @@ describe('User search library', () => {

it('handles authenticated user removing searches from the search library', async () => {
customRender(<App searchQuery={activeSearch} />, {
token: 'token',
usesRecoil: true,
options: {
token: 'token',
},
});

// Check applicable components render
Expand All @@ -593,6 +595,11 @@ describe('User search library', () => {
const cart = await screen.findByTestId('cart');
expect(cart).toBeTruthy();

// Check there is a saved search card
const savedSearches = await screen.findByTestId('saved-search-library');
expect(savedSearches).toBeTruthy();
expect(within(savedSearches).getByText('Search #', { exact: false })).toBeTruthy();

// Check delete button renders for the saved search and click it
const deleteBtn = await screen.findByRole('img', {
name: 'delete',
Expand All @@ -601,17 +608,16 @@ describe('User search library', () => {
expect(deleteBtn).toBeTruthy();

await userEvent.click(deleteBtn);

await screen.findByTestId('cart');

// Check removed message appears
const removeText = await screen.findByText('Removed search query from your library');
const removeText = await screen.findByText('Your search library is empty');
expect(removeText).toBeTruthy();
});

it('handles anonymous user saving and applying searches', async () => {
// Render component as anonymous
customRender(<App searchQuery={activeSearch} />, {}, false);
customRender(<App searchQuery={activeSearch} />, { authenticated: false });

// Check applicable components render
const leftMenuComponent = await screen.findByTestId('left-menu');
Expand Down Expand Up @@ -657,7 +663,7 @@ describe('User search library', () => {

it('handles anonymous user removing searches from the search library', async () => {
// Render component as anonymous
customRender(<App searchQuery={activeSearch} />, {}, false);
customRender(<App searchQuery={activeSearch} />, { authenticated: false });

// Wait for components to rerender
await screen.findByTestId('main-query-string-label');
Expand Down Expand Up @@ -694,7 +700,7 @@ describe('User search library', () => {
});

it('handles anonymous user copying search to clipboard', async () => {
customRender(<App searchQuery={activeSearch} />, {}, false);
customRender(<App searchQuery={activeSearch} />, { authenticated: false });

// Check applicable components render
const rightMenuComponent = await screen.findByTestId('right-menu');
Expand Down Expand Up @@ -730,7 +736,10 @@ describe('User search library', () => {

it('shows a disabled save search button due to failed search results', async () => {
customRender(<App searchQuery={activeSearch} />, {
token: 'token',
usesRecoil: true,
options: {
token: 'token',
},
});

server.use(rest.post(apiRoutes.userSearches.path, (_req, res, ctx) => res(ctx.status(404))));
Expand All @@ -750,7 +759,8 @@ describe('User search library', () => {
server.use(rest.delete(apiRoutes.userSearch.path, (_req, res, ctx) => res(ctx.status(404))));

customRender(<App searchQuery={activeSearch} />, {
token: 'token',
usesRecoil: true,
options: { token: 'token' },
});

// Check delete button renders for the saved search and click it
Expand Down
Loading
Loading