Files
cellxgene/client/__tests__/e2e/e2e.test.js
Severiano Badajoz 023a73cab8 smoke-test centroids + graph overlay layer (#1189)
* add test labels

* prettier + add clcik return to clickOn()

* prettier + begin test

* finish label counting test

* add util to get coordinates of element

* add test id to labels

* add test to check overlay transform

* remove logs

* rename to match master
2020-03-09 17:01:22 -07:00

336 lines
12 KiB
JavaScript

/*
Smoke test suite that will be run in Travis CI
Tests included in this file are expected to be relatively stable and test core features
*/
import { appUrlBase, DATASET } from "./config";
import { setupTestBrowser } from "./testBrowser";
import { datasets } from "./data";
let browser, page, utils, cxgActions;
const data = datasets[DATASET];
beforeAll(async () => {
const browserViewport = { width: 1280, height: 960 };
[browser, page, utils, cxgActions] = await setupTestBrowser(browserViewport);
});
beforeEach(async () => {
await page.goto(appUrlBase);
});
afterAll(() => {
if (browser !== undefined) browser.close();
});
describe("did launch", () => {
test("page launched", async () => {
const element = await utils.getOneElementInnerHTML("[data-testid='header']");
expect(element).toBe(data.title);
});
});
describe("metadata loads", () => {
test("categories and values from dataset appear", async () => {
for (const label in data.categorical) {
await utils.waitByID(`category-${label}`);
const categoryName = await utils.getOneElementInnerText(`[data-testid="category-${label}"]`);
expect(categoryName).toMatch(label);
await utils.clickOn(`${label}:category-expand`);
const categories = await cxgActions.getAllCategoriesAndCounts(label);
expect(Object.keys(categories)).toMatchObject(
Object.keys(data.categorical[label])
);
expect(Object.values(categories)).toMatchObject(
Object.values(data.categorical[label])
);
}
});
test("continuous data appears", async () => {
for (const label in data.continuous) {
await utils.waitByID(`histogram-${label}`);
}
});
});
describe("cell selection", () => {
test("selects all cells cellset 1", async () => {
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(data.dataframe.nObs);
});
test("selects all cells cellset 2", async () => {
const cellCount = await cxgActions.cellSet(2);
expect(cellCount).toBe(data.dataframe.nObs);
});
test("selects cells via lasso", async () => {
for (const cellset of data.cellsets.lasso) {
const cellset1 = await cxgActions.calcDragCoordinates(
"layout-graph",
cellset["coordinates-as-percent"]
);
await cxgActions.drag("layout-graph", cellset1.start, cellset1.end, true);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(cellset.count);
}
});
test("selects cells via categorical", async () => {
for (const cellset of data.cellsets.categorical) {
await utils.clickOn(`${cellset.metadata}:category-expand`);
await utils.clickOn(`${cellset.metadata}:category-select`);
for (const val of cellset.values) {
await utils.clickOn(`categorical-value-select-${cellset.metadata}-${val}`);
}
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(cellset.count);
}
});
test("selects cells via continuous", async () => {
for (const cellset of data.cellsets.continuous) {
const histBrushableAreaId = `histogram-${cellset.metadata}-plot-brushable-area`;
const coords = await cxgActions.calcDragCoordinates(
histBrushableAreaId,
cellset["coordinates-as-percent"]
);
await cxgActions.drag(histBrushableAreaId, coords.start, coords.end);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(cellset.count);
}
});
});
describe("gene entry", () => {
test("search for single gene", async () => cxgActions.addGeneToSearch(data.genes.search));
test("bulk add genes", async () => {
const testGenes = data.genes.bulkadd;
await cxgActions.bulkAddGenes(testGenes);
const allHistograms = await cxgActions.getAllHistograms("histogram-user-gene", testGenes);
expect(allHistograms).toEqual(expect.arrayContaining(testGenes));
expect(allHistograms.length).toEqual(testGenes.length);
});
});
describe("differential expression", () => {
test("selects cells, saves them and performs diffexp", async () => {
await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2);
const allHistograms = await cxgActions.getAllHistograms(
"histogram-diffexp",
data.diffexp["gene-results"]
);
expect(allHistograms).toEqual(
expect.arrayContaining(data.diffexp["gene-results"])
);
expect(allHistograms.length).toEqual(data.diffexp["gene-results"].length);
});
});
describe("subset", () => {
test("subset - cell count matches", async () => {
for (const select of data.subset.cellset1) {
if (select.kind === "categorical") {
await cxgActions.selectCategory(select.metadata, select.values, true);
}
}
await utils.clickOn("subset-button");
for (const label in data.subset.categorical) {
const categories = await cxgActions.getAllCategoriesAndCounts(label);
expect(Object.keys(categories)).toMatchObject(
Object.keys(data.subset.categorical[label])
);
expect(Object.values(categories)).toMatchObject(
Object.values(data.subset.categorical[label])
);
}
});
test("lasso after subset", async () => {
for (const select of data.subset.cellset1) {
if (select.kind === "categorical") {
await cxgActions.selectCategory(select.metadata, select.values, true);
}
}
await utils.clickOn("subset-button");
const lassoSelection = await cxgActions.calcDragCoordinates(
"layout-graph",
data.subset.lasso["coordinates-as-percent"]
);
await cxgActions.drag(
"layout-graph",
lassoSelection.start,
lassoSelection.end,
true
);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(data.subset.lasso.count);
});
test("undo selection appends the top diff exp genes to user defined genes", async () => {
const userDefinedGenes = data.genes.bulkadd;
const diffExpGenes = data.diffexp["gene-results"];
await cxgActions.bulkAddGenes(userDefinedGenes);
const userDefinedHistograms = await cxgActions.getAllHistograms("histogram-user-gene", userDefinedGenes);
expect(userDefinedHistograms).toEqual(expect.arrayContaining(userDefinedGenes));
await cxgActions.subset({x1: 0.15, y1: 0.10, x2: 0.98, y2: 0.98});
await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2);
const diffExpHistograms = await cxgActions.getAllHistograms("histogram-diffexp", diffExpGenes);
expect(diffExpHistograms).toEqual(expect.arrayContaining(diffExpGenes));
await utils.clickOn("reset-subset-button");
const expected = [].concat(userDefinedGenes, diffExpGenes);
const userDefinedHistogramsAfterSubset = await cxgActions.getAllHistograms(
"histogram-user-gene",
expected
);
expect(userDefinedHistogramsAfterSubset).toEqual(expect.arrayContaining(expected));
});
test("subset selection appends the top diff exp genes to user defined genes", async () => {
const userDefinedGenes = data.genes.bulkadd;
const diffExpGenes = data.diffexp["gene-results"];
await cxgActions.bulkAddGenes(userDefinedGenes);
const userDefinedHistograms = await cxgActions.getAllHistograms("histogram-user-gene", userDefinedGenes);
expect(userDefinedHistograms).toEqual(expect.arrayContaining(userDefinedGenes));
await cxgActions.subset({x1: 0.15, y1: 0.10, x2: 0.98, y2: 0.98});
await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2);
const diffExpHistograms = await cxgActions.getAllHistograms("histogram-diffexp", diffExpGenes);
expect(diffExpHistograms).toEqual(expect.arrayContaining(diffExpGenes));
await cxgActions.subset({x1: 0.16, y1: 0.11, x2: 0.97, y2: 0.97});
const expected = [].concat(userDefinedGenes, diffExpGenes);
const userDefinedHistogramsAfterSubset = await cxgActions.getAllHistograms(
"histogram-user-gene",
expected
);
expect(userDefinedHistogramsAfterSubset).toEqual(expect.arrayContaining(expected));
});
});
describe("scatter plot", () => {
test("scatter plot appears", async () => {
await cxgActions.bulkAddGenes(Object.values(data.scatter.genes));
await utils.clickOn(`plot-x-${data.scatter.genes.x}`);
await utils.clickOn(`plot-y-${data.scatter.genes.y}`);
await utils.waitByID("scatterplot");
});
});
describe("clipping", () => {
test("clip continuous", async () => {
await cxgActions.clip(data.clip.min, data.clip.max);
const histBrushableAreaId = `histogram-${data.clip.metadata}-plot-brushable-area`;
const coords = await cxgActions.calcDragCoordinates(
histBrushableAreaId,
data.clip["coordinates-as-percent"]
);
await cxgActions.drag(histBrushableAreaId, coords.start, coords.end);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(data.clip.count);
});
test("clip gene", async () => {
await utils.typeInto("gene-search", data.clip.gene);
await page.keyboard.press("Enter");
await page.waitForSelector(`[data-testid='histogram-${data.clip.gene}']`);
await cxgActions.clip(data.clip.min, data.clip.max);
const histBrushableAreaId = `histogram-${data.clip.gene}-plot-brushable-area`;
const coords = await cxgActions.calcDragCoordinates(
histBrushableAreaId,
data.clip["coordinates-as-percent"]
);
await cxgActions.drag(histBrushableAreaId, coords.start, coords.end);
const cellCount = await cxgActions.cellSet(1);
expect(cellCount).toBe(data.clip["gene-cell-count"]);
});
});
// interact with UI elements just that they do not break
describe("ui elements don't error", () => {
test("color by", async () => {
for (const label in data.categorical) {
await utils.clickOn(`colorby-${label}`);
}
for (const label in data.continuous) {
await utils.clickOn(`colorby-${label}`);
}
});
test("color by for gene", async () => {
await utils.typeInto("gene-search", data.genes.search);
await page.keyboard.press("Enter");
await page.waitForSelector(
`[data-testid='histogram-${data.genes.search}']`
);
await utils.clickOn(`colorby-${data.genes.search}`);
});
test("pan and zoom", async () => {
await utils.clickOn("mode-pan-zoom");
const panCoords = await cxgActions.calcDragCoordinates(
"layout-graph",
data.pan["coordinates-as-percent"]
);
await cxgActions.drag(
"layout-graph",
panCoords.start,
panCoords.end,
false
);
await page.evaluate("window.scrollBy(0, 1000);");
});
});
describe("centroid labels", () => {
test("labels are created", async () => {
await utils.clickOn("centroid-label-toggle");
const labels = Object.keys(data.categorical);
/* eslint-disable no-await-in-loop */
// Toggle colorby for each category and check to see if labels are generated
for (let i = 0, { length } = labels; i < length; i += 1) {
const label = labels[i];
await utils.clickOn(`colorby-${label}`);
const generatedLabels = await utils.getAllByClass("centroid-label");
// Number of labels generated should be equal to size of the object
expect(generatedLabels).toHaveLength(
Object.keys(data.categorical[label]).length
);
}
/* eslint-enable no-await-in-loop */
});
});
describe("graph overlay", () => {
test("transform centroids correctly", async () => {
const category = Object.keys(data.categorical)[0];
await utils.clickOn("centroid-label-toggle");
await utils.clickOn(`colorby-${category}`);
await utils.clickOn("mode-pan-zoom");
const panCoords = await cxgActions.calcDragCoordinates(
"layout-graph",
data.pan["coordinates-as-percent"]
);
const categoryValue = Object.keys(data.categorical[category])[0];
const initialCoordinates = await utils.getElementCoordinates(
`${categoryValue}-centroid-label`
);
await cxgActions.drag(
"layout-graph",
panCoords.start,
panCoords.end,
false
);
const terminalCoordinates = await utils.getElementCoordinates(
`${categoryValue}-centroid-label`
);
expect(terminalCoordinates[0] - initialCoordinates[0]).toBeCloseTo(
panCoords.end.x - panCoords.start.x
);
expect(terminalCoordinates[1] - initialCoordinates[1]).toBeCloseTo(
panCoords.end.y - panCoords.start.y
);
});
});