From f0d9d873beb8cdd523ae9ba5fc8d1773bd6e38c6 Mon Sep 17 00:00:00 2001 From: Bruce Martin Date: Thu, 27 Sep 2018 17:52:17 -0700 Subject: [PATCH] Fix jest test suites (#268) * CRLF to LF * add babel-jest * use ES6 style imports * fix bugs manifest by test suite * add babel test config --- client/__tests__/util/bitArray.test.js | 369 +++---- .../__tests__/util/positiveInterval.test.js | 281 +++--- .../__tests__/util/typedCrossfilter.test.js | 924 +++++++++--------- client/package.json | 13 + client/src/util/typedCrossfilter/index.js | 8 +- 5 files changed, 807 insertions(+), 788 deletions(-) diff --git a/client/__tests__/util/bitArray.test.js b/client/__tests__/util/bitArray.test.js index 72e91882..cdf072f3 100644 --- a/client/__tests__/util/bitArray.test.js +++ b/client/__tests__/util/bitArray.test.js @@ -1,184 +1,185 @@ -// jshint esversion: 6 - -const BitArray = require("../../src/util/typedCrossfilter/bitArray"); -const defaultTestLength = 8; - -describe("default select state", () => { - test("newly created Bitarray should be deselected", () => { - const ba = new BitArray(defaultTestLength); - expect(ba).toBeDefined(); - - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - const dim = ba.allocDimension(); - expect(dim).toBeDefined(); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.freeDimension(dim); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - }); -}); - -describe("select and deselect", () => { - test("selectAll and deselectAll", () => { - const ba = new BitArray(defaultTestLength); - expect(ba).toBeDefined(); - const dim1 = ba.allocDimension(); - expect(dim1).toBeDefined(); - ba.selectAll(dim1); - - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(true); - } - - const dim2 = ba.allocDimension(); - expect(dim2).toBeDefined(); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.selectAll(dim2); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(true); - } - - ba.deselectAll(dim1); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.deselectAll(dim2); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.selectAll(dim1); - ba.selectAll(dim2); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(true); - } - - ba.freeDimension(dim1); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(true); - } - - ba.freeDimension(dim2); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - }); - - test("selectOne and deselectOne", () => { - const ba = new BitArray(defaultTestLength); - expect(ba).toBeDefined(); - const dim = ba.allocDimension(); - expect(dim).toBeDefined(); - - ba.selectOne(dim, 0); - expect(ba.isSelected(0)).toEqual(true); - for (let i = 1; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.deselectOne(dim, 0); - for (let i = 0; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.selectOne(dim, 1); - expect(ba.isSelected(1)).toEqual(true); - expect(ba.isSelected(0)).toEqual(false); - for (let i = 2; i < defaultTestLength; i++) { - expect(ba.isSelected(i)).toEqual(false); - } - - ba.selectAll(dim); - ba.deselectOne(dim, defaultTestLength - 1); - expect(ba.isSelected(defaultTestLength - 1)).toEqual(false); - for (let i = 0; i < defaultTestLength - 1; i++) { - expect(ba.isSelected(i)).toEqual(true); - } - }); -}); - -describe("selectionCount", () => { - test("simple", () => { - const ba = new BitArray(defaultTestLength); - expect(ba).toBeDefined(); - const dim1 = ba.allocDimension(); - expect(dim1).toBeDefined(); - const dim2 = ba.allocDimension(); - expect(dim2).toBeDefined(); - - expect(ba.selectionCount).toEqual(0); - ba.selectAll(dim1); - expect(ba.selectionCount).toEqual(0); - ba.selectAll(dim2); - expect(ba.selectionCount).toEqual(defaultTestLength); - - for (let i = 0; i < defaultTestLength; i++) { - ba.deselectOne(dim1, i); - expect(ba.selectionCount).toEqual(defaultTestLength - i - 1); - expect(ba.selectionCount).toEqual(ba.countAllOnes()); - } - - ba.freeDimension(dim1); - ba.freeDimension(dim2); - }); -}); - -describe("fillBySelection", () => { - test("sets values correctly", () => { - const ba = new BitArray(defaultTestLength); - expect(ba).toBeDefined(); - const dim = ba.allocDimension(); - expect(dim).toBeDefined(); - - const arr = new Int32Array(defaultTestLength); - arr.fill(0); - const truth = new Int32Array(defaultTestLength); - truth.fill(0); - - // initial state should be deselected - ba.fillBySelection(arr, 1, 0); - expect(arr).toEqual(expect.not.arrayContaining([1])); - - // selectAll - ba.selectAll(dim); - ba.fillBySelection(arr, 1, 0); - expect(arr).toEqual(expect.not.arrayContaining([0])); - - // deselectOne - ba.deselectOne(dim, 3); - ba.fillBySelection(arr, 1, 0); - truth.fill(1); - truth[3] = 0; - expect(arr).toEqual(truth); - - // deselectAll - ba.deselectAll(dim); - ba.fillBySelection(arr, 1, 0); - truth.fill(0); - expect(arr).toEqual(truth); - - // selectOne - ba.selectOne(dim, 5); - ba.fillBySelection(arr, 6, 1); - truth.fill(1); - truth[5] = 6; - expect(arr).toEqual(truth); - - // should be deselected after dimension disposal - ba.freeDimension(dim); - ba.fillBySelection(arr, 3, 9); - truth.fill(9); - expect(arr).toEqual(truth); - }); -}); +// jshint esversion: 6 + +import BitArray from "../../src/util/typedCrossfilter/bitArray"; + +const defaultTestLength = 8; + +describe("default select state", () => { + test("newly created Bitarray should be deselected", () => { + const ba = new BitArray(defaultTestLength); + expect(ba).toBeDefined(); + + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + const dim = ba.allocDimension(); + expect(dim).toBeDefined(); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.freeDimension(dim); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + }); +}); + +describe("select and deselect", () => { + test("selectAll and deselectAll", () => { + const ba = new BitArray(defaultTestLength); + expect(ba).toBeDefined(); + const dim1 = ba.allocDimension(); + expect(dim1).toBeDefined(); + ba.selectAll(dim1); + + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(true); + } + + const dim2 = ba.allocDimension(); + expect(dim2).toBeDefined(); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.selectAll(dim2); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(true); + } + + ba.deselectAll(dim1); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.deselectAll(dim2); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.selectAll(dim1); + ba.selectAll(dim2); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(true); + } + + ba.freeDimension(dim1); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(true); + } + + ba.freeDimension(dim2); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + }); + + test("selectOne and deselectOne", () => { + const ba = new BitArray(defaultTestLength); + expect(ba).toBeDefined(); + const dim = ba.allocDimension(); + expect(dim).toBeDefined(); + + ba.selectOne(dim, 0); + expect(ba.isSelected(0)).toEqual(true); + for (let i = 1; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.deselectOne(dim, 0); + for (let i = 0; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.selectOne(dim, 1); + expect(ba.isSelected(1)).toEqual(true); + expect(ba.isSelected(0)).toEqual(false); + for (let i = 2; i < defaultTestLength; i++) { + expect(ba.isSelected(i)).toEqual(false); + } + + ba.selectAll(dim); + ba.deselectOne(dim, defaultTestLength - 1); + expect(ba.isSelected(defaultTestLength - 1)).toEqual(false); + for (let i = 0; i < defaultTestLength - 1; i++) { + expect(ba.isSelected(i)).toEqual(true); + } + }); +}); + +describe("selectionCount", () => { + test("simple", () => { + const ba = new BitArray(defaultTestLength); + expect(ba).toBeDefined(); + const dim1 = ba.allocDimension(); + expect(dim1).toBeDefined(); + const dim2 = ba.allocDimension(); + expect(dim2).toBeDefined(); + + expect(ba.selectionCount).toEqual(0); + ba.selectAll(dim1); + expect(ba.selectionCount).toEqual(0); + ba.selectAll(dim2); + expect(ba.selectionCount).toEqual(defaultTestLength); + + for (let i = 0; i < defaultTestLength; i++) { + ba.deselectOne(dim1, i); + expect(ba.selectionCount).toEqual(defaultTestLength - i - 1); + expect(ba.selectionCount).toEqual(ba.countAllOnes()); + } + + ba.freeDimension(dim1); + ba.freeDimension(dim2); + }); +}); + +describe("fillBySelection", () => { + test("sets values correctly", () => { + const ba = new BitArray(defaultTestLength); + expect(ba).toBeDefined(); + const dim = ba.allocDimension(); + expect(dim).toBeDefined(); + + const arr = new Int32Array(defaultTestLength); + arr.fill(0); + const truth = new Int32Array(defaultTestLength); + truth.fill(0); + + // initial state should be deselected + ba.fillBySelection(arr, 1, 0); + expect(arr).toEqual(expect.not.arrayContaining([1])); + + // selectAll + ba.selectAll(dim); + ba.fillBySelection(arr, 1, 0); + expect(arr).toEqual(expect.not.arrayContaining([0])); + + // deselectOne + ba.deselectOne(dim, 3); + ba.fillBySelection(arr, 1, 0); + truth.fill(1); + truth[3] = 0; + expect(arr).toEqual(truth); + + // deselectAll + ba.deselectAll(dim); + ba.fillBySelection(arr, 1, 0); + truth.fill(0); + expect(arr).toEqual(truth); + + // selectOne + ba.selectOne(dim, 5); + ba.fillBySelection(arr, 6, 1); + truth.fill(1); + truth[5] = 6; + expect(arr).toEqual(truth); + + // should be deselected after dimension disposal + ba.freeDimension(dim); + ba.fillBySelection(arr, 3, 9); + truth.fill(9); + expect(arr).toEqual(truth); + }); +}); diff --git a/client/__tests__/util/positiveInterval.test.js b/client/__tests__/util/positiveInterval.test.js index 81c44496..a50c9029 100644 --- a/client/__tests__/util/positiveInterval.test.js +++ b/client/__tests__/util/positiveInterval.test.js @@ -1,140 +1,141 @@ -// jshint esversion: 6 - -const PositiveIntervals = require("../../src/util/typedCrossfilter/positiveIntervals"); - -describe("canonicalize", () => { - test("empty", () => { - expect(PositiveIntervals.canonicalize([])).toEqual([]); - }); - - test("simple, already correct", () => { - expect(PositiveIntervals.canonicalize([[0, 1]])).toEqual([[0, 1]]); - expect(PositiveIntervals.canonicalize([[0, 1], [2, 3]])).toEqual([ - [0, 1], - [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]]); - }); -}); - -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([ - [1, 2], - [3, 4] - ]); - expect(PositiveIntervals.union([[3, 4]], [])).toEqual([[3, 4]]); - expect(PositiveIntervals.union([[1, 2], [3, 4]], [])).toEqual([ - [1, 2], - [3, 4] - ]); - expect(PositiveIntervals.union([[3, 3]], [])).toEqual([[3, 3]]); - expect(PositiveIntervals.union([], [[3, 3]])).toEqual([[3, 3]]); - }); - - test("simple ranges", () => { - expect(PositiveIntervals.union([[1, 2]], [[2, 3]])).toEqual([[1, 3]]); - expect(PositiveIntervals.union([[2, 3]], [[1, 2]])).toEqual([[1, 3]]); - expect(PositiveIntervals.union([[1, 2]], [[3, 4]])).toEqual([ - [1, 2], - [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] - ]); - expect(PositiveIntervals.union([[3, 3]], [[4, 4]])).toEqual([ - [3, 3], - [4, 4] - ]); - }); -}); - -describe("intersection", () => { - test("empty range", () => { - expect(PositiveIntervals.intersection([], [])).toEqual([]); - expect(PositiveIntervals.intersection([], [[1, 2]])).toEqual([]); - expect(PositiveIntervals.intersection([[1, 2]], [])).toEqual([]); - }); - - test("simple", () => { - 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] - ]); - expect(PositiveIntervals.intersection([[1, 10]], [[2, 8]])).toEqual([ - [2, 8] - ]); - expect(PositiveIntervals.intersection([[2, 8]], [[1, 10]])).toEqual([ - [2, 8] - ]); - expect(PositiveIntervals.intersection([[1, 10]], [[2, 12]])).toEqual([ - [2, 10] - ]); - expect(PositiveIntervals.intersection([[2, 12]], [[1, 10]])).toEqual([ - [2, 10] - ]); - expect(PositiveIntervals.intersection([[1, 10]], [[1, 8]])).toEqual([ - [1, 8] - ]); - expect(PositiveIntervals.intersection([[1, 8]], [[1, 10]])).toEqual([ - [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, 2]], [[1, 2]])).toEqual([ - [1, 2] - ]); - }); -}); - -describe("difference", () => { - test("empty", () => { - expect(PositiveIntervals.difference([], [])).toEqual([]); - expect(PositiveIntervals.difference([], [[1, 10]])).toEqual([]); - expect(PositiveIntervals.difference([[1, 10]], [])).toEqual([[1, 10]]); - }); - - test("simple", () => { - 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] - ]); - expect( - PositiveIntervals.difference([[0, 2638]], [[0, 1363], [2055, 2638]]) - ).toEqual([[1363, 2055]]); - expect( - PositiveIntervals.difference([[0, 1363], [2055, 2638]], [[0, 2638]]) - ).toEqual([]); - expect(PositiveIntervals.difference([[0, 10]], [[0, 1]])).toEqual([ - [1, 10] - ]); - expect(PositiveIntervals.difference([[0, 10]], [[1, 2]])).toEqual([ - [0, 1], - [2, 10] - ]); - expect(PositiveIntervals.difference([[0, 10]], [[9, 10]])).toEqual([ - [0, 9] - ]); - }); -}); +// jshint esversion: 6 + +// const PositiveIntervals = require("../../src/util/typedCrossfilter/positiveIntervals"); +import PositiveIntervals from "../../src/util/typedCrossfilter/positiveIntervals"; + +describe("canonicalize", () => { + test("empty", () => { + expect(PositiveIntervals.canonicalize([])).toEqual([]); + }); + + test("simple, already correct", () => { + expect(PositiveIntervals.canonicalize([[0, 1]])).toEqual([[0, 1]]); + expect(PositiveIntervals.canonicalize([[0, 1], [2, 3]])).toEqual([ + [0, 1], + [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]]); + }); +}); + +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([ + [1, 2], + [3, 4] + ]); + expect(PositiveIntervals.union([[3, 4]], [])).toEqual([[3, 4]]); + expect(PositiveIntervals.union([[1, 2], [3, 4]], [])).toEqual([ + [1, 2], + [3, 4] + ]); + expect(PositiveIntervals.union([[3, 3]], [])).toEqual([[3, 3]]); + expect(PositiveIntervals.union([], [[3, 3]])).toEqual([[3, 3]]); + }); + + test("simple ranges", () => { + expect(PositiveIntervals.union([[1, 2]], [[2, 3]])).toEqual([[1, 3]]); + expect(PositiveIntervals.union([[2, 3]], [[1, 2]])).toEqual([[1, 3]]); + expect(PositiveIntervals.union([[1, 2]], [[3, 4]])).toEqual([ + [1, 2], + [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] + ]); + expect(PositiveIntervals.union([[3, 3]], [[4, 4]])).toEqual([ + [3, 3], + [4, 4] + ]); + }); +}); + +describe("intersection", () => { + test("empty range", () => { + expect(PositiveIntervals.intersection([], [])).toEqual([]); + expect(PositiveIntervals.intersection([], [[1, 2]])).toEqual([]); + expect(PositiveIntervals.intersection([[1, 2]], [])).toEqual([]); + }); + + test("simple", () => { + 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] + ]); + expect(PositiveIntervals.intersection([[1, 10]], [[2, 8]])).toEqual([ + [2, 8] + ]); + expect(PositiveIntervals.intersection([[2, 8]], [[1, 10]])).toEqual([ + [2, 8] + ]); + expect(PositiveIntervals.intersection([[1, 10]], [[2, 12]])).toEqual([ + [2, 10] + ]); + expect(PositiveIntervals.intersection([[2, 12]], [[1, 10]])).toEqual([ + [2, 10] + ]); + expect(PositiveIntervals.intersection([[1, 10]], [[1, 8]])).toEqual([ + [1, 8] + ]); + expect(PositiveIntervals.intersection([[1, 8]], [[1, 10]])).toEqual([ + [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, 2]], [[1, 2]])).toEqual([ + [1, 2] + ]); + }); +}); + +describe("difference", () => { + test("empty", () => { + expect(PositiveIntervals.difference([], [])).toEqual([]); + expect(PositiveIntervals.difference([], [[1, 10]])).toEqual([]); + expect(PositiveIntervals.difference([[1, 10]], [])).toEqual([[1, 10]]); + }); + + test("simple", () => { + 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] + ]); + expect( + PositiveIntervals.difference([[0, 2638]], [[0, 1363], [2055, 2638]]) + ).toEqual([[1363, 2055]]); + expect( + PositiveIntervals.difference([[0, 1363], [2055, 2638]], [[0, 2638]]) + ).toEqual([]); + expect(PositiveIntervals.difference([[0, 10]], [[0, 1]])).toEqual([ + [1, 10] + ]); + expect(PositiveIntervals.difference([[0, 10]], [[1, 2]])).toEqual([ + [0, 1], + [2, 10] + ]); + expect(PositiveIntervals.difference([[0, 10]], [[9, 10]])).toEqual([ + [0, 9] + ]); + }); +}); diff --git a/client/__tests__/util/typedCrossfilter.test.js b/client/__tests__/util/typedCrossfilter.test.js index 1ebbcaf1..d9929c7b 100644 --- a/client/__tests__/util/typedCrossfilter.test.js +++ b/client/__tests__/util/typedCrossfilter.test.js @@ -1,462 +1,462 @@ -// jshint esversion: 6 -const _ = require("lodash"); -const crossfilter = require("../../src/util/typedCrossfilter"); - -const someData = [ - { - date: "2011-11-14T16:17:54Z", - quantity: 2, - total: 190, - tip: 100, - type: "tab", - productIDs: ["001"] - }, - { - date: "2011-11-14T16:20:19Z", - quantity: 2, - total: 190, - tip: 100, - type: "tab", - productIDs: ["001", "005"] - }, - { - date: "2011-11-14T16:28:54Z", - quantity: 1, - total: 300, - tip: 200, - type: "visa", - productIDs: ["004", "005"] - }, - { - date: "2011-11-14T16:30:43Z", - quantity: 2, - total: 90, - tip: 0, - type: "tab", - productIDs: ["001", "002"] - }, - { - date: "2011-11-14T16:48:46Z", - quantity: 2, - total: 90, - tip: 0, - type: "tab", - productIDs: ["005"] - }, - { - date: "2011-11-14T16:53:41Z", - quantity: 2, - total: 90, - tip: 0, - type: "tab", - productIDs: ["001", "004", "005"] - }, - { - date: "2011-11-14T16:54:06Z", - quantity: 1, - total: 100, - tip: 0, - type: "cash", - productIDs: ["001", "002", "003", "004", "005"] - }, - { - date: "2011-11-14T16:58:03Z", - quantity: 2, - total: 90, - tip: 0, - type: "tab", - productIDs: ["001"] - }, - { - date: "2011-11-14T17:07:21Z", - quantity: 2, - total: 90, - tip: 0, - type: "tab", - productIDs: ["004", "005"] - }, - { - date: "2011-11-14T17:22:59Z", - quantity: 2, - total: 90, - tip: 0, - type: "tab", - productIDs: ["001", "002", "004", "005"] - }, - { - date: "2011-11-14T17:25:45Z", - quantity: 2, - total: 200, - tip: 0, - type: "cash", - productIDs: ["002"] - }, - { - date: "2011-11-14T17:29:52Z", - quantity: 1, - total: 200, - tip: 100, - type: "visa", - productIDs: ["004"] - } -]; - -function groupReduce(data, valueMap, valueReduce, valueInit) { - return _ - .reduce( - data, - (acc, value) => { - const k = valueMap(value); - let r = _.find(acc, o => o.key === k); - if (!r) { - r = { key: k, value: valueInit() }; - acc.push(r); - } - r.value = valueReduce(r.value, value); - return acc; - }, - [] - ) - .sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)); -} - -function groupCount(data, map) { - return groupReduce(data, map, (p, v) => p + 1, () => 0); -} - -function groupSum(data, map) { - return groupReduce(data, map, (p, v) => (p += map(v)), () => 0); -} - -var payments = null; -beforeEach(() => { - payments = crossfilter(someData); -}); - -describe("typedCrossfilter", () => { - test("alloc and free", () => { - expect(payments).toBeDefined(); - expect(payments.size()).toEqual(someData.length); - expect(payments.all()).toEqual(someData); - - const quantity = payments.dimension(r => r.quantity, Int32Array); - expect(quantity).toBeDefined(); - expect(quantity.id()).toBeDefined(); - - quantity.dispose(); - expect(payments.size()).toEqual(someData.length); - expect(payments.all()).toEqual(someData); - }); - - test("filterAll and filterNone", () => { - expect(payments).toBeDefined(); - const quantity = payments.dimension(r => r.quantity, Int32Array); - const tip = payments.dimension(r => r.tip, Float32Array); - const total = payments.dimension(r => r.total, Float32Array); - const type = payments.dimension(r => r.type, "enum"); - - expect(quantity).toBeDefined(); - expect(tip).toBeDefined(); - expect(total).toBeDefined(); - expect(type).toBeDefined(); - - // initially, all should be filtered - expect(payments.allFiltered().length).toEqual(payments.size()); - expect(payments.allFiltered()).toEqual(payments.all()); - expect(payments.countFiltered()).toEqual(someData.length); - - // filterAll - tip.filterAll(); // should change nothing - expect(payments.allFiltered()).toEqual(payments.all()); - expect(payments.countFiltered()).toEqual(someData.length); - - // ditto - total.filterAll(); - expect(payments.allFiltered()).toEqual(payments.all()); - expect(payments.countFiltered()).toEqual(someData.length); - - // filterNone - type.filterNone(); - expect(payments.allFiltered()).toEqual([]); - expect(payments.countFiltered()).toEqual(0); - - quantity.filterNone(); - expect(payments.allFiltered()).toEqual([]); - expect(payments.countFiltered()).toEqual(0); - - // invert the first none; should have no effect because type is - // still not filtered - quantity.filterAll(); - expect(payments.allFiltered()).toEqual([]); - expect(payments.countFiltered()).toEqual(0); - - // filter all of type; should select all - type.filterAll(); - expect(payments.allFiltered()).toEqual(payments.all()); - expect(payments.countFiltered()).toEqual(payments.size()); - }); - - test("filterExact", () => { - expect(payments).toBeDefined(); - const quantity = payments.dimension(r => r.quantity, Int32Array); - const tip = payments.dimension(r => r.tip, Float32Array); - const total = payments.dimension(r => r.total, Float32Array); - const type = payments.dimension(r => r.type, "enum"); - - quantity.filterExact(1); - expect(payments.countFiltered()).toEqual( - _.countBy(someData, "quantity")[1] - ); - expect(payments.allFiltered()).toEqual(_.filter(someData, { quantity: 1 })); - - tip.filterExact(0); - expect(payments.allFiltered()).toEqual( - _.filter(someData, { tip: 0, quantity: 1 }) - ); - - type.filterExact("cash"); - expect(payments.allFiltered()).toEqual( - _.filter(someData, { tip: 0, quantity: 1, type: "cash" }) - ); - }); - - test("filterRange", () => { - expect(payments).toBeDefined(); - const quantity = payments.dimension(r => r.quantity, Int32Array); - const tip = payments.dimension(r => r.tip, Float32Array); - const total = payments.dimension(r => r.total, Float32Array); - const type = payments.dimension(r => r.type, "enum"); - - tip.filterRange([0, 91]); - expect(payments.allFiltered()).toEqual( - _(someData) - .filter(r => r.tip >= 0 && r.tip < 91) - .value() - ); - - tip.filterRange([0, 90]); - expect(payments.allFiltered()).toEqual( - _(someData) - .filter(r => r.tip >= 0 && r.tip < 90) - .value() - ); - - tip.filterRange([1, 90]); - expect(payments.allFiltered()).toEqual( - _(someData) - .filter(r => r.tip >= 1 && r.tip < 91) - .value() - ); - }); - - test("filterEnum", () => { - expect(payments).toBeDefined(); - const quantity = payments.dimension(r => r.quantity, Int32Array); - const tip = payments.dimension(r => r.tip, Float32Array); - const total = payments.dimension(r => r.total, Float32Array); - const type = payments.dimension(r => r.type, "enum"); - - type.filterEnum(["tab", "cash"]); - expect(payments.allFiltered()).toEqual( - _(someData) - .filter(r => r.type === "cash" || r.type === "tab") - .value() - ); - - tip.filterEnum([0, 100]); - expect(payments.allFiltered()).toEqual( - _(someData) - .filter(r => r.type === "cash" || r.type === "tab") - .filter(r => r.tip === 0 || r.tip === 100) - .value() - ); - }); - - test("more than 32 dimensions", () => { - expect(payments).toBeDefined(); - const quantity = payments.dimension(r => r.quantity, Int32Array); - const tip = payments.dimension(r => r.tip, Float32Array); - const total = payments.dimension(r => r.total, Float32Array); - const type = payments.dimension(r => r.type, "enum"); - - // Create a bunch of fake dimensions to ensure we can handle > 32 - let dimMap = {}; - for (let i = 0; i < 65; i++) { - dimMap[i] = payments.dimension(r => Math.random(), Float32Array); - expect(dimMap[i]).toBeDefined(); - expect(dimMap[i].id()).toBeDefined(); - } - - // everything should start as selected/filtered - expect(payments.countFiltered()).toEqual(someData.length); - - dimMap[0].filterAll(); - dimMap[64].filterAll(); - expect(payments.countFiltered()).toEqual(someData.length); - - dimMap[33].filterNone(); - expect(payments.allFiltered()).toEqual([]); - - dimMap[33].filterAll(); - expect(payments.allFiltered()).toEqual(someData); - }); - - test("group, default mapping, default reducer, no filter", () => { - expect(payments).toBeDefined(); - - var quantity = payments.dimension(r => r.quantity, Int32Array); - var tip = payments.dimension(r => r.tip, Int32Array); - var type = payments.dimension(r => r.type, "enum"); - var total = payments.dimension(r => r.total, Int32Array); - - _.each( - { - tip: tip.group(r => r), - type: type.group(), - total: total.group(), - quantity: quantity.group() - }, - (grp, k) => { - const whatWeExpect = groupCount(someData, v => v[k]); - expect(grp.all()).toEqual(whatWeExpect); - expect(grp.size()).toEqual(whatWeExpect.length); - expect(grp.dispose()).toEqual(grp); - } - ); - }); - - test("group, custom map, default reducer, no filters", () => { - expect(payments).toBeDefined(); - - // custom mapping in groups only works for scalar types. Enums do not - // currently implement it. - - const tip = payments.dimension(r => r.tip, Int32Array); - const totalX10 = payments.dimension(r => r.total * 10, Int32Array); - const type = payments.dimension(r => r.type, "enum"); - - const paymentsByTip_A = tip.group(); - const paymentsByTip_B = tip.group(r => 10 * r); - const paymentsByType = type.group(); // identity only - const paymentsByTotalX10_A = totalX10.group(); - const paymentsByTotalX10_B = totalX10.group(r => r / 10); - - expect(paymentsByTip_A.all()).toEqual(groupCount(someData, v => v.tip)); - expect(paymentsByTip_B.all()).toEqual( - groupCount(someData, v => 10 * v.tip) - ); - expect(paymentsByType.all()).toEqual(groupCount(someData, v => v.type)); - expect(paymentsByTotalX10_A.all()).toEqual( - groupCount(someData, v => 10 * v.total) - ); - expect(paymentsByTotalX10_B.all()).toEqual( - groupCount(someData, v => (10 * v.total) / 10) - ); - - for (let i of [ - paymentsByTip_A, - paymentsByTip_B, - paymentsByType, - paymentsByTotalX10_A, - paymentsByTotalX10_B, - tip, - totalX10, - type - ]) { - expect(i.dispose()).toEqual(i); - } - }); - - test("group, default map, custom reducer, no filters", () => { - expect(payments).toBeDefined(); - - const total = payments.dimension(r => r.total, Float32Array); - const type = payments.dimension(r => r.type, "enum"); - - const paymentsByTotal = total.group(); - const paymentsByType = type.group(); - - // reduceCount - expect(paymentsByTotal.reduceCount()).toEqual(paymentsByTotal); - expect(paymentsByTotal.all()).toEqual(groupCount(someData, v => v.total)); - - // reduceSum - expect(paymentsByTotal.reduceSum(v => v.total)).toEqual(paymentsByTotal); - expect(paymentsByTotal.all()).toEqual(groupSum(someData, v => v.total)); - - // use custom reducers (my reducers) - count by three, init 1 - expect( - paymentsByTotal.reduce((p, v) => (p += 3), (p, v) => (p -= 3), () => 1) - ).toEqual(paymentsByTotal); - expect(paymentsByTotal.all()).toEqual( - groupReduce(someData, v => v.total, (p, v) => p + 3, () => 1) - ); - - for (let i of [paymentsByTotal, paymentsByType, type]) { - expect(i.dispose()).toEqual(i); - } - }); - - test("group, default map, default reducer, filters", () => { - // From the docs: - // Note: a grouping intersects the crossfilter's current filters, except for the - // associated dimension's filter. Thus, group methods consider only records that - // satisfy every filter except this dimension's filter. So, if the crossfilter of - // payments is filtered by type and total, then group by total only observes the - // filter by type. - - expect(payments).toBeDefined(); - - const tip = payments.dimension(r => r.tip, Int32Array); - const total = payments.dimension(r => r.total, Int32Array); - const type = payments.dimension(r => r.type, "enum"); - - const paymentsByTip = tip.group(); - const paymentsByTotal = total.group(); - const paymentsByType = type.group(); - - // 1. confirm that changing the filter on a dimension does NOT change that - // dimensions groups. - { - tip.filterAll(), total.filterAll(), type.filterAll(); - let before = _.cloneDeep(paymentsByTip.all()); - tip.filterExact(0); - expect(paymentsByTip.all()).toEqual(before); - } - - // 2. confirm that changing a filter on a different dimension DOES change - // all other groups. - { - tip.filterAll(), total.filterAll(), type.filterAll(); - const before = _.cloneDeep([paymentsByTotal.all(), paymentsByType.all()]); - tip.filterExact(0); - const after = [paymentsByTotal.all(), paymentsByType.all()]; - expect(after).not.toEqual(before); - expect(after).toEqual([ - groupReduce( - someData, - v => v.total, - (p, v) => (v.tip !== 0 ? p : p + 1), - () => 0 - ), - groupReduce( - someData, - v => v.type, - (p, v) => (v.tip !== 0 ? p : p + 1), - () => 0 - ) - ]); - } - - for (let i of [ - paymentsByTip, - paymentsByTotal, - paymentsByType, - tip, - total, - type - ]) { - expect(i.dispose()).toEqual(i); - } - }); -}); +// jshint esversion: 6 +import _ from "lodash"; +import crossfilter from "../../src/util/typedCrossfilter"; + +const someData = [ + { + date: "2011-11-14T16:17:54Z", + quantity: 2, + total: 190, + tip: 100, + type: "tab", + productIDs: ["001"] + }, + { + date: "2011-11-14T16:20:19Z", + quantity: 2, + total: 190, + tip: 100, + type: "tab", + productIDs: ["001", "005"] + }, + { + date: "2011-11-14T16:28:54Z", + quantity: 1, + total: 300, + tip: 200, + type: "visa", + productIDs: ["004", "005"] + }, + { + date: "2011-11-14T16:30:43Z", + quantity: 2, + total: 90, + tip: 0, + type: "tab", + productIDs: ["001", "002"] + }, + { + date: "2011-11-14T16:48:46Z", + quantity: 2, + total: 90, + tip: 0, + type: "tab", + productIDs: ["005"] + }, + { + date: "2011-11-14T16:53:41Z", + quantity: 2, + total: 90, + tip: 0, + type: "tab", + productIDs: ["001", "004", "005"] + }, + { + date: "2011-11-14T16:54:06Z", + quantity: 1, + total: 100, + tip: 0, + type: "cash", + productIDs: ["001", "002", "003", "004", "005"] + }, + { + date: "2011-11-14T16:58:03Z", + quantity: 2, + total: 90, + tip: 0, + type: "tab", + productIDs: ["001"] + }, + { + date: "2011-11-14T17:07:21Z", + quantity: 2, + total: 90, + tip: 0, + type: "tab", + productIDs: ["004", "005"] + }, + { + date: "2011-11-14T17:22:59Z", + quantity: 2, + total: 90, + tip: 0, + type: "tab", + productIDs: ["001", "002", "004", "005"] + }, + { + date: "2011-11-14T17:25:45Z", + quantity: 2, + total: 200, + tip: 0, + type: "cash", + productIDs: ["002"] + }, + { + date: "2011-11-14T17:29:52Z", + quantity: 1, + total: 200, + tip: 100, + type: "visa", + productIDs: ["004"] + } +]; + +function groupReduce(data, valueMap, valueReduce, valueInit) { + return _ + .reduce( + data, + (acc, value) => { + const k = valueMap(value); + let r = _.find(acc, o => o.key === k); + if (!r) { + r = { key: k, value: valueInit() }; + acc.push(r); + } + r.value = valueReduce(r.value, value); + return acc; + }, + [] + ) + .sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)); +} + +function groupCount(data, map) { + return groupReduce(data, map, (p, v) => p + 1, () => 0); +} + +function groupSum(data, map) { + return groupReduce(data, map, (p, v) => (p += map(v)), () => 0); +} + +var payments = null; +beforeEach(() => { + payments = crossfilter(someData); +}); + +describe("typedCrossfilter", () => { + test("alloc and free", () => { + expect(payments).toBeDefined(); + expect(payments.size()).toEqual(someData.length); + expect(payments.all()).toEqual(someData); + + const quantity = payments.dimension(r => r.quantity, Int32Array); + expect(quantity).toBeDefined(); + expect(quantity.id()).toBeDefined(); + + quantity.dispose(); + expect(payments.size()).toEqual(someData.length); + expect(payments.all()).toEqual(someData); + }); + + test("filterAll and filterNone", () => { + expect(payments).toBeDefined(); + const quantity = payments.dimension(r => r.quantity, Int32Array); + const tip = payments.dimension(r => r.tip, Float32Array); + const total = payments.dimension(r => r.total, Float32Array); + const type = payments.dimension(r => r.type, "enum"); + + expect(quantity).toBeDefined(); + expect(tip).toBeDefined(); + expect(total).toBeDefined(); + expect(type).toBeDefined(); + + // initially, all should be filtered + expect(payments.allFiltered().length).toEqual(payments.size()); + expect(payments.allFiltered()).toEqual(payments.all()); + expect(payments.countFiltered()).toEqual(someData.length); + + // filterAll + tip.filterAll(); // should change nothing + expect(payments.allFiltered()).toEqual(payments.all()); + expect(payments.countFiltered()).toEqual(someData.length); + + // ditto + total.filterAll(); + expect(payments.allFiltered()).toEqual(payments.all()); + expect(payments.countFiltered()).toEqual(someData.length); + + // filterNone + type.filterNone(); + expect(payments.allFiltered()).toEqual([]); + expect(payments.countFiltered()).toEqual(0); + + quantity.filterNone(); + expect(payments.allFiltered()).toEqual([]); + expect(payments.countFiltered()).toEqual(0); + + // invert the first none; should have no effect because type is + // still not filtered + quantity.filterAll(); + expect(payments.allFiltered()).toEqual([]); + expect(payments.countFiltered()).toEqual(0); + + // filter all of type; should select all + type.filterAll(); + expect(payments.allFiltered()).toEqual(payments.all()); + expect(payments.countFiltered()).toEqual(payments.size()); + }); + + test("filterExact", () => { + expect(payments).toBeDefined(); + const quantity = payments.dimension(r => r.quantity, Int32Array); + const tip = payments.dimension(r => r.tip, Float32Array); + const total = payments.dimension(r => r.total, Float32Array); + const type = payments.dimension(r => r.type, "enum"); + + quantity.filterExact(1); + expect(payments.countFiltered()).toEqual( + _.countBy(someData, "quantity")[1] + ); + expect(payments.allFiltered()).toEqual(_.filter(someData, { quantity: 1 })); + + tip.filterExact(0); + expect(payments.allFiltered()).toEqual( + _.filter(someData, { tip: 0, quantity: 1 }) + ); + + type.filterExact("cash"); + expect(payments.allFiltered()).toEqual( + _.filter(someData, { tip: 0, quantity: 1, type: "cash" }) + ); + }); + + test("filterRange", () => { + expect(payments).toBeDefined(); + const quantity = payments.dimension(r => r.quantity, Int32Array); + const tip = payments.dimension(r => r.tip, Float32Array); + const total = payments.dimension(r => r.total, Float32Array); + const type = payments.dimension(r => r.type, "enum"); + + tip.filterRange([0, 91]); + expect(payments.allFiltered()).toEqual( + _(someData) + .filter(r => r.tip >= 0 && r.tip < 91) + .value() + ); + + tip.filterRange([0, 90]); + expect(payments.allFiltered()).toEqual( + _(someData) + .filter(r => r.tip >= 0 && r.tip < 90) + .value() + ); + + tip.filterRange([1, 90]); + expect(payments.allFiltered()).toEqual( + _(someData) + .filter(r => r.tip >= 1 && r.tip < 91) + .value() + ); + }); + + test("filterEnum", () => { + expect(payments).toBeDefined(); + const quantity = payments.dimension(r => r.quantity, Int32Array); + const tip = payments.dimension(r => r.tip, Float32Array); + const total = payments.dimension(r => r.total, Float32Array); + const type = payments.dimension(r => r.type, "enum"); + + type.filterEnum(["tab", "cash"]); + expect(payments.allFiltered()).toEqual( + _(someData) + .filter(r => r.type === "cash" || r.type === "tab") + .value() + ); + + tip.filterEnum([0, 100]); + expect(payments.allFiltered()).toEqual( + _(someData) + .filter(r => r.type === "cash" || r.type === "tab") + .filter(r => r.tip === 0 || r.tip === 100) + .value() + ); + }); + + test("more than 32 dimensions", () => { + expect(payments).toBeDefined(); + const quantity = payments.dimension(r => r.quantity, Int32Array); + const tip = payments.dimension(r => r.tip, Float32Array); + const total = payments.dimension(r => r.total, Float32Array); + const type = payments.dimension(r => r.type, "enum"); + + // Create a bunch of fake dimensions to ensure we can handle > 32 + let dimMap = {}; + for (let i = 0; i < 65; i++) { + dimMap[i] = payments.dimension(r => Math.random(), Float32Array); + expect(dimMap[i]).toBeDefined(); + expect(dimMap[i].id()).toBeDefined(); + } + + // everything should start as selected/filtered + expect(payments.countFiltered()).toEqual(someData.length); + + dimMap[0].filterAll(); + dimMap[64].filterAll(); + expect(payments.countFiltered()).toEqual(someData.length); + + dimMap[33].filterNone(); + expect(payments.allFiltered()).toEqual([]); + + dimMap[33].filterAll(); + expect(payments.allFiltered()).toEqual(someData); + }); + + test("group, default mapping, default reducer, no filter", () => { + expect(payments).toBeDefined(); + + var quantity = payments.dimension(r => r.quantity, Int32Array); + var tip = payments.dimension(r => r.tip, Int32Array); + var type = payments.dimension(r => r.type, "enum"); + var total = payments.dimension(r => r.total, Int32Array); + + _.each( + { + tip: tip.group(r => r), + type: type.group(), + total: total.group(), + quantity: quantity.group() + }, + (grp, k) => { + const whatWeExpect = groupCount(someData, v => v[k]); + expect(grp.all()).toEqual(whatWeExpect); + expect(grp.size()).toEqual(whatWeExpect.length); + expect(grp.dispose()).toEqual(grp); + } + ); + }); + + test("group, custom map, default reducer, no filters", () => { + expect(payments).toBeDefined(); + + // custom mapping in groups only works for scalar types. Enums do not + // currently implement it. + + const tip = payments.dimension(r => r.tip, Int32Array); + const totalX10 = payments.dimension(r => r.total * 10, Int32Array); + const type = payments.dimension(r => r.type, "enum"); + + const paymentsByTip_A = tip.group(); + const paymentsByTip_B = tip.group(r => 10 * r); + const paymentsByType = type.group(); // identity only + const paymentsByTotalX10_A = totalX10.group(); + const paymentsByTotalX10_B = totalX10.group(r => r / 10); + + expect(paymentsByTip_A.all()).toEqual(groupCount(someData, v => v.tip)); + expect(paymentsByTip_B.all()).toEqual( + groupCount(someData, v => 10 * v.tip) + ); + expect(paymentsByType.all()).toEqual(groupCount(someData, v => v.type)); + expect(paymentsByTotalX10_A.all()).toEqual( + groupCount(someData, v => 10 * v.total) + ); + expect(paymentsByTotalX10_B.all()).toEqual( + groupCount(someData, v => (10 * v.total) / 10) + ); + + for (let i of [ + paymentsByTip_A, + paymentsByTip_B, + paymentsByType, + paymentsByTotalX10_A, + paymentsByTotalX10_B, + tip, + totalX10, + type + ]) { + expect(i.dispose()).toEqual(i); + } + }); + + test("group, default map, custom reducer, no filters", () => { + expect(payments).toBeDefined(); + + const total = payments.dimension(r => r.total, Float32Array); + const type = payments.dimension(r => r.type, "enum"); + + const paymentsByTotal = total.group(); + const paymentsByType = type.group(); + + // reduceCount + expect(paymentsByTotal.reduceCount()).toEqual(paymentsByTotal); + expect(paymentsByTotal.all()).toEqual(groupCount(someData, v => v.total)); + + // reduceSum + expect(paymentsByTotal.reduceSum(v => v.total)).toEqual(paymentsByTotal); + expect(paymentsByTotal.all()).toEqual(groupSum(someData, v => v.total)); + + // use custom reducers (my reducers) - count by three, init 1 + expect( + paymentsByTotal.reduce((p, v) => (p += 3), (p, v) => (p -= 3), () => 1) + ).toEqual(paymentsByTotal); + expect(paymentsByTotal.all()).toEqual( + groupReduce(someData, v => v.total, (p, v) => p + 3, () => 1) + ); + + for (let i of [paymentsByTotal, paymentsByType, type]) { + expect(i.dispose()).toEqual(i); + } + }); + + test("group, default map, default reducer, filters", () => { + // From the docs: + // Note: a grouping intersects the crossfilter's current filters, except for the + // associated dimension's filter. Thus, group methods consider only records that + // satisfy every filter except this dimension's filter. So, if the crossfilter of + // payments is filtered by type and total, then group by total only observes the + // filter by type. + + expect(payments).toBeDefined(); + + const tip = payments.dimension(r => r.tip, Int32Array); + const total = payments.dimension(r => r.total, Int32Array); + const type = payments.dimension(r => r.type, "enum"); + + const paymentsByTip = tip.group(); + const paymentsByTotal = total.group(); + const paymentsByType = type.group(); + + // 1. confirm that changing the filter on a dimension does NOT change that + // dimensions groups. + { + tip.filterAll(), total.filterAll(), type.filterAll(); + let before = _.cloneDeep(paymentsByTip.all()); + tip.filterExact(0); + expect(paymentsByTip.all()).toEqual(before); + } + + // 2. confirm that changing a filter on a different dimension DOES change + // all other groups. + { + tip.filterAll(), total.filterAll(), type.filterAll(); + const before = _.cloneDeep([paymentsByTotal.all(), paymentsByType.all()]); + tip.filterExact(0); + const after = [paymentsByTotal.all(), paymentsByType.all()]; + expect(after).not.toEqual(before); + expect(after).toEqual([ + groupReduce( + someData, + v => v.total, + (p, v) => (v.tip !== 0 ? p : p + 1), + () => 0 + ), + groupReduce( + someData, + v => v.type, + (p, v) => (v.tip !== 0 ? p : p + 1), + () => 0 + ) + ]); + } + + for (let i of [ + paymentsByTip, + paymentsByTotal, + paymentsByType, + tip, + total, + type + ]) { + expect(i.dispose()).toEqual(i); + } + }); +}); diff --git a/client/package.json b/client/package.json index 2ed57ed5..d1ecb3a6 100644 --- a/client/package.json +++ b/client/package.json @@ -59,6 +59,7 @@ "autoprefixer": "^9.1.1", "babel-core": "^6.13.2", "babel-eslint": "^8.2.6", + "babel-jest": "^23.6.0", "babel-loader": "^7.1.2", "babel-plugin-istanbul": "^4.1.6", "babel-plugin-transform-decorators-legacy": "^1.3.4", @@ -105,5 +106,17 @@ "**/__tests__/**/?(*.)(spec|test).js?(x)" ], "testURL": "http://localhost/" + }, + "babel": { + "env": { + "test": { + "presets": [ + [ + "env" + ], + "react" + ] + } + } } } diff --git a/client/src/util/typedCrossfilter/index.js b/client/src/util/typedCrossfilter/index.js index 64b7617b..bf7a25ea 100644 --- a/client/src/util/typedCrossfilter/index.js +++ b/client/src/util/typedCrossfilter/index.js @@ -401,7 +401,11 @@ class ScalarGroup { this.dimension = dimension; // generate group names from dimension values - this.mapValue = this._map(groupValue, groupValueType, dimension); + this.mapValue = this.constructor._map( + groupValue, + groupValueType, + dimension + ); // group index is mapping from data record index to group index this.groupIndex = new Uint32Array(dimension.crossfilter.data.length); @@ -469,7 +473,7 @@ class ScalarGroup { // Each item in the range will be remved from `dim`. reduceRemove if it // is currently selected. - const { data, selection } = this.dimension.crossfilter.selection; + const { data, selection } = this.dimension.crossfilter; intv.forEach(rng => { for (let r = rng[0]; r < rng[1]; r += 1) { const i = dim.index[r];