lucid-ui
Version:
A UI component library from AppNexus.
337 lines (312 loc) • 14.3 kB
JavaScript
import _upperCase from "lodash/upperCase";
import _isFunction from "lodash/isFunction";
function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest(); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
jest.mock('./logger');
import assert from 'assert';
import sinon from 'sinon';
import { cleanArgs, thunk, getReduxPrimitives } from './redux';
describe('redux utils', function () {
describe('#cleanArgs', function () {
it('it should remove the last element if it has an `event` property', function () {
assert.deepEqual(cleanArgs(['foo', 'bar', {
event: 'event'
}]), ['foo', 'bar']);
assert.deepEqual(cleanArgs(['foo', 'bar', {
event: null
}]), ['foo', 'bar']);
});
it('it should not remove the last element if it has no `event` property', function () {
assert.deepEqual(cleanArgs(['foo', 'bar']), ['foo', 'bar']);
});
});
describe('#thunk', function () {
it('should set `isThunk` property on the input function to `true`', function () {
assert(thunk(function () {}).isThunk, 'must have `isThunk`');
});
});
describe('#getReduxPrimitives', function () {
var reducers = {
foo: {
onChange: function onChange(_state, payload) {
return {
value: payload
};
},
bar: {
onChange: function onChange(_state, payload) {
return {
value: payload
};
}
}
}
};
var initialState = {
foo: {
value: 'foo',
bar: {
value: null
}
}
};
describe('reducer', function () {
var _getReduxPrimitives = getReduxPrimitives({
reducers: reducers,
initialState: initialState
}),
reducer = _getReduxPrimitives.reducer;
it('should return initialState on unmatched type', function () {
var action = {
type: 'UNKNOWN'
};
assert.deepEqual(reducer(initialState, action), initialState, 'must deep equal initialState');
});
it('should correctly apply state change', function () {
var action = {
type: 'foo.onChange',
payload: 'bar'
};
var nextState = reducer(initialState, action);
assert.equal(nextState.foo.value, 'bar', 'must equal action payload');
});
describe('nested reducer', function () {
it('should correctly apply state change', function () {
var action = {
type: 'foo.bar.onChange',
payload: 'baz'
};
var nextState = reducer(initialState, action);
assert.equal(nextState.foo.bar.value, 'baz', 'must equal action payload');
});
});
describe('with rootPath', function () {
var _getReduxPrimitives2 = getReduxPrimitives({
reducers: reducers,
initialState: initialState,
rootPath: ['root']
}),
reducerWithRootPath = _getReduxPrimitives2.reducer;
it('should correctly apply state change', function () {
var action = {
type: 'root.foo.onChange',
payload: 'bar'
};
var nextState = reducerWithRootPath(initialState, action);
assert.equal(nextState.foo.value, 'bar', 'must equal action payload');
});
});
describe('thunks', function () {
it('should not include thunk paths in reducer', function () {
var action = {
type: 'root.foo.asyncOperation'
};
var nextState = reducer(initialState, action);
assert.deepEqual(initialState, nextState, 'must deep equal initialState');
});
});
});
describe('connectors', function () {
describe('selector/mapStateToProps', function () {
var selectors = {
foo: {
uppercase: function uppercase(_ref) {
var value = _ref.value;
return _upperCase(value);
}
}
};
var _getReduxPrimitives3 = getReduxPrimitives({
reducers: reducers,
initialState: initialState,
selectors: selectors
}),
_getReduxPrimitives3$ = _slicedToArray(_getReduxPrimitives3.connectors, 1),
mapStateToProps = _getReduxPrimitives3$[0];
it('should apply selector', function () {
var viewState = mapStateToProps(initialState, null, null);
assert.equal(viewState.foo.uppercase, 'FOO', 'must equal "FOO"');
});
it('should pass state through unharmed if selectors are undefined', function () {
var _getReduxPrimitives4 = getReduxPrimitives({
reducers: reducers,
initialState: initialState
}),
_getReduxPrimitives4$ = _slicedToArray(_getReduxPrimitives4.connectors, 1),
mapStateToProps = _getReduxPrimitives4$[0];
var viewState = mapStateToProps(initialState, null, null);
assert.deepEqual(viewState, initialState);
});
describe('rootPath', function () {
var _getReduxPrimitives5 = getReduxPrimitives({
reducers: reducers,
initialState: initialState,
selectors: selectors,
rootPath: ['root']
}),
_getReduxPrimitives5$ = _slicedToArray(_getReduxPrimitives5.connectors, 1),
mapStateToProps = _getReduxPrimitives5$[0];
it('should apply selector', function () {
var viewState = mapStateToProps({
root: initialState
}, null, null);
assert.equal(viewState.foo.uppercase, 'FOO', 'must equal "FOO"');
});
});
describe('rootSelector', function () {
var _getReduxPrimitives6 = getReduxPrimitives({
reducers: reducers,
initialState: initialState,
selectors: selectors,
rootSelector: function rootSelector(state) {
return _objectSpread(_objectSpread({}, state), {}, {
computed: state.foo.uppercase + state.foo.value
});
}
}),
_getReduxPrimitives6$ = _slicedToArray(_getReduxPrimitives6.connectors, 1),
mapStateToProps = _getReduxPrimitives6$[0];
it('should apply rootSelector', function () {
var viewState = mapStateToProps(initialState, null, null);
assert.equal(viewState.computed, 'FOOfoo', 'must equal "FOOfoo"');
});
});
});
describe('dispatchTree/mapDispatchToProps', function () {
describe('synchronous dispatch', function () {
var rootState = {
qux: {
quux: {
foo: {
value: 'foo',
bar: {
value: null
}
}
}
}
};
var initialState = rootState.qux.quux;
var _getReduxPrimitives7 = getReduxPrimitives({
reducers: reducers,
initialState: initialState,
rootPath: ['qux', 'quux']
}),
connectors = _getReduxPrimitives7.connectors;
var mockDispatch = sinon.spy(function (action) {
return action;
});
var mapDispatchToProps = connectors[1];
var dispatchTree = mapDispatchToProps(mockDispatch, null, null);
beforeEach(function () {
mockDispatch.reset();
});
it('should dispatch the correct action', function () {
dispatchTree.foo.onChange('bar', 'baz');
var dispatchedAction = mockDispatch.getCall(0).args[0];
assert.deepEqual(dispatchedAction, {
type: 'qux.quux.foo.onChange',
payload: 'bar',
meta: ['baz']
}, 'must include path as type, first param as payload, and subsequent params as meta');
});
});
describe('thunks', function () {
var thunkSpy = sinon.spy();
var reducers = {
foo: {
onChange: function onChange(state, payload) {
return {
value: payload
};
},
bar: {
onChange: function onChange(state, payload) {
return {
value: payload
};
}
},
asyncOperation: thunk(function (payload) {
return function (dispatchTree) {
return dispatchTree.onChange(payload);
};
}),
thunkSpy: thunk(function () {
return thunkSpy;
})
}
};
var rootState = {
qux: {
quux: {
foo: {
value: 'foo',
bar: {
value: null
}
}
}
}
};
var initialState = rootState.qux.quux;
var _getReduxPrimitives8 = getReduxPrimitives({
reducers: reducers,
initialState: initialState,
rootPath: ['qux', 'quux']
}),
connectors = _getReduxPrimitives8.connectors;
var extraArgs = ['rest1', 'rest2'];
var mapDispatchToProps = connectors[1];
var mockGetState = sinon.spy(function () {
return rootState;
});
var mockDispatch = sinon.spy(function (action) {
return _isFunction(action) ? action.apply(void 0, [mockDispatch, mockGetState].concat(extraArgs)) : action;
});
var dispatchTree = mapDispatchToProps(mockDispatch, null, null);
beforeEach(function () {
thunkSpy.reset();
dispatchTree.foo.asyncOperation('qux');
});
it('should dispatch a thunk', function () {
var dispatchedThunk = mockDispatch.getCall(0).args[0];
assert(_isFunction(dispatchedThunk), 'must be a function');
});
it('should dispatch the correct action', function () {
var dispatchedAction = mockDispatch.getCall(1).args[0];
assert.deepEqual(dispatchedAction, {
type: 'qux.quux.foo.onChange',
payload: 'qux',
meta: []
}, 'must include path as type and param on payload');
});
it('should call the thunk with the correct arguments', function () {
dispatchTree.foo.thunkSpy();
var _thunkSpy$getCall = thunkSpy.getCall(0),
_thunkSpy$getCall$arg = _toArray(_thunkSpy$getCall.args),
localDispatchTree = _thunkSpy$getCall$arg[0],
getLocalState = _thunkSpy$getCall$arg[1],
dispatch = _thunkSpy$getCall$arg[2],
getState = _thunkSpy$getCall$arg[3],
rest = _thunkSpy$getCall$arg.slice(4);
assert.equal(dispatchTree.foo, localDispatchTree, 'must be called with local dispatchTree');
assert.equal(getLocalState(), rootState.qux.quux.foo, 'must be called with getLocalState');
assert.equal(dispatch, mockDispatch, 'must be called with redux.dispatch');
assert.equal(getState, mockGetState, 'must be called with redux.getState');
assert.deepEqual(rest, extraArgs, 'must pass through extra arguments');
});
});
});
});
});
});