UNPKG

graph-crdt

Version:
287 lines (201 loc) 8.14 kB
'use strict'; var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray'); var _slicedToArray3 = _interopRequireDefault(_slicedToArray2); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _expect = require('expect'); var _expect2 = _interopRequireDefault(_expect); var _index = require('./index'); var _index2 = _interopRequireDefault(_index); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* eslint-env mocha */ describe('A node merge', function () { var node = void 0; beforeEach(function () { node = new _index2.default(); }); it('namespaces to avoid conflicts', function () { node.merge({ read: 'not a function' }); (0, _expect2.default)(node.value).toBeA(Function); }); it('converts POJOs into Nodes', function () { node.merge({ data: 'success' }); (0, _expect2.default)(node.value('data')).toBe('success'); }); it('uses the same node ID for new change nodes', function () { var _node$merge = node.merge({}), update = _node$merge.update, history = _node$merge.history; var _node$meta = node.meta(), uid = _node$meta.uid; (0, _expect2.default)(update.meta()).toContain({ uid: uid }); (0, _expect2.default)(history.meta()).toContain({ uid: uid }); }); describe('within operating state bounds', function () { it('adds all new properties', function () { var update = _index2.default.from({ data: true }); node.merge(update); var keys = [].concat((0, _toConsumableArray3.default)(node)).map(function (_ref) { var _ref2 = (0, _slicedToArray3.default)(_ref, 1), key = _ref2[0]; return key; }); (0, _expect2.default)(keys).toContain('data'); }); it('updates existing properties', function () { var incoming = _index2.default.from({ data: false }); node.merge(incoming); (0, _expect2.default)(node.value('data')).toBe(false); incoming.merge({ data: true }); node.merge(incoming); (0, _expect2.default)(node.value('data')).toBe(true); }); it('emits `update` after updates', function () { var spy = (0, _expect.createSpy)(); node.on('update', spy); node.merge({ data: 'yep' }); var _spy$calls$0$argument = (0, _slicedToArray3.default)(spy.calls[0].arguments, 1), value = _spy$calls$0$argument[0]; (0, _expect2.default)(value).toBeA(_index2.default); var object = value.snapshot(); (0, _expect2.default)(object).toEqual({ data: 'yep' }); }); it('returns the updates', function () { var _node$merge2 = node.merge({ data: 'yep' }), update = _node$merge2.update; (0, _expect2.default)(update).toBeA(_index2.default); var object = update.snapshot(); (0, _expect2.default)(object).toEqual({ data: 'yep' }); }); it('does not emit `update` without updates', function () { var spy = (0, _expect.createSpy)(); node.on('update', spy); // No properties. node.merge({}); (0, _expect2.default)(spy).toNotHaveBeenCalled(); }); it('does not emit `update` for the same update', function () { var spy = (0, _expect.createSpy)(); node.on('update', spy); var update = _index2.default.from({ update: true }); node.merge(update); node.merge(update); (0, _expect2.default)(spy.calls.length).toBe(1); }); it('merges other nodes', function () { var weather = new _index2.default({ uid: 'weather' }); weather.merge({ condition: 'sunny', temp: 65 }); var change = new _index2.default({ uid: 'weather' }); change.merge(weather); change.merge({ temp: 70 }); weather.merge(change); (0, _expect2.default)(weather.state('temp')).toBe(2); (0, _expect2.default)(weather.value('temp')).toBe(70); }); }); describe('in historical state', function () { var incoming = void 0; beforeEach(function () { incoming = _index2.default.create(); }); it('does not overwrite more recent properties', function () { // Stale update. incoming.merge({ hello: 'Mars' }); incoming.meta('hello').state = 1; var update = _index2.default.from({ hello: 'World' }); update.meta('hello').state = 2; node.merge(update); node.merge(incoming); (0, _expect2.default)(node.value('hello')).toBe('World'); }); it('adds new properties', function () { // Really old state, but it's new to `node`. incoming.merge({ success: true }); incoming.meta('success').state = 10; node.merge(incoming); (0, _expect2.default)(node.value('success')).toBe(true); }); it('returns the history', function () { incoming.merge({ old: true }); incoming.meta('old').state = 1; node.merge({ old: false }); node.meta('old').state = 2; var _node$merge3 = node.merge(incoming), history = _node$merge3.history; (0, _expect2.default)(history).toBeA(_index2.default); var object = history.snapshot(); (0, _expect2.default)(object).toEqual({ old: true }); }); it('includes overwritten values in history', function () { node.merge({ old: true }); var _node$merge4 = node.merge({ old: false }), history = _node$merge4.history; var object = history.snapshot(); (0, _expect2.default)(object).toEqual({ old: true }); }); it('emits `history` if updates are outdated', function () { incoming.merge({ data: 'old state' }); incoming.meta('data').state = 1; node.merge({ data: 'new state' }); node.meta('data').state = 2; var spy = (0, _expect.createSpy)(); node.on('history', spy); node.merge(incoming); var _spy$calls$0$argument2 = (0, _slicedToArray3.default)(spy.calls[0].arguments, 1), history = _spy$calls$0$argument2[0]; (0, _expect2.default)(history).toBeA(_index2.default); var object = history.snapshot(); (0, _expect2.default)(object).toEqual({ data: 'old state' }); }); it('does not emit `history` without stale updates', function () { var spy = (0, _expect.createSpy)(); node.on('history', spy); incoming.merge({ 'new property': 'yeah' }); incoming.meta('new property').state = 1; node.merge({ hello: 'Earth' }); node.merge(incoming); (0, _expect2.default)(spy).toNotHaveBeenCalled(); }); }); describe('conflict', function () { var conflict = void 0; beforeEach(function () { conflict = new _index2.default(); node.merge({ value: '9' }); conflict.merge({ value: '5' }); // Same state. node.meta('value').state = conflict.meta('value').state; }); it('is ignored if it loses', function () { var _node$merge5 = node.merge(conflict), update = _node$merge5.update, history = _node$merge5.history; (0, _expect2.default)(update.snapshot()).toEqual({}); (0, _expect2.default)(history.snapshot()).toEqual({}); }); it('triggers an update if it wins', function () { node.meta('value').value = '1'; var _node$merge6 = node.merge(conflict), update = _node$merge6.update; (0, _expect2.default)(update.snapshot()).toEqual({ value: '5' }); }); it('emits `conflict` if it wins', function () { var spy = (0, _expect.createSpy)(); node.on('conflict', spy); var current = node.meta('value'); var update = conflict.meta('value'); current.value = '1'; node.merge(conflict); (0, _expect2.default)(spy).toHaveBeenCalled(); (0, _expect2.default)(spy).toHaveBeenCalledWith(update, current); }); it('does not emit `conflict` if it loses', function () { var spy = (0, _expect.createSpy)(); node.on('conflict', spy); node.merge(conflict); (0, _expect2.default)(spy).toNotHaveBeenCalled(); }); }); });