mirror of
https://github.com/apache/superset.git
synced 2024-09-07 06:17:45 -04:00
Merge pull request #19 from apache-superset/kristw--new-core
Add new core modules from incubator-superset
This commit is contained in:
parent
b9391d3c6b
commit
7097a0e89f
@ -0,0 +1,23 @@
|
|||||||
|
## @superset-ui/core
|
||||||
|
|
||||||
|
[![Version](https://img.shields.io/npm/v/@superset-ui/core.svg?style=flat)](https://img.shields.io/npm/v/@superset-ui/core.svg?style=flat)
|
||||||
|
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui.svg?path=packages%2Fsuperset-ui-core&style=flat-square)](https://david-dm.org/apache-superset/superset-ui?path=packages/superset-ui-core)
|
||||||
|
|
||||||
|
Description
|
||||||
|
|
||||||
|
#### Example usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { xxx } from '@superset-ui/core';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### API
|
||||||
|
|
||||||
|
`fn(args)`
|
||||||
|
|
||||||
|
- TBD
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
`@data-ui/build-config` is used to manage the build configuration for this package including babel
|
||||||
|
builds, jest testing, eslint, and prettier.
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "@superset-ui/core",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"description": "Superset UI core",
|
||||||
|
"sideEffects": false,
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "esm/index.js",
|
||||||
|
"files": [
|
||||||
|
"esm",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/apache-superset/superset-ui.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"superset"
|
||||||
|
],
|
||||||
|
"author": "Superset",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/apache-superset/superset-ui/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/apache-superset/superset-ui#readme",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.11"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
export { default as Plugin } from './models/Plugin';
|
||||||
|
export { default as Preset } from './models/Preset';
|
||||||
|
export { default as Registry } from './models/Registry';
|
||||||
|
|
||||||
|
export { default as convertKeysToCamelCase } from './utils/convertKeysToCamelCase';
|
||||||
|
export { default as isDefined } from './utils/isDefined';
|
||||||
|
export { default as isRequired } from './utils/isRequired';
|
||||||
|
export { default as makeSingleton } from './utils/makeSingleton';
|
@ -0,0 +1,27 @@
|
|||||||
|
export default class Plugin {
|
||||||
|
constructor() {
|
||||||
|
this.resetConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
resetConfig() {
|
||||||
|
// The child class can set default config
|
||||||
|
// by overriding this function.
|
||||||
|
this.config = {};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
configure(config, replace = false) {
|
||||||
|
if (replace) {
|
||||||
|
this.config = config;
|
||||||
|
} else {
|
||||||
|
this.config = { ...this.config, ...config };
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
register() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
export default class Preset {
|
||||||
|
constructor({ name = '', description = '', presets = [], plugins = [] } = {}) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.presets = presets;
|
||||||
|
this.plugins = plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
register() {
|
||||||
|
this.presets.forEach(preset => {
|
||||||
|
preset.register();
|
||||||
|
});
|
||||||
|
this.plugins.forEach(plugin => {
|
||||||
|
plugin.register();
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
export default class Registry {
|
||||||
|
constructor(name = '') {
|
||||||
|
this.name = name;
|
||||||
|
this.items = {};
|
||||||
|
this.promises = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.items = {};
|
||||||
|
this.promises = {};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
has(key) {
|
||||||
|
const item = this.items[key];
|
||||||
|
|
||||||
|
return item !== null && item !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerValue(key, value) {
|
||||||
|
const item = this.items[key];
|
||||||
|
if (!item || item.value !== value) {
|
||||||
|
this.items[key] = { value };
|
||||||
|
delete this.promises[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerLoader(key, loader) {
|
||||||
|
const item = this.items[key];
|
||||||
|
if (!item || item.loader !== loader) {
|
||||||
|
this.items[key] = { loader };
|
||||||
|
delete this.promises[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
const item = this.items[key];
|
||||||
|
if (item) {
|
||||||
|
return item.loader ? item.loader() : item.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAsPromise(key) {
|
||||||
|
const promise = this.promises[key];
|
||||||
|
if (promise) {
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
const item = this.get(key);
|
||||||
|
if (item) {
|
||||||
|
const newPromise = Promise.resolve(item);
|
||||||
|
this.promises[key] = newPromise;
|
||||||
|
|
||||||
|
return newPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(new Error(`Item with key "${key}" is not registered.`));
|
||||||
|
}
|
||||||
|
|
||||||
|
getMap() {
|
||||||
|
return this.keys().reduce((prev, key) => {
|
||||||
|
const map = prev;
|
||||||
|
map[key] = this.get(key);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
getMapAsPromise() {
|
||||||
|
const keys = this.keys();
|
||||||
|
|
||||||
|
return Promise.all(keys.map(key => this.getAsPromise(key))).then(values =>
|
||||||
|
values.reduce((prev, value, i) => {
|
||||||
|
const map = prev;
|
||||||
|
map[keys[i]] = value;
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}, {}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
keys() {
|
||||||
|
return Object.keys(this.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
values() {
|
||||||
|
return this.keys().map(key => this.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
valuesAsPromise() {
|
||||||
|
return Promise.all(this.keys().map(key => this.getAsPromise(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
entries() {
|
||||||
|
return this.keys().map(key => ({
|
||||||
|
key,
|
||||||
|
value: this.get(key),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
entriesAsPromise() {
|
||||||
|
const keys = this.keys();
|
||||||
|
|
||||||
|
return Promise.all(keys.map(key => this.getAsPromise(key))).then(values =>
|
||||||
|
values.map((value, i) => ({
|
||||||
|
key: keys[i],
|
||||||
|
value,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(key) {
|
||||||
|
delete this.items[key];
|
||||||
|
delete this.promises[key];
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import camelCase from 'lodash/fp/camelCase';
|
||||||
|
import isPlainObject from 'lodash/fp/isPlainObject';
|
||||||
|
import mapKeys from 'lodash/fp/mapKeys';
|
||||||
|
|
||||||
|
export default function convertKeysToCamelCase(object) {
|
||||||
|
if (object === null || object === undefined) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
if (isPlainObject(object)) {
|
||||||
|
return mapKeys(k => camelCase(k), object);
|
||||||
|
}
|
||||||
|
throw new Error(`Cannot convert input that is not a plain object: ${object}`);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function isDefined(x) {
|
||||||
|
return x !== null && x !== undefined;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export default function isRequired(field) {
|
||||||
|
throw new Error(`${field} is required.`);
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
export default function makeSingleton(BaseClass, ...args) {
|
||||||
|
let singleton;
|
||||||
|
|
||||||
|
return function getInstance() {
|
||||||
|
if (!singleton) {
|
||||||
|
singleton = new BaseClass(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return singleton;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
describe('My Test', () => {
|
||||||
|
it('tests something', () => {
|
||||||
|
expect(1).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
import Plugin from '../../src/models/Plugin';
|
||||||
|
|
||||||
|
describe('Plugin', () => {
|
||||||
|
it('exists', () => {
|
||||||
|
expect(Plugin).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('new Plugin()', () => {
|
||||||
|
it('creates a new plugin', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
expect(plugin).toBeInstanceOf(Plugin);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.configure(config, replace)', () => {
|
||||||
|
it('extends the default config with given config when replace is not set or false', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
plugin.configure({ key: 'abc', foo: 'bar' });
|
||||||
|
plugin.configure({ key: 'def' });
|
||||||
|
expect(plugin.config).toEqual({ key: 'def', foo: 'bar' });
|
||||||
|
});
|
||||||
|
it('replaces the default config with given config when replace is true', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
plugin.configure({ key: 'abc', foo: 'bar' });
|
||||||
|
plugin.configure({ key: 'def' }, true);
|
||||||
|
expect(plugin.config).toEqual({ key: 'def' });
|
||||||
|
});
|
||||||
|
it('returns the plugin itself', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
expect(plugin.configure({ key: 'abc' })).toBe(plugin);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.resetConfig()', () => {
|
||||||
|
it('resets config back to default', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
plugin.configure({ key: 'abc', foo: 'bar' });
|
||||||
|
plugin.resetConfig();
|
||||||
|
expect(plugin.config).toEqual({});
|
||||||
|
});
|
||||||
|
it('returns the plugin itself', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
expect(plugin.resetConfig()).toBe(plugin);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.register()', () => {
|
||||||
|
it('returns the plugin itself', () => {
|
||||||
|
const plugin = new Plugin();
|
||||||
|
expect(plugin.register()).toBe(plugin);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,60 @@
|
|||||||
|
import Preset from '../../src/models/Preset';
|
||||||
|
import Plugin from '../../src/models/Plugin';
|
||||||
|
|
||||||
|
describe('Preset', () => {
|
||||||
|
it('exists', () => {
|
||||||
|
expect(Preset).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('new Preset()', () => {
|
||||||
|
it('creates new preset', () => {
|
||||||
|
const preset = new Preset();
|
||||||
|
expect(preset).toBeInstanceOf(Preset);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.register()', () => {
|
||||||
|
it('register all listed presets then plugins', () => {
|
||||||
|
const values = [];
|
||||||
|
class Plugin1 extends Plugin {
|
||||||
|
register() {
|
||||||
|
values.push(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Plugin2 extends Plugin {
|
||||||
|
register() {
|
||||||
|
values.push(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Plugin3 extends Plugin {
|
||||||
|
register() {
|
||||||
|
values.push(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Plugin4 extends Plugin {
|
||||||
|
register() {
|
||||||
|
const { key } = this.config;
|
||||||
|
values.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const preset1 = new Preset({
|
||||||
|
plugins: [new Plugin1()],
|
||||||
|
});
|
||||||
|
const preset2 = new Preset({
|
||||||
|
plugins: [new Plugin2()],
|
||||||
|
});
|
||||||
|
const preset3 = new Preset({
|
||||||
|
presets: [preset1, preset2],
|
||||||
|
plugins: [new Plugin3(), new Plugin4().configure({ key: 'abc' })],
|
||||||
|
});
|
||||||
|
preset3.register();
|
||||||
|
expect(values).toEqual([1, 2, 3, 'abc']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns itself', () => {
|
||||||
|
const preset = new Preset();
|
||||||
|
expect(preset.register()).toBe(preset);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,244 @@
|
|||||||
|
import Registry from '../../src/models/Registry';
|
||||||
|
|
||||||
|
describe('Registry', () => {
|
||||||
|
it('exists', () => {
|
||||||
|
expect(Registry !== undefined).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('new Registry(name)', () => {
|
||||||
|
it('can create a new registry when name is not given', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(registry).toBeInstanceOf(Registry);
|
||||||
|
});
|
||||||
|
it('can create a new registry when name is given', () => {
|
||||||
|
const registry = new Registry('abc');
|
||||||
|
expect(registry).toBeInstanceOf(Registry);
|
||||||
|
expect(registry.name).toBe('abc');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.clear()', () => {
|
||||||
|
it('clears all registered items', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
registry.clear();
|
||||||
|
expect(Object.keys(registry.items)).toHaveLength(0);
|
||||||
|
expect(Object.keys(registry.promises)).toHaveLength(0);
|
||||||
|
});
|
||||||
|
it('returns the registry itself', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(registry.clear()).toBe(registry);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.has(key)', () => {
|
||||||
|
it('returns true if an item with the given key exists', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
expect(registry.has('a')).toBe(true);
|
||||||
|
registry.registerLoader('b', () => 'testValue2');
|
||||||
|
expect(registry.has('b')).toBe(true);
|
||||||
|
});
|
||||||
|
it('returns false if an item with the given key does not exist', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(registry.has('a')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.registerValue(key, value)', () => {
|
||||||
|
it('registers the given value with the given key', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
expect(registry.has('a')).toBe(true);
|
||||||
|
expect(registry.get('a')).toBe('testValue');
|
||||||
|
});
|
||||||
|
it('returns the registry itself', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(registry.registerValue('a', 'testValue')).toBe(registry);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.registerLoader(key, loader)', () => {
|
||||||
|
it('registers the given loader with the given key', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerLoader('a', () => 'testValue');
|
||||||
|
expect(registry.has('a')).toBe(true);
|
||||||
|
expect(registry.get('a')).toBe('testValue');
|
||||||
|
});
|
||||||
|
it('returns the registry itself', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(registry.registerLoader('a', () => 'testValue')).toBe(registry);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.get(key)', () => {
|
||||||
|
it('given the key, returns the value if the item is a value', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
expect(registry.get('a')).toBe('testValue');
|
||||||
|
});
|
||||||
|
it('given the key, returns the result of the loader function if the item is a loader', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerLoader('b', () => 'testValue2');
|
||||||
|
expect(registry.get('b')).toBe('testValue2');
|
||||||
|
});
|
||||||
|
it('returns null if the item with specified key does not exist', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(registry.get('a')).toBeNull();
|
||||||
|
});
|
||||||
|
it('If the key was registered multiple times, returns the most recent item.', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
expect(registry.get('a')).toBe('testValue');
|
||||||
|
registry.registerLoader('a', () => 'newValue');
|
||||||
|
expect(registry.get('a')).toBe('newValue');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.getAsPromise(key)', () => {
|
||||||
|
it('given the key, returns a promise of item value if the item is a value', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
|
||||||
|
return registry.getAsPromise('a').then(value => expect(value).toBe('testValue'));
|
||||||
|
});
|
||||||
|
it('given the key, returns a promise of result of the loader function if the item is a loader ', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerLoader('a', () => 'testValue');
|
||||||
|
|
||||||
|
return registry.getAsPromise('a').then(value => expect(value).toBe('testValue'));
|
||||||
|
});
|
||||||
|
it('returns same promise object for the same key unless user re-registers new value with the key.', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerLoader('a', () => 'testValue');
|
||||||
|
const promise1 = registry.getAsPromise('a');
|
||||||
|
const promise2 = registry.getAsPromise('a');
|
||||||
|
expect(promise1).toBe(promise2);
|
||||||
|
});
|
||||||
|
it('returns a rejected promise if the item with specified key does not exist', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
|
||||||
|
return registry.getAsPromise('a').then(null, err => {
|
||||||
|
expect(err.toString()).toEqual('Error: Item with key "a" is not registered.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('If the key was registered multiple times, returns a promise of the most recent item.', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
const promise1 = registry.getAsPromise('a').then(value => expect(value).toBe('testValue'));
|
||||||
|
registry.registerLoader('a', () => 'newValue');
|
||||||
|
const promise2 = registry.getAsPromise('a').then(value => expect(value).toBe('newValue'));
|
||||||
|
|
||||||
|
return Promise.all([promise1, promise2]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.getMap()', () => {
|
||||||
|
it('returns key-value map as plain object', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'cat');
|
||||||
|
registry.registerLoader('b', () => 'dog');
|
||||||
|
expect(registry.getMap()).toEqual({
|
||||||
|
a: 'cat',
|
||||||
|
b: 'dog',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.getMapAsPromise()', () => {
|
||||||
|
it('returns a promise of key-value map', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'test1');
|
||||||
|
registry.registerLoader('b', () => 'test2');
|
||||||
|
registry.registerLoader('c', () => Promise.resolve('test3'));
|
||||||
|
|
||||||
|
return registry.getMapAsPromise().then(map =>
|
||||||
|
expect(map).toEqual({
|
||||||
|
a: 'test1',
|
||||||
|
b: 'test2',
|
||||||
|
c: 'test3',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.keys()', () => {
|
||||||
|
it('returns an array of keys', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
registry.registerLoader('b', () => 'test2');
|
||||||
|
expect(registry.keys()).toEqual(['a', 'b']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.values()', () => {
|
||||||
|
it('returns an array of values', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'test1');
|
||||||
|
registry.registerLoader('b', () => 'test2');
|
||||||
|
expect(registry.values()).toEqual(['test1', 'test2']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.valuesAsPromise()', () => {
|
||||||
|
it('returns a Promise of an array { key, value }', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'test1');
|
||||||
|
registry.registerLoader('b', () => 'test2');
|
||||||
|
registry.registerLoader('c', () => Promise.resolve('test3'));
|
||||||
|
|
||||||
|
return registry
|
||||||
|
.valuesAsPromise()
|
||||||
|
.then(entries => expect(entries).toEqual(['test1', 'test2', 'test3']));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.entries()', () => {
|
||||||
|
it('returns an array of { key, value }', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'test1');
|
||||||
|
registry.registerLoader('b', () => 'test2');
|
||||||
|
expect(registry.entries()).toEqual([
|
||||||
|
{ key: 'a', value: 'test1' },
|
||||||
|
{ key: 'b', value: 'test2' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.entriesAsPromise()', () => {
|
||||||
|
it('returns a Promise of an array { key, value }', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'test1');
|
||||||
|
registry.registerLoader('b', () => 'test2');
|
||||||
|
registry.registerLoader('c', () => Promise.resolve('test3'));
|
||||||
|
|
||||||
|
return registry
|
||||||
|
.entriesAsPromise()
|
||||||
|
.then(entries =>
|
||||||
|
expect(entries).toEqual([
|
||||||
|
{ key: 'a', value: 'test1' },
|
||||||
|
{ key: 'b', value: 'test2' },
|
||||||
|
{ key: 'c', value: 'test3' },
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('.remove(key)', () => {
|
||||||
|
it('removes the item with given key', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
registry.remove('a');
|
||||||
|
expect(registry.get('a')).toBeNull();
|
||||||
|
});
|
||||||
|
it('does not throw error if the key does not exist', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
expect(() => registry.remove('a')).not.toThrowError();
|
||||||
|
});
|
||||||
|
it('returns itself', () => {
|
||||||
|
const registry = new Registry();
|
||||||
|
registry.registerValue('a', 'testValue');
|
||||||
|
expect(registry.remove('a')).toBe(registry);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,33 @@
|
|||||||
|
import convertKeysToCamelCase from '../../src/utils/convertKeysToCamelCase';
|
||||||
|
|
||||||
|
describe('convertKeysToCamelCase(object)', () => {
|
||||||
|
it('returns undefined for undefined input', () => {
|
||||||
|
expect(convertKeysToCamelCase(undefined)).toBeUndefined();
|
||||||
|
});
|
||||||
|
it('returns null for null input', () => {
|
||||||
|
expect(convertKeysToCamelCase(null)).toBeNull();
|
||||||
|
});
|
||||||
|
it('returns a new object that has all keys in camelCase', () => {
|
||||||
|
const input = {
|
||||||
|
is_happy: true,
|
||||||
|
'is-angry': false,
|
||||||
|
isHungry: false,
|
||||||
|
};
|
||||||
|
expect(convertKeysToCamelCase(input)).toEqual({
|
||||||
|
isHappy: true,
|
||||||
|
isAngry: false,
|
||||||
|
isHungry: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('throws error if input is not a plain object', () => {
|
||||||
|
expect(() => {
|
||||||
|
convertKeysToCamelCase({});
|
||||||
|
}).not.toThrowError();
|
||||||
|
expect(() => {
|
||||||
|
convertKeysToCamelCase('');
|
||||||
|
}).toThrowError();
|
||||||
|
expect(() => {
|
||||||
|
convertKeysToCamelCase(new Map());
|
||||||
|
}).toThrowError();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,20 @@
|
|||||||
|
import isDefined from '../../src/utils/isDefined';
|
||||||
|
|
||||||
|
describe('isDefined(value)', () => {
|
||||||
|
it('returns true if value is not null and not undefined', () => {
|
||||||
|
expect(isDefined(0)).toBe(true);
|
||||||
|
expect(isDefined(1)).toBe(true);
|
||||||
|
expect(isDefined('')).toBe(true);
|
||||||
|
expect(isDefined('a')).toBe(true);
|
||||||
|
expect(isDefined([])).toBe(true);
|
||||||
|
expect(isDefined([0])).toBe(true);
|
||||||
|
expect(isDefined([1])).toBe(true);
|
||||||
|
expect(isDefined({})).toBe(true);
|
||||||
|
expect(isDefined({ a: 1 })).toBe(true);
|
||||||
|
expect(isDefined([{}])).toBe(true);
|
||||||
|
});
|
||||||
|
it('returns false otherwise', () => {
|
||||||
|
expect(isDefined(null)).toBe(false);
|
||||||
|
expect(isDefined(undefined)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
import isRequired from '../../src/utils/isRequired';
|
||||||
|
|
||||||
|
describe('isRequired(field)', () => {
|
||||||
|
it('should throw error with the given field in the message', () => {
|
||||||
|
expect(() => isRequired('myField')).toThrowError(Error);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,36 @@
|
|||||||
|
import makeSingleton from '../../src/utils/makeSingleton';
|
||||||
|
|
||||||
|
describe('makeSingleton()', () => {
|
||||||
|
class Dog {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
sit() {
|
||||||
|
this.isSitting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
describe('makeSingleton(BaseClass)', () => {
|
||||||
|
const getInstance = makeSingleton(Dog);
|
||||||
|
|
||||||
|
it('returns a function for getting singleton instance of a given base class', () => {
|
||||||
|
expect(typeof getInstance).toBe('function');
|
||||||
|
expect(getInstance()).toBeInstanceOf(Dog);
|
||||||
|
});
|
||||||
|
it('returned function returns same instance across all calls', () => {
|
||||||
|
expect(getInstance()).toBe(getInstance());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('makeSingleton(BaseClass, ...args)', () => {
|
||||||
|
const getInstance = makeSingleton(Dog, 'Doug');
|
||||||
|
|
||||||
|
it('returns a function for getting singleton instance of a given base class constructed with the given arguments', () => {
|
||||||
|
expect(typeof getInstance).toBe('function');
|
||||||
|
expect(getInstance()).toBeInstanceOf(Dog);
|
||||||
|
expect(getInstance().name).toBe('Doug');
|
||||||
|
});
|
||||||
|
it('returned function returns same instance across all calls', () => {
|
||||||
|
expect(getInstance()).toBe(getInstance());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user