Files
cellxgene/client/__tests__/util/stateManager/universe.test.js
T
Bruce Martin 19f2728a18 Bkmartinjr/state mgr tests (#298)
Jest tests for part of util/stateManager

* reorganize test directories

* lint

* add Jest config to eslint

* add Jest config to eslint

* lint

* fix babel configuration for tests

* start at kvCache tests

* reorganize test directories

* lint

* add Jest config to eslint

* add Jest config to eslint

* lint

* fix babel configuration for tests

* start at kvCache tests

* fix cache flush bug manifest by new test cases

* new kvCache tests

* skeletal universe test

* fix race in test case

* more universe test cases
2018-10-04 17:41:26 -07:00

231 lines
5.7 KiB
JavaScript

/* eslint no-bitwise: "off" */
import _ from "lodash";
import * as Universe from "../../../src/util/stateManager/universe";
/*
test data mocking REST 0.2 API responses
*/
const nObs = 10;
const nVar = 32;
const field4Categories = [83, true, "foo", 2.222222];
const fieldDCategories = [99, false, "mumble", 3.1415];
const aConfigResponse = {
config: {
features: [
{ method: "POST", path: "/cluster/", available: false },
{ method: "POST", path: "/layout/", available: false },
{ method: "POST", path: "/diffexp/", available: false },
{ method: "POST", path: "/saveLocal/", available: false }
],
displayNames: {
engine: "the little engine that could",
dataset: "all your zeros are mine"
}
}
};
const aSchemaResponse = {
schema: {
dataframe: {
nObs,
nVar,
type: "float32"
},
annotations: {
obs: [
{ name: "name", type: "string" },
{ name: "field1", type: "int32" },
{ name: "field2", type: "float32" },
{ name: "field3", type: "boolean" },
{
name: "field4",
type: "categorical",
categories: field4Categories
}
],
var: [
{ name: "name", type: "string" },
{ name: "fieldA", type: "int32" },
{ name: "fieldB", type: "float32" },
{ name: "fieldC", type: "boolean" },
{
name: "fieldD",
type: "categorical",
categories: fieldDCategories
}
]
}
}
};
const anAnnotationsObsResponse = {
names: ["name", "field1", "field2", "field3", "field4"],
data: _()
.range(nObs)
.map(idx => [
idx,
`obs${idx}`,
2 * idx,
idx + 0.0133,
idx & 1,
field4Categories[idx % field4Categories.length]
])
.value()
};
const anAnnotationsVarResponse = {
names: ["fieldA", "fieldB", "fieldC", "fieldD", "name"],
data: _()
.range(nVar)
.map(idx => [
idx,
10 * idx,
idx + 2.90143,
idx & 1,
fieldDCategories[idx % fieldDCategories.length],
`var${idx}`
])
.value()
};
const aLayoutResponse = {
layout: {
ndims: 2,
coordinates: _()
.range(nObs)
.map(idx => [idx, Math.random(), Math.random()])
.value()
}
};
const aDataObsResponse = {
var: [2, 4, 29],
obs: _()
.range(nObs)
.map(idx => [idx, Math.random(), Math.random(), Math.random()])
.value()
};
describe("createUniverseFromRestV02Response", () => {
/*
test createUniverseFromRestV02Response - this function converts
a set of REST 0.2 responses into a "new" Universe.
createUniverseFromRestV02Response(
configResponse,
schemaResponse,
annotationsObsResponse,
annotationsVarResponse,
layoutObsResponse
) --> Universe
where:
configResponse: GET /.../config
schemaResponse: GET /.../schema
annotationsObsResponse: GET /.../annotations/obs
annotationsVarResponse: GET /.../annotations/var
layoutObsResponse: GET /.../layout/obs
See spec in docs/REST_API.md.
*/
test("create from test data", () => {
/*
create a universe from sample data nad validate its shape & contents
*/
const universe = Universe.createUniverseFromRestV02Response(
aConfigResponse,
aSchemaResponse,
anAnnotationsObsResponse,
anAnnotationsVarResponse,
aLayoutResponse
);
expect(universe).toBeDefined();
expect(universe).toMatchObject(
expect.objectContaining({
api: "0.2",
nObs,
nVar,
schema: aSchemaResponse.schema,
obsAnnotations: expect.any(Array),
varAnnotations: expect.any(Array),
obsNameToIndexMap: expect.any(Object),
varNameToIndexMap: expect.any(Object),
obsLayout: expect.objectContaining({
X: expect.any(Float32Array),
Y: expect.any(Float32Array)
}),
varDataCache: expect.any(Object)
})
);
expect(_.size(universe.obsAnnotations)).toBe(nObs);
expect(_.size(universe.obsNameToIndexMap)).toBe(nObs);
expect(_.size(universe.obsLayout.X)).toBe(nObs);
expect(_.size(universe.obsLayout.Y)).toBe(nObs);
expect(_.size(universe.varAnnotations)).toBe(nVar);
expect(_.size(universe.varNameToIndexMap)).toBe(nVar);
});
});
describe("convertExpressionRESTv02ToObject", () => {
/*
test convertExpressionRESTv02ToObject
convertExpressionRESTv02ToObject(
universe,
response) --> { geneName: Float32Array, geneName: Float32Array, ... }
reponse is a /data/obs response:
{
var: [ varIndices fetched ],
obs: [
[ obsIndex, evalue, ... ],
...
]
}
*/
test("create from response data", () => {
const universe = Universe.createUniverseFromRestV02Response(
aConfigResponse,
aSchemaResponse,
anAnnotationsObsResponse,
anAnnotationsVarResponse,
aLayoutResponse
);
const expression = Universe.convertExpressionRESTv02ToObject(
universe,
aDataObsResponse
);
/* Check that the expected keys are present */
const expectedGeneNames = _.map(
aDataObsResponse.var,
v => anAnnotationsVarResponse.data[v][5]
);
expect(Object.keys(expression)).toEqual(
expect.arrayContaining(expectedGeneNames)
);
const expectedExpressionValues = _.map(
_.unzip(aDataObsResponse.obs),
a => new Float32Array(a)
);
// console.log(aDataObsResponse);
// console.log(expression);
// console.log(_.unzip(aDataObsResponse.obs));
_.forEach(aDataObsResponse.var, (varIdx, idx) => {
const varName = universe.varAnnotations[varIdx].name;
expect(varName).toBeDefined();
expect(varIdx).toBe(universe.varNameToIndexMap[varName]);
expect(expression[varName]).toEqual(expectedExpressionValues[idx + 1]);
});
});
});