UNPKG

kibana-with-account

Version:

kibana-with-account is develop based kibana project

682 lines (558 loc) 26 kB
var _ = require('lodash'); var sinon = require('auto-release-sinon'); var noDigestPromises = require('testUtils/noDigestPromises'); var ngMock = require('ngMock'); var expect = require('expect.js'); var errors = require('ui/errors'); var PersistedState; var Events; describe('Persisted State', function () { noDigestPromises.activateForSuite(); beforeEach(function () { ngMock.module('kibana'); ngMock.inject(function (Private) { PersistedState = Private(require('ui/persisted_state/persisted_state')); Events = Private(require('ui/events')); }); }); describe('state creation', function () { var persistedState; it('should create an empty state instance', function () { persistedState = new PersistedState(); expect(persistedState.get()).to.eql({}); }); it('should be an event emitter', function () { persistedState = new PersistedState(); expect(persistedState).to.be.an(Events); }); it('should create a state instance with data', function () { var val = { red: 'blue' }; persistedState = new PersistedState(val); expect(persistedState.get()).to.eql(val); // ensure we get a copy of the state, not the actual state object expect(persistedState.get()).to.not.equal(val); }); it('should create a copy of the state passed in', function () { var val = { red: 'blue' }; persistedState = new PersistedState(val); expect(persistedState.get()).to.eql(val); expect(persistedState.get()).to.not.equal(val); }); it('should not throw if creating valid child object', function () { var run = function () { var val = { red: 'blue' }; var path = ['test.path']; var parent = new PersistedState(); new PersistedState(val, path, parent); }; expect(run).not.to.throwException(); }); it('should throw if given an invalid value', function () { var run = function () { var val = 'bananas'; new PersistedState(val); }; expect(run).to.throwException(function (err) { expect(err).to.be.a(errors.PersistedStateError); }); }); it('should not throw if given primitive to child', function () { var run = function () { var val = 'bananas'; var path = ['test.path']; var parent = new PersistedState(); new PersistedState(val, path, parent); }; expect(run).not.to.throwException(); }); it('should throw if given an invalid parent object', function () { var run = function () { var val = { red: 'blue' }; var path = ['test.path']; var parent = {}; new PersistedState(val, path, parent); }; expect(run).to.throwException(function (err) { expect(err).to.be.a(errors.PersistedStateError); }); }); it('should throw if given a parent without a path', function () { var run = function () { var val = { red: 'blue' }; var path; var parent = new PersistedState(); new PersistedState(val, path, parent); }; expect(run).to.throwException(function (err) { expect(err).to.be.a(errors.PersistedStateError); }); }); }); describe('child state creation', function () { var childState; it('should not append the child state to the parent, without parent value', function () { var childIndex = 'i can haz child'; var persistedState = new PersistedState(); childState = persistedState.createChild(childIndex); // parent state should not contain the child state expect(persistedState.get()).to.not.have.property(childIndex); expect(persistedState.get()).to.eql({}); }); it('should not append the child state to the parent, with parent value', function () { var childIndex = 'i can haz child'; var persistedStateValue = { original: true }; var persistedState = new PersistedState(persistedStateValue); childState = persistedState.createChild(childIndex); // child state should be empty, we didn't give it any default data expect(childState.get()).to.be(undefined); // parent state should not contain the child state expect(persistedState.get()).to.not.have.property(childIndex); expect(persistedState.get()).to.eql(persistedStateValue); }); it('should append the child state to the parent, with parent and child values', function () { var childIndex = 'i can haz child'; var childStateValue = { tacos: 'yes please' }; var persistedStateValue = { original: true }; var persistedState = new PersistedState(persistedStateValue); childState = persistedState.createChild(childIndex, childStateValue); // parent state should contain the child and its original state value var parentState = persistedState.get(); expect(parentState).to.have.property('original', true); expect(parentState).to.have.property(childIndex); expect(parentState[childIndex]).to.eql(childStateValue); }); }); describe('deep child state creation', function () { it('should delegate get/set calls to parent state', function () { var children = [{ path: 'first*child', value: { first: true, second: false } }, { path: 'second child', value: { first: false, second: true } }]; var persistedStateValue = { original: true }; var persistedState = new PersistedState(persistedStateValue); // first child is a child of the parent persistedState children[0].instance = persistedState.createChild(children[0].path, children[0].value); // second child is a child of the first child children[1].instance = children[0].instance.createChild(children[1].path, children[1].value); // second child getter should only return second child value expect(children[1].instance.get()).to.eql(children[1].value); // parent should contain original props and first child path, but not the second child path var parentState = persistedState.get(); _.keys(persistedStateValue).forEach(function (key) { expect(parentState).to.have.property(key); }); expect(parentState).to.have.property(children[0].path); expect(parentState).to.not.have.property(children[1].path); // second child path should be inside the first child var firstChildState = children[0].instance.get(); expect(firstChildState).to.have.property(children[1].path); expect(firstChildState[children[1].path]).to.eql(children[1].value); // check that the second child is still accessible from the parent instance var firstChild = persistedState.get(children[0].path); expect(firstChild).to.have.property(children[1].path); }); }); describe('child state removal', function () { it('should clear path from parent state', function () { var persistedState = new PersistedState(); var childState = persistedState.createChild('child', { userId: 1234 }); expect(persistedState.get()).to.eql({ child: { userId: 1234 }}); persistedState.removeChild('child'); expect(persistedState.get()).to.eql({}); }); it('should reset original parent value at path', function () { var persistedState = new PersistedState({ user: 1234 }); var childState = persistedState.createChild('user', { id: 5678 }); expect(persistedState.get()).to.eql({ user: { id: 5678 }}); persistedState.removeChild('user'); expect(persistedState.get()).to.eql({ user: 1234 }); }); it('should clear changedState', function () { var persistedState = new PersistedState({ user: 1234 }); var childState = persistedState.createChild('user'); childState.set('name', 'user name'); expect(persistedState.getChanges()).to.eql({ user: { name: 'user name' }}); persistedState.removeChild('user'); expect(persistedState.getChanges()).to.eql({}); }); }); describe('deep child state removal', function () { it('should clear path from parent state', function () { var persistedState = new PersistedState(); var childState = persistedState.createChild('child.state', { userId: 1234 }); expect(persistedState.get()).to.eql({ child: { state: { userId: 1234 }}}); persistedState.removeChild('child.state'); expect(persistedState.get()).to.eql({}); }); it('should reset original parent value at path', function () { var persistedState = new PersistedState({ user: { id: 1234 }}); var childState = persistedState.createChild('user.id', 5678); expect(persistedState.get()).to.eql({ user: { id: 5678 }}); persistedState.removeChild('user.id'); expect(persistedState.get()).to.eql({ user: { id: 1234 }}); }); it('should reset original parent other values at path', function () { var persistedState = new PersistedState({ user: { name: 'user' }}); var childState = persistedState.createChild('user.id', 5678); expect(persistedState.get()).to.eql({ user: { name: 'user', id: 5678 }}); persistedState.removeChild('user.id'); expect(persistedState.get()).to.eql({ user: { name: 'user' }}); }); it('should clear the changed state', function () { var persistedState = new PersistedState({ user: { id: 1234 }}); var childState = persistedState.createChild('user.name'); childState.set('user name'); expect(persistedState.getChanges()).to.eql({ user: { name: 'user name' }}); persistedState.removeChild('user.name'); expect(persistedState.getChanges()).to.eql({}); }); }); describe('child state conditions', function () { it('should be merged with the parent state', function () { var parent = new PersistedState({ name: 'test' }); var child = parent.createChild('child', 'value'); expect(parent.get()).to.eql({ name: 'test', child: 'value' }); parent.set('id', 1234); expect(parent.get()).to.eql({ id: 1234, name: 'test', child: 'value' }); parent.set({}); expect(parent.get()).to.eql({ child: 'value' }); }); it('should give child state precedence', function () { var parent = new PersistedState({ user: { id: 1234, name: 'test' }}); var child = parent.createChild('user', { name: 'child test' }); expect(parent.get()).to.eql({ user: { id: 1234, name: 'child test' } }); parent.set({}); expect(parent.get()).to.eql({ user: { name: 'child test' }}); }); it('should be cleaned up with removeChild', function () { var parent = new PersistedState({ name: 'test' }); var child = parent.createChild('child', 'value'); expect(parent.get()).to.eql({ name: 'test', child: 'value' }); parent.removeChild('child'); expect(parent.get()).to.eql({ name: 'test' }); }); }); describe('colliding child paths and parent state values', function () { it('should not change the child path value by default', function () { var childIndex = 'childTest'; var persistedStateValue = {}; persistedStateValue[childIndex] = { overlapping_index: true }; var persistedState = new PersistedState(persistedStateValue); var state = persistedState.get(); expect(state).to.have.property(childIndex); expect(state[childIndex]).to.eql(persistedStateValue[childIndex]); var childState = persistedState.createChild(childIndex); expect(childState.get()).to.eql(persistedStateValue[childIndex]); // make sure the parent state is still the same state = persistedState.get(); expect(state).to.have.property(childIndex); expect(state[childIndex]).to.eql(persistedStateValue[childIndex]); }); it('should merge default child state', function () { var childIndex = 'childTest'; var childStateValue = { child_index: false }; var persistedStateValue = {}; persistedStateValue[childIndex] = { parent_index: true }; var persistedState = new PersistedState(persistedStateValue); var state = persistedState.get(); expect(state).to.have.property(childIndex); expect(state[childIndex]).to.eql(persistedStateValue[childIndex]); // pass in child state value var childState = persistedState.createChild(childIndex, childStateValue); // parent's default state is merged with child state var compare = _.merge({}, childStateValue, persistedStateValue[childIndex]); expect(childState.get()).to.eql(compare); state = persistedState.get(); expect(state).to.have.property(childIndex); expect(state[childIndex]).to.eql(compare); }); }); describe('mutation', function () { it('should not mutate the internal object', function () { var persistedStateValue = { hello: 'world' }; var insertedObj = { farewell: 'cruel world' }; var persistedState = new PersistedState(persistedStateValue); var obj = persistedState.get(); _.assign(obj, insertedObj); expect(obj).to.have.property('farewell'); expect(persistedState.get()).to.not.have.property('farewell'); }); }); describe('JSON importing and exporting', function () { var persistedStateValue; beforeEach(function () { persistedStateValue = { one: 1, two: 2, 'meaning of life': 42 }; }); describe('exporting state to JSON', function () { it('should return the full JSON representation', function () { var persistedState = new PersistedState(persistedStateValue); var json = persistedState.toJSON(); expect(json).to.eql(persistedStateValue); }); it('should return the JSON representation of the child state', function () { var persistedState = new PersistedState(persistedStateValue); var childState = persistedState.createChild('awesome', { pants: false }); expect(childState.toJSON()).to.eql({ pants: false }); // verify JSON output of the parent state var parentCompare = _.assign({ awesome: { pants: false }}, persistedStateValue); expect(persistedState.toJSON()).to.eql(parentCompare); }); it('should export stringified version of state', function () { var persistedState = new PersistedState(persistedStateValue); var childState = persistedState.createChild('awesome', { pants: false }); var data = childState.toString(); expect(JSON.parse(data)).to.eql({ pants: false }); // verify JSON output of the parent state var parentCompare = _.assign({ awesome: { pants: false }}, persistedStateValue); expect(JSON.parse(persistedState.toString())).to.eql(parentCompare); }); }); describe('importing state from JSON string (hydration)', function () { it('should set the state from JSON string input', function () { var stateJSON = JSON.stringify(persistedStateValue); var persistedState = new PersistedState(); expect(persistedState.get()).to.eql({}); persistedState.fromString(stateJSON); expect(persistedState.get()).to.eql(persistedStateValue); }); }); }); describe('get state', function () { it('should perform deep gets with various formats', function () { var obj = { red: { green: { blue: 'yellow' } }, orange: [1, 2, false, 4], purple: { violet: '' } }; var persistedState = new PersistedState(obj); expect(persistedState.get()).to.eql(obj); expect(persistedState.get('red')).to.eql({ green: { blue: 'yellow' } }); expect(persistedState.get('red.green')).to.eql({ blue: 'yellow' }); expect(persistedState.get('red[green]')).to.eql({ blue: 'yellow' }); expect(persistedState.get(['red', 'green'])).to.eql({ blue: 'yellow' }); expect(persistedState.get('red.green.blue')).to.eql('yellow'); expect(persistedState.get('red[green].blue')).to.eql('yellow'); expect(persistedState.get('red.green[blue]')).to.eql('yellow'); expect(persistedState.get('red[green][blue]')).to.eql('yellow'); expect(persistedState.get('red.green.blue')).to.eql('yellow'); expect(persistedState.get('orange')).to.eql([1, 2, false, 4]); expect(persistedState.get('orange[0]')).to.equal(1); expect(persistedState.get('orange[2]')).to.equal(false); expect(persistedState.get('purple')).to.eql({ violet: '' }); }); it('should perform deep gets with arrays', function () { var persistedState = new PersistedState({ hello: { nouns: ['world', 'humans', 'everyone'] } }); expect(persistedState.get()).to.eql({ hello: { nouns: ['world', 'humans', 'everyone'] } }); expect(persistedState.get('hello')).to.eql({ nouns: ['world', 'humans', 'everyone'] }); expect(persistedState.get('hello.nouns')).to.eql(['world', 'humans', 'everyone']); }); it('should pass defaults to parent delegation', function () { var persistedState = new PersistedState({ parent: true }); var childState = persistedState.createChild('child', { account: { name: 'first child' }}); var defaultValue = 'i have no data'; expect(childState.get('account.name', defaultValue)).to.eql('first child'); expect(childState.get('account.age', defaultValue)).to.eql(defaultValue); }); }); describe('set state', function () { describe('path format support', function () { it('should create deep objects from dot notation', function () { var persistedState = new PersistedState(); persistedState.set('one.two.three', 4); expect(persistedState.get()).to.eql({ one: { two: { three: 4 } } }); }); it('should create deep objects from array notation', function () { var persistedState = new PersistedState(); persistedState.set('one[two][three]', 4); expect(persistedState.get()).to.eql({ one: { two: { three: 4 } } }); }); it('should create deep objects from arrays', function () { var persistedState = new PersistedState(); persistedState.set(['one', 'two', 'three'], 4); expect(persistedState.get()).to.eql({ one: { two: { three: 4 } } }); }); it('should create deep objects with an existing path', function () { var persistedState = new PersistedState({}, 'deep.path'); persistedState.set('green[red].blue', 4); expect(persistedState.get()).to.eql({ green: { red: { blue: 4 } }}); }); }); describe('simple replace operations', function () { var persistedState; it('should replace value with string', function () { persistedState = new PersistedState({ hello: 'world' }); expect(persistedState.get()).to.eql({ hello: 'world' }); persistedState.set('hello', 'fare thee well'); expect(persistedState.get()).to.eql({ hello: 'fare thee well' }); }); it('should replace value with array', function () { persistedState = new PersistedState({ hello: ['world', 'everyone'] }); expect(persistedState.get()).to.eql({ hello: ['world', 'everyone'] }); persistedState.set('hello', ['people']); expect(persistedState.get()).to.eql({ hello: ['people'] }); }); it('should replace value with object', function () { persistedState = new PersistedState({ hello: 'world' }); expect(persistedState.get()).to.eql({ hello: 'world' }); persistedState.set('hello', { message: 'fare thee well' }); expect(persistedState.get()).to.eql({ hello: { message: 'fare thee well' } }); }); it('should replace value with object, removing old properties', function () { persistedState = new PersistedState({ hello: { message: 'world' } }); expect(persistedState.get()).to.eql({ hello: { message: 'world' } }); persistedState.set('hello', { length: 5 }); expect(persistedState.get()).to.eql({ hello: { length: 5 }}); }); }); describe('deep replace operations', function () { var persistedState; it('should append to the object', function () { persistedState = new PersistedState({ hello: { message: 'world' } }); expect(persistedState.get()).to.eql({ hello: { message: 'world' } }); persistedState.set('hello.length', 5); expect(persistedState.get()).to.eql({ hello: { message: 'world', length: 5 } }); }); it('should change the value in the array', function () { persistedState = new PersistedState({ hello: { nouns: ['world', 'humans', 'everyone'] } }); persistedState.set('hello.nouns[1]', 'aliens'); expect(persistedState.get()).to.eql({ hello: { nouns: ['world', 'aliens', 'everyone'] } }); expect(persistedState.get('hello')).to.eql({ nouns: ['world', 'aliens', 'everyone'] }); expect(persistedState.get('hello.nouns')).to.eql(['world', 'aliens', 'everyone']); }); }); }); describe('internal state tracking', function () { it('should be an empty object', function () { var persistedState = new PersistedState(); expect(persistedState._defaultState).to.eql({}); }); it('should store the default state value', function () { var val = { one: 1, two: 2 }; var persistedState = new PersistedState(val); expect(persistedState._defaultState).to.eql(val); }); it('should keep track of changes', function () { var val = { one: 1, two: 2 }; var persistedState = new PersistedState(val); persistedState.set('two', 22); expect(persistedState._defaultState).to.eql(val); expect(persistedState._changedState).to.eql({ two: 22 }); }); }); describe('events', function () { var persistedState; var emitter; var getByType = function (type, spy) { spy = spy || emitter; return spy.getCalls().filter(function (call) { return call.args[0] === type; }); }; var watchEmitter = function (state) { return sinon.spy(state, 'emit'); }; beforeEach(function () { persistedState = new PersistedState({ checker: { events: 'event tests' } }); emitter = watchEmitter(persistedState); }); it('should emit set when setting values', function () { expect(getByType('set')).to.have.length(0); persistedState.set('checker.time', 'now'); expect(getByType('set')).to.have.length(1); }); it('should not emit when setting value silently', function () { expect(getByType('set')).to.have.length(0); persistedState.setSilent('checker.time', 'now'); expect(getByType('set')).to.have.length(0); }); it('should emit change when changing values', function () { expect(getByType('change')).to.have.length(0); persistedState.set('checker.time', 'now'); expect(getByType('change')).to.have.length(1); }); it('should not emit when changing values silently', function () { expect(getByType('change')).to.have.length(0); persistedState.setSilent('checker.time', 'now'); expect(getByType('change')).to.have.length(0); }); it('should not emit change when values are identical', function () { expect(getByType('change')).to.have.length(0); // check both forms of setting the same value persistedState.set('checker', { events: 'event tests' }); expect(getByType('change')).to.have.length(0); persistedState.set('checker.events', 'event tests'); expect(getByType('change')).to.have.length(0); }); it('should emit change when values change', function () { expect(getByType('change')).to.have.length(0); persistedState.set('checker.events', 'i changed'); expect(getByType('change')).to.have.length(1); }); it('should not emit change when createChild has no value', function () { expect(getByType('change')).to.have.length(0); persistedState.createChild('checker'); expect(getByType('change')).to.have.length(0); }); it('should not emit change when createChild is same value', function () { expect(getByType('change')).to.have.length(0); persistedState.createChild('checker', { events: 'event tests' }); expect(getByType('change')).to.have.length(0); persistedState.createChild('checker.events', 'event tests'); expect(getByType('change')).to.have.length(0); }); it('should emit change when createChild changes existing value', function () { expect(getByType('change')).to.have.length(0); persistedState.createChild('checker', { events: 'changed via child' }); expect(getByType('change')).to.have.length(1); }); it('should not emit when createChild set to silent', function () { expect(getByType('change')).to.have.length(0); persistedState.createChild('checker', { events: 'changed via child' }, true); expect(getByType('change')).to.have.length(0); }); it('should emit change when createChild adds new value', function () { expect(getByType('change')).to.have.length(0); persistedState.createChild('new.path', { another: 'thing' }); expect(getByType('change')).to.have.length(1); }); it('should emit on parent and child instances', function (done) { var child = persistedState.createChild('checker'); expect(getByType('change')).to.have.length(0); // parent and child should emit, set up listener to test child.on('change', function () { // child fired, make sure parent fires as well expect(getByType('change')).to.have.length(1); done(); }); child.set('events', 'changed via child set'); }); }); });