mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-27 03:38:13 +08:00
run prettier(2.0.5) (#1438)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { strict as assert } from "assert";
|
||||
|
||||
export const cellxgeneActions = (page, utils) => ({
|
||||
|
||||
async drag(testId, start, end, lasso = false) {
|
||||
const layout = await utils.waitByID(testId);
|
||||
const elBox = await layout.boxModel();
|
||||
@@ -31,22 +30,29 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
},
|
||||
|
||||
async getAllHistograms(testclass, testIds) {
|
||||
const histTestIds = testIds.map(tid => `histogram-${tid}`);
|
||||
const histTestIds = testIds.map((tid) => `histogram-${tid}`);
|
||||
// these load asynchronously, so we need to wait for each histogram individually
|
||||
await utils.waitForAllByIds(histTestIds);
|
||||
const allHistograms = await utils.getAllByClass(testclass);
|
||||
return allHistograms.map(hist => hist.replace(/^histogram-/, ""));
|
||||
return allHistograms.map((hist) => hist.replace(/^histogram-/, ""));
|
||||
},
|
||||
|
||||
async getAllCategoriesAndCounts(category) {
|
||||
await utils.waitByClass("categorical-row");
|
||||
return page.$$eval(
|
||||
`[data-testid="category-${category}"] [data-testclass='categorical-row']`,
|
||||
rows => Object.fromEntries(rows.map(row => {
|
||||
const cat = row.querySelector("[data-testclass='categorical-value']").innerText;
|
||||
const count = row.querySelector("[data-testclass='categorical-value-count']").innerText;
|
||||
return [cat, count];
|
||||
}))
|
||||
(rows) =>
|
||||
Object.fromEntries(
|
||||
rows.map((row) => {
|
||||
const cat = row.querySelector(
|
||||
"[data-testclass='categorical-value']"
|
||||
).innerText;
|
||||
const count = row.querySelector(
|
||||
"[data-testclass='categorical-value-count']"
|
||||
).innerText;
|
||||
return [cat, count];
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -60,12 +66,14 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
await utils.waitByID(checkboxId);
|
||||
const checkedPseudoclass = await page.$eval(
|
||||
`[data-testid='${checkboxId}']`,
|
||||
el => el.matches(":checked")
|
||||
(el) => el.matches(":checked")
|
||||
);
|
||||
if (!checkedPseudoclass) await utils.clickOn(checkboxId);
|
||||
try {
|
||||
const categoryRow = await utils.waitByID(`${category}:category-expand`);
|
||||
const isExpanded = await categoryRow.$("[data-testclass='category-expand-is-expanded']");
|
||||
const isExpanded = await categoryRow.$(
|
||||
"[data-testclass='category-expand-is-expanded']"
|
||||
);
|
||||
if (isExpanded) await utils.clickOn(`${category}:category-expand`);
|
||||
} catch {}
|
||||
},
|
||||
@@ -75,14 +83,22 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
const size = await el.boxModel();
|
||||
return {
|
||||
x: Math.floor(size.width * xAsPercent),
|
||||
y: Math.floor(size.height * yAsPercent)
|
||||
}
|
||||
y: Math.floor(size.height * yAsPercent),
|
||||
};
|
||||
},
|
||||
|
||||
async calcDragCoordinates(testId, coordinateAsPercent) {
|
||||
return {
|
||||
start: await this.calcCoordinate(testId, coordinateAsPercent.x1, coordinateAsPercent.y1),
|
||||
end: await this.calcCoordinate(testId, coordinateAsPercent.x2, coordinateAsPercent.y2)
|
||||
start: await this.calcCoordinate(
|
||||
testId,
|
||||
coordinateAsPercent.x1,
|
||||
coordinateAsPercent.y1
|
||||
),
|
||||
end: await this.calcCoordinate(
|
||||
testId,
|
||||
coordinateAsPercent.x2,
|
||||
coordinateAsPercent.y2
|
||||
),
|
||||
};
|
||||
},
|
||||
|
||||
@@ -97,7 +113,9 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
|
||||
async expandCategory(category) {
|
||||
const expand = await utils.waitByID(`${category}:category-expand`);
|
||||
const notExpanded = await expand.$("[data-testclass='category-expand-is-not-expanded']");
|
||||
const notExpanded = await expand.$(
|
||||
"[data-testclass='category-expand-is-not-expanded']"
|
||||
);
|
||||
if (notExpanded) await utils.clickOn(`${category}:category-expand`);
|
||||
},
|
||||
|
||||
@@ -117,7 +135,10 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
async renameCategory(oldCatgoryName, newCategoryName) {
|
||||
await utils.clickOn(`${oldCatgoryName}:see-actions`);
|
||||
await utils.clickOn(`${oldCatgoryName}:edit-category-mode`);
|
||||
await utils.clearInputAndTypeInto(`${oldCatgoryName}:edit-category-name-text`, newCategoryName);
|
||||
await utils.clearInputAndTypeInto(
|
||||
`${oldCatgoryName}:edit-category-name-text`,
|
||||
newCategoryName
|
||||
);
|
||||
await utils.clickOn(`${oldCatgoryName}:submit-category-edit`);
|
||||
},
|
||||
|
||||
@@ -136,7 +157,7 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
async deleteLabel(categoryName, labelName) {
|
||||
await this.expandCategory(categoryName);
|
||||
await utils.clickOn(`${categoryName}:${labelName}:see-actions`);
|
||||
await utils.clickOn( `${categoryName}:${labelName}:delete-label`);
|
||||
await utils.clickOn(`${categoryName}:${labelName}:delete-label`);
|
||||
},
|
||||
|
||||
async renameLabel(categoryName, oldLabelName, newLabelName) {
|
||||
@@ -153,17 +174,23 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
async addGeneToSearch(geneName) {
|
||||
await utils.typeInto("gene-search", geneName);
|
||||
await page.keyboard.press("Enter");
|
||||
await page.waitForSelector(
|
||||
`[data-testid='histogram-${geneName}']`
|
||||
);
|
||||
await page.waitForSelector(`[data-testid='histogram-${geneName}']`);
|
||||
},
|
||||
|
||||
async subset(coordinatesAsPercent) {
|
||||
// In order to deselect the selection after the subset, make sure we have some clear part
|
||||
// of the scatterplot we can click on
|
||||
assert(coordinatesAsPercent.x2 < 0.99 || coordinatesAsPercent.y2 < 0.99);
|
||||
const lassoSelection = await this.calcDragCoordinates( "layout-graph", coordinatesAsPercent);
|
||||
await this.drag("layout-graph", lassoSelection.start, lassoSelection.end, true );
|
||||
const lassoSelection = await this.calcDragCoordinates(
|
||||
"layout-graph",
|
||||
coordinatesAsPercent
|
||||
);
|
||||
await this.drag(
|
||||
"layout-graph",
|
||||
lassoSelection.start,
|
||||
lassoSelection.end,
|
||||
true
|
||||
);
|
||||
await utils.clickOn("subset-button");
|
||||
const clearCoordinate = await this.calcCoordinate(
|
||||
"layout-graph",
|
||||
@@ -174,7 +201,9 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
},
|
||||
|
||||
async setSellSet(cellSet, cellSetNum) {
|
||||
for (const selection of cellSet.filter(sel => sel.kind === "categorical")) {
|
||||
for (const selection of cellSet.filter(
|
||||
(sel) => sel.kind === "categorical"
|
||||
)) {
|
||||
await this.selectCategory(selection.metadata, selection.values, true);
|
||||
}
|
||||
await this.cellSet(cellSetNum);
|
||||
@@ -190,7 +219,5 @@ export const cellxgeneActions = (page, utils) => ({
|
||||
await utils.clickOn("section-bulk-add");
|
||||
await utils.typeInto("input-bulk-add", geneNames.join(","));
|
||||
await page.keyboard.press("Enter");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const jest_env = process.env.JEST_ENV;
|
||||
export const appPort = process.env.CXG_SERVER_PORT;
|
||||
export const appUrlBase = process.env.CXG_URL_BASE || `http://localhost:${appPort}`;
|
||||
export const appUrlBase =
|
||||
process.env.CXG_URL_BASE || `http://localhost:${appPort}`;
|
||||
export const DEV = jest_env === "dev";
|
||||
export const DEBUG = jest_env === "debug";
|
||||
export const DATASET = "pbmc3k";
|
||||
|
||||
@@ -4,7 +4,7 @@ export const datasets = {
|
||||
dataframe: {
|
||||
nObs: "2638",
|
||||
nVar: "1838",
|
||||
type: "float32"
|
||||
type: "float32",
|
||||
},
|
||||
categorical: {
|
||||
louvain: {
|
||||
@@ -15,47 +15,47 @@ export const datasets = {
|
||||
"Dendritic cells": "37",
|
||||
"FCGR3A+ Monocytes": "150",
|
||||
Megakaryocytes: "15",
|
||||
"NK cells": "154"
|
||||
}
|
||||
"NK cells": "154",
|
||||
},
|
||||
},
|
||||
continuous: {
|
||||
n_genes: "int32",
|
||||
percent_mito: "float32",
|
||||
n_counts: "float32"
|
||||
n_counts: "float32",
|
||||
},
|
||||
cellsets: {
|
||||
lasso: [
|
||||
{
|
||||
"coordinates-as-percent": { x1: 0.1, y1: 0.25, x2: 0.7, y2: 0.75 },
|
||||
count: "1181"
|
||||
}
|
||||
count: "1181",
|
||||
},
|
||||
],
|
||||
categorical: [
|
||||
{
|
||||
metadata: "louvain",
|
||||
values: ["B cells", "Megakaryocytes"],
|
||||
count: "357"
|
||||
}
|
||||
count: "357",
|
||||
},
|
||||
],
|
||||
continuous: [
|
||||
{
|
||||
metadata: "n_genes",
|
||||
"coordinates-as-percent": { x1: 0.25, y1: 0.5, x2: 0.55, y2: 0.5 },
|
||||
count: "1537"
|
||||
}
|
||||
]
|
||||
count: "1537",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
diffexp: {
|
||||
cellset1: [
|
||||
{ kind: "categorical", metadata: "louvain", values: ["B cells"] }
|
||||
{ kind: "categorical", metadata: "louvain", values: ["B cells"] },
|
||||
],
|
||||
cellset2: [
|
||||
{
|
||||
kind: "categorical",
|
||||
metadata: "louvain",
|
||||
values: ["CD4 T cells", "NK cells"]
|
||||
}
|
||||
values: ["CD4 T cells", "NK cells"],
|
||||
},
|
||||
],
|
||||
"gene-results": [
|
||||
"HLA-DRB1",
|
||||
@@ -67,21 +67,21 @@ export const datasets = {
|
||||
"HLA-DQB1",
|
||||
"MS4A1",
|
||||
"IL32",
|
||||
"CD37"
|
||||
]
|
||||
"CD37",
|
||||
],
|
||||
},
|
||||
|
||||
genes: {
|
||||
bulkadd: ["S100A8", "FCGR3A", "LGALS2", "GSTP1"],
|
||||
search: "ACD"
|
||||
search: "ACD",
|
||||
},
|
||||
subset: {
|
||||
cellset1: [
|
||||
{
|
||||
kind: "categorical",
|
||||
metadata: "louvain",
|
||||
values: ["B cells", "Megakaryocytes"]
|
||||
}
|
||||
values: ["B cells", "Megakaryocytes"],
|
||||
},
|
||||
],
|
||||
count: "357",
|
||||
categorical: {
|
||||
@@ -93,27 +93,27 @@ export const datasets = {
|
||||
"Dendritic cells": "0",
|
||||
"FCGR3A+ Monocytes": "0",
|
||||
Megakaryocytes: "15",
|
||||
"NK cells": "0"
|
||||
}
|
||||
"NK cells": "0",
|
||||
},
|
||||
},
|
||||
lasso: {
|
||||
"coordinates-as-percent": { x1: 0.25, y1: 0.05, x2: 0.75, y2: 0.55 },
|
||||
count: "329"
|
||||
}
|
||||
count: "329",
|
||||
},
|
||||
},
|
||||
scatter: {
|
||||
genes: { x: "S100A8", y: "FCGR3A" }
|
||||
genes: { x: "S100A8", y: "FCGR3A" },
|
||||
},
|
||||
pan: {
|
||||
"coordinates-as-percent": { x1: 0.75, y1: 0.75, x2: 0.35, y2: 0.35 }
|
||||
"coordinates-as-percent": { x1: 0.75, y1: 0.75, x2: 0.35, y2: 0.35 },
|
||||
},
|
||||
features: {
|
||||
panzoom: {
|
||||
lasso: {
|
||||
"coordinates-as-percent": { x1: 0.3, y1: 0.3, x2: 0.5, y2: 0.5 },
|
||||
count: "24"
|
||||
}
|
||||
}
|
||||
count: "24",
|
||||
},
|
||||
},
|
||||
},
|
||||
categoryLabel: {
|
||||
lasso: {
|
||||
@@ -122,17 +122,17 @@ export const datasets = {
|
||||
newCount: {
|
||||
bySubsetConfig: {
|
||||
false: "600",
|
||||
true: "591"
|
||||
}
|
||||
}
|
||||
true: "591",
|
||||
},
|
||||
},
|
||||
},
|
||||
annotationsFromFile: {
|
||||
count: {
|
||||
bySubsetConfig: {
|
||||
false: "1161",
|
||||
true: "856"
|
||||
}
|
||||
}
|
||||
true: "856",
|
||||
},
|
||||
},
|
||||
},
|
||||
clip: {
|
||||
min: "30",
|
||||
@@ -141,7 +141,7 @@ export const datasets = {
|
||||
gene: "S100A8",
|
||||
"coordinates-as-percent": { x1: 0.25, y1: 0.5, x2: 0.55, y2: 0.5 },
|
||||
count: "386",
|
||||
"gene-cell-count": "416"
|
||||
}
|
||||
}
|
||||
"gene-cell-count": "416",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,7 +24,9 @@ afterAll(() => {
|
||||
|
||||
describe("did launch", () => {
|
||||
test("page launched", async () => {
|
||||
const element = await utils.getOneElementInnerHTML("[data-testid='header']");
|
||||
const element = await utils.getOneElementInnerHTML(
|
||||
"[data-testid='header']"
|
||||
);
|
||||
expect(element).toBe(data.title);
|
||||
});
|
||||
});
|
||||
@@ -32,7 +34,9 @@ describe("did launch", () => {
|
||||
describe("metadata loads", () => {
|
||||
test("categories and values from dataset appear", async () => {
|
||||
for (const label in data.categorical) {
|
||||
const categoryName = await utils.getOneElementInnerText(`[data-testid="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);
|
||||
@@ -50,7 +54,6 @@ describe("metadata loads", () => {
|
||||
await utils.waitByID(`histogram-${label}`);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("cell selection", () => {
|
||||
@@ -81,7 +84,9 @@ describe("cell selection", () => {
|
||||
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}`);
|
||||
await utils.clickOn(
|
||||
`categorical-value-select-${cellset.metadata}-${val}`
|
||||
);
|
||||
}
|
||||
const cellCount = await cxgActions.cellSet(1);
|
||||
expect(cellCount).toBe(cellset.count);
|
||||
@@ -103,12 +108,16 @@ describe("cell selection", () => {
|
||||
});
|
||||
|
||||
describe("gene entry", () => {
|
||||
test("search for single gene", async () => cxgActions.addGeneToSearch(data.genes.search));
|
||||
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);
|
||||
const allHistograms = await cxgActions.getAllHistograms(
|
||||
"histogram-user-gene",
|
||||
testGenes
|
||||
);
|
||||
expect(allHistograms).toEqual(expect.arrayContaining(testGenes));
|
||||
expect(allHistograms.length).toEqual(testGenes.length);
|
||||
});
|
||||
@@ -172,11 +181,19 @@ describe("subset", () => {
|
||||
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});
|
||||
const userDefinedHistograms = await cxgActions.getAllHistograms(
|
||||
"histogram-user-gene",
|
||||
userDefinedGenes
|
||||
);
|
||||
expect(userDefinedHistograms).toEqual(
|
||||
expect.arrayContaining(userDefinedGenes)
|
||||
);
|
||||
await cxgActions.subset({ x1: 0.15, y1: 0.1, x2: 0.98, y2: 0.98 });
|
||||
await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2);
|
||||
const diffExpHistograms = await cxgActions.getAllHistograms("histogram-diffexp", diffExpGenes);
|
||||
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);
|
||||
@@ -184,26 +201,38 @@ describe("subset", () => {
|
||||
"histogram-user-gene",
|
||||
expected
|
||||
);
|
||||
expect(userDefinedHistogramsAfterSubset).toEqual(expect.arrayContaining(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});
|
||||
const userDefinedHistograms = await cxgActions.getAllHistograms(
|
||||
"histogram-user-gene",
|
||||
userDefinedGenes
|
||||
);
|
||||
expect(userDefinedHistograms).toEqual(
|
||||
expect.arrayContaining(userDefinedGenes)
|
||||
);
|
||||
await cxgActions.subset({ x1: 0.15, y1: 0.1, x2: 0.98, y2: 0.98 });
|
||||
await cxgActions.runDiffExp(data.diffexp.cellset1, data.diffexp.cellset2);
|
||||
const diffExpHistograms = await cxgActions.getAllHistograms("histogram-diffexp", diffExpGenes);
|
||||
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});
|
||||
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));
|
||||
expect(userDefinedHistogramsAfterSubset).toEqual(
|
||||
expect.arrayContaining(expected)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -13,14 +13,13 @@ beforeAll(async () => {
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
if (browser !== undefined) browser.close()
|
||||
if (browser !== undefined) browser.close();
|
||||
});
|
||||
|
||||
describe.each([
|
||||
{withSubset: true, tag: "subset"},
|
||||
{withSubset: false, tag: "whole"}
|
||||
{ withSubset: true, tag: "subset" },
|
||||
{ withSubset: false, tag: "whole" },
|
||||
])("annotations", (config) => {
|
||||
|
||||
const perTestCategoryName = "per-test-category";
|
||||
const perTestLabelName = "per-test-label";
|
||||
|
||||
@@ -31,7 +30,8 @@ describe.each([
|
||||
// setup the test fixtures
|
||||
await actions.createCategory(perTestCategoryName);
|
||||
await actions.createLabel(perTestCategoryName, perTestLabelName);
|
||||
if (config.withSubset) await actions.subset({x1: 0.10, y1: 0.10, x2: 0.80, y2: 0.80});
|
||||
if (config.withSubset)
|
||||
await actions.subset({ x1: 0.1, y1: 0.1, x2: 0.8, y2: 0.8 });
|
||||
await utils.waitByClass("autosave-complete");
|
||||
});
|
||||
|
||||
@@ -74,7 +74,11 @@ describe.each([
|
||||
test("rename a label", async () => {
|
||||
const newLabelName = "my-cool-new-label";
|
||||
await assertLabelDoesNotExist(perTestCategoryName, newLabelName);
|
||||
await actions.renameLabel(perTestCategoryName, perTestLabelName, newLabelName);
|
||||
await actions.renameLabel(
|
||||
perTestCategoryName,
|
||||
perTestLabelName,
|
||||
newLabelName
|
||||
);
|
||||
await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName);
|
||||
await assertLabelExists(perTestCategoryName, newLabelName);
|
||||
});
|
||||
@@ -83,8 +87,10 @@ describe.each([
|
||||
const categoryName = "cluster-test";
|
||||
const labelName = "four";
|
||||
await actions.expandCategory(categoryName);
|
||||
const result = await utils.waitByID(`categorical-value-count-${categoryName}-${labelName}`);
|
||||
expect(await result.evaluate(node => node.innerText)).toBe(
|
||||
const result = await utils.waitByID(
|
||||
`categorical-value-count-${categoryName}-${labelName}`
|
||||
);
|
||||
expect(await result.evaluate((node) => node.innerText)).toBe(
|
||||
data.annotationsFromFile.count.bySubsetConfig[config.withSubset]
|
||||
);
|
||||
});
|
||||
@@ -101,11 +107,17 @@ describe.each([
|
||||
lassoSelection.end,
|
||||
true
|
||||
);
|
||||
await utils.waitByID("lasso-element", {visible: true});
|
||||
await utils.clickOn(`${perTestCategoryName}:${perTestLabelName}:see-actions`);
|
||||
await utils.clickOn(`${perTestCategoryName}:${perTestLabelName}:add-current-selection-to-this-label`);
|
||||
const result = await utils.waitByID(`categorical-value-count-${perTestCategoryName}-${perTestLabelName}`);
|
||||
expect(await result.evaluate(node => node.innerText)).toBe(
|
||||
await utils.waitByID("lasso-element", { visible: true });
|
||||
await utils.clickOn(
|
||||
`${perTestCategoryName}:${perTestLabelName}:see-actions`
|
||||
);
|
||||
await utils.clickOn(
|
||||
`${perTestCategoryName}:${perTestLabelName}:add-current-selection-to-this-label`
|
||||
);
|
||||
const result = await utils.waitByID(
|
||||
`categorical-value-count-${perTestCategoryName}-${perTestLabelName}`
|
||||
);
|
||||
expect(await result.evaluate((node) => node.innerText)).toBe(
|
||||
data.categoryLabel.newCount.bySubsetConfig[config.withSubset]
|
||||
);
|
||||
});
|
||||
@@ -170,7 +182,11 @@ describe.each([
|
||||
test("undo/redo label rename", async () => {
|
||||
const newLabelName = `label-renamed-undo-${config.tag}`;
|
||||
await assertLabelDoesNotExist(perTestCategoryName, newLabelName);
|
||||
await actions.renameLabel(perTestCategoryName, perTestLabelName, newLabelName);
|
||||
await actions.renameLabel(
|
||||
perTestCategoryName,
|
||||
perTestLabelName,
|
||||
newLabelName
|
||||
);
|
||||
await assertLabelExists(perTestCategoryName, newLabelName);
|
||||
await assertLabelDoesNotExist(perTestCategoryName, perTestLabelName);
|
||||
await utils.clickOn("undo");
|
||||
@@ -183,14 +199,16 @@ describe.each([
|
||||
|
||||
async function assertCategoryExists(categoryName) {
|
||||
const handle = await utils.waitByID(`${categoryName}:category-expand`);
|
||||
const result = await handle.evaluate(node => node.innerText);
|
||||
const result = await handle.evaluate((node) => node.innerText);
|
||||
// slice beginning and end of category name result to account for truncation of long names
|
||||
expect(result.slice(0, 10)).toBe(categoryName.slice(0, 10));
|
||||
expect(result.slice(-10)).toBe(categoryName.slice(-10));
|
||||
}
|
||||
|
||||
async function assertCategoryDoesNotExist(categoryName) {
|
||||
const result = await page.$(`[data-testid='${categoryName}:category-expand']`);
|
||||
const result = await page.$(
|
||||
`[data-testid='${categoryName}:category-expand']`
|
||||
);
|
||||
expect(result).toBeNull();
|
||||
}
|
||||
|
||||
@@ -198,13 +216,17 @@ describe.each([
|
||||
const category = await utils.waitByID(`${categoryName}:category-expand`);
|
||||
expect(category).not.toBeNull();
|
||||
await actions.expandCategory(categoryName);
|
||||
const previous = await utils.waitByID(`categorical-value-${categoryName}-${labelName}`);
|
||||
expect(await previous.evaluate(node => node.innerText)).toBe(labelName);
|
||||
const previous = await utils.waitByID(
|
||||
`categorical-value-${categoryName}-${labelName}`
|
||||
);
|
||||
expect(await previous.evaluate((node) => node.innerText)).toBe(labelName);
|
||||
}
|
||||
|
||||
async function assertLabelDoesNotExist(categoryName, labelName) {
|
||||
await actions.expandCategory(categoryName);
|
||||
const result = await page.$(`[data-testid='categorical-value-${categoryName}-${labelName}']`);
|
||||
const result = await page.$(
|
||||
`[data-testid='categorical-value-${categoryName}-${labelName}']`
|
||||
);
|
||||
expect(result).toBeNull();
|
||||
}
|
||||
|
||||
@@ -212,10 +234,10 @@ describe.each([
|
||||
try {
|
||||
const category = await page.waitForSelector(
|
||||
`[data-testid='${categoryName}:category-expand']`,
|
||||
{timeout: 200}
|
||||
{ timeout: 200 }
|
||||
);
|
||||
if (category !== null) return await actions.deleteCategory(categoryName);
|
||||
} catch {}
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{
|
||||
"preset": "jest-puppeteer",
|
||||
"testMatch": [
|
||||
"**/__tests__/**/?(*.)(spec|test).js?(x)"
|
||||
],
|
||||
"setupFiles": [
|
||||
"../setupMissingGlobals.js"
|
||||
]
|
||||
"testMatch": ["**/__tests__/**/?(*.)(spec|test).js?(x)"],
|
||||
"setupFiles": ["../setupMissingGlobals.js"]
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ beforeAll(async () => {
|
||||
page = await browser.newPage();
|
||||
await page.setViewport(browserViewport);
|
||||
if (DEV || DEBUG) {
|
||||
page.on("console", msg => console.log(`PAGE LOG: ${msg.text()}`));
|
||||
page.on("console", (msg) => console.log(`PAGE LOG: ${msg.text()}`));
|
||||
}
|
||||
page.on("pageerror", err => {
|
||||
page.on("pageerror", (err) => {
|
||||
throw new Error(`Console error: ${err}`);
|
||||
});
|
||||
utils = puppeteerUtils(page);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const puppeteerUtils = page => ({
|
||||
export const puppeteerUtils = (page) => ({
|
||||
async waitByID(testId, props = {}) {
|
||||
return page.waitForSelector(`[data-testid='${testId}']`, props);
|
||||
},
|
||||
@@ -9,13 +9,13 @@ export const puppeteerUtils = page => ({
|
||||
|
||||
async waitForAllByIds(testIds) {
|
||||
await Promise.all(
|
||||
testIds.map(testId => page.waitForSelector(`[data-testid='${testId}']`))
|
||||
testIds.map((testId) => page.waitForSelector(`[data-testid='${testId}']`))
|
||||
);
|
||||
},
|
||||
|
||||
async getAllByClass(testClass) {
|
||||
return page.$$eval(`[data-testclass=${testClass}]`, eles =>
|
||||
eles.map(ele => ele.dataset.testid)
|
||||
return page.$$eval(`[data-testclass=${testClass}]`, (eles) =>
|
||||
eles.map((ele) => ele.dataset.testid)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -52,18 +52,18 @@ export const puppeteerUtils = page => ({
|
||||
|
||||
async getOneElementInnerHTML(selector) {
|
||||
await page.waitForSelector(selector);
|
||||
return page.$eval(selector, el => el.innerHTML);
|
||||
return page.$eval(selector, (el) => el.innerHTML);
|
||||
},
|
||||
|
||||
async getOneElementInnerText(selector) {
|
||||
await page.waitForSelector(selector);
|
||||
return page.$eval(selector, el => el.innerText);
|
||||
return page.$eval(selector, (el) => el.innerText);
|
||||
},
|
||||
|
||||
async getElementCoordinates(testid) {
|
||||
return page.$eval(`[data-testid='${testid}']`, elem => {
|
||||
return page.$eval(`[data-testid='${testid}']`, (elem) => {
|
||||
const { left, top } = elem.getBoundingClientRect();
|
||||
return [left, top];
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7,41 +7,48 @@ export async function setupTestBrowser() {
|
||||
const browserViewport = { width: 1280, height: 960 };
|
||||
const browserParams = DEV
|
||||
? {
|
||||
headless: false,
|
||||
slowMo: 5,
|
||||
args: [ `--window-size=${browserViewport.width},${browserViewport.height}`]
|
||||
}
|
||||
headless: false,
|
||||
slowMo: 5,
|
||||
args: [
|
||||
`--window-size=${browserViewport.width},${browserViewport.height}`,
|
||||
],
|
||||
}
|
||||
: DEBUG
|
||||
? {
|
||||
? {
|
||||
headless: false,
|
||||
slowMo: 100,
|
||||
devtools: true,
|
||||
args: [ `--window-size=${browserViewport.width + 560},${browserViewport.height}`]
|
||||
args: [
|
||||
`--window-size=${browserViewport.width + 560},${
|
||||
browserViewport.height
|
||||
}`,
|
||||
],
|
||||
}
|
||||
: {
|
||||
args: [ `--window-size=${browserViewport.width},${browserViewport.height}`]
|
||||
: {
|
||||
args: [
|
||||
`--window-size=${browserViewport.width},${browserViewport.height}`,
|
||||
],
|
||||
};
|
||||
const browser = await puppeteer.launch(browserParams);
|
||||
const page = await browser.pages().then(pages => pages[0]);
|
||||
const page = await browser.pages().then((pages) => pages[0]);
|
||||
await page.setViewport(browserViewport);
|
||||
if (DEV || DEBUG) {
|
||||
page.on("console", async msg => {
|
||||
page.on("console", async (msg) => {
|
||||
// If there is a console.error but an error is not thrown, this will ensure the test fails
|
||||
if (msg.type() === "error") {
|
||||
const errorMsgText = await Promise.all(
|
||||
// TODO can we do this without internal properties?
|
||||
msg.args().map(arg => arg._remoteObject.description)
|
||||
msg.args().map((arg) => arg._remoteObject.description)
|
||||
);
|
||||
throw new Error(`Console error: ${errorMsgText}`);
|
||||
}
|
||||
console.log(`PAGE LOG: ${msg.text()}`);
|
||||
});
|
||||
}
|
||||
page.on("pageerror", err => {
|
||||
page.on("pageerror", (err) => {
|
||||
throw new Error(`Console error: ${err}`);
|
||||
});
|
||||
const utils = puppeteerUtils(page);
|
||||
const cxgActions = cellxgeneActions(page, utils);
|
||||
return [browser, page, utils, cxgActions];
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("cascade", () => {
|
||||
expect(nextSharedState).toStrictEqual({});
|
||||
expect(prevSharedState).toBe(topLevelState);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
],
|
||||
[
|
||||
"bar",
|
||||
@@ -36,8 +36,8 @@ describe("cascade", () => {
|
||||
expect(nextSharedState).toStrictEqual({ foo: 0 });
|
||||
expect(prevSharedState).toBe(topLevelState);
|
||||
return 99;
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const nextState = reducer(topLevelState, topLevelAction);
|
||||
|
||||
@@ -23,7 +23,7 @@ describe("create", () => {
|
||||
describe("undo", () => {
|
||||
test("expected state modifications", () => {
|
||||
const initialState = { a: 0, b: 1000 };
|
||||
const reducer = state => {
|
||||
const reducer = (state) => {
|
||||
return { a: state.a + 1, b: state.b + 1 };
|
||||
};
|
||||
const undoableReducer = undoable(reducer, ["a"]);
|
||||
@@ -43,7 +43,7 @@ describe("undo", () => {
|
||||
|
||||
describe("redo", () => {
|
||||
const initialState = { a: 0, b: 1000 };
|
||||
const reducer = state => {
|
||||
const reducer = (state) => {
|
||||
return { a: state.a + 1, b: state.b + 1 };
|
||||
};
|
||||
let UR;
|
||||
@@ -58,7 +58,7 @@ describe("redo", () => {
|
||||
|
||||
// verify undo->redo reverts state.
|
||||
const s2 = UR(UR(s1, { type: "@@undoable/undo" }), {
|
||||
type: "@@undoable/redo"
|
||||
type: "@@undoable/redo",
|
||||
});
|
||||
expect(s2).toMatchObject({ a: 1, b: 1001 });
|
||||
|
||||
|
||||
@@ -13,16 +13,16 @@ describe("rangeEncodeIndices", () => {
|
||||
expect(rangeEncodeIndices([1, 9, 432], 10, true)).toMatchObject([
|
||||
1,
|
||||
9,
|
||||
432
|
||||
432,
|
||||
]);
|
||||
expect(rangeEncodeIndices([1, 9, 432], 10, false)).toMatchObject([
|
||||
1,
|
||||
9,
|
||||
432
|
||||
432,
|
||||
]);
|
||||
expect(rangeEncodeIndices([0, 1, 2, 3, 9, 10, 432], 2, true)).toMatchObject(
|
||||
[[0, 3], [9, 10], 432]
|
||||
);
|
||||
expect(
|
||||
rangeEncodeIndices([0, 1, 2, 3, 9, 10, 432], 2, true)
|
||||
).toMatchObject([[0, 3], [9, 10], 432]);
|
||||
expect(
|
||||
rangeEncodeIndices([0, 1, 2, 3, 9, 10, 432], 2, false)
|
||||
).toMatchObject([[0, 3], [9, 10], 432]);
|
||||
@@ -34,7 +34,10 @@ describe("rangeEncodeIndices", () => {
|
||||
).toMatchObject([[3, 7], [10, 12], 99]);
|
||||
expect(
|
||||
rangeEncodeIndices([3, 4, 5, 6, 7, 10, 11, 12], 3, false)
|
||||
).toMatchObject([[3, 7], [10, 12]]);
|
||||
).toMatchObject([
|
||||
[3, 7],
|
||||
[10, 12],
|
||||
]);
|
||||
expect(
|
||||
rangeEncodeIndices([0, 3, 4, 5, 6, 7, 10, 11, 12], 3, false)
|
||||
).toMatchObject([0, [3, 7], [10, 12]]);
|
||||
|
||||
@@ -31,7 +31,7 @@ describe("centroid", () => {
|
||||
...Universe.addObsLayout(
|
||||
universe,
|
||||
Universe.matrixFBSToDataframe(REST.layoutObs)
|
||||
)
|
||||
),
|
||||
};
|
||||
world = World.createWorldFromEntireUniverse(universe);
|
||||
|
||||
@@ -61,10 +61,10 @@ describe("centroid", () => {
|
||||
// This expected result assumes that all cells belong in all categorical values inside of sample response
|
||||
const expectedResult = [
|
||||
quantile([0.5], world.obsLayout.col("umap_0").asArray())[0],
|
||||
quantile([0.5], world.obsLayout.col("umap_1").asArray())[0]
|
||||
quantile([0.5], world.obsLayout.col("umap_1").asArray())[0],
|
||||
];
|
||||
|
||||
centroidResult.forEach(coordinate => {
|
||||
centroidResult.forEach((coordinate) => {
|
||||
expect(coordinate).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
@@ -86,10 +86,10 @@ describe("centroid", () => {
|
||||
// This expected result assumes that all cells belong in all categorical values inside of sample response
|
||||
const expectedResult = [
|
||||
quantile([0.5], world.obsLayout.col("umap_0").asArray())[0],
|
||||
quantile([0.5], world.obsLayout.col("umap_1").asArray())[0]
|
||||
quantile([0.5], world.obsLayout.col("umap_1").asArray())[0],
|
||||
];
|
||||
|
||||
centroidResult.forEach(coordinate => {
|
||||
centroidResult.forEach((coordinate) => {
|
||||
expect(coordinate).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ describe("simple data access", () => {
|
||||
[4, 2],
|
||||
[
|
||||
new Float64Array([0.0, Number.NaN, Number.POSITIVE_INFINITY, 3.14159]),
|
||||
["red", "blue", "green", "nan"]
|
||||
["red", "blue", "green", "nan"],
|
||||
],
|
||||
new Dataframe.DenseInt32Index([3, 2, 1, 0]),
|
||||
new Dataframe.KeyIndex(["numbers", "colors"])
|
||||
@@ -136,7 +136,7 @@ describe("dataframe subsetting", () => {
|
||||
new Int32Array([0, 1, 2]),
|
||||
["A", "B", "C"],
|
||||
new Float32Array([4.4, 5.5, 6.6]),
|
||||
["red", "green", "blue"]
|
||||
["red", "green", "blue"],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||
@@ -258,7 +258,7 @@ describe("dataframe subsetting", () => {
|
||||
new Int32Array([0, 1, 2]),
|
||||
["A", "B", "C"],
|
||||
new Float32Array([4.4, 5.5, 6.6]),
|
||||
["red", "green", "blue"]
|
||||
["red", "green", "blue"],
|
||||
],
|
||||
new Dataframe.DenseInt32Index([2, 4, 6]),
|
||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||
@@ -283,7 +283,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
new Array(3).fill(0),
|
||||
new Int16Array(3).fill(99),
|
||||
new Float64Array(3).fill(1.1)
|
||||
new Float64Array(3).fill(1.1),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -323,7 +323,7 @@ describe("dataframe factories", () => {
|
||||
[2, 2],
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false]
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["colors", "bools"])
|
||||
@@ -346,7 +346,7 @@ describe("dataframe factories", () => {
|
||||
[2, 2],
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false]
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
new Dataframe.DenseInt32Index([74, 75])
|
||||
@@ -371,7 +371,7 @@ describe("dataframe factories", () => {
|
||||
[2, 2],
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false]
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
new Dataframe.DenseInt32Index([74, 75])
|
||||
@@ -396,7 +396,7 @@ describe("dataframe factories", () => {
|
||||
[2, 2],
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false]
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
null
|
||||
@@ -421,7 +421,7 @@ describe("dataframe factories", () => {
|
||||
[2, 2],
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false]
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
null
|
||||
@@ -479,7 +479,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
@@ -553,7 +553,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
@@ -595,7 +595,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
@@ -618,7 +618,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
@@ -641,7 +641,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
null
|
||||
@@ -665,7 +665,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
null
|
||||
@@ -689,7 +689,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
["red", "blue"],
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.DenseInt32Index([102, 101, 100])
|
||||
@@ -715,7 +715,7 @@ describe("dataframe factories", () => {
|
||||
[
|
||||
new Array(3).fill(0),
|
||||
new Int16Array(3).fill(99),
|
||||
new Float64Array(3).fill(1.1)
|
||||
new Float64Array(3).fill(1.1),
|
||||
]
|
||||
);
|
||||
const dfB = dfA.mapColumns((col, idx) => {
|
||||
@@ -760,7 +760,7 @@ describe("dataframe factories", () => {
|
||||
[2, 2],
|
||||
[
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
@@ -781,7 +781,7 @@ describe("dataframe col", () => {
|
||||
[2, 2],
|
||||
[
|
||||
[true, false],
|
||||
[1, 0]
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
|
||||
@@ -14,7 +14,7 @@ describe("Dataframe column histogram", () => {
|
||||
new Map([
|
||||
["n1", new Map([["c1", 1]])],
|
||||
["n2", new Map([["c2", 1]])],
|
||||
["n3", new Map([["c3", 1]])]
|
||||
["n3", new Map([["c3", 1]])],
|
||||
])
|
||||
);
|
||||
// memoized?
|
||||
@@ -31,7 +31,11 @@ describe("Dataframe column histogram", () => {
|
||||
|
||||
const h1 = df.col("value").histogram(3, [0, 2], df.col("name"));
|
||||
expect(h1).toMatchObject(
|
||||
new Map([["n1", [1, 0, 0]], ["n2", [0, 1, 0]], ["n3", [0, 0, 1]]])
|
||||
new Map([
|
||||
["n1", [1, 0, 0]],
|
||||
["n2", [0, 1, 0]],
|
||||
["n3", [0, 0, 1]],
|
||||
])
|
||||
);
|
||||
// memoized?
|
||||
expect(df.col("value").histogram(3, [0, 2], df.col("name"))).toMatchObject(
|
||||
@@ -48,7 +52,13 @@ describe("Dataframe column histogram", () => {
|
||||
);
|
||||
|
||||
const h1 = df.col("cat").histogram();
|
||||
expect(h1).toMatchObject(new Map([["c1", 1], ["c2", 1], ["c3", 1]]));
|
||||
expect(h1).toMatchObject(
|
||||
new Map([
|
||||
["c1", 1],
|
||||
["c2", 1],
|
||||
["c3", 1],
|
||||
])
|
||||
);
|
||||
// memoized?
|
||||
expect(df.col("value").histogram(3, [0, 2])).toMatchObject(h1);
|
||||
});
|
||||
@@ -87,7 +97,7 @@ describe("Dataframe column histogram", () => {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
2,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ describe("Dataframe column summary", () => {
|
||||
categorical: true,
|
||||
categories: [],
|
||||
categoryCounts: new Map(),
|
||||
numCategories: 0
|
||||
numCategories: 0,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -27,7 +27,7 @@ describe("Dataframe column summary", () => {
|
||||
[true],
|
||||
new Float32Array([39.3]),
|
||||
new Int32Array([99]),
|
||||
[1]
|
||||
[1],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex([
|
||||
@@ -36,7 +36,7 @@ describe("Dataframe column summary", () => {
|
||||
"nameBoolean",
|
||||
"nameFloat32",
|
||||
"nameInt32",
|
||||
"nameCategorical"
|
||||
"nameCategorical",
|
||||
])
|
||||
);
|
||||
|
||||
@@ -45,7 +45,7 @@ describe("Dataframe column summary", () => {
|
||||
categorical: true,
|
||||
categories: ["n1"],
|
||||
categoryCounts: new Map([["n1", 1]]),
|
||||
numCategories: 1
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(1).summarize()).toEqual(
|
||||
@@ -53,7 +53,7 @@ describe("Dataframe column summary", () => {
|
||||
categorical: true,
|
||||
categories: ["hi"],
|
||||
categoryCounts: new Map([["hi", 1]]),
|
||||
numCategories: 1
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(2).summarize()).toEqual(
|
||||
@@ -61,7 +61,7 @@ describe("Dataframe column summary", () => {
|
||||
categorical: true,
|
||||
categories: [true],
|
||||
categoryCounts: new Map([[true, 1]]),
|
||||
numCategories: 1
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(3).summarize()).toEqual(
|
||||
@@ -71,7 +71,7 @@ describe("Dataframe column summary", () => {
|
||||
max: float32Conversion(39.3),
|
||||
nan: 0,
|
||||
ninf: 0,
|
||||
pinf: 0
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(4).summarize()).toEqual(
|
||||
@@ -81,7 +81,7 @@ describe("Dataframe column summary", () => {
|
||||
max: 99,
|
||||
nan: 0,
|
||||
ninf: 0,
|
||||
pinf: 0
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(5).summarize()).toEqual(
|
||||
@@ -89,7 +89,7 @@ describe("Dataframe column summary", () => {
|
||||
categorical: true,
|
||||
categories: [1],
|
||||
categoryCounts: new Map([[1, 1]]),
|
||||
numCategories: 1
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -103,7 +103,7 @@ describe("Dataframe column summary", () => {
|
||||
[false, true, true],
|
||||
new Float32Array([39.3, 39.3, 0]),
|
||||
new Int32Array([99, 99, 99]),
|
||||
[1, false, "0"]
|
||||
[1, false, "0"],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex([
|
||||
@@ -112,7 +112,7 @@ describe("Dataframe column summary", () => {
|
||||
"nameBoolean",
|
||||
"nameFloat32",
|
||||
"nameInt32",
|
||||
"nameCategorical"
|
||||
"nameCategorical",
|
||||
])
|
||||
);
|
||||
|
||||
@@ -120,24 +120,34 @@ describe("Dataframe column summary", () => {
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["n0", "n1", "n2"]),
|
||||
categoryCounts: new Map([["n0", 1], ["n1", 1], ["n2", 1]]),
|
||||
numCategories: 3
|
||||
categoryCounts: new Map([
|
||||
["n0", 1],
|
||||
["n1", 1],
|
||||
["n2", 1],
|
||||
]),
|
||||
numCategories: 3,
|
||||
})
|
||||
);
|
||||
expect(df.icol(1).summarize()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["hi", "bye"]),
|
||||
categoryCounts: new Map([["hi", 2], ["bye", 1]]),
|
||||
numCategories: 2
|
||||
categoryCounts: new Map([
|
||||
["hi", 2],
|
||||
["bye", 1],
|
||||
]),
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(2).summarize()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([true, false]),
|
||||
categoryCounts: new Map([[true, 2], [false, 1]]),
|
||||
numCategories: 2
|
||||
categoryCounts: new Map([
|
||||
[true, 2],
|
||||
[false, 1],
|
||||
]),
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(3).summarize()).toEqual(
|
||||
@@ -147,7 +157,7 @@ describe("Dataframe column summary", () => {
|
||||
max: float32Conversion(39.3),
|
||||
nan: 0,
|
||||
ninf: 0,
|
||||
pinf: 0
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(4).summarize()).toEqual(
|
||||
@@ -157,15 +167,19 @@ describe("Dataframe column summary", () => {
|
||||
max: 99,
|
||||
nan: 0,
|
||||
ninf: 0,
|
||||
pinf: 0
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(5).summarize()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([1, false, "0"]),
|
||||
categoryCounts: new Map([[1, 1], [false, 1], ["0", 1]]),
|
||||
numCategories: 3
|
||||
categoryCounts: new Map([
|
||||
[1, 1],
|
||||
[false, 1],
|
||||
["0", 1],
|
||||
]),
|
||||
numCategories: 3,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -181,10 +195,10 @@ describe("Dataframe column summary", () => {
|
||||
39.3,
|
||||
Number.NEGATIVE_INFINITY,
|
||||
Number.NaN,
|
||||
Number.POSITIVE_INFINITY
|
||||
Number.POSITIVE_INFINITY,
|
||||
]),
|
||||
new Int32Array([99, 99, 99, 99]),
|
||||
[1, false, "0", "0"]
|
||||
[1, false, "0", "0"],
|
||||
],
|
||||
null,
|
||||
new Dataframe.KeyIndex([
|
||||
@@ -193,7 +207,7 @@ describe("Dataframe column summary", () => {
|
||||
"nameBoolean",
|
||||
"nameFloat32",
|
||||
"nameInt32",
|
||||
"nameCategorical"
|
||||
"nameCategorical",
|
||||
])
|
||||
);
|
||||
|
||||
@@ -201,24 +215,34 @@ describe("Dataframe column summary", () => {
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["n0", "n1", "n2"]),
|
||||
categoryCounts: new Map([["n0", 1], ["n1", 1], ["n2", 2]]),
|
||||
numCategories: 3
|
||||
categoryCounts: new Map([
|
||||
["n0", 1],
|
||||
["n1", 1],
|
||||
["n2", 2],
|
||||
]),
|
||||
numCategories: 3,
|
||||
})
|
||||
);
|
||||
expect(df.icol(1).summarize()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["hi", "bye"]),
|
||||
categoryCounts: new Map([["hi", 2], ["bye", 1]]),
|
||||
numCategories: 2
|
||||
categoryCounts: new Map([
|
||||
["hi", 2],
|
||||
["bye", 1],
|
||||
]),
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(2).summarize()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([true, false]),
|
||||
categoryCounts: new Map([[true, 2], [false, 1]]),
|
||||
numCategories: 2
|
||||
categoryCounts: new Map([
|
||||
[true, 2],
|
||||
[false, 1],
|
||||
]),
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(3).summarize()).toEqual(
|
||||
@@ -228,7 +252,7 @@ describe("Dataframe column summary", () => {
|
||||
max: float32Conversion(39.3),
|
||||
nan: 1,
|
||||
ninf: 1,
|
||||
pinf: 1
|
||||
pinf: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(4).summarize()).toEqual(
|
||||
@@ -238,15 +262,19 @@ describe("Dataframe column summary", () => {
|
||||
max: 99,
|
||||
nan: 0,
|
||||
ninf: 0,
|
||||
pinf: 0
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(5).summarize()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([1, false, "0"]),
|
||||
categoryCounts: new Map([[1, 1], [false, 1], ["0", 1]]),
|
||||
numCategories: 3
|
||||
categoryCounts: new Map([
|
||||
[1, 1],
|
||||
[false, 1],
|
||||
["0", 1],
|
||||
]),
|
||||
numCategories: 3,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
obsAnnoDimensionName,
|
||||
diffexpDimensionName,
|
||||
userDefinedDimensionName,
|
||||
makeContinuousDimensionName
|
||||
makeContinuousDimensionName,
|
||||
} from "../../src/util/nameCreators";
|
||||
|
||||
describe("nameCreators", () => {
|
||||
@@ -14,25 +14,25 @@ describe("nameCreators", () => {
|
||||
layoutDimensionName,
|
||||
obsAnnoDimensionName,
|
||||
diffexpDimensionName,
|
||||
userDefinedDimensionName
|
||||
userDefinedDimensionName,
|
||||
];
|
||||
|
||||
test("check for namespace isolation", () => {
|
||||
const foo = "foo";
|
||||
nameCreators.forEach(fn => expect(fn(foo)).not.toBe(foo));
|
||||
nameCreators.forEach((fn) => expect(fn(foo)).not.toBe(foo));
|
||||
|
||||
const bar = "bar";
|
||||
nameCreators.forEach(fn => expect(fn(foo)).not.toBe(fn(bar)));
|
||||
nameCreators.forEach((fn) => expect(fn(foo)).not.toBe(fn(bar)));
|
||||
|
||||
nameCreators.forEach(fn => {
|
||||
const allOtherFn = nameCreators.filter(elmnt => elmnt !== fn);
|
||||
allOtherFn.forEach(otherFn => expect(fn(foo)).not.toBe(otherFn(foo)));
|
||||
nameCreators.forEach((fn) => {
|
||||
const allOtherFn = nameCreators.filter((elmnt) => elmnt !== fn);
|
||||
allOtherFn.forEach((otherFn) => expect(fn(foo)).not.toBe(otherFn(foo)));
|
||||
});
|
||||
});
|
||||
|
||||
test("check for legal keys", () => {
|
||||
/* need namespace creators to return strings only */
|
||||
nameCreators.forEach(fn => expect(fn("X")).toMatch(/X/));
|
||||
nameCreators.forEach((fn) => expect(fn("X")).toMatch(/X/));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
import { PromiseLimit } from "../../src/util/promiseLimit";
|
||||
import { range } from "../../src/util/range";
|
||||
|
||||
const delay = t => new Promise((resolve, reject) => setTimeout(resolve, t));
|
||||
const delay = (t) => new Promise((resolve, reject) => setTimeout(resolve, t));
|
||||
|
||||
describe("PromiseLimit", () => {
|
||||
test("simple evaluation, concurrency 1", async () => {
|
||||
const plimit = new PromiseLimit(1);
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve(1)),
|
||||
plimit.add(() => Promise.resolve(2)),
|
||||
plimit.add(() => Promise.resolve(3)),
|
||||
plimit.add(() => Promise.resolve(4))
|
||||
]);
|
||||
expect(result).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
test("simple evaluation, concurrency 1", async () => {
|
||||
const plimit = new PromiseLimit(1);
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve(1)),
|
||||
plimit.add(() => Promise.resolve(2)),
|
||||
plimit.add(() => Promise.resolve(3)),
|
||||
plimit.add(() => Promise.resolve(4)),
|
||||
]);
|
||||
expect(result).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test("simple evaluation, concurrency > 1", async () => {
|
||||
const plimit = new PromiseLimit(100);
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve(1)),
|
||||
plimit.add(() => Promise.resolve(2)),
|
||||
plimit.add(() => Promise.resolve(3)),
|
||||
plimit.add(() => Promise.resolve(4))
|
||||
]);
|
||||
expect(result).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
test("simple evaluation, concurrency > 1", async () => {
|
||||
const plimit = new PromiseLimit(100);
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve(1)),
|
||||
plimit.add(() => Promise.resolve(2)),
|
||||
plimit.add(() => Promise.resolve(3)),
|
||||
plimit.add(() => Promise.resolve(4)),
|
||||
]);
|
||||
expect(result).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test("eval in order of insertion", async () => {
|
||||
const plimit = new PromiseLimit(100);
|
||||
let counter = 0;
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
plimit.add(() => Promise.resolve((counter += 1)))
|
||||
]);
|
||||
expect(result).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
test("eval in order of insertion", async () => {
|
||||
const plimit = new PromiseLimit(100);
|
||||
let counter = 0;
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
plimit.add(() => Promise.resolve((counter += 1))),
|
||||
]);
|
||||
expect(result).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test("obeys concurrency limit", async () => {
|
||||
const plimit = new PromiseLimit(2);
|
||||
let running = 0;
|
||||
let maxRunning = 0;
|
||||
test("obeys concurrency limit", async () => {
|
||||
const plimit = new PromiseLimit(2);
|
||||
let running = 0;
|
||||
let maxRunning = 0;
|
||||
|
||||
const cbfn = async i => {
|
||||
running = running + 1;
|
||||
maxRunning = running > maxRunning ? running : maxRunning;
|
||||
await delay(100);
|
||||
running = running - 1;
|
||||
};
|
||||
const cbfn = async (i) => {
|
||||
running = running + 1;
|
||||
maxRunning = running > maxRunning ? running : maxRunning;
|
||||
await delay(100);
|
||||
running = running - 1;
|
||||
};
|
||||
|
||||
const result = await Promise.all(
|
||||
range(10).map(i => plimit.add(() => cbfn(i)))
|
||||
);
|
||||
expect(maxRunning).toEqual(2);
|
||||
});
|
||||
const result = await Promise.all(
|
||||
range(10).map((i) => plimit.add(() => cbfn(i)))
|
||||
);
|
||||
expect(maxRunning).toEqual(2);
|
||||
});
|
||||
|
||||
test("rejection", async () => {
|
||||
const plimit = new PromiseLimit(2);
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve("OK")),
|
||||
plimit.add(() => Promise.reject("not OK")).catch(e => e),
|
||||
plimit.add(() => Promise.resolve("OK")),
|
||||
plimit
|
||||
.add(() => {
|
||||
throw new Error("not OK");
|
||||
})
|
||||
.catch(e => e.message)
|
||||
]);
|
||||
expect(result).toEqual(["OK", "not OK", "OK", "not OK"]);
|
||||
});
|
||||
test("rejection", async () => {
|
||||
const plimit = new PromiseLimit(2);
|
||||
const result = await Promise.all([
|
||||
plimit.add(() => Promise.resolve("OK")),
|
||||
plimit.add(() => Promise.reject("not OK")).catch((e) => e),
|
||||
plimit.add(() => Promise.resolve("OK")),
|
||||
plimit
|
||||
.add(() => {
|
||||
throw new Error("not OK");
|
||||
})
|
||||
.catch((e) => e.message),
|
||||
]);
|
||||
expect(result).toEqual(["OK", "not OK", "OK", "not OK"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import quantile from "../../src/util/quantile";
|
||||
|
||||
describe("quantile", () => {
|
||||
test("single q", () => {
|
||||
const arr = new Float32Array([9, 3, 5, 6, 0]);
|
||||
expect(quantile([1.0], arr)).toMatchObject([9]);
|
||||
expect(quantile([0.9], arr)).toMatchObject([9]);
|
||||
expect(quantile([0.8], arr)).toMatchObject([9]);
|
||||
expect(quantile([0.7], arr)).toMatchObject([6]);
|
||||
expect(quantile([0.6], arr)).toMatchObject([6]);
|
||||
expect(quantile([0.5], arr)).toMatchObject([5]);
|
||||
expect(quantile([0.4], arr)).toMatchObject([5]);
|
||||
expect(quantile([0.3], arr)).toMatchObject([3]);
|
||||
expect(quantile([0.2], arr)).toMatchObject([3]);
|
||||
expect(quantile([0.1], arr)).toMatchObject([0]);
|
||||
expect(quantile([0], arr)).toMatchObject([0]);
|
||||
});
|
||||
test("single q", () => {
|
||||
const arr = new Float32Array([9, 3, 5, 6, 0]);
|
||||
expect(quantile([1.0], arr)).toMatchObject([9]);
|
||||
expect(quantile([0.9], arr)).toMatchObject([9]);
|
||||
expect(quantile([0.8], arr)).toMatchObject([9]);
|
||||
expect(quantile([0.7], arr)).toMatchObject([6]);
|
||||
expect(quantile([0.6], arr)).toMatchObject([6]);
|
||||
expect(quantile([0.5], arr)).toMatchObject([5]);
|
||||
expect(quantile([0.4], arr)).toMatchObject([5]);
|
||||
expect(quantile([0.3], arr)).toMatchObject([3]);
|
||||
expect(quantile([0.2], arr)).toMatchObject([3]);
|
||||
expect(quantile([0.1], arr)).toMatchObject([0]);
|
||||
expect(quantile([0], arr)).toMatchObject([0]);
|
||||
});
|
||||
|
||||
test("multi q", () => {
|
||||
const arr = new Float32Array([9, 3, 5, 6, 0]);
|
||||
expect(quantile([0, 0.25, 0.5, 0.75, 1.0], arr)).toMatchObject([
|
||||
0,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
9
|
||||
]);
|
||||
});
|
||||
test("multi q", () => {
|
||||
const arr = new Float32Array([9, 3, 5, 6, 0]);
|
||||
expect(quantile([0, 0.25, 0.5, 0.75, 1.0], arr)).toMatchObject([
|
||||
0,
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
9,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,50 +1,48 @@
|
||||
import { range, rangeFill, linspace } from "../../src/util/range";
|
||||
|
||||
describe("range", () => {
|
||||
test("no defaults", () => {
|
||||
expect(range(0, 3, 1)).toMatchObject([0, 1, 2]);
|
||||
});
|
||||
test("no defaults", () => {
|
||||
expect(range(0, 3, 1)).toMatchObject([0, 1, 2]);
|
||||
});
|
||||
|
||||
test("range(stop)", () => {
|
||||
expect(range(3)).toMatchObject([0, 1, 2]);
|
||||
expect(range(0)).toMatchObject([]);
|
||||
expect(range(1)).toMatchObject([0]);
|
||||
});
|
||||
test("range(stop)", () => {
|
||||
expect(range(3)).toMatchObject([0, 1, 2]);
|
||||
expect(range(0)).toMatchObject([]);
|
||||
expect(range(1)).toMatchObject([0]);
|
||||
});
|
||||
|
||||
test("range(start,stop)", () => {
|
||||
expect(range(0, 0)).toMatchObject([]);
|
||||
expect(range(0, 2)).toMatchObject([0, 1]);
|
||||
expect(range(4, 8)).toMatchObject([4, 5, 6, 7]);
|
||||
});
|
||||
test("range(start,stop)", () => {
|
||||
expect(range(0, 0)).toMatchObject([]);
|
||||
expect(range(0, 2)).toMatchObject([0, 1]);
|
||||
expect(range(4, 8)).toMatchObject([4, 5, 6, 7]);
|
||||
});
|
||||
|
||||
test("range(start, stop, step", () => {
|
||||
expect(range(4, 0, -1)).toMatchObject([4, 3, 2, 1]);
|
||||
expect(range(0, 4, 2)).toMatchObject([0, 2]);
|
||||
});
|
||||
test("range(start, stop, step", () => {
|
||||
expect(range(4, 0, -1)).toMatchObject([4, 3, 2, 1]);
|
||||
expect(range(0, 4, 2)).toMatchObject([0, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("rangefill", () => {
|
||||
test("rangeFill(arr)", () => {
|
||||
expect(rangeFill(new Int32Array(3))).toMatchObject(
|
||||
new Int32Array([0, 1, 2])
|
||||
);
|
||||
});
|
||||
test("rangeFill(arr, start)", () => {
|
||||
expect(rangeFill(new Int32Array(2), 1)).toMatchObject(
|
||||
new Int32Array([1, 2])
|
||||
);
|
||||
});
|
||||
test("rangeFill(arr, start, step)", () => {
|
||||
expect(rangeFill(new Int32Array(3), 2, -1)).toMatchObject(
|
||||
new Int32Array([2, 1, 0])
|
||||
);
|
||||
});
|
||||
test("rangeFill(arr)", () => {
|
||||
expect(rangeFill(new Int32Array(3))).toMatchObject(
|
||||
new Int32Array([0, 1, 2])
|
||||
);
|
||||
});
|
||||
test("rangeFill(arr, start)", () => {
|
||||
expect(rangeFill(new Int32Array(2), 1)).toMatchObject(
|
||||
new Int32Array([1, 2])
|
||||
);
|
||||
});
|
||||
test("rangeFill(arr, start, step)", () => {
|
||||
expect(rangeFill(new Int32Array(3), 2, -1)).toMatchObject(
|
||||
new Int32Array([2, 1, 0])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("linspace", () => {
|
||||
test("linspace(arr, start, step)", () => {
|
||||
expect(linspace(0.0, 2.0, 5)).toMatchObject(
|
||||
[0.0, 0.5, 1.0, 1.5, 2.0]
|
||||
);
|
||||
});
|
||||
test("linspace(arr, start, step)", () => {
|
||||
expect(linspace(0.0, 2.0, 5)).toMatchObject([0.0, 0.5, 1.0, 1.5, 2.0]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,20 +5,23 @@ import { subsetAndResetGeneLists } from "../../../src/util/stateManager/controls
|
||||
import * as globals from "../../../src/globals";
|
||||
|
||||
describe("controls helpers", () => {
|
||||
|
||||
test("subsetAndResetGeneLists", () => {
|
||||
const geneList = [...Array(150).keys()].map(() =>
|
||||
Math.random().toString(36).substring(2, 6) // random string of 4 characters
|
||||
const geneList = [...Array(150).keys()].map(
|
||||
() => Math.random().toString(36).substring(2, 6) // random string of 4 characters
|
||||
);
|
||||
const state = {
|
||||
userDefinedGenes: geneList.slice(0, 20),
|
||||
diffexpGenes: geneList.slice(20),
|
||||
};
|
||||
const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists(state);
|
||||
const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists(
|
||||
state
|
||||
);
|
||||
expect(globals.maxUserDefinedGenes).toBeLessThan(globals.maxGenes);
|
||||
expect(geneList.length).toBeGreaterThan(globals.maxGenes);
|
||||
expect(newUserDefinedGenes).toHaveLength(globals.maxGenes);
|
||||
expect(newUserDefinedGenes).toStrictEqual(geneList.slice(0, globals.maxGenes));
|
||||
expect(newUserDefinedGenes).toStrictEqual(
|
||||
geneList.slice(0, globals.maxGenes)
|
||||
);
|
||||
expect(newDiffExpGenes).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,32 +3,32 @@ test FBS encode/decode API
|
||||
*/
|
||||
import { Dataframe, KeyIndex } from "../../../src/util/dataframe";
|
||||
import {
|
||||
decodeMatrixFBS,
|
||||
encodeMatrixFBS
|
||||
decodeMatrixFBS,
|
||||
encodeMatrixFBS,
|
||||
} from "../../../src/util/stateManager/matrix";
|
||||
|
||||
describe("encode/decode", () => {
|
||||
test("round trip", () => {
|
||||
const columns = [
|
||||
["red", "green", "blue"],
|
||||
new Int32Array(3).fill(0),
|
||||
new Uint32Array(3).fill(1),
|
||||
new Float32Array(3).fill(2)
|
||||
];
|
||||
test("round trip", () => {
|
||||
const columns = [
|
||||
["red", "green", "blue"],
|
||||
new Int32Array(3).fill(0),
|
||||
new Uint32Array(3).fill(1),
|
||||
new Float32Array(3).fill(2),
|
||||
];
|
||||
|
||||
const dfNoColIdx = new Dataframe([3, 4], columns);
|
||||
const dfA = decodeMatrixFBS(encodeMatrixFBS(dfNoColIdx));
|
||||
expect([dfA.nRows, dfA.nCols]).toEqual(dfNoColIdx.dims);
|
||||
expect(dfA.colIdx).toBeNull();
|
||||
expect(dfA.rowIdx).toBeNull();
|
||||
expect(dfA.columns).toEqual(columns);
|
||||
const dfNoColIdx = new Dataframe([3, 4], columns);
|
||||
const dfA = decodeMatrixFBS(encodeMatrixFBS(dfNoColIdx));
|
||||
expect([dfA.nRows, dfA.nCols]).toEqual(dfNoColIdx.dims);
|
||||
expect(dfA.colIdx).toBeNull();
|
||||
expect(dfA.rowIdx).toBeNull();
|
||||
expect(dfA.columns).toEqual(columns);
|
||||
|
||||
const colIndex = new KeyIndex(["a", "b", "c", "d"]);
|
||||
const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex);
|
||||
const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx));
|
||||
expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims);
|
||||
expect(dfB.colIdx).toEqual(colIndex.keys());
|
||||
expect(dfB.rowIdx).toBeNull();
|
||||
expect(dfB.columns).toEqual(columns);
|
||||
});
|
||||
const colIndex = new KeyIndex(["a", "b", "c", "d"]);
|
||||
const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex);
|
||||
const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx));
|
||||
expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims);
|
||||
expect(dfB.colIdx).toEqual(colIndex.keys());
|
||||
expect(dfB.rowIdx).toBeNull();
|
||||
expect(dfB.columns).toEqual(columns);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,13 +17,13 @@ const aConfigResponse = {
|
||||
{ method: "POST", path: "/cluster/", available: false },
|
||||
{ method: "POST", path: "/layout/", available: false },
|
||||
{ method: "POST", path: "/diffexp/", available: false },
|
||||
{ method: "POST", path: "/saveLocal/", available: false }
|
||||
{ method: "POST", path: "/saveLocal/", available: false },
|
||||
],
|
||||
displayNames: {
|
||||
engine: "the little engine that could",
|
||||
dataset: "all your zeros are mine"
|
||||
}
|
||||
}
|
||||
dataset: "all your zeros are mine",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const aSchemaResponse = {
|
||||
@@ -31,7 +31,7 @@ const aSchemaResponse = {
|
||||
dataframe: {
|
||||
nObs,
|
||||
nVar,
|
||||
type: "float32"
|
||||
type: "float32",
|
||||
},
|
||||
annotations: {
|
||||
obs: {
|
||||
@@ -44,9 +44,9 @@ const aSchemaResponse = {
|
||||
{
|
||||
name: "field4",
|
||||
type: "categorical",
|
||||
categories: field4Categories
|
||||
}
|
||||
]
|
||||
categories: field4Categories,
|
||||
},
|
||||
],
|
||||
},
|
||||
var: {
|
||||
index: "name",
|
||||
@@ -58,46 +58,46 @@ const aSchemaResponse = {
|
||||
{
|
||||
name: "fieldD",
|
||||
type: "categorical",
|
||||
categories: fieldDCategories
|
||||
}
|
||||
]
|
||||
}
|
||||
categories: fieldDCategories,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
obs: [{ name: "umap", type: "float32", dims: ["umap_0", "umap_1"] }],
|
||||
var: []
|
||||
}
|
||||
}
|
||||
var: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const anAnnotationsObsJSONResponse = {
|
||||
names: ["name", "field1", "field2", "field3", "field4"],
|
||||
data: _()
|
||||
.range(nObs)
|
||||
.map(idx => [
|
||||
.map((idx) => [
|
||||
idx,
|
||||
`obs${idx}`,
|
||||
2 * idx,
|
||||
idx + 0.0133,
|
||||
!!(idx & 1),
|
||||
field4Categories[idx % field4Categories.length]
|
||||
field4Categories[idx % field4Categories.length],
|
||||
])
|
||||
.value()
|
||||
.value(),
|
||||
};
|
||||
|
||||
const anAnnotationsVarJSONResponse = {
|
||||
names: ["fieldA", "fieldB", "fieldC", "fieldD", "name"],
|
||||
data: _()
|
||||
.range(nVar)
|
||||
.map(idx => [
|
||||
.map((idx) => [
|
||||
idx,
|
||||
10 * idx,
|
||||
idx + 2.90143,
|
||||
!!(idx & 1),
|
||||
fieldDCategories[idx % fieldDCategories.length],
|
||||
`var${idx}`
|
||||
`var${idx}`,
|
||||
])
|
||||
.value()
|
||||
.value(),
|
||||
};
|
||||
|
||||
function encodeTypedArray(builder, uType, uData) {
|
||||
@@ -120,7 +120,7 @@ function encodeMatrix(columns, colIndex = undefined) {
|
||||
*/
|
||||
const utf8Encoder = new TextEncoder("utf-8");
|
||||
const builder = new flatbuffers.Builder(1024);
|
||||
const cols = _.map(columns, carr => {
|
||||
const cols = _.map(columns, (carr) => {
|
||||
let uType;
|
||||
let tarr;
|
||||
if (_.every(carr, _.isNumber)) {
|
||||
@@ -178,7 +178,7 @@ const anAnnotationsVarFBSResponse = (() => {
|
||||
const aLayoutFBSResponse = (() => {
|
||||
const coords = [
|
||||
new Float32Array(nObs).fill(Math.random()),
|
||||
new Float32Array(nObs).fill(Math.random())
|
||||
new Float32Array(nObs).fill(Math.random()),
|
||||
];
|
||||
return encodeMatrix(coords, ["umap_0", "umap_1"]);
|
||||
})();
|
||||
@@ -187,8 +187,8 @@ const aDataObsResponse = {
|
||||
var: [2, 4, 29],
|
||||
obs: _()
|
||||
.range(nObs)
|
||||
.map(idx => [idx, Math.random(), Math.random(), Math.random()])
|
||||
.value()
|
||||
.map((idx) => [idx, Math.random(), Math.random(), Math.random()])
|
||||
.value(),
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -197,5 +197,5 @@ export {
|
||||
anAnnotationsVarFBSResponse as annotationsVar,
|
||||
anAnnotationsObsFBSResponse as annotationsObs,
|
||||
aSchemaResponse as schema,
|
||||
aConfigResponse as config
|
||||
aConfigResponse as config,
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ describe("createUniverseFromResponse", () => {
|
||||
obsAnnotations: expect.any(Dataframe.Dataframe),
|
||||
varAnnotations: expect.any(Dataframe.Dataframe),
|
||||
obsLayout: expect.any(Dataframe.Dataframe),
|
||||
varData: expect.any(Dataframe.Dataframe)
|
||||
varData: expect.any(Dataframe.Dataframe),
|
||||
})
|
||||
);
|
||||
|
||||
@@ -60,7 +60,7 @@ describe("createUniverseFromResponse", () => {
|
||||
...Universe.addObsLayout(
|
||||
universe,
|
||||
Universe.matrixFBSToDataframe(REST.layoutObs)
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
expect(universe).toMatchObject(
|
||||
@@ -71,13 +71,13 @@ describe("createUniverseFromResponse", () => {
|
||||
obsAnnotations: expect.any(Dataframe.Dataframe),
|
||||
varAnnotations: expect.any(Dataframe.Dataframe),
|
||||
obsLayout: expect.any(Dataframe.Dataframe),
|
||||
varData: expect.any(Dataframe.Dataframe)
|
||||
varData: expect.any(Dataframe.Dataframe),
|
||||
})
|
||||
);
|
||||
|
||||
expect(universe.obsAnnotations.dims).toEqual([
|
||||
nObs,
|
||||
REST.schema.schema.annotations.obs.columns.length
|
||||
REST.schema.schema.annotations.obs.columns.length,
|
||||
]);
|
||||
expect(universe.obsLayout.dims).toEqual([nObs, 2]);
|
||||
expect(universe.obsLayout.colIndex.keys()).toEqual(
|
||||
@@ -85,7 +85,7 @@ describe("createUniverseFromResponse", () => {
|
||||
);
|
||||
expect(universe.varAnnotations.dims).toEqual([
|
||||
nVar,
|
||||
REST.schema.schema.annotations.var.columns.length
|
||||
REST.schema.schema.annotations.var.columns.length,
|
||||
]);
|
||||
expect(universe.varData.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DimTypes } from "../../../src/util/typedCrossfilter/crossfilter";
|
||||
import * as REST from "./sampleResponses";
|
||||
import {
|
||||
obsAnnoDimensionName,
|
||||
layoutDimensionName
|
||||
layoutDimensionName,
|
||||
} from "../../../src/util/nameCreators";
|
||||
|
||||
/*
|
||||
@@ -35,7 +35,7 @@ const defaultBigBang = () => {
|
||||
...Universe.addObsLayout(
|
||||
universe,
|
||||
Universe.matrixFBSToDataframe(REST.layoutObs)
|
||||
)
|
||||
),
|
||||
};
|
||||
|
||||
/* create world */
|
||||
@@ -50,7 +50,7 @@ const defaultBigBang = () => {
|
||||
return {
|
||||
universe,
|
||||
world,
|
||||
crossfilter
|
||||
crossfilter,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -80,8 +80,8 @@ describe("createWorldFromEntireUniverse", () => {
|
||||
clipQuantiles: { min: 0, max: 1 },
|
||||
unclipped: {
|
||||
obsAnnotations: expect.any(Dataframe.Dataframe),
|
||||
varData: expect.any(Dataframe.Dataframe)
|
||||
}
|
||||
varData: expect.any(Dataframe.Dataframe),
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -92,7 +92,7 @@ describe("createWorldFromCurrentSelection", () => {
|
||||
const {
|
||||
universe,
|
||||
world: originalWorld,
|
||||
crossfilter: originalCrossfilter
|
||||
crossfilter: originalCrossfilter,
|
||||
} = defaultBigBang();
|
||||
|
||||
/* mock a selection */
|
||||
@@ -100,7 +100,7 @@ describe("createWorldFromCurrentSelection", () => {
|
||||
.select(obsAnnoDimensionName("field1"), { mode: "range", lo: 0, hi: 5 })
|
||||
.select(obsAnnoDimensionName("field3"), {
|
||||
mode: "exact",
|
||||
values: [false]
|
||||
values: [false],
|
||||
});
|
||||
|
||||
/* create the world from the selection */
|
||||
@@ -124,7 +124,7 @@ describe("createWorldFromCurrentSelection", () => {
|
||||
};
|
||||
const matchingIndices = _()
|
||||
.range(universe.nObs)
|
||||
.filter(idx => matchFilter(universe.obsAnnotations, idx))
|
||||
.filter((idx) => matchFilter(universe.obsAnnotations, idx))
|
||||
.value();
|
||||
|
||||
expect(world).toMatchObject(
|
||||
@@ -139,8 +139,8 @@ describe("createWorldFromCurrentSelection", () => {
|
||||
varData: expect.any(Dataframe.Dataframe),
|
||||
unclipped: {
|
||||
obsAnnotations: expect.any(Dataframe.Dataframe),
|
||||
varData: expect.any(Dataframe.Dataframe)
|
||||
}
|
||||
varData: expect.any(Dataframe.Dataframe),
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
@@ -170,7 +170,7 @@ describe("createObsDimensionMap", () => {
|
||||
const { crossfilter } = defaultBigBang();
|
||||
const annotationNames = _.map(
|
||||
REST.schema.schema.annotations.obs.columns,
|
||||
c => c.name
|
||||
(c) => c.name
|
||||
);
|
||||
const obsIndexColName = REST.schema.schema.annotations.obs.index;
|
||||
const schemaByObsName = _.keyBy(
|
||||
@@ -178,7 +178,7 @@ describe("createObsDimensionMap", () => {
|
||||
"name"
|
||||
);
|
||||
expect(crossfilter).toBeDefined();
|
||||
annotationNames.forEach(name => {
|
||||
annotationNames.forEach((name) => {
|
||||
const dim = crossfilter.dimensions[obsAnnoDimensionName(name)];
|
||||
if (name === obsIndexColName) {
|
||||
expect(dim).toBeUndefined();
|
||||
|
||||
@@ -187,7 +187,7 @@ describe("fillBySelection", () => {
|
||||
describe("wide bitarray", () => {
|
||||
test.each([9, 30, 31, 32, 33, 54, 63, 64, 65, 127, 128, 129])(
|
||||
"more than %d dimensions",
|
||||
ndim => {
|
||||
(ndim) => {
|
||||
/* ensure we move across the uint boundary correctly */
|
||||
|
||||
const ba = new BitArray(defaultTestLength);
|
||||
|
||||
@@ -11,7 +11,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["001"],
|
||||
coords: [0, 0],
|
||||
nonFinite: 0.0
|
||||
nonFinite: 0.0,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:20:19Z",
|
||||
@@ -21,7 +21,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["001", "005"],
|
||||
coords: [0.4, 0.4],
|
||||
nonFinite: Number.NaN
|
||||
nonFinite: Number.NaN,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:28:54Z",
|
||||
@@ -31,7 +31,7 @@ const someData = [
|
||||
type: "visa",
|
||||
productIDs: ["004", "005"],
|
||||
coords: [0.3, 0.1],
|
||||
nonFinite: Number.POSITIVE_INFINITY
|
||||
nonFinite: Number.POSITIVE_INFINITY,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:30:43Z",
|
||||
@@ -41,7 +41,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["001", "002"],
|
||||
coords: [0.392, 0.1],
|
||||
nonFinite: Number.NEGATIVE_INFINITY
|
||||
nonFinite: Number.NEGATIVE_INFINITY,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:48:46Z",
|
||||
@@ -51,7 +51,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["005"],
|
||||
coords: [0.7, 0.0482],
|
||||
nonFinite: 1.0
|
||||
nonFinite: 1.0,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:53:41Z",
|
||||
@@ -61,7 +61,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["001", "004", "005"],
|
||||
coords: [0.9999, 1.0],
|
||||
nonFinite: Number.NaN
|
||||
nonFinite: Number.NaN,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:54:06Z",
|
||||
@@ -71,7 +71,7 @@ const someData = [
|
||||
type: "cash",
|
||||
productIDs: ["001", "002", "003", "004", "005"],
|
||||
coords: [0.384, 0.6938],
|
||||
nonFinite: 99.0
|
||||
nonFinite: 99.0,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T16:58:03Z",
|
||||
@@ -81,7 +81,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["001"],
|
||||
coords: [0.4822, 0.482],
|
||||
nonFinite: Number.NaN
|
||||
nonFinite: Number.NaN,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T17:07:21Z",
|
||||
@@ -91,7 +91,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["004", "005"],
|
||||
coords: [0.2234, 0],
|
||||
nonFinite: Number.NaN
|
||||
nonFinite: Number.NaN,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T17:22:59Z",
|
||||
@@ -101,7 +101,7 @@ const someData = [
|
||||
type: "tab",
|
||||
productIDs: ["001", "002", "004", "005"],
|
||||
coords: [0.382, 0.38485],
|
||||
nonFinite: -1
|
||||
nonFinite: -1,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T17:25:45Z",
|
||||
@@ -111,7 +111,7 @@ const someData = [
|
||||
type: "cash",
|
||||
productIDs: ["002"],
|
||||
coords: [0.998, 0.8472],
|
||||
nonFinite: 0.0
|
||||
nonFinite: 0.0,
|
||||
},
|
||||
{
|
||||
date: "2011-11-14T17:29:52Z",
|
||||
@@ -121,8 +121,8 @@ const someData = [
|
||||
type: "visa",
|
||||
productIDs: ["004"],
|
||||
coords: [0.8273, 0.3384],
|
||||
nonFinite: 0.0
|
||||
}
|
||||
nonFinite: 0.0,
|
||||
},
|
||||
];
|
||||
|
||||
let payments = null;
|
||||
@@ -248,16 +248,21 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
test("none", () => {
|
||||
expect(p.select("quantity", { mode: "none" }).countSelected()).toEqual(0);
|
||||
});
|
||||
test.each([[[]], [[2]], [[2, 1]], [[9, 82]], [[0, 1]]])("exact: %p", v =>
|
||||
test.each([[[]], [[2]], [[2, 1]], [[9, 82]], [[0, 1]]])("exact: %p", (v) =>
|
||||
expect(
|
||||
p.select("quantity", { mode: "exact", values: v }).countSelected()
|
||||
).toEqual(_.filter(someData, d => v.includes(d.quantity)).length)
|
||||
).toEqual(_.filter(someData, (d) => v.includes(d.quantity)).length)
|
||||
);
|
||||
test.each([[0, 1], [1, 2], [0, 99], [99, 100000]])("range %p", (lo, hi) =>
|
||||
test.each([
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[0, 99],
|
||||
[99, 100000],
|
||||
])("range %p", (lo, hi) =>
|
||||
expect(
|
||||
p.select("quantity", { mode: "range", lo, hi }).countSelected()
|
||||
).toEqual(
|
||||
_.filter(someData, d => d.quantity >= lo && d.quantity < hi).length
|
||||
_.filter(someData, (d) => d.quantity >= lo && d.quantity < hi).length
|
||||
)
|
||||
);
|
||||
test("bad mode", () => {
|
||||
@@ -284,11 +289,11 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
[["tab"]],
|
||||
[["visa"]],
|
||||
[["visa", "tab"]],
|
||||
[["cash", "tab", "visa"]]
|
||||
])("exact: %p", v =>
|
||||
[["cash", "tab", "visa"]],
|
||||
])("exact: %p", (v) =>
|
||||
expect(
|
||||
p.select("type", { mode: "exact", values: v }).countSelected()
|
||||
).toEqual(_.filter(someData, d => v.includes(d.type)).length)
|
||||
).toEqual(_.filter(someData, (d) => v.includes(d.type)).length)
|
||||
);
|
||||
test("range", () => {
|
||||
expect(() => p.select("type", { mode: "range", lo: 0, hi: 9 })).toThrow(
|
||||
@@ -303,8 +308,8 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
describe("spatial dimension", () => {
|
||||
let p;
|
||||
beforeEach(() => {
|
||||
const X = someData.map(r => r.coords[0]);
|
||||
const Y = someData.map(r => r.coords[1]);
|
||||
const X = someData.map((r) => r.coords[0]);
|
||||
const Y = someData.map((r) => r.coords[1]);
|
||||
p = payments.addDimension("coords", "spatial", X, Y);
|
||||
});
|
||||
|
||||
@@ -316,34 +321,76 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
test("none", () => {
|
||||
expect(p.select("coords", { mode: "none" }).countSelected()).toEqual(0);
|
||||
});
|
||||
test.each([[0, 0, 1, 1], [0, 0, 0.5, 0.5], [0.5, 0.5, 1, 1]])(
|
||||
"within-rect %d %d %d %d",
|
||||
(minX, minY, maxX, maxY) => {
|
||||
expect(
|
||||
p
|
||||
.select("coords", { mode: "within-rect", minX, minY, maxX, maxY })
|
||||
.allSelected()
|
||||
).toEqual(
|
||||
_.filter(someData, d => {
|
||||
const [x, y] = d.coords;
|
||||
return minX <= x && x < maxX && minY <= y && y < maxY;
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
test.each([
|
||||
[0, 0, 1, 1],
|
||||
[0, 0, 0.5, 0.5],
|
||||
[0.5, 0.5, 1, 1],
|
||||
])("within-rect %d %d %d %d", (minX, minY, maxX, maxY) => {
|
||||
expect(
|
||||
p
|
||||
.select("coords", { mode: "within-rect", minX, minY, maxX, maxY })
|
||||
.allSelected()
|
||||
).toEqual(
|
||||
_.filter(someData, (d) => {
|
||||
const [x, y] = d.coords;
|
||||
return minX <= x && x < maxX && minY <= y && y < maxY;
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test.each([
|
||||
[
|
||||
[[0, 0], [0, 1], [1, 1], [1, 0]],
|
||||
[true, true, true, true, true, false, true, true, true, true, true, true]
|
||||
[
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[1, 1],
|
||||
[1, 0],
|
||||
],
|
||||
[
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
],
|
||||
],
|
||||
[
|
||||
[[0, 0], [0, 0.5], [0.5, 0.5], [0.5, 0]],
|
||||
[true, true, true, true, false, false, false, true, true, true, false, false]
|
||||
]
|
||||
[
|
||||
[0, 0],
|
||||
[0, 0.5],
|
||||
[0.5, 0.5],
|
||||
[0.5, 0],
|
||||
],
|
||||
[
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
],
|
||||
])("within-polygon %p", (polygon, expected) => {
|
||||
expect(p.select("coords", { mode: "within-polygon", polygon }).allSelected())
|
||||
.toEqual(_.zip(someData, expected).filter(x => x[1]).map(x => x[0]));
|
||||
expect(
|
||||
p.select("coords", { mode: "within-polygon", polygon }).allSelected()
|
||||
).toEqual(
|
||||
_.zip(someData, expected)
|
||||
.filter((x) => x[1])
|
||||
.map((x) => x[0])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -381,7 +428,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
p
|
||||
.select("nonFinite", {
|
||||
mode: "exact",
|
||||
values: [Number.POSITIVE_INFINITY]
|
||||
values: [Number.POSITIVE_INFINITY],
|
||||
})
|
||||
.countSelected()
|
||||
).toEqual(1);
|
||||
@@ -389,7 +436,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
p
|
||||
.select("nonFinite", {
|
||||
mode: "exact",
|
||||
values: [Number.NEGATIVE_INFINITY]
|
||||
values: [Number.NEGATIVE_INFINITY],
|
||||
})
|
||||
.countSelected()
|
||||
).toEqual(1);
|
||||
@@ -402,7 +449,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
p
|
||||
.select("nonFinite", {
|
||||
mode: "exact",
|
||||
values: [Number.POSITIVE_INFINITY, 0, 1, 99]
|
||||
values: [Number.POSITIVE_INFINITY, 0, 1, 99],
|
||||
})
|
||||
.countSelected()
|
||||
).toEqual(6);
|
||||
@@ -414,7 +461,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
.select("nonFinite", {
|
||||
mode: "range",
|
||||
lo: 0,
|
||||
hi: Number.POSITIVE_INFINITY
|
||||
hi: Number.POSITIVE_INFINITY,
|
||||
})
|
||||
.countSelected()
|
||||
).toEqual(5);
|
||||
@@ -423,7 +470,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
.select("nonFinite", {
|
||||
mode: "range",
|
||||
lo: 0,
|
||||
hi: Number.NaN
|
||||
hi: Number.NaN,
|
||||
})
|
||||
.countSelected()
|
||||
).toEqual(6);
|
||||
@@ -432,7 +479,7 @@ describe("ImmutableTypedCrossfilter", () => {
|
||||
.select("nonFinite", {
|
||||
mode: "range",
|
||||
lo: Number.NEGATIVE_INFINITY,
|
||||
hi: Number.POSITIVE_INFINITY
|
||||
hi: Number.POSITIVE_INFINITY,
|
||||
})
|
||||
.countSelected()
|
||||
).toEqual(7);
|
||||
|
||||
@@ -10,15 +10,30 @@ describe("canonicalize", () => {
|
||||
|
||||
test("simple, already correct", () => {
|
||||
expect(PositiveIntervals.canonicalize([[0, 1]])).toEqual([[0, 1]]);
|
||||
expect(PositiveIntervals.canonicalize([[0, 1], [2, 3]])).toEqual([
|
||||
expect(
|
||||
PositiveIntervals.canonicalize([
|
||||
[0, 1],
|
||||
[2, 3],
|
||||
])
|
||||
).toEqual([
|
||||
[0, 1],
|
||||
[2, 3]
|
||||
[2, 3],
|
||||
]);
|
||||
});
|
||||
|
||||
test("non-canonical, need to be canonicalized", () => {
|
||||
expect(PositiveIntervals.canonicalize([[0, 1], [1, 2]])).toEqual([[0, 2]]);
|
||||
expect(PositiveIntervals.canonicalize([[1, 2], [2, 3]])).toEqual([[1, 3]]);
|
||||
expect(
|
||||
PositiveIntervals.canonicalize([
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
])
|
||||
).toEqual([[0, 2]]);
|
||||
expect(
|
||||
PositiveIntervals.canonicalize([
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
])
|
||||
).toEqual([[1, 3]]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,14 +41,30 @@ describe("union", () => {
|
||||
test("empty range", () => {
|
||||
expect(PositiveIntervals.union([], [])).toEqual([]);
|
||||
expect(PositiveIntervals.union([], [[1, 2]])).toEqual([[1, 2]]);
|
||||
expect(PositiveIntervals.union([], [[1, 2], [3, 4]])).toEqual([
|
||||
expect(
|
||||
PositiveIntervals.union(
|
||||
[],
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
]
|
||||
)
|
||||
).toEqual([
|
||||
[1, 2],
|
||||
[3, 4]
|
||||
[3, 4],
|
||||
]);
|
||||
expect(PositiveIntervals.union([[3, 4]], [])).toEqual([[3, 4]]);
|
||||
expect(PositiveIntervals.union([[1, 2], [3, 4]], [])).toEqual([
|
||||
expect(
|
||||
PositiveIntervals.union(
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
],
|
||||
[]
|
||||
)
|
||||
).toEqual([
|
||||
[1, 2],
|
||||
[3, 4]
|
||||
[3, 4],
|
||||
]);
|
||||
expect(PositiveIntervals.union([[3, 3]], [])).toEqual([[3, 3]]);
|
||||
expect(PositiveIntervals.union([], [[3, 3]])).toEqual([[3, 3]]);
|
||||
@@ -44,17 +75,37 @@ describe("union", () => {
|
||||
expect(PositiveIntervals.union([[2, 3]], [[1, 2]])).toEqual([[1, 3]]);
|
||||
expect(PositiveIntervals.union([[1, 2]], [[3, 4]])).toEqual([
|
||||
[1, 2],
|
||||
[3, 4]
|
||||
[3, 4],
|
||||
]);
|
||||
expect(
|
||||
PositiveIntervals.union([[1, 2], [3, 4]], [[6, 7], [19, 40]])
|
||||
).toEqual([[1, 2], [3, 4], [6, 7], [19, 40]]);
|
||||
expect(PositiveIntervals.union([[1, 4]], [[1, 1], [3, 4]])).toEqual([
|
||||
[1, 4]
|
||||
PositiveIntervals.union(
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
],
|
||||
[
|
||||
[6, 7],
|
||||
[19, 40],
|
||||
]
|
||||
)
|
||||
).toEqual([
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[6, 7],
|
||||
[19, 40],
|
||||
]);
|
||||
expect(
|
||||
PositiveIntervals.union(
|
||||
[[1, 4]],
|
||||
[
|
||||
[1, 1],
|
||||
[3, 4],
|
||||
]
|
||||
)
|
||||
).toEqual([[1, 4]]);
|
||||
expect(PositiveIntervals.union([[3, 3]], [[4, 4]])).toEqual([
|
||||
[3, 3],
|
||||
[4, 4]
|
||||
[4, 4],
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -70,34 +121,43 @@ describe("intersection", () => {
|
||||
expect(PositiveIntervals.intersection([[1, 2]], [[2, 3]])).toEqual([]);
|
||||
expect(PositiveIntervals.intersection([[2, 3]], [[1, 2]])).toEqual([]);
|
||||
expect(PositiveIntervals.intersection([[1, 10]], [[1, 10]])).toEqual([
|
||||
[1, 10]
|
||||
[1, 10],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[1, 10]], [[2, 8]])).toEqual([
|
||||
[2, 8]
|
||||
[2, 8],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[2, 8]], [[1, 10]])).toEqual([
|
||||
[2, 8]
|
||||
[2, 8],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[1, 10]], [[2, 12]])).toEqual([
|
||||
[2, 10]
|
||||
[2, 10],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[2, 12]], [[1, 10]])).toEqual([
|
||||
[2, 10]
|
||||
[2, 10],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[1, 10]], [[1, 8]])).toEqual([
|
||||
[1, 8]
|
||||
[1, 8],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[1, 8]], [[1, 10]])).toEqual([
|
||||
[1, 8]
|
||||
[1, 8],
|
||||
]);
|
||||
expect(PositiveIntervals.intersection([[1, 10]], [[1, 2], [6, 9]])).toEqual(
|
||||
[[1, 2], [6, 9]]
|
||||
);
|
||||
expect(PositiveIntervals.intersection([[0, 2638]], [[1363, 2638]])).toEqual(
|
||||
[[1363, 2638]]
|
||||
);
|
||||
expect(
|
||||
PositiveIntervals.intersection(
|
||||
[[1, 10]],
|
||||
[
|
||||
[1, 2],
|
||||
[6, 9],
|
||||
]
|
||||
)
|
||||
).toEqual([
|
||||
[1, 2],
|
||||
[6, 9],
|
||||
]);
|
||||
expect(
|
||||
PositiveIntervals.intersection([[0, 2638]], [[1363, 2638]])
|
||||
).toEqual([[1363, 2638]]);
|
||||
expect(PositiveIntervals.intersection([[1, 2]], [[1, 2]])).toEqual([
|
||||
[1, 2]
|
||||
[1, 2],
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -110,32 +170,66 @@ describe("difference", () => {
|
||||
});
|
||||
|
||||
test("simple", () => {
|
||||
expect(PositiveIntervals.difference([[1, 2], [3, 4]], [])).toEqual([
|
||||
expect(
|
||||
PositiveIntervals.difference(
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
],
|
||||
[]
|
||||
)
|
||||
).toEqual([
|
||||
[1, 2],
|
||||
[3, 4]
|
||||
]);
|
||||
expect(PositiveIntervals.difference([[1, 2], [3, 10]], [[5, 10]])).toEqual([
|
||||
[1, 2],
|
||||
[3, 5]
|
||||
]);
|
||||
expect(PositiveIntervals.difference([[1, 2], [3, 10]], [[0, 5]])).toEqual([
|
||||
[5, 10]
|
||||
[3, 4],
|
||||
]);
|
||||
expect(
|
||||
PositiveIntervals.difference([[0, 2638]], [[0, 1363], [2055, 2638]])
|
||||
PositiveIntervals.difference(
|
||||
[
|
||||
[1, 2],
|
||||
[3, 10],
|
||||
],
|
||||
[[5, 10]]
|
||||
)
|
||||
).toEqual([
|
||||
[1, 2],
|
||||
[3, 5],
|
||||
]);
|
||||
expect(
|
||||
PositiveIntervals.difference(
|
||||
[
|
||||
[1, 2],
|
||||
[3, 10],
|
||||
],
|
||||
[[0, 5]]
|
||||
)
|
||||
).toEqual([[5, 10]]);
|
||||
expect(
|
||||
PositiveIntervals.difference(
|
||||
[[0, 2638]],
|
||||
[
|
||||
[0, 1363],
|
||||
[2055, 2638],
|
||||
]
|
||||
)
|
||||
).toEqual([[1363, 2055]]);
|
||||
expect(
|
||||
PositiveIntervals.difference([[0, 1363], [2055, 2638]], [[0, 2638]])
|
||||
PositiveIntervals.difference(
|
||||
[
|
||||
[0, 1363],
|
||||
[2055, 2638],
|
||||
],
|
||||
[[0, 2638]]
|
||||
)
|
||||
).toEqual([]);
|
||||
expect(PositiveIntervals.difference([[0, 10]], [[0, 1]])).toEqual([
|
||||
[1, 10]
|
||||
[1, 10],
|
||||
]);
|
||||
expect(PositiveIntervals.difference([[0, 10]], [[1, 2]])).toEqual([
|
||||
[0, 1],
|
||||
[2, 10]
|
||||
[2, 10],
|
||||
]);
|
||||
expect(PositiveIntervals.difference([[0, 10]], [[9, 10]])).toEqual([
|
||||
[0, 9]
|
||||
[0, 9],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
lowerBound,
|
||||
upperBound,
|
||||
lowerBoundIndirect,
|
||||
upperBoundIndirect
|
||||
upperBoundIndirect,
|
||||
} from "../../../src/util/typedCrossfilter/sort";
|
||||
|
||||
/*
|
||||
@@ -40,7 +40,7 @@ describe("sortArray", () => {
|
||||
["a", "b", "0", "1"],
|
||||
[0, "a", true, null, undefined, 3.1415],
|
||||
fillRand(new Array(1000)),
|
||||
["a", NaN, null, pInf]
|
||||
["a", NaN, null, pInf],
|
||||
].map((val, idx) =>
|
||||
test(`JS vals ${idx}`, () => {
|
||||
expect(sortArray(val)).toMatchObject(val.sort());
|
||||
@@ -49,7 +49,7 @@ describe("sortArray", () => {
|
||||
});
|
||||
|
||||
describe("finite numbers", () => {
|
||||
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map(Type =>
|
||||
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) =>
|
||||
test(Type.name, () => {
|
||||
expect(sortArray(Type.from([6, 5, 4, 3, 2, 1, 0]))).toMatchObject(
|
||||
Type.from([0, 1, 2, 3, 4, 5, 6])
|
||||
@@ -131,7 +131,7 @@ describe("sortArray", () => {
|
||||
|
||||
describe("sortIndex", () => {
|
||||
describe("finite numbers", () => {
|
||||
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map(Type =>
|
||||
[Array, Float32Array, Uint32Array, Int32Array, Float64Array].map((Type) =>
|
||||
test(Type.name, () => {
|
||||
const source1 = Type.from([6, 5, 4, 3, 2, 1, 0]);
|
||||
const index1 = fillRange(new Uint32Array(source1.length));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
sliceByIndex,
|
||||
makeSortIndex
|
||||
makeSortIndex,
|
||||
} from "../../../src/util/typedCrossfilter/util";
|
||||
import { rangeFill as fillRange } from "../../../src/util/range";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user