Skip to content

Commit

Permalink
test: add snapshots to graph related tests also disable chromatic on …
Browse files Browse the repository at this point in the history
…geneset names and tooltips (#802)
  • Loading branch information
seve authored Mar 8, 2024
1 parent 49f8bc9 commit d2e1ea2
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 150 deletions.
34 changes: 0 additions & 34 deletions client/__tests__/common/playwrightContext.ts

This file was deleted.

65 changes: 41 additions & 24 deletions client/__tests__/e2e/cellxgeneActions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
import { Page, expect } from "@playwright/test";
import { Page, TestInfo, expect } from "@playwright/test";
import { Classes } from "@blueprintjs/core";
import { takeSnapshot } from "@chromatic-com/playwright";
import { clearInputAndTypeInto, tryUntil, typeInto } from "./puppeteerUtils";

interface Coordinate {
Expand Down Expand Up @@ -90,7 +91,7 @@ export async function waitUntilNoSkeletonDetected(page: Page): Promise<void> {
* (thuang): The diff exp test needs more retry, since the API call takes
* some time to complete.
*/
maxRetry: 300
maxRetry: 300,
}
);
}
Expand All @@ -114,28 +115,30 @@ export async function clickOnCoordinate(
export async function getAllCategoriesAndCounts(
category: string,
page: Page
): Promise<{ [cat: string]: string }[]> {
): Promise<{ [cat: string]: string }> {
// these load asynchronously, so we have to wait for the specific category.
const categoryRows = await page
.getByTestId(`category-${category}`)
.getByTestId("categorical-row")
.all();

return Object.fromEntries(
await Promise.all(
categoryRows.map(async (row) => {
const cat = await row
.getByTestId("categorical-value")
.getAttribute("aria-label");
const arrayOfLabelsAndCounts = await Promise.all(
categoryRows.map(async (row): Promise<[string, string]> => {
const cat = await row
.getByTestId("categorical-value")
.getAttribute("aria-label");

const count = await row
.getByTestId("categorical-value-count")
.innerText();
if (!cat) throw new Error("category value not found");

return [cat, count];
})
)
const count: string = await row
.getByTestId("categorical-value-count")
.innerText();

return [cat, count];
})
);

return Object.fromEntries(arrayOfLabelsAndCounts);
}

export async function getCellSetCount(
Expand Down Expand Up @@ -421,7 +424,7 @@ export async function assertGenesetExists(
/**
* (thuang): Don't wait for the default timeout, since we want to fail fast
*/
timeout: 1 * 1000
timeout: 1 * 1000,
});

expect(result).toBe(genesetName);
Expand Down Expand Up @@ -643,18 +646,32 @@ export async function assertUndoRedo(
assertOne: () => Promise<void>,
assertTwo: () => Promise<void>
): Promise<void> {
await tryUntil(async () => {
await keyboardUndo(page);
await assertOne();
}, { page });
await tryUntil(
async () => {
await keyboardUndo(page);
await assertOne();
},
{ page }
);

// if we redo too quickly after undo, the shortcut handler capture the action
await page.waitForTimeout(1000);

await tryUntil(async () => {
await keyboardRedo(page);
await assertTwo();
}, { page });
await tryUntil(
async () => {
await keyboardRedo(page);
await assertTwo();
},
{ page }
);
}

export async function snapshotTestGraph(page: Page, testInfo: TestInfo) {
const buttonID = "capture-and-display-graph";
const imageID = "graph-image";
await page.getByTestId(buttonID).click();

Check failure on line 672 in client/__tests__/e2e/cellxgeneActions.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:342:7 › ui elements don't error › color by

1) [chromium] › e2e/e2e.test.ts:342:7 › ui elements don't error › color by ─────────────────────── Error: locator.click: Test timeout of 150000ms exceeded. Call log: - waiting for getByTestId('capture-and-display-graph') at e2e/cellxgeneActions.ts:672 670 | const buttonID = "capture-and-display-graph"; 671 | const imageID = "graph-image"; > 672 | await page.getByTestId(buttonID).click(); | ^ 673 | page.getByTestId(imageID).waitFor(); 674 | await takeSnapshot(page, testInfo); 675 | } at snapshotTestGraph (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/cellxgeneActions.ts:672:36) at /home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/e2e.test.ts:352:28

Check failure on line 672 in client/__tests__/e2e/cellxgeneActions.ts

View workflow job for this annotation

GitHub Actions / smoke-test

[chromium] › e2e/e2e.test.ts:355:7 › ui elements don't error › pan and zoom

2) [chromium] › e2e/e2e.test.ts:355:7 › ui elements don't error › pan and zoom ─────────────────── Error: locator.click: Test timeout of 150000ms exceeded. Call log: - waiting for getByTestId('capture-and-display-graph') at e2e/cellxgeneActions.ts:672 670 | const buttonID = "capture-and-display-graph"; 671 | const imageID = "graph-image"; > 672 | await page.getByTestId(buttonID).click(); | ^ 673 | page.getByTestId(imageID).waitFor(); 674 | await takeSnapshot(page, testInfo); 675 | } at snapshotTestGraph (/home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/cellxgeneActions.ts:672:36) at /home/runner/work/single-cell-explorer/single-cell-explorer/client/__tests__/e2e/e2e.test.ts:367:28
page.getByTestId(imageID).waitFor();
await takeSnapshot(page, testInfo);
}

