Skip to content

Commit

Permalink
Feat 709 add progress bar to edit study page with the ability to swit…
Browse files Browse the repository at this point in the history
…ch between different lists (#832)

* feat: add inital wireframes proposal

* feat: fixes

* fix: merge conflicts

* feat: update edit study page

* feat: finished edit study page

* feat: added feedback

* fix: feedback updats

* feat: update with feedback

* chore: add initial test files

* fix: finished tests

* fix: tests

* fix: lowercase to uppercase

* replace mark with set
  • Loading branch information
nicoalee authored Oct 22, 2024
1 parent 47dbf03 commit f8591a5
Show file tree
Hide file tree
Showing 64 changed files with 2,664 additions and 645 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ describe(PAGE_NAME, () => {
cy.intercept('GET', `**/api/base-studies/**`, {
fixture: 'study',
}).as('studyFixture');
cy.visit(PATH).wait('@semanticScholarFixture').wait('@studyFixture');
// .get('tr')
// .eq(2)
// .click()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ describe(PAGE_NAME, () => {
.wait('@studyFixture')
.wait('@projectFixture')
.wait('@annotationFixture')
.wait('@semanticScholarFixture')
.wait('@studysetFixture');
});

Expand All @@ -48,15 +47,14 @@ describe(PAGE_NAME, () => {
.wait('@studyFixture')
.wait('@projectFixture')
.wait('@annotationFixture')
.wait('@semanticScholarFixture')
.wait('@studysetFixture');

// ACT
cy.get('div').contains('(name, authors, description, doi, pmid, etc)').click();
cy.contains('label', 'doi').next().clear();
cy.contains('label', 'pmid').next().clear();
cy.contains('label', 'pmcid').next().clear();
cy.contains('button', 'save').click();
cy.get('[data-testid="SaveIcon"]').click();

// ASSERT
cy.get('@editStudy').its('request.body').should('not.have.a.property', 'doi');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export {};
const PATH = '/base-studies';
const PAGE_NAME = 'StudiesPage';

describe.skip(PAGE_NAME, () => {
describe(PAGE_NAME, () => {
beforeEach(() => {
cy.clearLocalStorage();
cy.intercept('GET', 'https://api.appzi.io/**', { fixture: 'appzi' }).as('appziFixture');
Expand All @@ -16,7 +16,7 @@ describe.skip(PAGE_NAME, () => {
it('should load successfully', () => {
cy.intercept('GET', `**/api/projects*`).as('realProjectsRequest');
cy.intercept('GET', `**/api/base-studies/**`).as('realStudiesRequest');
cy.visit(PATH).wait('@realStudiesRequest');
cy.visit(PATH);
});

// describe('Search', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { INeurosynthProjectReturn } from 'hooks/projects/useGetProjects';
import { StudyReturn, StudysetReturn } from 'neurostore-typescript-sdk';
import { IExtractionTableStudy } from 'pages/Extraction/components/ExtractionTable';
import { getAuthorShortName } from 'pages/Extraction/components/ExtractionTable.helpers';

describe('ExtractionTable', () => {
beforeEach(() => {
Expand Down Expand Up @@ -303,7 +304,12 @@ describe('ExtractionTable', () => {

cy.get('tbody > tr').each((tr, index) => {
cy.wrap(tr).within(() => {
cy.get('td').eq(2).should('have.text', sortedStudies[index].authors);
cy.get('td')
.eq(2)
.should(
'have.text',
getAuthorShortName(sortedStudies?.[index]?.authors || '')
);
});
});
});
Expand All @@ -324,7 +330,12 @@ describe('ExtractionTable', () => {

cy.get('tbody > tr').each((tr, index) => {
cy.wrap(tr).within(() => {
cy.get('td').eq(2).should('have.text', sortedStudies[index].authors);
cy.get('td')
.eq(2)
.should(
'have.text',
getAuthorShortName(sortedStudies?.[index]?.authors || '')
);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('CreateSpecificationDialog', () => {
cy.contains('FDRCorrector').should('exist');
});

it.only('should step through the wizard', () => {
it('should step through the wizard', () => {
cy.intercept('POST', '**/api/specifications', {
id: 'mockedSpecificationId',
}).as('createSpecificationFixture');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ describe('DoSleuthImport', () => {
});

describe('edge cases', () => {
it.only('should apply the pubmed details to the study if a matching pubmed study is found', () => {
it('should apply the pubmed details to the study if a matching pubmed study is found', () => {
// this stuff exists just to make sure cypress doesnt send any real requests. They are not under test
// synth API responses
cy.intercept('POST', `${neurostoreAPIBaseURL}/analyses/**`, {
Expand Down
17 changes: 0 additions & 17 deletions compose/neurosynth-frontend/src/App.spec.tsx

This file was deleted.

5 changes: 3 additions & 2 deletions compose/neurosynth-frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import useGoogleAnalytics from 'hooks/useGoogleAnalytics';
import { SnackbarKey, SnackbarProvider } from 'notistack';
import { useEffect, useRef } from 'react';
import { QueryCache, QueryClient, QueryClientProvider } from 'react-query';
import Navbar from './components/Navbar/Navbar';
import Navbar from 'components/Navbar/Navbar';
import useGetToken from './hooks/useGetToken';
import BaseNavigation from './pages/BaseNavigation/BaseNavigation';
import BaseNavigation from 'pages/BaseNavigation/BaseNavigation';
import { useLocation } from 'react-router-dom';

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 0,
refetchOnWindowFocus: false,
// staleTime: 5000, // https://tkdodo.eu/blog/practical-react-query#the-defaults-explained
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const useAuth0 = jest.fn().mockReturnValue({
loginWithPopup: jest.fn(),
logout: jest.fn(),
isAuthenticated: false,
isLoading: false,
user: {
sub: 'some-github-user',
},
Expand Down
5 changes: 5 additions & 0 deletions compose/neurosynth-frontend/src/__mocks__/notistack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const useSnackbar = jest.fn().mockReturnValue({
enqueueSnackbar: jest.fn(),
});

export { useSnackbar };
11 changes: 11 additions & 0 deletions compose/neurosynth-frontend/src/__mocks__/react-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const useQueryClient = jest.fn().mockReturnValue({
invalidateQueries: jest.fn(),
});

const useQuery = jest.fn().mockReturnValue({
data: null,
isLoading: false,
isError: false,
});

export { useQueryClient, useQuery };
9 changes: 0 additions & 9 deletions compose/neurosynth-frontend/src/__mocks__/react-router-dom.ts

This file was deleted.

25 changes: 25 additions & 0 deletions compose/neurosynth-frontend/src/__mocks__/react-router-dom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NavigateProps } from 'react-router-dom';

const useParams = jest.fn().mockReturnValue({
projectId: 'test-project-id',
});

const useNavigate = jest.fn().mockReturnValue(jest.fn());

const useLocation = jest.fn().mockReturnValue({
location: {
search: '',
},
});

const Navigate = ({ to, replace, state }: NavigateProps) => {
return (
<>
<div data-testid="to">{to}</div>
<div data-testid="replace">{replace}</div>
<div data-testid="state">{JSON.stringify(state)}</div>
</>
);
};

export { useNavigate, useLocation, useParams, Navigate };
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('ConfirmationDialog', () => {

const rejectButton = screen.getByRole('button', { name: 'reject' });
userEvent.click(rejectButton);
expect(mockOnClose).toBeCalledWith(false, undefined);
expect(mockOnClose).toBeCalledWith(false);
});

it('should signal true when confirm is clicked', () => {
Expand All @@ -57,7 +57,7 @@ describe('ConfirmationDialog', () => {

const confirmButton = screen.getByRole('button', { name: 'confirm' });
userEvent.click(confirmButton);
expect(mockOnClose).toBeCalledWith(true, undefined);
expect(mockOnClose).toBeCalledWith(true);
});

it('should signal undefined when clicked away', async () => {
Expand All @@ -77,7 +77,7 @@ describe('ConfirmationDialog', () => {
// we need to trigger a click away by clicking the backdrop. For some reason,
// the second presentation div accomplishes this
userEvent.click(screen.getAllByRole('presentation')[1]);
expect(mockOnClose).toBeCalledWith(undefined, undefined);
expect(mockOnClose).toBeCalledWith(undefined);
});

it('should close when close icon button is clicked', () => {
Expand All @@ -92,7 +92,7 @@ describe('ConfirmationDialog', () => {
);

userEvent.click(screen.getByTestId('CloseIcon'));
expect(mockOnClose).toHaveBeenCalledWith(undefined, undefined);
expect(mockOnClose).toHaveBeenCalledWith(undefined);
});

it('should be called with the data', () => {
Expand All @@ -103,13 +103,12 @@ describe('ConfirmationDialog', () => {
onCloseDialog={mockOnClose}
confirmText="confirm"
rejectText="reject"
data={{ data: 'test-data' }}
/>
);

const confirmButton = screen.getByRole('button', { name: 'confirm' });
userEvent.click(confirmButton);

expect(mockOnClose).toHaveBeenCalledWith(true, { data: 'test-data' });
expect(mockOnClose).toHaveBeenCalledWith(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ import {
IconButton,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import React, { useMemo } from 'react';
import React, { ReactNode, useMemo } from 'react';

export interface IConfirmationDialog {
isOpen: boolean;
onCloseDialog: (confirm: boolean | undefined, data?: any) => void;
onCloseDialog: (confirm: boolean | undefined) => void;
dialogTitle: string;
dialogMessage?: JSX.Element | string;
dialogMessage?: ReactNode | string;
confirmText?: string;
rejectText?: string;
data?: any;
}

const ConfirmationDialog: React.FC<IConfirmationDialog> = (props) => {
Expand All @@ -33,13 +32,13 @@ const ConfirmationDialog: React.FC<IConfirmationDialog> = (props) => {
}, [props.dialogMessage]);

return (
<Dialog open={props.isOpen} onClose={() => props.onCloseDialog(undefined, props.data)}>
<Dialog open={props.isOpen} onClose={() => props.onCloseDialog(undefined)}>
<DialogTitle sx={{ display: 'flex' }}>
<Box sx={{ display: 'flex', flexGrow: 1, alignItems: 'center' }}>
<Typography variant="h6">{props.dialogTitle}</Typography>
</Box>
<Box>
<IconButton onClick={() => props.onCloseDialog(undefined, props.data)}>
<IconButton onClick={() => props.onCloseDialog(undefined)}>
<CloseIcon sx={{ fontSize: '2rem' }} />
</IconButton>
</Box>
Expand All @@ -49,15 +48,15 @@ const ConfirmationDialog: React.FC<IConfirmationDialog> = (props) => {
<Box sx={{ display: 'flex', justifyContent: 'space-between', marginTop: '1rem' }}>
<Button
sx={{ width: '250px', marginRight: '15px' }}
onClick={() => props.onCloseDialog(false, props.data)}
onClick={() => props.onCloseDialog(false)}
variant="text"
color="error"
>
{props.rejectText ? props.rejectText : 'Reject'}
</Button>
<Button
sx={{ width: '250px' }}
onClick={() => props.onCloseDialog(true, props.data)}
onClick={() => props.onCloseDialog(true)}
variant="contained"
color="primary"
disableElevation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ const mockConfirmationDialog: React.FC<IConfirmationDialog> = (props) => {
<>
{props.isOpen && (
<div data-testid="mock-confirmation-dialog">
<h1>{props.dialogTitle}</h1>
<div>{props.dialogMessage}</div>
<button
data-testid="accept-close-confirmation"
onClick={(_event) => props.onCloseDialog(true)}
></button>
>
{props.confirmText}
</button>
<button
data-testid="deny-close-confirmation"
onClick={(_event) => props.onCloseDialog(false)}
></button>
<button
data-testid="undecided-close-confirmation"
onClick={(_event) => props.onCloseDialog(undefined)}
></button>
>
{props.rejectText}
</button>
</div>
)}
</>
Expand Down
21 changes: 3 additions & 18 deletions compose/neurosynth-frontend/src/components/Navbar/Navbar.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useAuth0 } from '@auth0/auth0-react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from 'react-query';
import Navbar from './Navbar';

jest.mock('@auth0/auth0-react');
Expand All @@ -11,37 +10,23 @@ jest.mock('components/Navbar/NavToolbar.tsx');
jest.mock('hooks');

describe('Navbar', () => {
const queryClient = new QueryClient();

it('should render', () => {
render(
<QueryClientProvider client={queryClient}>
<Navbar />
</QueryClientProvider>
);
render(<Navbar />);

expect(screen.getByTestId('mock-nav-drawer')).toBeInTheDocument();
expect(screen.getByTestId('mock-nav-toolbar')).toBeInTheDocument();
});

it('should call the auth0 login method when logging in', () => {
render(
<QueryClientProvider client={queryClient}>
<Navbar />
</QueryClientProvider>
);
render(<Navbar />);

userEvent.click(screen.getByTestId('toolbar-trigger-login'));

expect(useAuth0().loginWithPopup).toHaveBeenCalled();
});

it('should call the auth0 logout method when logging out', () => {
render(
<QueryClientProvider client={queryClient}>
<Navbar />
</QueryClientProvider>
);
render(<Navbar />);

userEvent.click(screen.getByTestId('toolbar-trigger-logout'));

Expand Down
Loading

0 comments on commit f8591a5

Please sign in to comment.