run prettier(2.0.5) (#1438)

This commit is contained in:
Severiano Badajoz
2020-05-04 10:26:42 -07:00
committed by GitHub
parent b255e32548
commit 6cccc41c0f
118 changed files with 1979 additions and 1584 deletions
+53 -26
View File
@@ -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");
}
},
});
+2 -1
View File
@@ -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";
+37 -37
View File
@@ -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",
},
},
};
+46 -17
View File
@@ -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)
);
});
});
+43 -21
View File
@@ -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;
}
});
+2 -6
View File
@@ -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"]
}
+2 -2
View File
@@ -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);
+8 -8
View File
@@ -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];
});
}
},
});
+20 -13
View File
@@ -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];
}
+3 -3
View File
@@ -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);
+3 -3
View File
@@ -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 });
+9 -6
View File
@@ -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]]);
+5 -5
View File
@@ -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,
})
);
});
+8 -8
View File
@@ -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/));
});
});
+61 -61
View File
@@ -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"]);
});
});
+24 -24
View File
@@ -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,
]);
});
});
+35 -37
View File
@@ -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([]);
});
});
+23 -23
View File
@@ -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";