Files
cellxgene/client/__tests__/e2e/e2eAnnotations.test.js
Bruce Martin 1269e188be Redux refactor (#1571)
* refactor categorical controls state

* lint

* fix race condition in tests

* fix typo

* add missing update on subset

* remove obsolete code

* update jest and puppeteer major version; update all minors

* update when label changes

* remove lint from tests; increase timeouts in e2e tests

* initial refactoring to new async annomatrix

* refine error handling

* fix bad merge

* add continuous legend

* lint

* fix memoization in color table creators

* partial implementation of user defined annotations

* add new annotations action creator file

* first pass at user annotations

* additional user annotation bug fixes

* user annotation auto-save

* unit test cleanup

* lint

* refactor into multiple files

* cleanup

* add column GC

* fix several bugs in user annotations

* remove debug code

* no anonymous functions

* undo redo cleanup

* file cleanup

* scatterplot

* performance

* cleanup

* remove old code

* render in parallel with load

* fix race condition

* simply graph rendering

* render throttle DRY

* fix category label order

* fix typo in e2e test setup

* re-fix the e2e test setup

* be more tolerant of races

* anno matrix unit tests

* temp disable reembedding

* pilot port continuous histo to react-async

* name change

* lint

* fix repaint bug

* typo fix

* update snap to match new ids

* world/universe name cleanup

* move annoMatrix to src dir

* use private underscore naming convention

* fix corner case in all selected

* name cleanup

* add layout control

* init edge case

* lint

* port scatterplot

* fix label indexing bug and improve tests

* port category to react-async

* fix user annotation labelling while subset

* select all of prev layout on layout switch

* fix race with crossfilter update

* prettier lint

* fix misleading comment

* fix url composition in loader

* first pass at crossfilter tests

* lint

* lint

* fix typo

* improved error handling for network errors

* fix memoization bug

* add memo

* refactor for performnce

* add missing single-value handling in select exact parser

* small bugs discovered by tests

* lint

* additional crossfilter unit tests

* remove extraneous comment

* add support for automatic category determination

* lint

* fix render bug in category

* take advantage of schema categories guarantee

* lint

* do not clear history when resetting

* enhanced annomatrix gc

* lint

* finish renaming to follow conventions; fix clone race bug

* lint

* add priority based loading to improve initial data load UX

* crossfilter cache perf

* perf tuning

* remove timers

* documentation

* PR review changes

* PR review changes

* more PR review edits

* improve clarity of comment

* more PR review fixes

* port centroidLabels to use react-async

* remove dead code

* pr review updates

* oops, remove logging
2020-07-14 13:53:33 -07:00

334 lines
9.5 KiB
JavaScript

/*
Tests included in this file are specific to annotation features
*/
import { appUrlBase, DATASET } from "./config";
import { datasets } from "./data";
import {
clickOn,
goToPage,
waitByClass,
waitByID,
getTestId,
getTestClass,
getAllByClass,
} from "./puppeteerUtils";
import {
assertCategoryDoesNotExist,
calcDragCoordinates,
createCategory,
createLabel,
deleteCategory,
deleteLabel,
drag,
expandCategory,
renameCategory,
renameLabel,
subset,
duplicateCategory,
} from "./cellxgeneActions";
const data = datasets[DATASET];
const perTestCategoryName = "TEST-CATEGORY";
const perTestLabelName = "TEST-LABEL";
async function setup(config) {
await goToPage(appUrlBase);
// setup the test fixtures
await createCategory(perTestCategoryName);
await createLabel(perTestCategoryName, perTestLabelName);
if (config.withSubset) {
await subset({ x1: 0.1, y1: 0.1, x2: 0.8, y2: 0.8 });
}
await waitByClass("autosave-complete");
}
describe.each([
{ withSubset: true, tag: "subset" },
{ withSubset: false, tag: "whole" },
])("annotations", (config) => {
test("create a category", async () => {
await setup(config);
const categoryName = `category-created-${config.tag}`;
await assertCategoryDoesNotExist(categoryName);
await createCategory(categoryName);
await assertCategoryExists(categoryName);
});
test("delete a category", async () => {
await setup(config);
await deleteCategory(perTestCategoryName);
await assertCategoryDoesNotExist(perTestCategoryName);
});
test("rename a category", async () => {
await setup(config);
const newCategoryName = `NEW-${config.tag}`;
await renameCategory(perTestCategoryName, newCategoryName);
await assertCategoryDoesNotExist(perTestCategoryName);
await assertCategoryExists(newCategoryName);
});
test("create a label", async () => {
await setup(config);
const labelName = `new-label-${config.tag}`;
await assertLabelDoesNotExist(perTestCategoryName, labelName);
await createLabel(perTestCategoryName, labelName);
await assertLabelExists(perTestCategoryName, labelName);
});
test("delete a label", async () => {
await setup(config);
await deleteLabel(perTestCategoryName, perTestLabelName);
await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName);
});
test("rename a label", async () => {
await setup(config);
const newLabelName = "my-cool-new-label";
await assertLabelDoesNotExist(perTestCategoryName, newLabelName);
await renameLabel(perTestCategoryName, perTestLabelName, newLabelName);
await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName);
await assertLabelExists(perTestCategoryName, newLabelName);
});
test("check cell count for a label loaded from file", async () => {
await setup(config);
const duplicateCategoryName = "duplicate";
await duplicateCategory(duplicateCategoryName);
await page.reload({ waitUntil: ["networkidle0", "domcontentloaded"] });
const firstCategoryExpandIcon = await expect(page).toMatchElement(
getTestClass("category-expand")
);
await firstCategoryExpandIcon.click();
const expectedCategoryRow = await expect(page).toMatchElement(
getTestClass("categorical-row")
);
const expectedLabelName = await getInnerText(
expectedCategoryRow,
"categorical-value"
);
const expectedLabelCount = await getInnerText(
expectedCategoryRow,
"categorical-value-count"
);
await expandCategory(duplicateCategoryName);
const expectedCategory = await expect(page).toMatchElement(
getTestClass("category")
);
const actualCategoryRow = await expect(expectedCategory).toMatchElement(
getTestClass("categorical-row")
);
const actualLabelName = await getInnerText(
actualCategoryRow,
"categorical-value"
);
const actualLabelCount = await getInnerText(
actualCategoryRow,
"categorical-value-count"
);
expect(actualLabelName).toBe(expectedLabelName);
expect(actualLabelCount).toBe(expectedLabelCount);
async function getInnerText(element, className) {
return element.$eval(getTestClass(className), (node) => node?.innerText);
}
});
test("assign cells to a label", async () => {
await setup(config);
await expandCategory(perTestCategoryName);
const lassoSelection = await calcDragCoordinates(
"layout-graph",
data.categoryLabel.lasso["coordinates-as-percent"]
);
await drag("layout-graph", lassoSelection.start, lassoSelection.end, true);
await waitByID("lasso-element", { visible: true });
await clickOn(`${perTestCategoryName}:${perTestLabelName}:see-actions`);
await clickOn(
`${perTestCategoryName}:${perTestLabelName}:add-current-selection-to-this-label`
);
const result = await waitByID(
`categorical-value-count-${perTestCategoryName}-${perTestLabelName}`
);
expect(await result.evaluate((node) => node.innerText)).toBe(
data.categoryLabel.newCount.bySubsetConfig[config.withSubset]
);
});
test("undo/redo category creation", async () => {
await setup(config);
const categoryName = `category-created-undo-${config.tag}`;
await assertCategoryDoesNotExist(categoryName);
await createCategory(categoryName);
await assertCategoryExists(categoryName);
await clickOn("undo");
await assertCategoryDoesNotExist(categoryName);
await clickOn("redo");
await assertCategoryExists(categoryName);
});
test("undo/redo category deletion", async () => {
await setup(config);
const categoryName = `category-deleted-undo-${config.tag}`;
await createCategory(categoryName);
await assertCategoryExists(categoryName);
await deleteCategory(categoryName);
await assertCategoryDoesNotExist(categoryName);
await clickOn("undo");
await assertCategoryExists(categoryName);
await clickOn("redo");
await assertCategoryDoesNotExist(categoryName);
});
test("undo/redo category rename", async () => {
await setup(config);
const newCategoryName = `category-renamed-undo-${config.tag}`;
await assertCategoryDoesNotExist(newCategoryName);
await renameCategory(perTestCategoryName, newCategoryName);
await assertCategoryExists(newCategoryName);
await assertCategoryDoesNotExist(perTestCategoryName);
await clickOn("undo");
await assertCategoryExists(perTestCategoryName);
await assertCategoryDoesNotExist(newCategoryName);
await clickOn("redo");
await assertCategoryExists(newCategoryName);
await assertCategoryDoesNotExist(perTestCategoryName);
});
test("undo/redo label creation", async () => {
await setup(config);
const labelName = `label-created-undo-${config.tag}`;
await assertLabelDoesNotExist(perTestCategoryName, labelName);
await createLabel(perTestCategoryName, labelName);
await assertLabelExists(perTestCategoryName, labelName);
await clickOn("undo");
await assertLabelDoesNotExist(perTestCategoryName);
await clickOn("redo");
await assertLabelExists(perTestCategoryName, labelName);
});
test("undo/redo label deletion", async () => {
await setup(config);
await deleteLabel(perTestCategoryName, perTestLabelName);
await assertLabelDoesNotExist(perTestCategoryName);
await clickOn("undo");
await assertLabelExists(perTestCategoryName, perTestLabelName);
await clickOn("redo");
await assertLabelDoesNotExist(perTestCategoryName);
});
test("undo/redo label rename", async () => {
await setup(config);
const newLabelName = `label-renamed-undo-${config.tag}`;
await assertLabelDoesNotExist(perTestCategoryName, newLabelName);
await renameLabel(perTestCategoryName, perTestLabelName, newLabelName);
await assertLabelExists(perTestCategoryName, newLabelName);
await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName);
await clickOn("undo");
await assertLabelExists(perTestCategoryName, perTestLabelName);
await assertLabelDoesNotExist(perTestCategoryName, newLabelName);
await clickOn("redo");
await assertLabelExists(perTestCategoryName, newLabelName);
await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName);
});
test("stacked bar graph renders", async () => {
await setup(config);
await expandCategory(perTestCategoryName);
await clickOn(`colorby-louvain`);
const labels = await getAllByClass("categorical-row");
const result = await Promise.all(
labels.map((label) => {
return page.evaluate((element) => {
return element.outerHTML;
}, label);
})
);
expect(result).toMatchSnapshot();
});
async function assertCategoryExists(categoryName) {
const handle = await waitByID(`${categoryName}:category-label`);
const result = await handle.evaluate((node) =>
node.getAttribute("aria-label")
);
return expect(result).toBe(categoryName);
}
async function assertLabelExists(categoryName, labelName) {
await expect(page).toMatchElement(
getTestId(`${categoryName}:category-expand`)
);
await expandCategory(categoryName);
const previous = await waitByID(
`categorical-value-${categoryName}-${labelName}`
);
expect(
await previous.evaluate((node) => node.getAttribute("aria-label"))
).toBe(labelName);
}
async function assertLabelDoesNotExist(categoryName, labelName) {
await expandCategory(categoryName);
const result = await page.$(
`[data-testid='categorical-value-${categoryName}-${labelName}']`
);
expect(result).toBeNull();
}
});