Skip to content

Commit

Permalink
Nickakhmetov/HMP-103 Improve publication cypress tests (#3145)
Browse files Browse the repository at this point in the history
* Ignore `settings.json`, add `default.settings.json`

* bump linting-related dependencies, add typescrip-eslint deps, remove babel

* WIP - adding typescript, updating eslint config

* Expand eslint/prettier config

* Get tsconfig working, adjust swcrc config to allow typescript

* target more file types with eslint formatter

* allow webpack files to import devDependencies

* Apply webpack overrides to entire build-utils folder to cover alias.js as well

* add paths to tsconfig, add optional config to default settings, add autopep8 to recommended extensions

* No need to limit to only `node` types

* remove babel dependencies

* added changelog

* `npm run lint:fix` autofixes only
converted components to use `function`
adjusts jest tests to use `not.toBeInTheDocument` instead of `toBeNull`
removes unnecessary fragments
removes trailing spaces

* Fix `react/no-unstable-nested-components` error

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “VerticalStackedBarChart” and pass data as props.

* allow use of require in jest tests

* fix resolution of `fonts.ts` file asking for the extension

* Fix `react/jsx-no-constructed-context-values` errors

The object passed as the value prop to the Context provider changes every render. To fix this consider wrapping it in a useMemo hook

I also turned the functions in the Files component into callbacks since they're provided in the context

* Allow helpers that contain `expect` statements to be used as the only expects in tests

* add tsconfig to dockerfile

* Fix `react/no-unstable-nested-components` with `DetailPanel` getting defined inside of `ProvGraph`

* Fix undefined `test` global in test fixtures

* Disable `jsx-no-bind` rule

* Must use destructuring `themeContext` assignment (`react/destructuring-assignment`)

* `Default parameters should be last`

* Reorganized debounced vitessce config setter to avoid using `useCallback` with unknown dependencies

* Name HOC components (`func-names`)

* fix `no-unused-vars`; allow unused vars if they start with `_` prefix

* use destructuring props assignment

* `react/jsx-no-constructed-context-values`
The object passed as the value prop to the Context provider changes every render. To fix this consider wrapping it in a useMemo hook

* allow empty function placeholders in test files

* add assertions to accordion list filter tests

* Avoid destructuring queries from `render` result, use `screen.getByText` instead

* another "screen" fix

* allow "redundant" story names pending further investigation

* reorganize to make sure components are only referenced after they're defined, fix optional chain safety

* uncomment test for the time being, will troubleshoot

* prepend unused var with `_`

* fix describe block name

* remove `as default`, make it an explicit default export

* allow variables to remain unused if spreading object to remove those keys

* Add explicit explanation for empty effect cleanup function

* Use `getBy*` queries rather than `queryBy*` for checking element is present  `testing-library/prefer-presence-queries`

* explicitly use default export instead of `as default`

* use `useMemo` to manage SearchKitManager instance to fix `useEffect` dependencies

* add swc helpers package to dev dependencies to make jest test suites run successfully

* Fix ProvVis test

* fix accordion filter tests

* Add `buffer` polyfill to make docker image build correctly

* Fix maintenance cypress test

* rework existing tests to work with vitessce publication

* remove waits from tests, add tests for authors/provenance sections

* test vignette accordion

* Add changelog

* propagate changes to `.eslintrc.yml` from fixes branch

* remove unnecessary usecallbacks

* Update context/app/static/js/components/entity-search/SearchWrapper/utils.spec.js

Co-authored-by: John Conroy <[email protected]>

* Fix Jest test-utils resolution

* remove unnecessary import

* Update CHANGELOG-lint-updates.md

Co-authored-by: John Conroy <[email protected]>

* Change ProvData constructor to an object

* Nickakhmetov/HMP-194 Apply fixes from lint config (#3143)

* `npm run lint:fix` autofixes only
converted components to use `function`
adjusts jest tests to use `not.toBeInTheDocument` instead of `toBeNull`
removes unnecessary fragments
removes trailing spaces

* Fix `react/no-unstable-nested-components` error

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “VerticalStackedBarChart” and pass data as props.

* allow use of require in jest tests

* fix resolution of `fonts.ts` file asking for the extension

* Fix `react/jsx-no-constructed-context-values` errors

The object passed as the value prop to the Context provider changes every render. To fix this consider wrapping it in a useMemo hook

I also turned the functions in the Files component into callbacks since they're provided in the context

* Allow helpers that contain `expect` statements to be used as the only expects in tests

* add tsconfig to dockerfile

* Fix `react/no-unstable-nested-components` with `DetailPanel` getting defined inside of `ProvGraph`

* Fix undefined `test` global in test fixtures

* Disable `jsx-no-bind` rule

* Must use destructuring `themeContext` assignment (`react/destructuring-assignment`)

* `Default parameters should be last`

* Reorganized debounced vitessce config setter to avoid using `useCallback` with unknown dependencies

* Name HOC components (`func-names`)

* fix `no-unused-vars`; allow unused vars if they start with `_` prefix

* use destructuring props assignment

* `react/jsx-no-constructed-context-values`
The object passed as the value prop to the Context provider changes every render. To fix this consider wrapping it in a useMemo hook

* allow empty function placeholders in test files

* add assertions to accordion list filter tests

* Avoid destructuring queries from `render` result, use `screen.getByText` instead

* another "screen" fix

* allow "redundant" story names pending further investigation

* reorganize to make sure components are only referenced after they're defined, fix optional chain safety

* uncomment test for the time being, will troubleshoot

* prepend unused var with `_`

* fix describe block name

* remove `as default`, make it an explicit default export

* allow variables to remain unused if spreading object to remove those keys

* Add explicit explanation for empty effect cleanup function

* Use `getBy*` queries rather than `queryBy*` for checking element is present  `testing-library/prefer-presence-queries`

* explicitly use default export instead of `as default`

* use `useMemo` to manage SearchKitManager instance to fix `useEffect` dependencies

* add swc helpers package to dev dependencies to make jest test suites run successfully

* Fix ProvVis test

* fix accordion filter tests

* Add `buffer` polyfill to make docker image build correctly

* Fix maintenance cypress test

* remove unnecessary usecallbacks

* Update context/app/static/js/components/entity-search/SearchWrapper/utils.spec.js

Co-authored-by: John Conroy <[email protected]>

* Fix Jest test-utils resolution

* remove unnecessary import

* Change ProvData constructor to an object

---------

Co-authored-by: John Conroy <[email protected]>

* remove ESLint changelog that propagated from a merge

* Remove `table` from provenance section tests (publications don't have prov tables)

* Try waiting before searching for entity header?

* force click for vignette test

---------

Co-authored-by: John Conroy <[email protected]>
  • Loading branch information
NickAkhmetov and john-conroy authored Jul 10, 2023
1 parent af99656 commit 5b835ff
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 77 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-hmp-103-round-2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Expanded test suite for Publication pages
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,33 @@ function ContributorsTable({ title, contributors = [] }) {
];

return (
<DetailPageSection id={title.toLowerCase()}>
<DetailPageSection id={title.toLowerCase()} data-testid={title.toLowerCase()}>
<SectionHeader>{title}</SectionHeader>
<Paper>
<StyledTableContainer>
<Table stickyHeader>
<TableHead>
<TableRow>
{columns.map((column) => (
<HeaderCell key={column.id}>{column.label}</HeaderCell>
<HeaderCell
key={column.id}
data-testid={`${title.toLowerCase()}-${column.label.toLowerCase()}-header`}
>
{column.label}
</HeaderCell>
))}
<IconTooltipCell component={HeaderCell} tooltipTitle="Open Researcher and Contributor ID">
<IconTooltipCell
component={HeaderCell}
tooltipTitle="Open Researcher and Contributor ID"
data-testid={`${title.toLowerCase()}-orcid-header`}
>
ORCID
</IconTooltipCell>
</TableRow>
</TableHead>
<TableBody>
{contributors.map(({ orcid_id, name, affiliation }) => (
<TableRow key={orcid_id}>
<TableRow key={orcid_id} data-testid="contributor-row">
<TableCell>{name}</TableCell>
<TableCell>{affiliation}</TableCell>
<TableCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function Files({ files, uuid, hubmap_id, visLiftedUUID }) {

return (
<FilesContext.Provider value={filesContext}>
<DetailPageSection id="files">
<DetailPageSection id="files" data-testid="files">
<SectionHeader>Files</SectionHeader>
{files.length > 0 && (
<MarginBottomDiv>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ function ProvTabs({ provData }) {
return (
<Paper>
<Tabs value={open} onChange={handleChange} aria-label="Provenance Tabs">
{shouldDisplayTable && <Tab label="Table" index={0} />}
<Tab label="Graph" index={graphIndex} />
{shouldDisplayDag && <Tab label="Analysis Details" index={dagIndex} />}
{shouldDisplayTable && <Tab label="Table" index={0} data-testid="prov-table-tab" />}
<Tab label="Graph" index={graphIndex} data-testid="prov-graph-tab" />
{shouldDisplayDag && <Tab label="Analysis Details" index={dagIndex} data-testid="prov-dag-tab" />}
</Tabs>
{shouldDisplayTable && (
<TabPanel value={open} index={0} pad={1}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function PublicationsVisualizationSection({ vignette_json: { vignettes }, uuid }
const handleChange = useCallback((i) => (event, isExpanded) => setExpandedIndex(isExpanded ? i : false), []);

return (
<DetailPageSection id="visualizations">
<DetailPageSection id="visualizations" data-testid="vignettes">
<SectionHeader>Visualizations</SectionHeader>
{sortedVignettes.map((vignette, i) => {
return (
Expand All @@ -32,11 +32,16 @@ function PublicationsVisualizationSection({ vignette_json: { vignettes }, uuid }
expanded={i === expandedIndex}
TransitionProps={{ onEntered: () => setDisplayedVignettes((prev) => ({ ...prev, [i]: true })) }}
onChange={handleChange(i)}
data-testid="vignette"
>
<PrimaryColorAccordionSummary $isExpanded={i === expandedIndex} expandIcon={<ArrowDropUpRoundedIcon />}>
<PrimaryColorAccordionSummary
$isExpanded={i === expandedIndex}
expandIcon={<ArrowDropUpRoundedIcon />}
data-testid={`vignette-${i}-button`}
>
<Typography variant="subtitle1">{`Vignette ${i + 1}: ${vignette.name}`}</Typography>
</PrimaryColorAccordionSummary>
<StyledAccordionDetails>
<StyledAccordionDetails data-testid={`vignette-${i}-content`}>
<PublicationVignette
vignette={vignette}
uuid={uuid}
Expand Down
244 changes: 178 additions & 66 deletions end-to-end/cypress/e2e/portal/publication-page.cy.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,59 @@
// This test was written against a existing publication in the dev/test env and will need to be updated if that publication is deleted

const publicationId = "cd03fa15322492f4173cdbdc30c74a62";
const title = "sdarfg";
// TODO: This will need to be updated when TEST is overwritten with prod data.
const publicationId = "0bac279e054856ca1b98a2bfb28bb011";
const title =
"Vitessce: integrative visualization of multimodal and spatially-resolved single-cell data";

describe("Publication page", () => {
context("macbook-size", () => {
beforeEach(() => {
cy.viewport("macbook-15");
cy.visit(`/browse/publication/${publicationId}`);
cy.intercept(
{
hostname: "hubmapconsortium.org",
url: new RegExp(`.*${publicationId}\/data.*`),
},
(res) => res.destroy()
).then(() => {
cy.visit(`/browse/publication/${publicationId}`);
});
});
it("has a title, abstract, manuscript link, citation, data types, organs, and publication date listed", () => {
it("has a title", () => {
cy.findByTestId("entity-title").contains(title);
cy.findByTestId("publication-abstract").should("exist");
cy.findByTestId("publication-manuscript-link").should("exist");
cy.findByTestId("publication-citation").should("exist");
cy.findByTestId("publication-data-types").contains("CODEX");
cy.findByTestId("publication-organs").contains("Lymph Node");
cy.findByTestId("publication-date").contains("2023-02-27");
});
it("has a table of contents with links to the publication summary, data, files, authors, and provenance", () => {
});
it("has an abstract", () => {
cy.findByTestId("publication-abstract").contains(
"Vitessce is an open-source interactive visualization framework"
);
});
it("has a manuscript link", () => {
cy.findByTestId("publication-manuscript-link").contains(
"https://osf.io/y8thv"
);
});
it("has a citation section", () => {
cy.findByTestId("publication-citation")
.should("contain", title)
.and("contain", "Keller");
});
it("has data types listed", () => {
cy.findByTestId("publication-data-types")
.should("contain", "CODEX")
.and("contain", "CODEX [Cytokit + SPRM]")
.and("contain", "MALDI IMS");
});
it("has organs listed", () => {
cy.findByTestId("publication-organs")
.should("contain", "Kidney (Left)")
.and("contain", "Spleen");
});
it("has a publication date", () => {
cy.findByTestId("publication-date").contains("2021-10-18");
});
it("has a table of contents with links to the summary, data, visualizations, files, authors, and provenance sections", () => {
cy.findByTestId("table-of-contents")
.should("contain", "Summary")
.and("contain", "Data")
.and("contain", "Visualizations")
.and("contain", "Files")
.and("contain", "Authors")
.and("contain", "Provenance");
Expand All @@ -31,80 +63,160 @@ describe("Publication page", () => {
cy.findByTestId("donors-tab")
.should("exist")
.and("contain", "Donors")
.and("contain", "(1)");
cy.findAllByTestId("donor-row").should("have.length", 1);
.and("contain", "(2)");
cy.findAllByTestId("donor-row").should("have.length", 2);

// Samples tab needs to be clicked to activate
cy.findByTestId("samples-tab")
.should("exist")
.and("have.attr", "aria-selected", "false")
.and("contain", "Samples")
.and("contain", "(3)")
.and("contain", "(7)")
.click();
cy.wait(100);
cy.findAllByTestId("sample-row").should("have.length", 3);
cy.findByTestId("samples-tab").should(
"have.attr",
"aria-selected",
"true"
);
cy.findAllByTestId("sample-row").should("have.length", 7);

// Datasets tab needs to be clicked to activate
cy.findByTestId("datasets-tab")
.should("exist")
.and("have.attr", "aria-selected", "false")
.and("contain", "Datasets")
.and("contain", "(1)")
.and("contain", "(3)")
.click();
cy.wait(100);
cy.findAllByTestId("dataset-row").should("have.length", 1);

cy.findByTestId("datasets-tab").should(
"have.attr",
"aria-selected",
"true"
);
cy.findAllByTestId("dataset-row").should("have.length", 3);
});

it('has dynamic links to the search page that change when different tabs in the "Data" section are clicked', () => {
describe("donors tab link", () => {
cy.visit(`/browse/publication/${publicationId}`);
cy.findByTestId("donors-tab")
.should("exist")
.and("have.attr", "aria-selected", "true");
cy.findByTestId("view-related-data-button")
.invoke("attr", "href")
.then((href) =>
cy.visit(href).then(() => {
cy.title().should("include", "Donors");
})
);
});
describe("samples tab link", () => {
cy.visit(`/browse/publication/${publicationId}`);
cy.findByTestId("samples-tab")
.should("exist")
.and("have.attr", "aria-selected", "false")
.click();
cy.wait(100);
cy.findByTestId("view-related-data-button")
.invoke("attr", "href")
.then((href) =>
cy.visit(href).then(() => {
cy.title().should("include", "Samples");
})
);
});
describe("datasets tab link", () => {
cy.visit(`/browse/publication/${publicationId}`);
cy.findByTestId("datasets-tab")
.should("exist")
.and("have.attr", "aria-selected", "false")
.click();
cy.wait(100);
cy.findByTestId("view-related-data-button")
.invoke("attr", "href")
.then((href) =>
cy.visit(href).then(() => {
cy.title().should("include", "Datasets");
})
);
});
it("links to the donors search page when the Donors tab is active", () => {
cy.findByTestId("donors-tab")
.should("exist")
.and("have.attr", "aria-selected", "true");
cy.findByTestId("view-related-data-button")
.invoke("attr", "href")
.then((href) =>
cy.visit(href).then(() => {
cy.title().should("include", "Donors");
})
);
});
it("links to the samples search page when the Samples tab is active", () => {
cy.findByTestId("samples-tab")
.should("exist")
.and("have.attr", "aria-selected", "false")
.click();
cy.findByTestId("samples-tab").should(
"have.attr",
"aria-selected",
"true"
);
cy.findByTestId("view-related-data-button")
.invoke("attr", "href")
.then((href) =>
cy.visit(href).then(() => {
cy.title().should("include", "Samples");
})
);
});

it("links to the datasets search page when the Datasets tab is active", () => {
cy.findByTestId("datasets-tab")
.should("exist")
.and("have.attr", "aria-selected", "false")
.click();
cy.findByTestId("datasets-tab").should(
"have.attr",
"aria-selected",
"true"
);
cy.findByTestId("view-related-data-button")
.invoke("attr", "href")
.then((href) =>
cy.visit(href).then(() => {
cy.title().should("include", "Datasets");
})
);
});

it("has a visible Entity Header when the user scrolls down the page", () => {
cy.findByTestId("entity-header").should("not.exist");
cy.scrollTo("bottom");
cy.wait(50);
cy.findByTestId("entity-header")
.should("be.visible")
.and("contain", title);
});

it("has six vignettes", () => {
cy.findAllByTestId("vignette").should("have.length", 6);
});

it("has the first vignette expanded by default", () => {
cy.findByTestId("vignette-0-button").should(
"have.attr",
"aria-expanded",
"true"
);
cy.findByTestId("vignette-0-content").should("be.visible");
["1", "2", "3", "4", "5"].forEach((i) => {
cy.findByTestId(`vignette-${i}-button`).should(
"have.attr",
"aria-expanded",
"false"
);
cy.findByTestId(`vignette-${i}-content`).should("not.be.visible");
});
});

it("expands other vignettes when they're clicked", () => {
["1", "2", "3", "4", "5"].forEach((i) => {
// Force it to allow clicking while the button is animating since this is a bit flaky
// Once we switch to `createRoot` this action should be performant enough to remove the { force: true }
cy.findByTestId(`vignette-${i}-button`).click({ force: true });
cy.findByTestId(`vignette-${i}-button`).should(
"have.attr",
"aria-expanded",
"true"
);
cy.findByTestId(`vignette-${i}-content`).should("be.visible");
});
});

it("has a link to the files in Globus", () => {
cy.findByTestId("files")
.should("contain", "Bulk Data Transfer")
.and(
"contain",
"Files are available through the Globus Research Data Management System"
);
});

it('has a "Authors" section with a list of author names, affiliations, and ORCIDs', () => {
cy.findByTestId("authors").should("exist");
cy.findByTestId("authors-name-header").should("exist");
cy.findByTestId("authors-affiliation-header").should("exist");
cy.findByTestId("authors-orcid-header").should("exist");
cy.findAllByTestId("contributor-row").should("have.length", 6);
});

it('has a "Provenance" section with a "graph" tab', () => {
cy.get("#provenance")
.should("exist")
.and("contain", "Provenance")
.and("contain", "Graph");
cy.findByTestId("prov-graph-tab").should(
"have.attr",
"aria-selected",
"true"
);
});
});
});

0 comments on commit 5b835ff

Please sign in to comment.