Skip to content

Commit

Permalink
chore: add e2e tests for cellguide cxgs and related features (chanzuc…
Browse files Browse the repository at this point in the history
…kerberg#902)

Co-authored-by: Timmy Huang <[email protected]>
  • Loading branch information
atarashansky and tihuan authored Apr 29, 2024
1 parent 4ca479d commit be168f7
Show file tree
Hide file tree
Showing 69 changed files with 289 additions and 86 deletions.
11 changes: 10 additions & 1 deletion client/__tests__/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import * as ENV_DEFAULT from "../../../environment.default.json";
export const DATASET = "pbmc3k.cxg";
export const DATASET_TRUNCATE = "truncation-test.cxg";
export const SPATIAL_DATASET = "super-cool-spatial.cxg";

export const CELL_GUIDE_DATASET = "example.cxg";
export const CELLGUIDE_CXGS_PATH = "cellguide-cxgs";
export const APP_URL_BASE =
process.env.CXG_URL_BASE || `http://localhost:${ENV_DEFAULT.CXG_CLIENT_PORT}`;

Expand All @@ -25,6 +26,14 @@ export const pageURLSpatial = [
"",
].join("/");

export const pageURLCellGuide = [
APP_URL_BASE,
DEFAULT_BASE_PATH,
CELLGUIDE_CXGS_PATH,
CELL_GUIDE_DATASET,
"",
].join("/");

export const BLUEPRINT_SAFE_TYPE_OPTIONS = { delay: 50 };

export const ERROR_NO_TEST_ID_OR_LOCATOR =
Expand Down
148 changes: 148 additions & 0 deletions client/__tests__/e2e/cell-guide.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/**
* Smoke test suite that will be run in GHA
* Tests included in this file are expected to be relatively stable and test core features
*
* (seve): `locator.click({force: true})` is required on some elements due to weirdness with bp3 elements which route clicks to non-target elements
* https://playwright.dev/docs/input#forcing-the-click
*/

/* eslint-disable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
import { test, expect } from "@chromatic-com/playwright";

import { tryUntil } from "./puppeteerUtils";
import mockSetup from "./playwright.global.setup";

import {
deleteGeneset,
snapshotTestGraph,
expandGeneset,
expandMarkerGeneSetsHeader,
} from "./cellxgeneActions";

import { pageURLCellGuide } from "../common/constants";

import { goToPage } from "../util/helpers";

const { describe } = test;

// TODO #754
test.beforeEach(mockSetup);

describe(`Testing CellGuideCXG at ${pageURLCellGuide}`, () => {
test("page launched", async ({ page }, testInfo) => {
await goToPage(page, pageURLCellGuide);

const element = await page.getByTestId("header").innerHTML();

expect(element).toMatchSnapshot();

await snapshotTestGraph(page, testInfo);
});

test("assert absence of 'Standard Categories' and 'Author Categories'", async ({
page,
}) => {
await goToPage(page, pageURLCellGuide);

// Check for the absence of 'Standard Categories'
const standardCategories = await page
.locator("text='Standard Categories'")
.count();
expect(standardCategories).toBe(0);

// Check for the absence of 'Author Categories'
const authorCategories = await page
.locator("text='Author Categories'")
.count();
expect(authorCategories).toBe(0);
});

test("assert 'Marker Gene Sets' header is present and collapsed", async ({
page,
}) => {
await goToPage(page, pageURLCellGuide);

// Check for the presence of 'Marker Gene Sets' header
const markerGeneSetsHeader = await page.locator(
"h5:has-text('Marker Gene Sets')"
);
await expect(markerGeneSetsHeader).toBeVisible();

// Check if the header is collapsed by looking for a child with a chevron-right icon
const chevronRightIcon = markerGeneSetsHeader.locator(
"svg[data-icon='chevron-right']"
);
await expect(chevronRightIcon).toBeVisible();
});

test("expansion of 'Marker Gene Sets' reveals specific genesets", async ({
page,
}) => {
await goToPage(page, pageURLCellGuide);

// Locate and expand the 'Marker Gene Sets' header
const markerGeneSetsHeader = await page.locator(
"h5:has-text('Marker Gene Sets')"
);

tryUntil(
async () => {
await markerGeneSetsHeader.click(); // Assuming clicking will expand the section

// Assert the presence of specific genesets
const geneset1 = await page.locator(
`div[data-testid="geneset"]:has-text("enteric smooth muscle cell")`
);
const geneset2 = await page.locator(
`div[data-testid="geneset"]:has-text("smooth muscle fiber of ileum")`
);

await expect(geneset1).toBeVisible();
await expect(geneset2).toBeVisible();
},
{ page }
);
});

test("expansion of 'enteric smooth muscle cell' reveals genes", async ({
page,
}) => {
await goToPage(page, pageURLCellGuide);

await expandMarkerGeneSetsHeader(page);

// Locate and expand 'enteric smooth muscle cell' geneset
await expandGeneset("enteric smooth muscle cell - marker genes", page);

// Assert the presence of the genes div and that it contains 55 child divs
const genesDiv = await page.locator(`div[data-testid="gene-set-genes"]`);
await expect(genesDiv).toBeVisible();
const childDivs = await genesDiv.locator(
'div[data-testid*=":gene-expand"]'
);
await expect(childDivs).toHaveCount(55);
});

test("deleting 'enteric smooth muscle cell' geneset and refreshing adds it back", async ({
page,
}) => {
await goToPage(page, pageURLCellGuide);

await expandMarkerGeneSetsHeader(page);

await deleteGeneset("enteric smooth muscle cell - marker genes", page);

// Refresh the page
await page.reload();

await expandMarkerGeneSetsHeader(page);

// Check if the geneset is added back
const genesetPresence = await page.locator(
`div[data-testid="geneset"]:has-text("enteric smooth muscle cell")`
);
await expect(genesetPresence).toBeVisible();
});
});

/* eslint-enable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="css-6q0ddy"><span class="css-iz9ysv"><a href="/"><svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.10758 5.97949H0.521711C0.233578 5.97949 0 6.21307 0 6.5012V22.1616C0 22.4497 0.233578 22.6833 0.521711 22.6833H3.10758C3.39571 22.6833 3.62929 22.4497 3.62929 22.1616V6.5012C3.62929 6.21307 3.39571 5.97949 3.10758 5.97949Z" fill="white"></path><path d="M22.6741 22.1613C22.6741 22.4471 22.4382 22.683 22.1523 22.683H6.50102C6.21521 22.683 5.97931 22.4471 5.97931 22.1613V6.50999C5.97931 6.22419 6.21521 5.98828 6.50102 5.98828H22.1523C22.4382 5.98828 22.6741 6.22419 22.6741 6.50999V22.1613ZM9.6086 18.532C9.6086 18.8178 9.84451 19.0537 10.1303 19.0537H18.5231C18.8089 19.0537 19.0448 18.8178 19.0448 18.532V10.1393C19.0448 9.85348 18.8089 9.61757 18.5231 9.61757H10.1303C9.84451 9.61757 9.6086 9.85348 9.6086 10.1393V18.532Z" fill="white"></path><path d="M22.1569 0H6.4965C6.20837 0 5.97479 0.233578 5.97479 0.521711V3.10758C5.97479 3.39571 6.20837 3.62929 6.4965 3.62929H22.1569C22.445 3.62929 22.6786 3.39571 22.6786 3.10758V0.521711C22.6786 0.233578 22.445 0 22.1569 0Z" fill="#8282FF"></path></svg></a><span class="css-1o97835"><span class="css-nel2x3"><span class="css-j42i0i">Application</span><span class="css-1o97835"><span class="css-1kqb0rz"><a role="button" href="/collections" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Collections</span></a></span><span class="css-1kqb0rz"><a role="button" href="/datasets" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Datasets</span></a></span><span class="css-1kqb0rz"><a role="button" href="/gene-expression" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Gene Expression</span></a></span><span class="css-1kqb0rz"><a role="button" href="/cellguide" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Cell Guide</span></a><div class="MuiChip-root css-1012r7m MuiChip-sizeSmall"><span class="MuiChip-label MuiChip-labelSmall">Beta</span></div></span></span></span><hr class="MuiDivider-root css-15784bj MuiDivider-flexItem MuiDivider-vertical"><span class="css-nel2x3"><span class="css-j42i0i">Census</span><span class="css-1o97835"><span class="css-1kqb0rz"><a role="button" href="https://cellxgene-census.readthedocs.io/en/latest" rel="noopener" target="_self" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">API</span></a></span><span class="css-1kqb0rz"><a role="button" href="/census-models" rel="noopener" target="_self" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Models</span></a></span></span></span></span></span><span class="css-13tdomi"><span class="css-1kqb0rz"><span class="bp3-popover2-target"><a role="button" data-testid="menu" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Help &amp; Documentation</span><span icon="chevron-down" aria-hidden="true" class="bp3-icon bp3-icon-chevron-down"><svg data-icon="chevron-down" width="16" height="16" viewBox="0 0 16 16"><path d="M12 5c-.28 0-.53.11-.71.29L8 8.59l-3.29-3.3a1.003 1.003 0 00-1.42 1.42l4 4c.18.18.43.29.71.29s.53-.11.71-.29l4-4A1.003 1.003 0 0012 5z" fill-rule="evenodd"></path></svg></span></a></span></span></span></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="css-6q0ddy"><span class="css-iz9ysv"><a href="/"><svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.10758 5.97949H0.521711C0.233578 5.97949 0 6.21307 0 6.5012V22.1616C0 22.4497 0.233578 22.6833 0.521711 22.6833H3.10758C3.39571 22.6833 3.62929 22.4497 3.62929 22.1616V6.5012C3.62929 6.21307 3.39571 5.97949 3.10758 5.97949Z" fill="white"></path><path d="M22.6741 22.1613C22.6741 22.4471 22.4382 22.683 22.1523 22.683H6.50102C6.21521 22.683 5.97931 22.4471 5.97931 22.1613V6.50999C5.97931 6.22419 6.21521 5.98828 6.50102 5.98828H22.1523C22.4382 5.98828 22.6741 6.22419 22.6741 6.50999V22.1613ZM9.6086 18.532C9.6086 18.8178 9.84451 19.0537 10.1303 19.0537H18.5231C18.8089 19.0537 19.0448 18.8178 19.0448 18.532V10.1393C19.0448 9.85348 18.8089 9.61757 18.5231 9.61757H10.1303C9.84451 9.61757 9.6086 9.85348 9.6086 10.1393V18.532Z" fill="white"></path><path d="M22.1569 0H6.4965C6.20837 0 5.97479 0.233578 5.97479 0.521711V3.10758C5.97479 3.39571 6.20837 3.62929 6.4965 3.62929H22.1569C22.445 3.62929 22.6786 3.39571 22.6786 3.10758V0.521711C22.6786 0.233578 22.445 0 22.1569 0Z" fill="#8282FF"></path></svg></a><span class="css-1o97835"><span class="css-nel2x3"><span class="css-j42i0i">Application</span><span class="css-1o97835"><span class="css-1kqb0rz"><a role="button" href="/collections" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Collections</span></a></span><span class="css-1kqb0rz"><a role="button" href="/datasets" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Datasets</span></a></span><span class="css-1kqb0rz"><a role="button" href="/gene-expression" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Gene Expression</span></a></span><span class="css-1kqb0rz"><a role="button" href="/cellguide" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Cell Guide</span></a><div class="MuiChip-root css-1012r7m MuiChip-sizeSmall"><span class="MuiChip-label MuiChip-labelSmall">Beta</span></div></span></span></span><hr class="MuiDivider-root css-15784bj MuiDivider-flexItem MuiDivider-vertical"><span class="css-nel2x3"><span class="css-j42i0i">Census</span><span class="css-1o97835"><span class="css-1kqb0rz"><a role="button" href="https://cellxgene-census.readthedocs.io/en/latest" rel="noopener" target="_self" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">API</span></a></span><span class="css-1kqb0rz"><a role="button" href="/census-models" rel="noopener" target="_self" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Models</span></a></span></span></span></span></span><span class="css-13tdomi"><span class="css-1kqb0rz"><span class="bp3-popover2-target"><a role="button" data-testid="menu" class="bp3-button bp3-minimal" tabindex="0"><span class="bp3-button-text">Help &amp; Documentation</span><span icon="chevron-down" aria-hidden="true" class="bp3-icon bp3-icon-chevron-down"><svg data-icon="chevron-down" width="16" height="16" viewBox="0 0 16 16"><path d="M12 5c-.28 0-.53.11-.71.29L8 8.59l-3.29-3.3a1.003 1.003 0 00-1.42 1.42l4 4c.18.18.43.29.71.29s.53-.11.71-.29l4-4A1.003 1.003 0 0012 5z" fill-rule="evenodd"></path></svg></span></a></span></span></span></div>
48 changes: 46 additions & 2 deletions client/__tests__/e2e/cellxgeneActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,50 @@ export async function getAllCategoriesAndCounts(
return Object.fromEntries(arrayOfLabelsAndCounts);
}

export async function expandMarkerGeneSetsHeader(page: Page): Promise<void> {
// Locate and expand the 'Marker Gene Sets' header if not already expanded
const markerGeneSetsHeader = await page.locator(
"h5:has-text('Marker Gene Sets')"
);
const chevronDownIcon = markerGeneSetsHeader.locator(
"svg[data-icon='chevron-down']"
);
await tryUntil(
async () => {
if ((await chevronDownIcon.count()) === 0) {
await markerGeneSetsHeader.click();
}
const count = await chevronDownIcon.count();
expect(count).toBeGreaterThan(0);
},
{ page }
);
}
export async function getAllCategories(
category: string,
page: Page
): Promise<string[]> {
// these load asynchronously, so we have to wait for the specific category.
const categoryRows = await page
.getByTestId(`category-${category}`)
.getByTestId("categorical-row")
.all();

const arrayOfLabels = await Promise.all(
categoryRows.map(async (row): Promise<string> => {
const cat = await row
.getByTestId("categorical-value")
.getAttribute("aria-label");

if (!cat) throw new Error("category value not found");

return cat;
})
);

return arrayOfLabels;
}

export async function getCellSetCount(
num: number,
page: Page
Expand Down Expand Up @@ -405,10 +449,10 @@ export async function checkGenesetDescription(

const editButton = `${genesetName}:edit-genesetName-mode`;
await page.getByTestId(editButton).click({
force: true
force: true,
/**
* (thuang): Don't wait for the default timeout, since we want to fail fast
*/,
*/
timeout: 1 * 1000,
});

