test: Deprecating after work tests in favour of jest - Part 4 (#948)

* chore: adjust `maxWorkers` for jest
* test: `test-utils` and `theme` directory covered
This commit is contained in:
Ahmad Mirzaei
2022-10-07 09:23:21 +02:00
committed by GitHub
parent 25cb571ec5
commit 4f483dd11a
17 changed files with 569 additions and 527 deletions

View File

@@ -0,0 +1,98 @@
/* eslint no-underscore-dangle:0 */
import * as stardustUtils from '@nebula.js/stardust';
import { create } from '../index';
jest.mock('@nebula.js/stardust');
describe('test-utils', () => {
let hookMock;
let hooked;
let fnMock;
let initiateMock;
let runMock;
let runRestMock;
let teardownMock;
let runSnapsMock;
let observeActionsMock;
let getImperativeHandleMock;
let updateRectOnNextRunMock;
beforeEach(() => {
fnMock = jest.fn();
initiateMock = jest.fn();
runMock = jest.fn();
runRestMock = jest.fn();
runMock.reset = runRestMock;
teardownMock = jest.fn();
runSnapsMock = jest.fn();
observeActionsMock = jest.fn();
getImperativeHandleMock = jest.fn();
updateRectOnNextRunMock = jest.fn();
hooked = {
__hooked: true,
fn: fnMock,
initiate: initiateMock,
run: runMock,
teardown: teardownMock,
runSnaps: runSnapsMock,
observeActions: observeActionsMock,
getImperativeHandle: getImperativeHandleMock,
updateRectOnNextRun: updateRectOnNextRunMock,
fromTest: true,
};
hookMock = jest.fn().mockReturnValue(hooked);
jest.spyOn(stardustUtils.__DO_NOT_USE__, 'hook').mockImplementation(hookMock);
});
afterEach(() => {
jest.restoreAllMocks();
jest.resetAllMocks();
});
test('should return api', () => {
const c = create();
expect(c.update instanceof Function).toBe(true);
expect(c.unmount instanceof Function).toBe(true);
expect(c.takeSnapshot instanceof Function).toBe(true);
expect(c.actions instanceof Function).toBe(true);
});
test('should update', () => {
const c = create();
c.update();
expect(runMock).toHaveBeenCalledTimes(1);
runMock.reset();
expect(runRestMock).toHaveBeenCalledTimes(1);
const context = { translator: {} };
c.update(context);
expect(runMock).toHaveBeenCalledWith(
expect.objectContaining({
context,
})
);
});
test('should update', () => {
const c = create();
c.unmount();
expect(teardownMock).toHaveBeenCalledTimes(1);
});
test('should take snapshot', () => {
const c = create();
c.takeSnapshot();
expect(runSnapsMock).toHaveBeenCalledTimes(1);
});
test.skip('should do actions', () => {
// hooked.observeActions.callsArgWith(1, ['action']);
const c = create();
// hooked.observeActions.reset();
expect(c.actions()).toEqual(['action']);
});
});

View File

@@ -1,71 +0,0 @@
describe('test-utils', () => {
let sandbox;
let create;
let hook;
let hooked;
before(() => {
sandbox = sinon.createSandbox();
hooked = {
__hooked: true,
fn: sandbox.stub(),
initiate: sandbox.stub(),
run: sandbox.stub(),
teardown: sandbox.stub(),
runSnaps: sandbox.stub(),
observeActions: sandbox.stub(),
getImperativeHandle: sandbox.stub(),
updateRectOnNextRun: sandbox.stub(),
};
hook = sandbox.stub().returns(hooked);
[{ create }] = aw.mock([['@nebula.js/stardust', () => ({ __DO_NOT_USE__: { hook } })]], ['../index']);
});
afterEach(() => {
sandbox.restore();
});
it('should return api', () => {
const c = create();
expect(c.update).to.be.a('function');
expect(c.unmount).to.be.a('function');
expect(c.takeSnapshot).to.be.a('function');
expect(c.actions).to.be.a('function');
});
it('should update', () => {
const c = create();
c.update();
expect(hooked.run.callCount).to.equal(1);
hooked.run.reset();
const translator = {};
const context = { translator };
c.update(context);
expect(hooked.run).to.have.been.calledWithExactly(
sinon.match({
context,
})
);
});
it('should update', () => {
const c = create();
c.unmount();
expect(hooked.teardown.callCount).to.equal(1);
});
it('should take snapshot', () => {
const c = create();
c.takeSnapshot();
expect(hooked.runSnaps.callCount).to.equal(1);
});
it('should do actions', () => {
hooked.observeActions.callsArgWith(1, ['action']);
const c = create();
hooked.observeActions.reset();
expect(c.actions()).to.deep.equals(['action']);
});
});

View File

@@ -1,7 +1,7 @@
import paletteResolverFn from '../palette-resolver';
describe('palette-resolver', () => {
it('dataScales()', () => {
test('dataScales()', () => {
expect(
paletteResolverFn({
scales: [
@@ -14,7 +14,7 @@ describe('palette-resolver', () => {
},
],
}).dataScales()
).to.eql([
).toEqual([
{
key: 'p',
name: 'name',
@@ -26,7 +26,7 @@ describe('palette-resolver', () => {
]);
});
it('dataPalettes()', () => {
test('dataPalettes()', () => {
expect(
paletteResolverFn({
palettes: {
@@ -41,7 +41,7 @@ describe('palette-resolver', () => {
],
},
}).dataPalettes()
).to.eql([
).toEqual([
{
key: 'p',
name: 'name',
@@ -52,7 +52,7 @@ describe('palette-resolver', () => {
]);
});
it('uiPalettes()', () => {
test('uiPalettes()', () => {
expect(
paletteResolverFn({
palettes: {
@@ -65,7 +65,7 @@ describe('palette-resolver', () => {
],
},
}).uiPalettes()
).to.eql([
).toEqual([
{
key: 'ui',
name: 'name',
@@ -76,7 +76,7 @@ describe('palette-resolver', () => {
]);
});
it('dataColors()', () => {
test('dataColors()', () => {
expect(
paletteResolverFn({
dataColors: {
@@ -85,7 +85,7 @@ describe('palette-resolver', () => {
othersColor: 'others',
},
}).dataColors()
).to.eql({
).toEqual({
primary: 'primary',
nil: 'null',
others: 'others',
@@ -94,40 +94,43 @@ describe('palette-resolver', () => {
describe('uiColor', () => {
let p;
let uiPalettes;
let uiPalettesMock;
beforeEach(() => {
uiPalettesMock = jest.fn();
p = paletteResolverFn();
uiPalettes = sinon.stub(p, 'uiPalettes');
jest.spyOn(p, 'uiPalettes').mockImplementation(uiPalettesMock);
});
afterEach(() => {
uiPalettes.restore();
jest.resetAllMocks();
jest.restoreAllMocks();
});
it('should return color when index < 0 or undefined', () => {
expect(p.uiColor({ color: 'red' })).to.equal('red');
expect(p.uiColor({ color: 'red', index: -1 })).to.equal('red');
expect(uiPalettes.callCount).to.equal(0);
test('should return color when index < 0 or undefined', () => {
expect(p.uiColor({ color: 'red' })).toBe('red');
expect(p.uiColor({ color: 'red', index: -1 })).toBe('red');
expect(uiPalettesMock).toHaveBeenCalledTimes(0);
});
it('should return color when ui palette is falsy', () => {
uiPalettes.returns([]);
expect(p.uiColor({ color: 'red', index: 0 })).to.equal('red');
expect(uiPalettes.callCount).to.equal(1);
test('should return color when ui palette is falsy', () => {
uiPalettesMock.mockReturnValue([]);
expect(p.uiColor({ color: 'red', index: 0 })).toEqual('red');
expect(uiPalettesMock).toHaveBeenCalledTimes(1);
});
it('should return color when index is out of bounds', () => {
uiPalettes.returns([{ colors: ['a', 'b', 'c'] }]);
expect(p.uiColor({ color: 'red', index: 3 })).to.equal('red');
test('should return color when index is out of bounds', () => {
uiPalettesMock.mockReturnValue([{ colors: ['a', 'b', 'c'] }]);
expect(p.uiColor({ color: 'red', index: 3 })).toEqual('red');
expect(uiPalettes.callCount).to.equal(1);
expect(uiPalettesMock).toHaveBeenCalledTimes(1);
// should keep cached palette
p.uiColor({ color: 'red', index: 3 });
expect(uiPalettes.callCount).to.equal(1);
expect(uiPalettesMock).toHaveBeenCalledTimes(1);
});
it('should return index from palette when index is within bounds', () => {
uiPalettes.returns([{ colors: ['a', 'b', 'c'] }]);
expect(p.uiColor({ color: 'red', index: 1 })).to.equal('b');
test('should return index from palette when index is within bounds', () => {
uiPalettesMock.mockReturnValue([{ colors: ['a', 'b', 'c'] }]);
expect(p.uiColor({ color: 'red', index: 1 })).toBe('b');
});
});
});

View File

@@ -0,0 +1,96 @@
import * as extendModule from 'extend';
import create from '../set-theme';
import base from '../themes/base.json';
import light from '../themes/light.json';
import dark from '../themes/dark.json';
jest.mock('extend');
jest.mock('../themes/base.json', () => ({
font: 'Arial',
}));
jest.mock('../themes/light.json', () => ({
background: 'white',
}));
jest.mock('../themes/dark.json', () => ({
background: 'black',
}));
describe('set theme', () => {
let extendMock;
let resolveMock;
beforeEach(() => {
extendMock = jest.fn();
resolveMock = jest.fn();
jest.spyOn(extendModule, 'default').mockImplementation(extendMock);
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
test('should extend from light theme by default', () => {
extendMock.mockReturnValue({
palettes: {},
});
create({}, resolveMock);
expect(extendMock.mock.calls[0]).toEqual([true, {}, base, light]);
});
test('should extend from dark theme when type is dark', () => {
extendMock.mockReturnValue({
palettes: {},
});
create({ type: 'dark' }, resolveMock);
expect(extendMock.mock.calls[0]).toEqual([true, {}, base, dark]);
});
test('should not extend scales and palette arrays', () => {
const root = { color: 'pink', palettes: {} };
const merged = { palettes: { data: [], ui: [] }, scales: [] };
extendMock.mockReturnValueOnce(root);
extendMock.mockReturnValueOnce(merged);
const t = { color: 'red' };
const prevent = { scales: null, palettes: { data: null, ui: null } };
create(t, resolveMock);
expect(extendMock.mock.calls[1]).toEqual([true, {}, root, prevent, t]);
expect(resolveMock).toHaveBeenCalledWith(merged);
});
test('should add defaults if custom scales and palettes are not provided', () => {
const root = { color: 'pink', palettes: { data: 'data', ui: 'ui' }, scales: 'scales' };
const merged = { palettes: {} };
extendMock.mockReturnValueOnce(root);
extendMock.mockReturnValueOnce(merged);
const custom = { color: 'red' };
create(custom, resolveMock);
expect(resolveMock).toHaveBeenCalledWith({
palettes: { data: 'data', ui: 'ui' },
scales: 'scales',
});
});
test('should add defaults if custom scales and palettes are empty', () => {
const root = { color: 'pink', palettes: { data: 'data', ui: 'ui' }, scales: 'scales' };
const merged = { palettes: { data: [], ui: [] }, scales: [] };
extendMock.mockReturnValueOnce(root);
extendMock.mockReturnValueOnce(merged);
const custom = { color: 'red' };
create(custom, resolveMock);
expect(resolveMock).toHaveBeenCalledWith({
palettes: { data: 'data', ui: 'ui' },
scales: 'scales',
});
});
test('should return resolved theme', () => {
extendMock.mockReturnValueOnce({ palettes: { data: [], ui: [] }, scales: [] });
extendMock.mockReturnValueOnce({ palettes: { data: [], ui: [] }, scales: [] });
resolveMock.mockReturnValue('resolved');
expect(create({}, resolveMock)).toBe('resolved');
});
});

View File

@@ -1,96 +0,0 @@
describe('set theme', () => {
let sandbox;
let create;
let extend;
let base;
let light;
let dark;
let resolve;
before(() => {
sandbox = sinon.createSandbox();
extend = sandbox.stub();
resolve = sandbox.stub();
base = { font: 'Arial' };
light = { background: 'white' };
dark = { background: 'black' };
[{ default: create }] = aw.mock(
[
[require.resolve('extend'), () => extend],
['**/base.json', () => base],
['**/light.json', () => light],
['**/dark.json', () => dark],
],
['../set-theme.js']
);
});
afterEach(() => {
sandbox.reset();
});
it('should extend from light theme by default', () => {
extend.returns({
palettes: {},
});
create({}, resolve);
expect(extend.firstCall).to.have.been.calledWithExactly(true, {}, base, light);
});
it('should extend from dark theme when type is dark', () => {
extend.returns({
palettes: {},
});
create(
{
type: 'dark',
},
resolve
);
expect(extend.firstCall).to.have.been.calledWithExactly(true, {}, base, dark);
});
it('should not extend scales and palette arrays', () => {
const root = { color: 'pink', palettes: {} };
const merged = { palettes: { data: [], ui: [] }, scales: [] };
extend.onFirstCall().returns(root);
extend.onSecondCall().returns(merged);
const t = { color: 'red' };
const prevent = { scales: null, palettes: { data: null, ui: null } };
create(t, resolve);
expect(extend.secondCall).to.have.been.calledWithExactly(true, {}, root, prevent, t);
expect(resolve).to.have.been.calledWithExactly(merged);
});
it('should add defaults if custom scales and palettes are not provided', () => {
const root = { color: 'pink', palettes: { data: 'data', ui: 'ui' }, scales: 'scales' };
const merged = { palettes: {} };
extend.onFirstCall().returns(root);
extend.onSecondCall().returns(merged);
const custom = { color: 'red' };
create(custom, resolve);
expect(resolve).to.have.been.calledWithExactly({
palettes: { data: 'data', ui: 'ui' },
scales: 'scales',
});
});
it('should add defaults if custom scales and palettes are empty', () => {
const root = { color: 'pink', palettes: { data: 'data', ui: 'ui' }, scales: 'scales' };
const merged = { palettes: { data: [], ui: [] }, scales: [] };
extend.onFirstCall().returns(root);
extend.onSecondCall().returns(merged);
const custom = { color: 'red' };
create(custom, resolve);
expect(resolve).to.have.been.calledWithExactly({
palettes: { data: 'data', ui: 'ui' },
scales: 'scales',
});
});
it('should return resolved theme', () => {
extend.onFirstCall().returns({ palettes: { data: [], ui: [] }, scales: [] });
extend.onSecondCall().returns({ palettes: { data: [], ui: [] }, scales: [] });
resolve.returns('resolved');
expect(create({}, resolve)).to.equal('resolved');
});
});

View File

@@ -0,0 +1,81 @@
import * as extendModule from 'extend';
import create from '../style-resolver';
describe('style-resolver', () => {
let extendMock;
beforeEach(() => {
extendMock = jest.fn();
jest.spyOn(extendModule, 'default').mockImplementation(extendMock);
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
test('getStyle from root', () => {
const t = {
fontSize: '16px',
};
const s = create('base.path', t);
expect(s.getStyle('', 'fontSize')).toBe('16px');
});
test('getStyle from object', () => {
const t = {
object: {
bar: {
legend: {
title: {
fontSize: '13px',
},
},
},
},
fontSize: '16px',
};
const s = create('object.bar', t);
expect(s.getStyle('', 'fontSize')).toBe('16px');
expect(s.getStyle('legend', 'fontSize')).toBe('16px');
expect(s.getStyle('legend.content', 'fontSize')).toBe('16px');
expect(s.getStyle('title', 'fontSize')).toBe('16px');
expect(s.getStyle('legend.title', 'fontSize')).toBe('13px');
expect(s.getStyle('legend.content', 'color')).toBe(undefined);
expect(s.getStyle('.', 'legend.title.fontSize')).toBe('13px');
expect(s.getStyle('legend.', 'title.fontSize')).toBe('13px');
expect(s.getStyle('legend.', 'content.fontSize')).toBe(undefined);
expect(s.getStyle('legend.', 'content.color')).toBe(undefined);
expect(s.getStyle('table', 'fontSize')).toBe('16px');
expect(s.getStyle('table', 'content.fontSize')).toBe(undefined);
});
test('resolveRawTheme', () => {
const variables = {
'@text': 'pink',
'@size': 'mini',
};
const raw = {
chart: {
bg: 'red',
color: '@text',
},
responsive: '@size',
_variables: variables,
};
extendMock.mockReturnValue(raw);
expect(create.resolveRawTheme(raw)).toEqual({
chart: {
bg: 'red',
color: 'pink',
},
responsive: 'mini',
_variables: variables,
});
});
});

View File

@@ -1,79 +0,0 @@
describe('style-resolver', () => {
let sandbox;
let create;
let extend;
before(() => {
sandbox = sinon.createSandbox();
extend = sandbox.stub();
[{ default: create }] = aw.mock([[require.resolve('extend'), () => extend]], ['../style-resolver.js']);
});
afterEach(() => {
sandbox.reset();
});
it('getStyle from root', () => {
const t = {
fontSize: '16px',
};
const s = create('base.path', t);
expect(s.getStyle('', 'fontSize')).to.equal('16px');
});
it('getStyle from object', () => {
const t = {
object: {
bar: {
legend: {
title: {
fontSize: '13px',
},
},
},
},
fontSize: '16px',
};
const s = create('object.bar', t);
expect(s.getStyle('', 'fontSize')).to.equal('16px');
expect(s.getStyle('legend', 'fontSize')).to.equal('16px');
expect(s.getStyle('legend.content', 'fontSize')).to.equal('16px');
expect(s.getStyle('title', 'fontSize')).to.equal('16px');
expect(s.getStyle('legend.title', 'fontSize')).to.equal('13px');
expect(s.getStyle('legend.content', 'color')).to.equal(undefined);
expect(s.getStyle('.', 'legend.title.fontSize')).to.equal('13px');
expect(s.getStyle('legend.', 'title.fontSize')).to.equal('13px');
expect(s.getStyle('legend.', 'content.fontSize')).to.equal(undefined);
expect(s.getStyle('legend.', 'content.color')).to.equal(undefined);
expect(s.getStyle('table', 'fontSize')).to.equal('16px');
expect(s.getStyle('table', 'content.fontSize')).to.equal(undefined);
});
it('resolveRawTheme', () => {
const variables = {
'@text': 'pink',
'@size': 'mini',
};
const raw = {
chart: {
bg: 'red',
color: '@text',
},
responsive: '@size',
_variables: variables,
};
extend.returns(raw);
expect(create.resolveRawTheme(raw)).to.eql({
chart: {
bg: 'red',
color: 'pink',
},
responsive: 'mini',
_variables: variables,
});
});
});

View File

@@ -4,29 +4,27 @@ describe('Theme scale generator', () => {
const input = ['#ffffff', '#000000'];
const base8 = ['#ffffff', '#d4d4d4', '#aaaaaa', '#7f7f7f', '#545454', '#2a2a2a', '#000000'];
beforeEach(() => {});
it('Should generate a pyramid', () => {
test('Should generate a pyramid', () => {
const scales = [{ type: 'class', scale: input }];
scaleGenerator(scales);
expect(scales).to.have.length(1);
expect(scales.length).toBe(1);
const { scale, type } = scales[0];
expect(type).to.equals('class-pyramid');
expect(scale.length).to.equal(8);
expect(scale[scale.length - 1].length).to.equal(7);
expect(type).toBe('class-pyramid');
expect(scale.length).toBe(8);
expect(scale[scale.length - 1].length).toBe(7);
});
it('Should generate a correct base of colors', () => {
test('Should generate a correct base of colors', () => {
const scales = [{ type: 'class', scale: input }];
scaleGenerator(scales);
const { scale } = scales[0];
const colors = scale[scale.length - 1];
expect(colors).to.deep.equal(base8);
expect(colors).toEqual(base8);
});
it('Should work correctly on a scale from the sense theme', () => {
test('Should work correctly on a scale from the sense theme', () => {
const senseDivergentScale = [
'#ae1c3e',
'#d24d3e',
@@ -42,7 +40,7 @@ describe('Theme scale generator', () => {
const scales = [{ type: 'class', scale: senseDivergentScale }];
scaleGenerator(scales);
const { scale } = scales[0];
expect(scale).to.deep.equal([
expect(scale).toEqual([
null,
['#e6f5fe'],
['#ed875e', '#3a89c9'],

View File

@@ -0,0 +1,143 @@
import * as EventEmitter from 'node-event-emitter';
import * as setThemeModule from '../set-theme';
import * as paletterResolverFnModule from '../palette-resolver';
import * as styleResolverFnModule from '../style-resolver';
import * as contrasterFnModule from '../contraster/contraster';
import * as luminanceFnModule from '../contraster/luminance';
import create from '../index';
jest.mock('node-event-emitter');
describe('theme', () => {
let setThemeMock;
let paletterResolverFnMock;
let styleResolverFnMock;
let contrasterFnMock;
let luminanceFnMock;
let emitter;
let emitterEmitMock;
let emitterInitMock;
beforeEach(() => {
setThemeMock = jest.fn();
paletterResolverFnMock = jest.fn();
styleResolverFnMock = jest.fn();
contrasterFnMock = jest.fn();
luminanceFnMock = jest.fn();
emitterEmitMock = jest.fn();
emitterInitMock = jest.fn();
jest.spyOn(setThemeModule, 'default').mockImplementation(setThemeMock);
jest.spyOn(paletterResolverFnModule, 'default').mockImplementation(paletterResolverFnMock);
jest.spyOn(styleResolverFnModule, 'default').mockImplementation(styleResolverFnMock);
styleResolverFnMock.resolveRawTheme = 'raw';
jest.spyOn(contrasterFnModule, 'default').mockImplementation(contrasterFnMock);
jest.spyOn(luminanceFnModule, 'default').mockImplementation(luminanceFnMock);
emitter = {
prototype: {
emit: emitterEmitMock,
},
init: emitterInitMock,
};
EventEmitter.EventEmitter.mockReturnValue(emitter);
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
describe('initiate', () => {
beforeEach(() => {
setThemeMock.mockReturnValue('resolvedJSON');
const getStyle = jest.fn().mockReturnValue('red');
styleResolverFnMock.mockReturnValue({
getStyle,
});
});
test('should create paletteResolver', () => {
create();
expect(paletterResolverFnMock).toHaveBeenCalledWith('resolvedJSON');
});
test('should create contraster for dark text color', () => {
luminanceFnMock.mockReturnValue(0.19);
create();
expect(contrasterFnMock).toHaveBeenCalledWith(['red', '#ffffff']);
});
test('should create contraster for light text color', () => {
create();
expect(contrasterFnMock).toHaveBeenCalledWith(['red', '#333333']);
});
test("should emit 'changed' event", () => {
const t = create();
expect(t.externalAPI.emit).toHaveBeenCalledTimes(1);
expect(t.externalAPI.emit).toHaveBeenCalledWith('changed');
});
});
describe('api', () => {
let t;
let resolved;
beforeEach(() => {
resolved = 'resolved';
setThemeMock.mockReturnValue(resolved);
paletterResolverFnMock.mockReturnValue({
dataScales: () => 'p scales',
dataPalettes: () => 'p data palettes',
uiPalettes: () => `p ui palettes`,
dataColors: () => 'p data colors',
uiColor: (a) => `p ui ${a}`,
});
styleResolverFnMock.mockReturnValue({
getStyle: () => '#eeeeee',
});
contrasterFnMock.mockReturnValue({ getBestContrastColor: (c) => `contrast ${c}` });
t = create().externalAPI;
});
test('getDataColorScales()', () => {
expect(t.getDataColorScales()).toBe('p scales');
});
test('getDataColorPalettes()', () => {
expect(t.getDataColorPalettes()).toBe('p data palettes');
});
test('getDataColorPickerPalettes()', () => {
expect(t.getDataColorPickerPalettes()).toBe('p ui palettes');
});
test('getDataColorSpecials()', () => {
expect(t.getDataColorSpecials()).toBe('p data colors');
});
test('getColorPickerColor()', () => {
expect(t.getColorPickerColor('color')).toBe('p ui color');
});
test('getContrastingColorTo()', () => {
expect(t.getContrastingColorTo('color')).toBe('contrast color');
});
test('getStyle()', () => {
const getStyle = jest.fn();
getStyle.mockReturnValue('style');
styleResolverFnMock.mockReturnValue({
getStyle,
});
expect(t.getStyle('base', 'path', 'attribute')).toBe('style');
// calling additional getStyle with same params should use cached style resolver
expect(styleResolverFnMock).toHaveBeenCalledTimes(2);
t.getStyle('base', 'path', 'attribute');
t.getStyle('base', 'path', 'attribute');
t.getStyle('base', 'path', 'attribute');
expect(styleResolverFnMock).toHaveBeenCalledTimes(2);
});
});
});

View File

@@ -1,136 +0,0 @@
describe('theme', () => {
let sandbox;
let create;
let setTheme;
let paletterResolverFn;
let styleResolverFn;
let contrasterFn;
let luminanceFn;
let emitter;
before(() => {
sandbox = sinon.createSandbox();
setTheme = sandbox.stub();
paletterResolverFn = sandbox.stub();
styleResolverFn = sandbox.stub();
styleResolverFn.resolveRawTheme = 'raw';
contrasterFn = sandbox.stub();
luminanceFn = sandbox.stub();
emitter = {
prototype: {
emit: sandbox.stub(),
},
init: sandbox.stub(),
};
[{ default: create }] = aw.mock(
[
[require.resolve('node-event-emitter'), () => emitter],
['**/set-theme.js', () => setTheme],
['**/palette-resolver.js', () => paletterResolverFn],
['**/style-resolver.js', () => styleResolverFn],
['**/contraster.js', () => contrasterFn],
['**/luminance.js', () => luminanceFn],
],
['../index.js']
);
});
afterEach(() => {
sandbox.reset();
});
describe('initiate', () => {
beforeEach(() => {
setTheme.withArgs({}, 'raw').returns('resolvedJSON');
const getStyle = sandbox.stub();
getStyle.returns('red');
styleResolverFn.withArgs('', 'resolvedJSON').returns({
getStyle,
});
});
it('should create paletteResolver', () => {
create();
expect(paletterResolverFn).to.have.been.calledWithExactly('resolvedJSON');
});
it('should create contraster for dark text color', () => {
luminanceFn.returns(0.19);
create();
expect(contrasterFn).to.have.been.calledWithExactly(['red', '#ffffff']);
});
it('should create contraster for light text color', () => {
create();
expect(contrasterFn).to.have.been.calledWithExactly(['red', '#333333']);
});
it("should emit 'changed' event", () => {
const t = create();
expect(t.externalAPI.emit).to.have.been.calledWithExactly('changed');
});
});
describe('api', () => {
let t;
let resolved;
beforeEach(() => {
resolved = 'resolved';
setTheme.returns(resolved);
paletterResolverFn.returns({
dataScales: () => 'p scales',
dataPalettes: () => 'p data palettes',
uiPalettes: () => `p ui palettes`,
dataColors: () => 'p data colors',
uiColor: (a) => `p ui ${a}`,
});
styleResolverFn.withArgs('', 'resolved').returns({
getStyle: () => '#eeeeee',
});
contrasterFn.returns({ getBestContrastColor: (c) => `contrast ${c}` });
t = create().externalAPI;
});
it('getDataColorScales()', () => {
expect(t.getDataColorScales()).to.equal('p scales');
});
it('getDataColorPalettes()', () => {
expect(t.getDataColorPalettes()).to.equal('p data palettes');
});
it('getDataColorPickerPalettes()', () => {
expect(t.getDataColorPickerPalettes()).to.equal('p ui palettes');
});
it('getDataColorSpecials()', () => {
expect(t.getDataColorSpecials()).to.equal('p data colors');
});
it('getColorPickerColor()', () => {
expect(t.getColorPickerColor('color')).to.equal('p ui color');
});
it('getContrastingColorTo()', () => {
expect(t.getContrastingColorTo('color')).to.equal('contrast color');
});
it('getStyle()', () => {
const getStyle = sandbox.stub();
getStyle.returns('style');
styleResolverFn.withArgs('base', 'resolved').returns({
getStyle,
});
expect(t.getStyle('base', 'path', 'attribute')).to.equal('style');
// calling additional getStyle with same params should use cached style resolver
expect(styleResolverFn.callCount).to.equal(2);
t.getStyle('base', 'path', 'attribute');
t.getStyle('base', 'path', 'attribute');
t.getStyle('base', 'path', 'attribute');
expect(styleResolverFn.callCount).to.equal(2);
});
});
});

View File

@@ -0,0 +1,22 @@
import contrast from '../contrast';
describe('contrast', () => {
test('should be 1 for same luminance', () => {
expect(contrast(0, 0)).toBe(1);
});
test('should be 21 when delta in luminance is 1', () => {
expect(contrast(0, 1)).toBe(21);
});
test('should return same value even when luminances are in wrong order', () => {
const v = 2.6;
const lums = [0.2, 0.6];
expect(contrast(...lums)).toBe(v);
expect(contrast(...lums.reverse())).toBe(v);
});
test('should be 1.72727 when luminances are [0.9, 0.5]', () => {
expect(contrast(0.9, 0.5)).toBe(1.72727);
});
});

View File

@@ -1,22 +0,0 @@
import contrast from '../contrast';
describe('contrast', () => {
it('should be 1 for same luminance', () => {
expect(contrast(0, 0)).to.equal(1);
});
it('should be 21 when delta in luminance is 1', () => {
expect(contrast(0, 1)).to.equal(21);
});
it('should return same value even when luminances are in wrong order', () => {
const v = 2.6;
const lums = [0.2, 0.6];
expect(contrast(...lums)).to.equal(v);
expect(contrast(...lums.reverse())).to.equal(v);
});
it('should be 1.72727 when luminances are [0.9, 0.5]', () => {
expect(contrast(0.9, 0.5)).to.equal(1.72727);
});
});

View File

@@ -0,0 +1,49 @@
import create from '../contraster';
import * as luminanceModule from '../luminance';
import * as contrastModule from '../contrast';
describe('contraster', () => {
let luminanceMock;
let contrastMock;
beforeEach(() => {
luminanceMock = jest.fn();
contrastMock = jest.fn();
jest.spyOn(luminanceModule, 'default').mockImplementation(luminanceMock);
jest.spyOn(contrastModule, 'default').mockImplementation(contrastMock);
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
test('should return #ffffff by default when input is dark', () => {
luminanceMock.mockReturnValue(0.05);
contrastMock.mockReturnValueOnce(5);
contrastMock.mockReturnValueOnce(20);
expect(create().getBestContrastColor('#111111')).toBe('#ffffff');
});
test('should return #333333 by default when input is light', () => {
luminanceMock.mockReturnValue(0.8);
contrastMock.mockReturnValueOnce(10);
contrastMock.mockReturnValueOnce(2);
expect(create().getBestContrastColor('#afa')).toBe('#333333');
});
test('should return cached value', () => {
luminanceMock.mockReturnValue(0.8);
contrastMock.mockReturnValueOnce(10);
contrastMock.mockReturnValueOnce(2);
const c = create();
c.getBestContrastColor('#afa');
expect(luminanceMock).toHaveBeenCalledTimes(3);
c.getBestContrastColor('#afa');
c.getBestContrastColor('#afa');
expect(luminanceMock).toHaveBeenCalledTimes(3);
});
});

View File

@@ -1,55 +0,0 @@
describe('contraster', () => {
let sandbox;
let create;
let luminance;
let contrast;
before(() => {
sandbox = sinon.createSandbox();
luminance = sandbox.stub();
contrast = sandbox.stub();
[{ default: create }] = aw.mock(
[
['**/luminance.js', () => luminance],
['**/contrast.js', () => contrast],
],
['../contraster.js']
);
});
afterEach(() => {
sandbox.reset();
});
beforeEach(() => {
luminance.withArgs('#ffffff').returns(1);
luminance.withArgs('#333333').returns(0.1);
});
it('should return #ffffff by default when input is dark', () => {
luminance.withArgs('#111111').returns(0.05);
contrast.withArgs(0.05, 0.1).returns(5);
contrast.withArgs(0.05, 1).returns(20);
expect(create().getBestContrastColor('#111111')).to.equal('#ffffff');
});
it('should return #333333 by default when input is light', () => {
luminance.withArgs('#afa').returns(0.8);
contrast.withArgs(0.8, 0.1).returns(10);
contrast.withArgs(0.8, 1).returns(2);
expect(create().getBestContrastColor('#afa')).to.equal('#333333');
});
it('should return cached value', () => {
luminance.withArgs('#afa').returns(0.8);
contrast.withArgs(0.8, 0.1).returns(10);
contrast.withArgs(0.8, 1).returns(2);
const c = create();
c.getBestContrastColor('#afa');
expect(luminance.callCount).to.equal(3);
c.getBestContrastColor('#afa');
c.getBestContrastColor('#afa');
expect(luminance.callCount).to.equal(3);
});
});

View File

@@ -0,0 +1,31 @@
import * as d3ColorUtil from 'd3-color';
import luminance from '../luminance';
describe('luminance', () => {
let d3ColorMock;
beforeAll(() => {
d3ColorMock = jest.fn();
jest.spyOn(d3ColorUtil, 'color').mockImplementation(d3ColorMock);
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
test('for #ffffff should be 1', () => {
d3ColorMock.mockReturnValue({ rgb: () => ({ r: 255, g: 255, b: 255 }) });
expect(luminance('#ffffff')).toBe(1);
});
test('for #000000 should be 0', () => {
d3ColorMock.mockReturnValue({ rgb: () => ({ r: 0, g: 0, b: 0 }) });
expect(luminance('#000000')).toBe(0);
});
test('for #ff6633 should be 0.31002', () => {
d3ColorMock.mockReturnValue({ rgb: () => ({ r: 255, g: 102, b: 51 }) });
expect(luminance('#ff6633')).toBe(0.31002);
});
});

View File

@@ -1,30 +0,0 @@
describe('luminance', () => {
let sandbox;
let luminance;
let d3Color;
before(() => {
sandbox = sinon.createSandbox();
d3Color = sandbox.stub();
luminance = sandbox.stub();
[{ default: luminance }] = aw.mock([['**/d3-color.js', () => ({ color: d3Color })]], ['../luminance.js']);
});
afterEach(() => {
sandbox.reset();
});
it('for #ffffff should be 1', () => {
d3Color.withArgs('#ffffff').returns({ rgb: () => ({ r: 255, g: 255, b: 255 }) });
expect(luminance('#ffffff')).to.equal(1);
});
it('for #000000 should be 0', () => {
d3Color.withArgs('#000000').returns({ rgb: () => ({ r: 0, g: 0, b: 0 }) });
expect(luminance('#000000')).to.equal(0);
});
it('for #ff6633 should be 0.31002', () => {
d3Color.withArgs('#ff6633').returns({ rgb: () => ({ r: 255, g: 102, b: 51 }) });
expect(luminance('#ff6633')).to.equal(0.31002);
});
});

View File

@@ -8,6 +8,8 @@ module.exports = {
'apis/locale/.+\\.inspect\\.[jt]sx?$',
'apis/snapshooter/.+\\.inspect\\.[jt]sx?$',
'apis/supernova/.+\\.inspect\\.[jt]sx?$',
'apis/test-utils/.+\\.inspect\\.[jt]sx?$',
'apis/theme/.+\\.inspect\\.[jt]sx?$',
],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
collectCoverageFrom: [
@@ -17,11 +19,19 @@ module.exports = {
'apis/locale/**/*.{js,jsx}',
'apis/snapshooter/**/*.{js,jsx}',
'apis/supernova/**/*.{js,jsx}',
'apis/test-utils/**/*.{js,jsx}',
'apis/theme/**/*.{js,jsx}',
'!apis/enigma-mocker/examples/**',
'!apis/enigma-mocker/index.js',
'!commands/create/**/*.{js,jsx}',
'!commands/build/command.js',
'!commands/sense/command.js',
'!commands/serve/command.js',
'!commands/sense/src/ext.js',
'!commands/sense/src/empty-ext.js',
'!apis/snapshooter/client.js',
'!apis/test-utils/index.js',
'!**/lib/**',
'!**/dist/**',