From e84153225d224d048536d461e5de1ae629f640c3 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Mon, 19 Feb 2024 15:44:13 -0500 Subject: [PATCH 01/26] Bumped Cypress --- package-lock.json | 13 +++++++------ package.json | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index a80a1fa2..eb19e313 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "@vitejs/plugin-react-swc": "^3.5.0", "@vitest/ui": "^1.1.3", "autoprefixer": "^10.4.16", - "cypress": "^13.6.2", + "cypress": "^13.6.4", "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", @@ -1968,6 +1968,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.5.tgz", "integrity": "sha512-22MG6T02Hos2JWfa1o5jsIByn+bc5iOt1IS4xyg6OG68Bu+wMonVZzdrgCw693++rpLE9RUT/Bx15BeDzO0j+g==", "dev": true, + "optional": true, "dependencies": { "undici-types": "~5.26.4" } @@ -3417,15 +3418,14 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.6.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.6.2.tgz", - "integrity": "sha512-TW3bGdPU4BrfvMQYv1z3oMqj71YI4AlgJgnrycicmPZAXtvywVFZW9DAToshO65D97rCWfG/kqMFsYB6Kp91gQ==", + "version": "13.6.4", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.6.4.tgz", + "integrity": "sha512-pYJjCfDYB+hoOoZuhysbbYhEmNW7DEDsqn+ToCLwuVowxUXppIWRr7qk4TVRIU471ksfzyZcH+mkoF0CQUKnpw==", "dev": true, "hasInstallScript": true, "dependencies": { "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", - "@types/node": "^18.17.5", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", @@ -8872,7 +8872,8 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "optional": true }, "node_modules/universalify": { "version": "2.0.1", diff --git a/package.json b/package.json index 328aab1f..9a357514 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@vitejs/plugin-react-swc": "^3.5.0", "@vitest/ui": "^1.1.3", "autoprefixer": "^10.4.16", - "cypress": "^13.6.2", + "cypress": "^13.6.4", "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", From 9226eba377e694a77c690eb4d64e915c4c05b618 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Mon, 19 Feb 2024 15:46:33 -0500 Subject: [PATCH 02/26] Implemented `CategoricalField` component test --- cypress/component/CategoricalField.cy.tsx | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 cypress/component/CategoricalField.cy.tsx diff --git a/cypress/component/CategoricalField.cy.tsx b/cypress/component/CategoricalField.cy.tsx new file mode 100644 index 00000000..c22268d1 --- /dev/null +++ b/cypress/component/CategoricalField.cy.tsx @@ -0,0 +1,38 @@ +import CategoricalField from "../../src/components/CategoricalField"; + +const props = { + label: "Categorical Field", + options: [ + { id: "1", label: "Option 1" }, + { id: "2", label: "Option 2" }, + { id: "3", label: "Option 3" }, + ], + onFieldChange: () => {}, + multiple: false, + inputValue: null, +}; + +describe("CategoricalField", () => { + it("Displays a MUI Autocomplete with the label and options passed as props", () => { + cy.mount(); + cy.get('[data-cy="Categorical Field-categorical-field"]').should("be.visible") + cy.get('[data-cy="Categorical Field-categorical-field"] label').should("contain", "Categorical Field") + props.options.forEach((option) => { + cy.get('[data-cy="Categorical Field-categorical-field"]').type(`${option.label}{downarrow}{enter}`) + cy.get('[data-cy="Categorical Field-categorical-field"] input').should("have.value", option.label); + cy.get('[data-cy="Categorical Field-categorical-field"]').clear(); + + }) + }) + it("Displays the input value passed as props", () => { + cy.mount(); + cy.get('[data-cy="Categorical Field-categorical-field"] input').should("have.value", "Option 1") + + }) + it("Fires onFieldChange event handler with the appropriate payload when a value is selected", () => { + const onFieldChange = cy.spy().as("onFieldChange"); + cy.mount(); + cy.get('[data-cy="Categorical Field-categorical-field"]').type("Option 1{downarrow}{enter}") + cy.get('@onFieldChange').should("have.been.calledWith", "Categorical Field", {id: "1", label: "Option 1"}); + }) +}) \ No newline at end of file From 4fa9955ba550e2dba3994a30d1fa47cd7ad3f6f4 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Mon, 19 Feb 2024 15:47:20 -0500 Subject: [PATCH 03/26] Implemented `ContinuousField` component test --- cypress/component/ContinuousField.cy.tsx | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 cypress/component/ContinuousField.cy.tsx diff --git a/cypress/component/ContinuousField.cy.tsx b/cypress/component/ContinuousField.cy.tsx new file mode 100644 index 00000000..078a97f5 --- /dev/null +++ b/cypress/component/ContinuousField.cy.tsx @@ -0,0 +1,27 @@ +import ContinuousField from "../../src/components/ContinuousField"; + +const props = { + helperText: "This is a helper text", + label: "Continuous Field", + onFieldChange: () => {}, +}; + +describe("ContinuousField", () => { + it("Displays a MUI Textfield with the label passed as a prop", () => { + cy.mount(); + cy.get('[data-cy="Continuous Field-continuous-field"]').should("be.visible"); + cy.get('[data-cy="Continuous Field-continuous-field"] label').should("contain", "Continuous Field"); + cy.get('[data-cy="Continuous Field-continuous-field"] label').should("not.have.class", "MUI-error"); + }) + it("Displays a MUI Textfield in error state with the helper text passed as a prop", () => { + cy.mount(); + cy.get('[data-cy="Continuous Field-continuous-field"] p').should("contain", "This is a helper text"); + cy.get('[data-cy="Continuous Field-continuous-field"] label').should("have.class", "MUI-error"); + }) + it("Fires onFieldChange event handler with the appropriate payload when a value is entered", () => { + const onFieldChange = cy.spy().as("onFieldChange"); + cy.mount(); + cy.get('[data-cy="Continuous Field-continuous-field"]').type("10"); + cy.get('@onFieldChange').should("have.been.calledWith", "Continuous Field", 10); + }) +}) \ No newline at end of file From 9b163dd09811eba6aa070f73e7336bdf1a805ac3 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Mon, 19 Feb 2024 15:47:47 -0500 Subject: [PATCH 04/26] Implemented `DownloadResultButton` component test --- cypress/component/DownloadResultButton.cy.tsx | 28 +++++++++++++++++++ src/components/DownloadResultButton.tsx | 4 +-- src/components/ResultContainer.tsx | 4 +-- 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 cypress/component/DownloadResultButton.cy.tsx diff --git a/cypress/component/DownloadResultButton.cy.tsx b/cypress/component/DownloadResultButton.cy.tsx new file mode 100644 index 00000000..f01fac10 --- /dev/null +++ b/cypress/component/DownloadResultButton.cy.tsx @@ -0,0 +1,28 @@ +import DownloadResultButton from "../../src/components/DownloadResultButton"; + +const props = { + identifier: "test", + disabled: false, + handleClick: () => {}, +}; + +describe("DownloadResultButton", () => { + it("Displays an enabled MUI Button with the identifier passed as prop", () => { + cy.mount(); + cy.get('[data-cy="test-download-results-button"]').should("be.visible"); + cy.get('[data-cy="test-download-results-button"]').should("contain", "Download test Result"); + cy.get('[data-cy="test-download-results-button"]').should("not.be", "disabled"); + }) + it("Displays a disabled MUI Button and a tooltip when the button is hovered over", () => { + cy.mount(); + cy.get('[data-cy="test-download-results-button"]').trigger('mouseover', {force: true}); + cy.get('.MUITooltip-tooltip').should("contain", "Please select at least one dataset"); + }) + it("Fires the handleClick event handler with the appropriate payload when the button is clicked", () => { + const handleClick = cy.spy().as("handleClick"); + cy.mount(); + cy.get('[data-cy="test-download-results-button"]').click(); + cy.get('@handleClick').should("have.been.calledWith", "test"); + }) + +}) \ No newline at end of file diff --git a/src/components/DownloadResultButton.tsx b/src/components/DownloadResultButton.tsx index 0a7524a7..3e9cfbb3 100644 --- a/src/components/DownloadResultButton.tsx +++ b/src/components/DownloadResultButton.tsx @@ -8,14 +8,14 @@ function DownloadResultButton({ }: { identifier: string; disabled: boolean; - handleClick: () => void; + handleClick: (identifier: string) => void; }) { const button = ( setOpenModal(false)} /> From f7679a093f55a56df2ee31c2f126fa1b67d25454 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Wed, 21 Feb 2024 14:47:07 -0500 Subject: [PATCH 19/26] Fixed the issue with displaying error for an empty continuous field --- src/components/ContinuousField.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ContinuousField.tsx b/src/components/ContinuousField.tsx index f2b685b0..3f724f7a 100644 --- a/src/components/ContinuousField.tsx +++ b/src/components/ContinuousField.tsx @@ -3,7 +3,7 @@ import TextField from '@mui/material/TextField'; export interface ContinuousFieldProps { helperText?: string; label: string; - onFieldChange: (fieldLabel: string, value: number) => void; + onFieldChange: (fieldLabel: string, value: number | null) => void; } function ContinuousField({ helperText, label, onFieldChange }: ContinuousFieldProps) { @@ -14,7 +14,7 @@ function ContinuousField({ helperText, label, onFieldChange }: ContinuousFieldPr error={showError} label={label} className="w-full" - onChange={(event) => onFieldChange(label, parseInt(event.target.value, 10))} + onChange={(event) => onFieldChange(label, event.target.value === '' ? null : parseInt(event.target.value, 10))} helperText={helperText} /> ); From 2bedd0f8c480bf266cab0880a136a9fdc250f1ca Mon Sep 17 00:00:00 2001 From: rmanaem Date: Wed, 21 Feb 2024 17:34:47 -0500 Subject: [PATCH 20/26] Implemented `Form` e2e test --- cypress/e2e/Form.cy.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 cypress/e2e/Form.cy.ts diff --git a/cypress/e2e/Form.cy.ts b/cypress/e2e/Form.cy.ts new file mode 100644 index 00000000..f7397aec --- /dev/null +++ b/cypress/e2e/Form.cy.ts @@ -0,0 +1,31 @@ +describe('App', () => { + it('Validates input to continuous field, displays the appropriate error, and disables the submit query button', () => { + cy.visit('/'); + cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); + cy.get('[data-cy="Minimum age-continuous-field"]').type('some text'); + cy.get('[data-cy="Minimum age-continuous-field"] p').should('be.visible').should('contain', 'Please enter a valid number!'); + cy.get('[data-cy="submit-query-button"]').should('be.disabled'); + cy.get('[data-cy="Minimum age-continuous-field"] input').clear(); + cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); + cy.get('[data-cy="Minimum age-continuous-field"]').type('-10'); + cy.get('[data-cy="Minimum age-continuous-field"] p').should('be.visible').should('contain', 'Please enter a positive number!'); + cy.get('[data-cy="submit-query-button"]').should('be.disabled'); + }); + it("Disables the diagnosis field if healthy control checkbox is checked", () => { + cy.intercept({ + method: 'GET', + url: '/attributes/nb:Diagnosis', + }).as('getDiagnosisOptions'); + cy.visit('/'); + cy.wait('@getDiagnosisOptions'); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('not.be.disabled'); + cy.get('[data-cy="Diagnosis-categorical-field"]').type('parkin{downarrow}{enter}'); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('have.value', 'Parkinson\'s disease'); + cy.get('[data-cy="healthy-control-checkbox"]').click(); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('be.disabled'); + cy.get('[data-cy="healthy-control-checkbox"]').click(); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('not.be.disabled'); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('have.value', 'Parkinson\'s disease'); + }) + }); + \ No newline at end of file From 0a5d1fbc7e108545ca0b73a6bff308487f05b509 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Wed, 21 Feb 2024 17:35:20 -0500 Subject: [PATCH 21/26] Updated `component-test` workflow trigger event --- .github/workflows/component-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/component-test.yaml b/.github/workflows/component-test.yaml index 9314a2df..f0436f7e 100644 --- a/.github/workflows/component-test.yaml +++ b/.github/workflows/component-test.yaml @@ -3,7 +3,7 @@ name: component tests on: push: branches: - - maint-20 + - main pull_request: workflow_dispatch: From c09bfa80be9ad4b56431bfa647e937c59105892e Mon Sep 17 00:00:00 2001 From: rmanaem Date: Wed, 21 Feb 2024 17:43:57 -0500 Subject: [PATCH 22/26] Ran prettier --- cypress/component/CategoricalField.cy.tsx | 101 ++++--- cypress/component/ContinuousField.cy.tsx | 61 ++-- cypress/component/DownloadResultButton.cy.tsx | 65 ++-- cypress/component/NBDialog.cy.tsx | 45 +-- cypress/component/Navbar.cy.tsx | 37 ++- cypress/component/QueryForm.cy.tsx | 279 +++++++++--------- cypress/component/ResultCard.cy.tsx | 86 ++++-- cypress/component/ResultContainer.cy.tsx | 107 ++++--- cypress/e2e/Form.cy.ts | 67 +++-- src/components/ContinuousField.tsx | 4 +- src/components/DownloadResultButton.tsx | 2 +- src/components/QueryForm.tsx | 2 +- src/components/ResultContainer.tsx | 10 +- 13 files changed, 509 insertions(+), 357 deletions(-) diff --git a/cypress/component/CategoricalField.cy.tsx b/cypress/component/CategoricalField.cy.tsx index c22268d1..d9b0aae3 100644 --- a/cypress/component/CategoricalField.cy.tsx +++ b/cypress/component/CategoricalField.cy.tsx @@ -1,38 +1,71 @@ -import CategoricalField from "../../src/components/CategoricalField"; +import CategoricalField from '../../src/components/CategoricalField'; const props = { - label: "Categorical Field", - options: [ - { id: "1", label: "Option 1" }, - { id: "2", label: "Option 2" }, - { id: "3", label: "Option 3" }, - ], - onFieldChange: () => {}, - multiple: false, - inputValue: null, + label: 'Categorical Field', + options: [ + { id: '1', label: 'Option 1' }, + { id: '2', label: 'Option 2' }, + { id: '3', label: 'Option 3' }, + ], + onFieldChange: () => {}, + multiple: false, + inputValue: null, }; -describe("CategoricalField", () => { - it("Displays a MUI Autocomplete with the label and options passed as props", () => { - cy.mount(); - cy.get('[data-cy="Categorical Field-categorical-field"]').should("be.visible") - cy.get('[data-cy="Categorical Field-categorical-field"] label').should("contain", "Categorical Field") - props.options.forEach((option) => { - cy.get('[data-cy="Categorical Field-categorical-field"]').type(`${option.label}{downarrow}{enter}`) - cy.get('[data-cy="Categorical Field-categorical-field"] input').should("have.value", option.label); - cy.get('[data-cy="Categorical Field-categorical-field"]').clear(); - - }) - }) - it("Displays the input value passed as props", () => { - cy.mount(); - cy.get('[data-cy="Categorical Field-categorical-field"] input').should("have.value", "Option 1") - - }) - it("Fires onFieldChange event handler with the appropriate payload when a value is selected", () => { - const onFieldChange = cy.spy().as("onFieldChange"); - cy.mount(); - cy.get('[data-cy="Categorical Field-categorical-field"]').type("Option 1{downarrow}{enter}") - cy.get('@onFieldChange').should("have.been.calledWith", "Categorical Field", {id: "1", label: "Option 1"}); - }) -}) \ No newline at end of file +describe('CategoricalField', () => { + it('Displays a MUI Autocomplete with the label and options passed as props', () => { + cy.mount( + + ); + cy.get('[data-cy="Categorical Field-categorical-field"]').should('be.visible'); + cy.get('[data-cy="Categorical Field-categorical-field"] label').should( + 'contain', + 'Categorical Field' + ); + props.options.forEach((option) => { + cy.get('[data-cy="Categorical Field-categorical-field"]').type( + `${option.label}{downarrow}{enter}` + ); + cy.get('[data-cy="Categorical Field-categorical-field"] input').should( + 'have.value', + option.label + ); + cy.get('[data-cy="Categorical Field-categorical-field"]').clear(); + }); + }); + it('Displays the input value passed as props', () => { + cy.mount( + + ); + cy.get('[data-cy="Categorical Field-categorical-field"] input').should( + 'have.value', + 'Option 1' + ); + }); + it('Fires onFieldChange event handler with the appropriate payload when a value is selected', () => { + const onFieldChange = cy.spy().as('onFieldChange'); + cy.mount( + + ); + cy.get('[data-cy="Categorical Field-categorical-field"]').type('Option 1{downarrow}{enter}'); + cy.get('@onFieldChange').should('have.been.calledWith', 'Categorical Field', { + id: '1', + label: 'Option 1', + }); + }); +}); diff --git a/cypress/component/ContinuousField.cy.tsx b/cypress/component/ContinuousField.cy.tsx index db20bc9d..b13fe760 100644 --- a/cypress/component/ContinuousField.cy.tsx +++ b/cypress/component/ContinuousField.cy.tsx @@ -1,27 +1,42 @@ -import ContinuousField from "../../src/components/ContinuousField"; +import ContinuousField from '../../src/components/ContinuousField'; const props = { - helperText: "This is a helper text", - label: "Continuous Field", - onFieldChange: () => {}, + helperText: 'This is a helper text', + label: 'Continuous Field', + onFieldChange: () => {}, }; -describe("ContinuousField", () => { - it("Displays a MUI Textfield with the label passed as a prop", () => { - cy.mount(); - cy.get('[data-cy="Continuous Field-continuous-field"]').should("be.visible"); - cy.get('[data-cy="Continuous Field-continuous-field"] label').should("contain", "Continuous Field"); - cy.get('[data-cy="Continuous Field-continuous-field"] label').should("not.have.class", "Mui-error"); - }) - it("Displays a MUI Textfield in error state with the helper text passed as a prop", () => { - cy.mount(); - cy.get('[data-cy="Continuous Field-continuous-field"] p').should("contain", "This is a helper text"); - cy.get('[data-cy="Continuous Field-continuous-field"] label').should("have.class", "Mui-error"); - }) - it("Fires onFieldChange event handler with the appropriate payload when a value is entered", () => { - const onFieldChange = cy.spy().as("onFieldChange"); - cy.mount(); - cy.get('[data-cy="Continuous Field-continuous-field"]').type("10"); - cy.get('@onFieldChange').should("have.been.calledWith", "Continuous Field", 10); - }) -}) \ No newline at end of file +describe('ContinuousField', () => { + it('Displays a MUI Textfield with the label passed as a prop', () => { + cy.mount(); + cy.get('[data-cy="Continuous Field-continuous-field"]').should('be.visible'); + cy.get('[data-cy="Continuous Field-continuous-field"] label').should( + 'contain', + 'Continuous Field' + ); + cy.get('[data-cy="Continuous Field-continuous-field"] label').should( + 'not.have.class', + 'Mui-error' + ); + }); + it('Displays a MUI Textfield in error state with the helper text passed as a prop', () => { + cy.mount( + + ); + cy.get('[data-cy="Continuous Field-continuous-field"] p').should( + 'contain', + 'This is a helper text' + ); + cy.get('[data-cy="Continuous Field-continuous-field"] label').should('have.class', 'Mui-error'); + }); + it('Fires onFieldChange event handler with the appropriate payload when a value is entered', () => { + const onFieldChange = cy.spy().as('onFieldChange'); + cy.mount(); + cy.get('[data-cy="Continuous Field-continuous-field"]').type('10'); + cy.get('@onFieldChange').should('have.been.calledWith', 'Continuous Field', 10); + }); +}); diff --git a/cypress/component/DownloadResultButton.cy.tsx b/cypress/component/DownloadResultButton.cy.tsx index cd963e24..779899d7 100644 --- a/cypress/component/DownloadResultButton.cy.tsx +++ b/cypress/component/DownloadResultButton.cy.tsx @@ -1,28 +1,45 @@ -import DownloadResultButton from "../../src/components/DownloadResultButton"; +import DownloadResultButton from '../../src/components/DownloadResultButton'; const props = { - identifier: "test", - disabled: false, - handleClick: () => {}, + identifier: 'test', + disabled: false, + handleClick: () => {}, }; -describe("DownloadResultButton", () => { - it("Displays an enabled MUI Button with the identifier passed as prop", () => { - cy.mount(); - cy.get('[data-cy="test-download-results-button"]').should("be.visible"); - cy.get('[data-cy="test-download-results-button"]').should("contain", "Download test Result"); - cy.get('[data-cy="test-download-results-button"]').should("not.be", "disabled"); - }) - it("Displays a disabled MUI Button and a tooltip when the button is hovered over", () => { - cy.mount(); - cy.get('[data-cy="test-download-results-button"]').trigger('mouseover', {force: true}); - cy.get('.MuiTooltip-tooltip').should("contain", "Please select at least one dataset"); - }) - it("Fires the handleClick event handler with the appropriate payload when the button is clicked", () => { - const handleClick = cy.spy().as("handleClick"); - cy.mount(); - cy.get('[data-cy="test-download-results-button"]').click(); - cy.get('@handleClick').should("have.been.calledWith", "test"); - }) - -}) \ No newline at end of file +describe('DownloadResultButton', () => { + it('Displays an enabled MUI Button with the identifier passed as prop', () => { + cy.mount( + + ); + cy.get('[data-cy="test-download-results-button"]').should('be.visible'); + cy.get('[data-cy="test-download-results-button"]').should('contain', 'Download test Result'); + cy.get('[data-cy="test-download-results-button"]').should('not.be', 'disabled'); + }); + it('Displays a disabled MUI Button and a tooltip when the button is hovered over', () => { + cy.mount( + + ); + cy.get('[data-cy="test-download-results-button"]').trigger('mouseover', { force: true }); + cy.get('.MuiTooltip-tooltip').should('contain', 'Please select at least one dataset'); + }); + it('Fires the handleClick event handler with the appropriate payload when the button is clicked', () => { + const handleClick = cy.spy().as('handleClick'); + cy.mount( + + ); + cy.get('[data-cy="test-download-results-button"]').click(); + cy.get('@handleClick').should('have.been.calledWith', 'test'); + }); +}); diff --git a/cypress/component/NBDialog.cy.tsx b/cypress/component/NBDialog.cy.tsx index 6021b7ab..199c7712 100644 --- a/cypress/component/NBDialog.cy.tsx +++ b/cypress/component/NBDialog.cy.tsx @@ -1,25 +1,28 @@ -import NBDialog from "../../src/components/NBDialog"; +import NBDialog from '../../src/components/NBDialog'; const props = { - open: true, - onClose: () => {}, + open: true, + onClose: () => {}, }; -describe("NBDialog", () => { - it("Displays a MUI Diaglog with the title and content", () => { - cy.mount(); - cy.get('[data-cy="nb-dialog"]').should("be.visible"); - cy.get('[data-cy="nb-dialog"] h2').should("contain", "Example usage"); - cy.get('[data-cy="nb-dialog"] p').should("contain", "The command for automatically getting the data currently only applies to datasets available through datalad."); - }) - it("Doesn't display the dialog when open prop is set to false", () => { - cy.mount(); - cy.get('[data-cy="nb-dialog"]').should("not.exist"); - }) - it("Fires onClose event handler when the close button is clicked", () => { - const onClose = cy.spy().as("onClose"); - cy.mount(); - cy.get('[data-cy="nb-dialog"] button').click(); - cy.get('@onClose').should("have.been.called"); - }) -}) \ No newline at end of file +describe('NBDialog', () => { + it('Displays a MUI Diaglog with the title and content', () => { + cy.mount(); + cy.get('[data-cy="nb-dialog"]').should('be.visible'); + cy.get('[data-cy="nb-dialog"] h2').should('contain', 'Example usage'); + cy.get('[data-cy="nb-dialog"] p').should( + 'contain', + 'The command for automatically getting the data currently only applies to datasets available through datalad.' + ); + }); + it("Doesn't display the dialog when open prop is set to false", () => { + cy.mount(); + cy.get('[data-cy="nb-dialog"]').should('not.exist'); + }); + it('Fires onClose event handler when the close button is clicked', () => { + const onClose = cy.spy().as('onClose'); + cy.mount(); + cy.get('[data-cy="nb-dialog"] button').click(); + cy.get('@onClose').should('have.been.called'); + }); +}); diff --git a/cypress/component/Navbar.cy.tsx b/cypress/component/Navbar.cy.tsx index c88d90f4..aeec72b9 100644 --- a/cypress/component/Navbar.cy.tsx +++ b/cypress/component/Navbar.cy.tsx @@ -1,14 +1,25 @@ -import Navbar from "../../src/components/Navbar"; +import Navbar from '../../src/components/Navbar'; -describe("Navbar", () => { - it("Displays a MUI Toolbar with logo, title, subtitle, documentation link, and GitHub link", () => { - cy.mount(); - cy.get("[data-cy='navbar']").should("be.visible"); - cy.get("[data-cy='navbar'] img").should("have.attr", "src", "https://raw.githubusercontent.com/neurobagel/documentation/main/docs/imgs/logo/neurobagel_logo.png"); - cy.get("[data-cy='navbar'] h5").should("contain", "Neurobagel Query"); - cy.get("[data-cy='navbar'] p").should("contain", "Define and find cohorts at the subject level"); - cy.get("[data-cy='navbar'] a").should("contain", "Documentation").should("have.attr", "href", "https://neurobagel.org/query_tool/"); - cy.get("[data-cy='navbar'] a").eq(1).find('svg').should("be.visible"); - cy.get("[data-cy='navbar'] a").eq(1).should("have.attr", "href", "https://github.com/neurobagel/react-query-tool/"); - }) -}) \ No newline at end of file +describe('Navbar', () => { + it('Displays a MUI Toolbar with logo, title, subtitle, documentation link, and GitHub link', () => { + cy.mount(); + cy.get("[data-cy='navbar']").should('be.visible'); + cy.get("[data-cy='navbar'] img").should( + 'have.attr', + 'src', + 'https://raw.githubusercontent.com/neurobagel/documentation/main/docs/imgs/logo/neurobagel_logo.png' + ); + cy.get("[data-cy='navbar'] h5").should('contain', 'Neurobagel Query'); + cy.get("[data-cy='navbar'] p").should( + 'contain', + 'Define and find cohorts at the subject level' + ); + cy.get("[data-cy='navbar'] a") + .should('contain', 'Documentation') + .should('have.attr', 'href', 'https://neurobagel.org/query_tool/'); + cy.get("[data-cy='navbar'] a").eq(1).find('svg').should('be.visible'); + cy.get("[data-cy='navbar'] a") + .eq(1) + .should('have.attr', 'href', 'https://github.com/neurobagel/react-query-tool/'); + }); +}); diff --git a/cypress/component/QueryForm.cy.tsx b/cypress/component/QueryForm.cy.tsx index de968938..c6039d5a 100644 --- a/cypress/component/QueryForm.cy.tsx +++ b/cypress/component/QueryForm.cy.tsx @@ -1,35 +1,35 @@ -import QueryForm from "../../src/components/QueryForm"; +import QueryForm from '../../src/components/QueryForm'; const props = { -availableNodes: [ - { - NodeName: "Some Node Name", - ApiURL: "https://someurl/", - }, - { - NodeName: "Another Node Name", - ApiURL: "http://anotherurl/", - }, - ], + availableNodes: [ + { + NodeName: 'Some Node Name', + ApiURL: 'https://someurl/', + }, + { + NodeName: 'Another Node Name', + ApiURL: 'http://anotherurl/', + }, + ], diagnosisOptions: [ - { - Label: "Some Diagnosis", - TermURL: "https://someurl/", - }, - { - Label: "Another Diagnosis", - TermURL: "http://anotherurl/", - }, + { + Label: 'Some Diagnosis', + TermURL: 'https://someurl/', + }, + { + Label: 'Another Diagnosis', + TermURL: 'http://anotherurl/', + }, ], assessmentOptions: [ { - Label: "Some Assessment", - TermURL: "https://someurl/", + Label: 'Some Assessment', + TermURL: 'https://someurl/', }, { - Label: "Another Assessment", - TermURL: "http://anotherurl/", - } + Label: 'Another Assessment', + TermURL: 'http://anotherurl/', + }, ], selectedNode: [], minAge: null, @@ -45,118 +45,123 @@ availableNodes: [ updateContinuousQueryParams: () => {}, loading: false, onSubmitQuery: () => {}, -} - -describe("QueryForm", () => { - it("Displays a set of fields for user input and a button for submitting query", () => { - cy.mount( - ); - cy.get('[data-cy="Neurobagel graph-categorical-field"]').should("be.visible"); - cy.get('[data-cy="Minimum age-continuous-field"]').should("be.visible"); - cy.get('[data-cy="Maximum age-continuous-field"]').should("be.visible"); - cy.get('[data-cy="Neurobagel graph-categorical-field"]').should("be.visible"); - cy.get('[data-cy="Sex-categorical-field"]').should("be.visible"); - cy.get('[data-cy="Diagnosis-categorical-field"]').should("be.visible"); - cy.get('[data-cy="healthy-control-checkbox"]').should("be.visible"); - cy.get('[data-cy="Minimum number of sessions-continuous-field"]').should("be.visible"); - cy.get('[data-cy="Assessment tool-categorical-field"]').should("be.visible"); - cy.get('[data-cy="Imaging modality-categorical-field"]').should("be.visible"); - cy.get('[data-cy="submit-query-button"]').should("be.visible"); - }) - it("Fires updateCategoricalQueryParams event handler with the appropriate payload when a categorical field is selected", () => { - const updateCategoricalQueryParams = cy.spy().as("updateCategoricalQueryParams"); - cy.mount( - ); - - cy.get('[data-cy="Diagnosis-categorical-field"]').type("Some{downarrow}{enter}"); - cy.get('@updateCategoricalQueryParams').should("have.been.calledWith", "Diagnosis", {id: "https://someurl/", label: "Some Diagnosis"}); +}; - }) - it("Fires updateContinuousQueryParams event handler with the appropriate payload when a continuous field is selected", () => { - const updateContinuousQueryParams = cy.spy().as("updateContinuousQueryParams"); - cy.mount( - ); - cy.get('[data-cy="Minimum age-continuous-field"]').type("10"); - cy.get('@updateContinuousQueryParams').should("have.been.calledWith", "Minimum age", 10); - }) - it("Fires the onSubmitQuery event handler when the submit button is clicked", () => { - const onSubmitQuery = cy.spy().as("onSubmitQuery"); - cy.mount( - ); - cy.get('[data-cy="submit-query-button"]').click(); - cy.get('@onSubmitQuery').should("have.been.called"); - }) +describe('QueryForm', () => { + it('Displays a set of fields for user input and a button for submitting query', () => { + cy.mount( + + ); + cy.get('[data-cy="Neurobagel graph-categorical-field"]').should('be.visible'); + cy.get('[data-cy="Minimum age-continuous-field"]').should('be.visible'); + cy.get('[data-cy="Maximum age-continuous-field"]').should('be.visible'); + cy.get('[data-cy="Neurobagel graph-categorical-field"]').should('be.visible'); + cy.get('[data-cy="Sex-categorical-field"]').should('be.visible'); + cy.get('[data-cy="Diagnosis-categorical-field"]').should('be.visible'); + cy.get('[data-cy="healthy-control-checkbox"]').should('be.visible'); + cy.get('[data-cy="Minimum number of sessions-continuous-field"]').should('be.visible'); + cy.get('[data-cy="Assessment tool-categorical-field"]').should('be.visible'); + cy.get('[data-cy="Imaging modality-categorical-field"]').should('be.visible'); + cy.get('[data-cy="submit-query-button"]').should('be.visible'); + }); + it('Fires updateCategoricalQueryParams event handler with the appropriate payload when a categorical field is selected', () => { + const updateCategoricalQueryParams = cy.spy().as('updateCategoricalQueryParams'); + cy.mount( + + ); -}) \ No newline at end of file + cy.get('[data-cy="Diagnosis-categorical-field"]').type('Some{downarrow}{enter}'); + cy.get('@updateCategoricalQueryParams').should('have.been.calledWith', 'Diagnosis', { + id: 'https://someurl/', + label: 'Some Diagnosis', + }); + }); + it('Fires updateContinuousQueryParams event handler with the appropriate payload when a continuous field is selected', () => { + const updateContinuousQueryParams = cy.spy().as('updateContinuousQueryParams'); + cy.mount( + + ); + cy.get('[data-cy="Minimum age-continuous-field"]').type('10'); + cy.get('@updateContinuousQueryParams').should('have.been.calledWith', 'Minimum age', 10); + }); + it('Fires the onSubmitQuery event handler when the submit button is clicked', () => { + const onSubmitQuery = cy.spy().as('onSubmitQuery'); + cy.mount( + + ); + cy.get('[data-cy="submit-query-button"]').click(); + cy.get('@onSubmitQuery').should('have.been.called'); + }); +}); diff --git a/cypress/component/ResultCard.cy.tsx b/cypress/component/ResultCard.cy.tsx index 62ed0e16..52cb79db 100644 --- a/cypress/component/ResultCard.cy.tsx +++ b/cypress/component/ResultCard.cy.tsx @@ -1,31 +1,61 @@ -import ResultCard from "../../src/components/ResultCard"; +import ResultCard from '../../src/components/ResultCard'; const props = { - nodeName: "some node name", - datasetUUID: "some uuid", - datasetName: "some dataset name", - datasetTotalSubjects: 10, - numMatchingSubjects: 5, - imageModals: ["http://purl.org/nidash/nidm#ArterialSpinLabeling", "http://purl.org/nidash/nidm#DiffusionWeighted"], - checked: true, - onCheckboxChange: () => {}, -} + nodeName: 'some node name', + datasetUUID: 'some uuid', + datasetName: 'some dataset name', + datasetTotalSubjects: 10, + numMatchingSubjects: 5, + imageModals: [ + 'http://purl.org/nidash/nidm#ArterialSpinLabeling', + 'http://purl.org/nidash/nidm#DiffusionWeighted', + ], + checked: true, + onCheckboxChange: () => {}, +}; -describe("ResultCard", () => { - it("Displays a MUI card with node name, dataset name, number of matched subjects, total number of subjects, and a checkbox", () => { - cy.mount(); - cy.get('[data-cy="card-some uuid"]').should("be.visible"); - cy.get('[data-cy="card-some uuid"]').should("contain", "some dataset name"); - cy.get('[data-cy="card-some uuid"]').should("contain", "from some node name"); - cy.get('[data-cy="card-some uuid"]').should("contain", "5 subjects match / 10 total subjects"); - cy.get('[data-cy="card-some uuid-checkbox"] input').should("be.checked"); - cy.get('[data-cy="card-some uuid"] button').should("contain", "ASL").should("have.class", "bg-zinc-800"); - cy.get('[data-cy="card-some uuid"] button').eq(1).should("contain", "DWI").should("have.class", "bg-red-700"); - }) - it("Fires onCheckboxChange event handler with the appropriate payload when the checkbox is clicked", () => { - const onCheckboxChange = cy.spy().as("onCheckboxChange"); - cy.mount(); - cy.get('[data-cy="card-some uuid-checkbox"] input').check(); - cy.get("@onCheckboxChange").should("have.been.calledWith", props.datasetUUID); - }) -}) \ No newline at end of file +describe('ResultCard', () => { + it('Displays a MUI card with node name, dataset name, number of matched subjects, total number of subjects, and a checkbox', () => { + cy.mount( + + ); + cy.get('[data-cy="card-some uuid"]').should('be.visible'); + cy.get('[data-cy="card-some uuid"]').should('contain', 'some dataset name'); + cy.get('[data-cy="card-some uuid"]').should('contain', 'from some node name'); + cy.get('[data-cy="card-some uuid"]').should('contain', '5 subjects match / 10 total subjects'); + cy.get('[data-cy="card-some uuid-checkbox"] input').should('be.checked'); + cy.get('[data-cy="card-some uuid"] button') + .should('contain', 'ASL') + .should('have.class', 'bg-zinc-800'); + cy.get('[data-cy="card-some uuid"] button') + .eq(1) + .should('contain', 'DWI') + .should('have.class', 'bg-red-700'); + }); + it('Fires onCheckboxChange event handler with the appropriate payload when the checkbox is clicked', () => { + const onCheckboxChange = cy.spy().as('onCheckboxChange'); + cy.mount( + + ); + cy.get('[data-cy="card-some uuid-checkbox"] input').check(); + cy.get('@onCheckboxChange').should('have.been.calledWith', props.datasetUUID); + }); +}); diff --git a/cypress/component/ResultContainer.cy.tsx b/cypress/component/ResultContainer.cy.tsx index b57c6c6a..07d845f2 100644 --- a/cypress/component/ResultContainer.cy.tsx +++ b/cypress/component/ResultContainer.cy.tsx @@ -1,45 +1,66 @@ -import ResultContainer from "../../src/components/ResultContainer"; +import ResultContainer from '../../src/components/ResultContainer'; import { protectedResponse2 } from '../fixtures/mocked-responses'; -describe("ResultContainer", () => { - it("Displays a set of Result Cards, select all checkbox, disabled download result buttons, summary stats, and how to get data modal button", () => { - cy.mount(); - cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset"]').should("be.visible"); - cy.get('[data-cy="card-http://neurobagel.org/vocab/not-so-cool-dataset"]').should("be.visible"); - cy.get('[data-cy="select-all-checkbox"]').should("be.visible"); - cy.get('[data-cy="summary-stats"]').should("be.visible").should("contain", "Summary stats: 2 datasets, 4 subjects"); - cy.get('[data-cy="participant-level-download-results-button"]').should("be.visible").should("be.disabled"); - cy.get('[data-cy="dataset-level-download-results-button"]').should("be.visible").should("be.disabled"); - cy.get('[data-cy="how-to-get-data-modal-button"]').should("be.visible"); - }); - it('Selecting a dataset should enable the download result buttons', () => { - cy.mount(); - cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"] input').check(); - cy.get('[data-cy="participant-level-download-results-button"]').should("be.visible").should("not.be.disabled"); - cy.get('[data-cy="dataset-level-download-results-button"]').should("be.visible").should("not.be.disabled") - }); - it("Selecting/unselecting select all datasets checkbox should check/uncheck all dataset cards", () => { - cy.mount(); - cy.get('[data-cy="select-all-checkbox"] input').check(); - cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"] input').should("be.checked"); - cy.get('[data-cy="card-http://neurobagel.org/vocab/not-so-cool-dataset-checkbox"] input').should("be.checked"); - cy.get('[data-cy="select-all-checkbox"] input').uncheck(); - cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"] input').should("not.be.checked"); - cy.get('[data-cy="card-http://neurobagel.org/vocab/not-so-cool-dataset-checkbox"] input').should("not.be.checked"); - }); - it("Clicking the how to get data modal button should open the modal", () => { - cy.mount(); - cy.get('[data-cy="nb-dialog"]').should("not.exist"); - cy.get('[data-cy="how-to-get-data-modal-button"]').click(); - cy.get('[data-cy="nb-dialog"]').should("be.visible"); - }); - it("Shows no result view when result is empty", () => { - cy.mount(); - cy.get('[data-cy="empty-result-container-view"]').should("be.visible").should("contain", "No results"); - }) - it("Shows Click Submit Query view when result is null", () => { - cy.mount(); - cy.get('[data-cy="default-result-container-view"]').should("be.visible").should("contain", "Click 'Submit Query' for results"); - }) - -}) \ No newline at end of file +describe('ResultContainer', () => { + it('Displays a set of Result Cards, select all checkbox, disabled download result buttons, summary stats, and how to get data modal button', () => { + cy.mount(); + cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset"]').should('be.visible'); + cy.get('[data-cy="card-http://neurobagel.org/vocab/not-so-cool-dataset"]').should('be.visible'); + cy.get('[data-cy="select-all-checkbox"]').should('be.visible'); + cy.get('[data-cy="summary-stats"]') + .should('be.visible') + .should('contain', 'Summary stats: 2 datasets, 4 subjects'); + cy.get('[data-cy="participant-level-download-results-button"]') + .should('be.visible') + .should('be.disabled'); + cy.get('[data-cy="dataset-level-download-results-button"]') + .should('be.visible') + .should('be.disabled'); + cy.get('[data-cy="how-to-get-data-modal-button"]').should('be.visible'); + }); + it('Selecting a dataset should enable the download result buttons', () => { + cy.mount(); + cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"] input').check(); + cy.get('[data-cy="participant-level-download-results-button"]') + .should('be.visible') + .should('not.be.disabled'); + cy.get('[data-cy="dataset-level-download-results-button"]') + .should('be.visible') + .should('not.be.disabled'); + }); + it('Selecting/unselecting select all datasets checkbox should check/uncheck all dataset cards', () => { + cy.mount(); + cy.get('[data-cy="select-all-checkbox"] input').check(); + cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"] input').should( + 'be.checked' + ); + cy.get( + '[data-cy="card-http://neurobagel.org/vocab/not-so-cool-dataset-checkbox"] input' + ).should('be.checked'); + cy.get('[data-cy="select-all-checkbox"] input').uncheck(); + cy.get('[data-cy="card-http://neurobagel.org/vocab/cool-dataset-checkbox"] input').should( + 'not.be.checked' + ); + cy.get( + '[data-cy="card-http://neurobagel.org/vocab/not-so-cool-dataset-checkbox"] input' + ).should('not.be.checked'); + }); + it('Clicking the how to get data modal button should open the modal', () => { + cy.mount(); + cy.get('[data-cy="nb-dialog"]').should('not.exist'); + cy.get('[data-cy="how-to-get-data-modal-button"]').click(); + cy.get('[data-cy="nb-dialog"]').should('be.visible'); + }); + it('Shows no result view when result is empty', () => { + cy.mount(); + cy.get('[data-cy="empty-result-container-view"]') + .should('be.visible') + .should('contain', 'No results'); + }); + it('Shows Click Submit Query view when result is null', () => { + cy.mount(); + cy.get('[data-cy="default-result-container-view"]') + .should('be.visible') + .should('contain', "Click 'Submit Query' for results"); + }); +}); diff --git a/cypress/e2e/Form.cy.ts b/cypress/e2e/Form.cy.ts index f7397aec..b39c88b7 100644 --- a/cypress/e2e/Form.cy.ts +++ b/cypress/e2e/Form.cy.ts @@ -1,31 +1,40 @@ describe('App', () => { - it('Validates input to continuous field, displays the appropriate error, and disables the submit query button', () => { - cy.visit('/'); - cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); - cy.get('[data-cy="Minimum age-continuous-field"]').type('some text'); - cy.get('[data-cy="Minimum age-continuous-field"] p').should('be.visible').should('contain', 'Please enter a valid number!'); - cy.get('[data-cy="submit-query-button"]').should('be.disabled'); - cy.get('[data-cy="Minimum age-continuous-field"] input').clear(); - cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); - cy.get('[data-cy="Minimum age-continuous-field"]').type('-10'); - cy.get('[data-cy="Minimum age-continuous-field"] p').should('be.visible').should('contain', 'Please enter a positive number!'); - cy.get('[data-cy="submit-query-button"]').should('be.disabled'); - }); - it("Disables the diagnosis field if healthy control checkbox is checked", () => { - cy.intercept({ - method: 'GET', - url: '/attributes/nb:Diagnosis', - }).as('getDiagnosisOptions'); - cy.visit('/'); - cy.wait('@getDiagnosisOptions'); - cy.get('[data-cy="Diagnosis-categorical-field"] input').should('not.be.disabled'); - cy.get('[data-cy="Diagnosis-categorical-field"]').type('parkin{downarrow}{enter}'); - cy.get('[data-cy="Diagnosis-categorical-field"] input').should('have.value', 'Parkinson\'s disease'); - cy.get('[data-cy="healthy-control-checkbox"]').click(); - cy.get('[data-cy="Diagnosis-categorical-field"] input').should('be.disabled'); - cy.get('[data-cy="healthy-control-checkbox"]').click(); - cy.get('[data-cy="Diagnosis-categorical-field"] input').should('not.be.disabled'); - cy.get('[data-cy="Diagnosis-categorical-field"] input').should('have.value', 'Parkinson\'s disease'); - }) + it('Validates input to continuous field, displays the appropriate error, and disables the submit query button', () => { + cy.visit('/'); + cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); + cy.get('[data-cy="Minimum age-continuous-field"]').type('some text'); + cy.get('[data-cy="Minimum age-continuous-field"] p') + .should('be.visible') + .should('contain', 'Please enter a valid number!'); + cy.get('[data-cy="submit-query-button"]').should('be.disabled'); + cy.get('[data-cy="Minimum age-continuous-field"] input').clear(); + cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); + cy.get('[data-cy="Minimum age-continuous-field"]').type('-10'); + cy.get('[data-cy="Minimum age-continuous-field"] p') + .should('be.visible') + .should('contain', 'Please enter a positive number!'); + cy.get('[data-cy="submit-query-button"]').should('be.disabled'); }); - \ No newline at end of file + it('Disables the diagnosis field if healthy control checkbox is checked', () => { + cy.intercept({ + method: 'GET', + url: '/attributes/nb:Diagnosis', + }).as('getDiagnosisOptions'); + cy.visit('/'); + cy.wait('@getDiagnosisOptions'); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('not.be.disabled'); + cy.get('[data-cy="Diagnosis-categorical-field"]').type('parkin{downarrow}{enter}'); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should( + 'have.value', + "Parkinson's disease" + ); + cy.get('[data-cy="healthy-control-checkbox"]').click(); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('be.disabled'); + cy.get('[data-cy="healthy-control-checkbox"]').click(); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should('not.be.disabled'); + cy.get('[data-cy="Diagnosis-categorical-field"] input').should( + 'have.value', + "Parkinson's disease" + ); + }); +}); diff --git a/src/components/ContinuousField.tsx b/src/components/ContinuousField.tsx index 3f724f7a..4341a02c 100644 --- a/src/components/ContinuousField.tsx +++ b/src/components/ContinuousField.tsx @@ -14,7 +14,9 @@ function ContinuousField({ helperText, label, onFieldChange }: ContinuousFieldPr error={showError} label={label} className="w-full" - onChange={(event) => onFieldChange(label, event.target.value === '' ? null : parseInt(event.target.value, 10))} + onChange={(event) => + onFieldChange(label, event.target.value === '' ? null : parseInt(event.target.value, 10)) + } helperText={helperText} /> ); diff --git a/src/components/DownloadResultButton.tsx b/src/components/DownloadResultButton.tsx index 3e9cfbb3..7c407322 100644 --- a/src/components/DownloadResultButton.tsx +++ b/src/components/DownloadResultButton.tsx @@ -15,7 +15,7 @@ function DownloadResultButton({ data-cy={`${identifier}-download-results-button`} variant="contained" startIcon={} - onClick={() =>handleClick(identifier)} + onClick={() => handleClick(identifier)} disabled={disabled} > Download {identifier} Result diff --git a/src/components/QueryForm.tsx b/src/components/QueryForm.tsx index 38ab2180..4fe08fd7 100644 --- a/src/components/QueryForm.tsx +++ b/src/components/QueryForm.tsx @@ -144,7 +144,7 @@ function QueryForm({
} + control={} label="Healthy Control" onChange={() => setIsControl(!isControl)} /> diff --git a/src/components/ResultContainer.tsx b/src/components/ResultContainer.tsx index 3866aa47..a5af19be 100644 --- a/src/components/ResultContainer.tsx +++ b/src/components/ResultContainer.tsx @@ -185,7 +185,9 @@ function ResultContainer({ result }: { result: Result[] | null }) { />
- {summaryStats} + + {summaryStats} +
{result.map((item) => ( @@ -203,7 +205,11 @@ function ResultContainer({ result }: { result: Result[] | null }) { ))}
- setOpenModal(false)} /> From 481fdccee419e1fd810d4c36e0fe7367e750300e Mon Sep 17 00:00:00 2001 From: rmanaem Date: Wed, 21 Feb 2024 17:47:03 -0500 Subject: [PATCH 23/26] Updated `ResultsTSV` e2e test --- cypress/e2e/ResultsTSV.cy.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cypress/e2e/ResultsTSV.cy.ts b/cypress/e2e/ResultsTSV.cy.ts index 7f942b98..f1cb7e83 100644 --- a/cypress/e2e/ResultsTSV.cy.ts +++ b/cypress/e2e/ResultsTSV.cy.ts @@ -6,7 +6,7 @@ describe('Results TSV', () => { cy.visit('/'); cy.get('[data-cy="submit-query-button"]').click(); cy.wait('@call'); - cy.get('[data-cy="select-all"]').find('input').check(); + cy.get('[data-cy="select-all-checkbox"]').find('input').check(); cy.get('[data-cy="dataset-level-download-results-button"]').click(); cy.readFile('cypress/downloads/dataset-level-results.tsv').should('contain', 'some name'); }); @@ -15,7 +15,7 @@ describe('Results TSV', () => { cy.visit('/'); cy.get('[data-cy="submit-query-button"]').click(); cy.wait('@call'); - cy.get('[data-cy="select-all"]').find('input').check(); + cy.get('[data-cy="select-all-checkbox"]').find('input').check(); cy.get('[data-cy="dataset-level-download-results-button"]').click(); cy.readFile('cypress/downloads/dataset-level-results.tsv').then((fileContent) => { expect(fileContent).to.match(/^DatasetID/); @@ -30,7 +30,7 @@ describe('Results TSV', () => { cy.visit('/'); cy.get('[data-cy="submit-query-button"]').click(); cy.wait('@call'); - cy.get('[data-cy="select-all"]').find('input').check(); + cy.get('[data-cy="select-all-checkbox"]').find('input').check(); cy.get('[data-cy="dataset-level-download-results-button"]').click(); cy.get('[data-cy="participant-level-download-results-button"]').click(); cy.readFile('cypress/downloads/participant-level-results.tsv').then((fileContent) => { From d8d456533c1e39a56755039262c94514530300b2 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Fri, 23 Feb 2024 10:40:56 -0500 Subject: [PATCH 24/26] Refactored tests --- cypress/component/CategoricalField.cy.tsx | 6 +++--- cypress/component/ContinuousField.cy.tsx | 10 +++++----- cypress/component/DownloadResultButton.cy.tsx | 6 +++--- cypress/component/NBDialog.cy.tsx | 6 +++--- cypress/component/QueryForm.cy.tsx | 18 +++++++++--------- cypress/component/ResultCard.cy.tsx | 6 +++--- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cypress/component/CategoricalField.cy.tsx b/cypress/component/CategoricalField.cy.tsx index d9b0aae3..91fccc95 100644 --- a/cypress/component/CategoricalField.cy.tsx +++ b/cypress/component/CategoricalField.cy.tsx @@ -53,17 +53,17 @@ describe('CategoricalField', () => { ); }); it('Fires onFieldChange event handler with the appropriate payload when a value is selected', () => { - const onFieldChange = cy.spy().as('onFieldChange'); + const onFieldChangeSpy = cy.spy().as('onFieldChangeSpy'); cy.mount( ); cy.get('[data-cy="Categorical Field-categorical-field"]').type('Option 1{downarrow}{enter}'); - cy.get('@onFieldChange').should('have.been.calledWith', 'Categorical Field', { + cy.get('@onFieldChangeSpy').should('have.been.calledWith', 'Categorical Field', { id: '1', label: 'Option 1', }); diff --git a/cypress/component/ContinuousField.cy.tsx b/cypress/component/ContinuousField.cy.tsx index b13fe760..04e33f91 100644 --- a/cypress/component/ContinuousField.cy.tsx +++ b/cypress/component/ContinuousField.cy.tsx @@ -7,7 +7,7 @@ const props = { }; describe('ContinuousField', () => { - it('Displays a MUI Textfield with the label passed as a prop', () => { + it('Displays a MUI Textfield and a label as passed via prop', () => { cy.mount(); cy.get('[data-cy="Continuous Field-continuous-field"]').should('be.visible'); cy.get('[data-cy="Continuous Field-continuous-field"] label').should( @@ -19,7 +19,7 @@ describe('ContinuousField', () => { 'Mui-error' ); }); - it('Displays a MUI Textfield in error state with the helper text passed as a prop', () => { + it('Displays a MUI Textfield in error state when the helper text is not empty', () => { cy.mount( { cy.get('[data-cy="Continuous Field-continuous-field"] label').should('have.class', 'Mui-error'); }); it('Fires onFieldChange event handler with the appropriate payload when a value is entered', () => { - const onFieldChange = cy.spy().as('onFieldChange'); - cy.mount(); + const onFieldChangeSpy = cy.spy().as('onFieldChangeSpy'); + cy.mount(); cy.get('[data-cy="Continuous Field-continuous-field"]').type('10'); - cy.get('@onFieldChange').should('have.been.calledWith', 'Continuous Field', 10); + cy.get('@onFieldChangeSpy').should('have.been.calledWith', 'Continuous Field', 10); }); }); diff --git a/cypress/component/DownloadResultButton.cy.tsx b/cypress/component/DownloadResultButton.cy.tsx index 779899d7..457571fe 100644 --- a/cypress/component/DownloadResultButton.cy.tsx +++ b/cypress/component/DownloadResultButton.cy.tsx @@ -31,15 +31,15 @@ describe('DownloadResultButton', () => { cy.get('.MuiTooltip-tooltip').should('contain', 'Please select at least one dataset'); }); it('Fires the handleClick event handler with the appropriate payload when the button is clicked', () => { - const handleClick = cy.spy().as('handleClick'); + const handleClickSpy = cy.spy().as('handleClickSpy'); cy.mount( ); cy.get('[data-cy="test-download-results-button"]').click(); - cy.get('@handleClick').should('have.been.calledWith', 'test'); + cy.get('@handleClickSpy').should('have.been.calledWith', 'test'); }); }); diff --git a/cypress/component/NBDialog.cy.tsx b/cypress/component/NBDialog.cy.tsx index 199c7712..1190f3d5 100644 --- a/cypress/component/NBDialog.cy.tsx +++ b/cypress/component/NBDialog.cy.tsx @@ -20,9 +20,9 @@ describe('NBDialog', () => { cy.get('[data-cy="nb-dialog"]').should('not.exist'); }); it('Fires onClose event handler when the close button is clicked', () => { - const onClose = cy.spy().as('onClose'); - cy.mount(); + const onCloseSpy = cy.spy().as('onCloseSpy'); + cy.mount(); cy.get('[data-cy="nb-dialog"] button').click(); - cy.get('@onClose').should('have.been.called'); + cy.get('@onCloseSpy').should('have.been.called'); }); }); diff --git a/cypress/component/QueryForm.cy.tsx b/cypress/component/QueryForm.cy.tsx index c6039d5a..74a5f33c 100644 --- a/cypress/component/QueryForm.cy.tsx +++ b/cypress/component/QueryForm.cy.tsx @@ -83,7 +83,7 @@ describe('QueryForm', () => { cy.get('[data-cy="submit-query-button"]').should('be.visible'); }); it('Fires updateCategoricalQueryParams event handler with the appropriate payload when a categorical field is selected', () => { - const updateCategoricalQueryParams = cy.spy().as('updateCategoricalQueryParams'); + const updateCategoricalQueryParamsSpy = cy.spy().as('updateCategoricalQueryParamsSpy'); cy.mount( { setIsControl={props.setIsControl} assessmentTool={props.assessmentTool} imagingModality={props.imagingModality} - updateCategoricalQueryParams={updateCategoricalQueryParams} + updateCategoricalQueryParams={updateCategoricalQueryParamsSpy} updateContinuousQueryParams={props.updateContinuousQueryParams} loading={props.loading} onSubmitQuery={props.onSubmitQuery} @@ -107,13 +107,13 @@ describe('QueryForm', () => { ); cy.get('[data-cy="Diagnosis-categorical-field"]').type('Some{downarrow}{enter}'); - cy.get('@updateCategoricalQueryParams').should('have.been.calledWith', 'Diagnosis', { + cy.get('@updateCategoricalQueryParamsSpy').should('have.been.calledWith', 'Diagnosis', { id: 'https://someurl/', label: 'Some Diagnosis', }); }); it('Fires updateContinuousQueryParams event handler with the appropriate payload when a continuous field is selected', () => { - const updateContinuousQueryParams = cy.spy().as('updateContinuousQueryParams'); + const updateContinuousQueryParamsSpy = cy.spy().as('updateContinuousQueryParamsSpy'); cy.mount( { assessmentTool={props.assessmentTool} imagingModality={props.imagingModality} updateCategoricalQueryParams={props.updateCategoricalQueryParams} - updateContinuousQueryParams={updateContinuousQueryParams} + updateContinuousQueryParams={updateContinuousQueryParamsSpy} loading={props.loading} onSubmitQuery={props.onSubmitQuery} /> ); cy.get('[data-cy="Minimum age-continuous-field"]').type('10'); - cy.get('@updateContinuousQueryParams').should('have.been.calledWith', 'Minimum age', 10); + cy.get('@updateContinuousQueryParamsSpy').should('have.been.calledWith', 'Minimum age', 10); }); it('Fires the onSubmitQuery event handler when the submit button is clicked', () => { - const onSubmitQuery = cy.spy().as('onSubmitQuery'); + const onSubmitQuerySpy = cy.spy().as('onSubmitQuerySpy'); cy.mount( { updateCategoricalQueryParams={props.updateCategoricalQueryParams} updateContinuousQueryParams={props.updateContinuousQueryParams} loading={props.loading} - onSubmitQuery={onSubmitQuery} + onSubmitQuery={onSubmitQuerySpy} /> ); cy.get('[data-cy="submit-query-button"]').click(); - cy.get('@onSubmitQuery').should('have.been.called'); + cy.get('@onSubmitQuerySpy').should('have.been.called'); }); }); diff --git a/cypress/component/ResultCard.cy.tsx b/cypress/component/ResultCard.cy.tsx index 52cb79db..a8691a70 100644 --- a/cypress/component/ResultCard.cy.tsx +++ b/cypress/component/ResultCard.cy.tsx @@ -42,7 +42,7 @@ describe('ResultCard', () => { .should('have.class', 'bg-red-700'); }); it('Fires onCheckboxChange event handler with the appropriate payload when the checkbox is clicked', () => { - const onCheckboxChange = cy.spy().as('onCheckboxChange'); + const onCheckboxChangeSpy = cy.spy().as('onCheckboxChangeSpy'); cy.mount( { numMatchingSubjects={props.numMatchingSubjects} imageModals={props.imageModals} checked={false} - onCheckboxChange={onCheckboxChange} + onCheckboxChange={onCheckboxChangeSpy} /> ); cy.get('[data-cy="card-some uuid-checkbox"] input').check(); - cy.get('@onCheckboxChange').should('have.been.calledWith', props.datasetUUID); + cy.get('@onCheckboxChangeSpy').should('have.been.calledWith', props.datasetUUID); }); }); From 45dc8fd110efcd404fc9500fcf3dbcb4b3b6b385 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Fri, 23 Feb 2024 10:47:27 -0500 Subject: [PATCH 25/26] Updated `Form` e2e test Added an assertion for the `Mui-error` class on the helper text --- cypress/e2e/Form.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/Form.cy.ts b/cypress/e2e/Form.cy.ts index b39c88b7..5adb0f4d 100644 --- a/cypress/e2e/Form.cy.ts +++ b/cypress/e2e/Form.cy.ts @@ -5,7 +5,8 @@ describe('App', () => { cy.get('[data-cy="Minimum age-continuous-field"]').type('some text'); cy.get('[data-cy="Minimum age-continuous-field"] p') .should('be.visible') - .should('contain', 'Please enter a valid number!'); + .should('contain', 'Please enter a valid number!') + .should('have.class', 'Mui-error'); cy.get('[data-cy="submit-query-button"]').should('be.disabled'); cy.get('[data-cy="Minimum age-continuous-field"] input').clear(); cy.get('[data-cy="submit-query-button"]').should('not.be.disabled'); From c312006b49144095a001d8d31dbcda90b74b3b4e Mon Sep 17 00:00:00 2001 From: rmanaem Date: Mon, 26 Feb 2024 10:30:21 -0500 Subject: [PATCH 26/26] Update `Navbar` component test --- cypress/component/Navbar.cy.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cypress/component/Navbar.cy.tsx b/cypress/component/Navbar.cy.tsx index aeec72b9..3da9df44 100644 --- a/cypress/component/Navbar.cy.tsx +++ b/cypress/component/Navbar.cy.tsx @@ -4,11 +4,7 @@ describe('Navbar', () => { it('Displays a MUI Toolbar with logo, title, subtitle, documentation link, and GitHub link', () => { cy.mount(); cy.get("[data-cy='navbar']").should('be.visible'); - cy.get("[data-cy='navbar'] img").should( - 'have.attr', - 'src', - 'https://raw.githubusercontent.com/neurobagel/documentation/main/docs/imgs/logo/neurobagel_logo.png' - ); + cy.get("[data-cy='navbar'] img").should('exist'); cy.get("[data-cy='navbar'] h5").should('contain', 'Neurobagel Query'); cy.get("[data-cy='navbar'] p").should( 'contain',