/* eslint-enable no-await-in-loop -- await in loop is needed to emulate sequential user actions */
45 changes: 14 additions & 31 deletions client/__tests__/e2e/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,13 @@ import {
waitUntilNoSkeletonDetected,
checkGenesetDescription,
assertUndoRedo,
snapshotTestGraph,
} from "./cellxgeneActions";

import { datasets } from "./data";

import { scaleMax } from "../../src/util/camera";
import {
DATASET,
DATASET_TRUNCATE,
pageURLTruncate,
testURL,
} from "../common/constants";
import { DATASET, pageURLTruncate, testURL } from "../common/constants";
import { goToPage } from "../util/helpers";

const { describe } = test;
Expand Down Expand Up @@ -91,7 +87,6 @@ const genesetDescriptionString = "fourth_gene_set: fourth description";
const genesetToCheckForDescription = "fourth_gene_set";

const data = datasets[DATASET];
const dataTruncate = datasets[DATASET_TRUNCATE];

// TODO #754
test.beforeEach(mockSetup);
Expand Down Expand Up @@ -158,30 +153,15 @@ describe("metadata loads", () => {
page,
}) => {
await goToPage(page, pageURLTruncate);

await tryUntil(
async () => {
for (const label of Object.keys(
dataTruncate.categorical
) as (keyof typeof dataTruncate.categorical)[]) {
const element = await page
.getByTestId(`category-${label}`)
.innerHTML();

expect(element).toMatchSnapshot();

await page.getByTestId(`${label}:category-expand`).click();
await page.getByTestId(`truncate:category-expand`).click();
const categoryRows = await page
.getByTestId(`category-truncate`)
.getByTestId("categorical-row")
.all();

const categories = await getAllCategoriesAndCounts(label, page);

expect(Object.keys(categories)).toMatchObject(
Object.keys(dataTruncate.categorical[label])
);

expect(Object.values(categories)).toMatchObject(
Object.values(dataTruncate.categorical[label])
);
}
expect(Object.keys(categoryRows).length).toBe(1001);
},
{ page }
);
Expand Down Expand Up @@ -359,7 +339,7 @@ describe("clipping", () => {

// interact with UI elements just that they do not break
describe("ui elements don't error", () => {
test("color by", async ({ page }) => {
test("color by", async ({ page }, testInfo) => {
await goToPage(page);
const allLabels = [
...Object.keys(data.categorical),
Expand All @@ -369,9 +349,10 @@ describe("ui elements don't error", () => {
for (const label of allLabels) {
await page.getByTestId(`colorby-${label}`).click();
}
await snapshotTestGraph(page, testInfo);
});

test("pan and zoom", async ({ page }) => {
test("pan and zoom", async ({ page }, testInfo) => {
await goToPage(page);
await page.getByTestId("mode-pan-zoom").click();
const panCoords = await calcDragCoordinates(
Expand All @@ -383,6 +364,7 @@ describe("ui elements don't error", () => {
await drag("layout-graph", panCoords.start, panCoords.end, page);

await page.evaluate("window.scrollBy(0, 1000);");
await snapshotTestGraph(page, testInfo);
});
});

Expand Down Expand Up @@ -613,13 +595,14 @@ for (const option of options) {
expect(cellCount).toBe("131");
}
});
test("color by mean expression", async ({ page }) => {
test("color by mean expression", async ({ page }, testInfo) => {
await setup(option, page);
await createGeneset(meanExpressionBrushGenesetName, page);
await addGeneToSetAndExpand(meanExpressionBrushGenesetName, "SIK1", page);

await colorByGeneset(meanExpressionBrushGenesetName, page);
await assertColorLegendLabel(meanExpressionBrushGenesetName, page);
await snapshotTestGraph(page, testInfo);
});
test("diffexp", async ({ page }) => {
if (option.withSubset) return;
Expand Down
16 changes: 8 additions & 8 deletions client/__tests__/e2e/playwright.global.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ const setup = async ({ page }: { page: Page }) => {
});
});

page.on("console", (message) => {
if (message.type() === "error") {
throw new Error(`CLIENT SIDE ERROR: ${ message.text()}`);
}
});
page.on("pageerror", (error) => {
throw new Error(`UNCAUGHT CLIENT ERROR: ${ error}`);
});
// page.on("console", (message) => {
// if (message.type() === "error") {
// throw new Error(`CLIENT SIDE ERROR: ${ message.text()}`);
// }
// });
// page.on("pageerror", (error) => {
// throw new Error(`UNCAUGHT CLIENT ERROR: ${ error}`);
// });
};

export default setup;
8 changes: 6 additions & 2 deletions client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,20 @@
<link
href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,400;0,700;1,400&display=swap"
rel="stylesheet"
crossorigin="anonymous"
/>
</head>
<body>
<script type="text/javascript">
window.CELLXGENE = {};
window.CELLXGENE.API = {
// When there's a trailing slash on location.pathname, local e2e tests fail because
// they attempt to access http://localhost:3000//pbmc3k.cxg/api/ instead of
// they attempt to access http://localhost:3000//pbmc3k.cxg/api/ instead of
// http://localhost:3000/pbmc3k.cxg/api/. This is a workaround for that issue.
prefix: `http://localhost:<%= CXG_SERVER_PORT %>${location.pathname.replace(/\/$/, "")}/api/`,
prefix: `http://localhost:<%= CXG_SERVER_PORT %>${location.pathname.replace(
/\/$/,
""
)}/api/`,
version: "v0.3/",
};
</script>
Expand Down
39 changes: 34 additions & 5 deletions client/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ReporterDescription, defineConfig, devices } from "@playwright/test";
import { COMMON_PLAYWRIGHT_CONTEXT } from "./__tests__/common/playwrightContext";
import { testURL } from "./__tests__/common/constants";

/**
Expand All @@ -18,6 +17,12 @@ if (!SHOULD_RETRY) {
console.log('Skipping retry because "RETRY" is set to false');
}

const isHeadful =
process.env.HEADFUL === "true" || process.env.HEADLESS === "false";

if (isHeadful) {
console.log("Running tests in headful mode");
}
/**
* (thuang): Playwright takes retries as part of the maxFailures count, so we
* need to set maxFailures to a high number to allow retries.
Expand Down Expand Up @@ -64,12 +69,36 @@ export default defineConfig({
reporter: PLAYWRIGHT_REPORTER,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
...COMMON_PLAYWRIGHT_CONTEXT,
acceptDownloads: true,
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
headless: !isHeadful,
ignoreHTTPSErrors: true,
screenshot: "only-on-failure",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "retain-on-failure",
video: {
mode: "retain-on-failure",
size: {
height: 960,
width: 1280,
},
},
storageState: {
cookies: [],
origins: [
{
localStorage: [{ name: "cxg-ff-test", value: "yes" }],
origin: testURL,
},
],
},
viewport: {
height: 960,
width: 1280,
},
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: testURL,

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
maxFailures: process.env.CI ? CICD_MAX_FAILURE : undefined,

Expand Down
Loading

0 comments on commit d2e1ea2

Please sign in to comment.