Expand Down
30 changes: 0 additions & 30 deletions client/__tests__/e2e/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,7 @@ export const datasets = {
categorical: {
louvain: {
"B cells": "342",
"CD14+ Monocytes": "0",
"CD4 T cells": "0",
"CD8 T cells": "0",
"Dendritic cells": "0",
"FCGR3A+ Monocytes": "0",
Megakaryocytes: "15",
"NK cells": "0",
},
},
lasso: {
Expand Down Expand Up @@ -242,31 +236,7 @@ export const datasets = {
categorical: {
cell_type: {
"B cell": "1",
"CD14-low, CD16-positive monocyte": "0",
"CD14-positive monocyte": "0",
"CD8-positive, alpha-beta cytotoxic T cell": "0",
"activated CD4-positive, alpha-beta T cell": "0",
adipocyte: "0",
"cardiac pacemaker cell of sinoatrial node": "0",
"dendritic cell, human": "0",
"endocardial cell": "0",
"endothelial cell": "0",
"endothelial cell of artery": "0",
"endothelial cell of lymphatic vessel": "0",
"fibroblast of cardiac tissue": "0",
"glial cell": "43",
macrophage: "0",
"mast cell": "0",
monocyte: "0",
"mucosal invariant T cell": "0",
"naive thymus-derived CD4-positive, alpha-beta T cell": "0",
neutrophil: "0",
pericyte: "0",
"plasma cell": "0",
"regular atrial cardiac myocyte": "0",
"smooth muscle cell": "0",
"smooth muscle cell of the pulmonary artery": "0",
"vein endothelial cell": "0",
},
},
lasso: {
Expand Down
64 changes: 50 additions & 14 deletions client/__tests__/e2e/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
checkGenesetDescription,
assertUndoRedo,
snapshotTestGraph,
getAllCategories,
} from "./cellxgeneActions";

import { datasets } from "./data";
Expand Down Expand Up @@ -290,6 +291,22 @@ for (const testDataset of testDatasets) {
await snapshotTestGraph(page, testInfo);
}
});
test("subset - categories with zero cells are filtered out", async ({
page,
}) => {
await goToPage(page, url);
const select = data.subset.cellset1[0];
await selectCategory(select.metadata, select.values, page, true);
await page.getByTestId("subset-button").click();

const actualCategories = await getAllCategoriesAndCounts(
select.metadata,
page
);
const actualCategoriesKeys = Object.keys(actualCategories).sort();
const expectedCateogriesKeys = select.values.slice().sort();
expect(actualCategoriesKeys).toEqual(expectedCateogriesKeys);
});

test("lasso after subset", async ({ page }, testInfo) => {
await goToPage(page, url);
Expand Down Expand Up @@ -659,6 +676,39 @@ for (const testDataset of testDatasets) {
await assertColorLegendLabel(meanExpressionBrushGenesetName, page);
await snapshotTestGraph(page, testInfo);
});
test("color by mean expression changes sorting of categories in 'cell_type'", async ({
page,
}) => {
await setup({ option, page, url });
const categories = await page
.locator('[data-testid*=":category-expand"]')
.all();
const category = categories[0];
const categoryName = (
await category.getAttribute("data-testid")
)?.split(":")[0] as string;

await expandCategory(categoryName, page);

await createGeneset(meanExpressionBrushGenesetName, page);
await addGeneToSetAndExpand(
meanExpressionBrushGenesetName,
"SIK1",
page
);

// Check initial order of categories
const initialOrder = await getAllCategories(categoryName, page);

// Color by the geneset mean expression
await colorByGeneset(meanExpressionBrushGenesetName, page);

// Check order of categories after sorting by mean expression
const sortedOrder = await getAllCategories(categoryName, page);

// Expect the sorted order to be different from the initial order
expect(sortedOrder).not.toEqual(initialOrder);
});

test("diffexp", async ({ page }, testInfo) => {
if (option.withSubset) return;
Expand Down Expand Up @@ -1007,17 +1057,3 @@ async function setup({
await subset({ x1: 0.1, y1: 0.15, x2: 0.8, y2: 0.85 }, page);
}
}

// TODO(atarashansky): write this test suite
// https://github.com/chanzuckerberg/single-cell-explorer/issues/811
// async function goToCellGuideCxg(page: Page) {
// await goToPage(page, "http://localhost:3000/d/cellguide-cxgs/example.cxg/");
// }

// describe(`CellGuide CXG tests`, () => {
// test.only("author and standard category headers are not present", async ({
// page,
// }) => {
// await goToPage(page, url);
// });
// });
2 changes: 1 addition & 1 deletion client/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export default defineConfig({
projects: [
{
name: "chromium",
testMatch: "**/e2e.test.ts",
testMatch: "**/e2e/*.test.ts",
use: {
...devices["Desktop Chrome"],
userAgent: devices["Desktop Chrome"].userAgent + CZI_CHECKER,
Expand Down
Loading

0 comments on commit be168f7

Please sign in to comment.