mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-17 22:08:00 +08:00
356 lines
10 KiB
JavaScript
356 lines
10 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();
|
|
});
|
|
|
|
test("truncate midpoint whitespace", async () => {
|
|
await setup(config);
|
|
const newLabelName = "123 456";
|
|
await renameLabel(perTestCategoryName, perTestLabelName, newLabelName);
|
|
const value = await waitByID(
|
|
`categorical-value-${perTestCategoryName}-${newLabelName}`
|
|
);
|
|
const result = await page.evaluate((elem) => elem.outerHTML, value);
|
|
expect(result).toMatchSnapshot();
|
|
});
|
|
|
|
test("truncate single character", async () => {
|
|
await setup(config);
|
|
const newLabelName = "T";
|
|
await renameLabel(perTestCategoryName, perTestLabelName, newLabelName);
|
|
const value = await waitByID(
|
|
`categorical-value-${perTestCategoryName}-${newLabelName}`
|
|
);
|
|
const result = await page.evaluate((elem) => elem.outerHTML, value);
|
|
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();
|
|
}
|
|
});
|