export const testObserveDeepProperties = tc => { const { testConnector, users, map1, map2, map3 } = init(tc, { users: 4 }) const _map1 = map1.set('map', new Y.Map()) let calls = 0 let dmapid map1.observeDeep(events => { events.forEach(event => { calls++ // @ts-ignore t.assert(event.keysChanged.has('deepmap')) t.assert(event.path.length === 1) t.assert(event.path[0] === 'map') // @ts-ignore dmapid = event.target.get('deepmap')._item.id }) }) testConnector.flushAllMessages() const _map3 = map3.get('map') _map3.set('deepmap', new Y.Map()) testConnector.flushAllMessages() const _map2 = map2.get('map') _map2.set('deepmap', new Y.Map()) testConnector.flushAllMessages() const dmap1 = _map1.get('deepmap') const dmap2 = _map2.get('deepmap') const dmap3 = _map3.get('deepmap') t.assert(calls > 0) t.assert(compareIDs(dmap1._item.id, dmap2._item.id)) t.assert(compareIDs(dmap1._item.id, dmap3._item.id)) // @ts-ignore we want the possibility of dmapid being undefined t.assert(compareIDs(dmap1._item.id, dmapid)) compare(users) }
export const testYmapSetsYmap = tc => { const { users, map0 } = init(tc, { users: 2 }) const map = map0.set('Map', new Y.Map()) t.assert(map0.get('Map') === map) map.set('one', 1) t.compare(map.get('one'), 1) compare(users) }
events.forEach(event => { calls++ // @ts-ignore t.assert(event.keysChanged.has('deepmap')) t.assert(event.path.length === 1) t.assert(event.path[0] === 'map') // @ts-ignore dmapid = event.target.get('deepmap')._item.id })
export const testYmapSetsYarray = tc => { const { users, map0 } = init(tc, { users: 2 }) const array = map0.set('Array', new Y.Array()) t.assert(array === map0.get('Array')) array.insert(0, [1, 2, 3]) // @ts-ignore t.compare(map0.toJSON(), { Array: [1, 2, 3] }) compare(users) }
export const testGetAndSetOfMapPropertySyncs = tc => { const { testConnector, users, map0 } = init(tc, { users: 2 }) map0.set('stuff', 'stuffy') t.compare(map0.get('stuff'), 'stuffy') testConnector.flushAllMessages() for (let user of users) { var u = user.getMap('map') t.compare(u.get('stuff'), 'stuffy') } compare(users) }
export const testBasicInsertAndDelete = tc => { const { users, text0 } = init(tc, { users: 2 }) let delta text0.observe(event => { delta = event.delta }) text0.delete(0, 0) t.assert(true, 'Does not throw when deleting zero elements with position 0') text0.insert(0, 'abc') t.assert(text0.toString() === 'abc', 'Basic insert works') t.compare(delta, [{ insert: 'abc' }]) text0.delete(0, 1) t.assert(text0.toString() === 'bc', 'Basic delete works (position 0)') t.compare(delta, [{ delete: 1 }]) text0.delete(1, 1) t.assert(text0.toString() === 'b', 'Basic delete works (position 1)') t.compare(delta, [{ retain: 1 }, { delete: 1 }]) users[0].transact(() => { text0.insert(0, '1') text0.delete(0, 1) }) t.compare(delta, []) compare(users) }
export const testGetAndSetOfMapProperty = tc => { const { testConnector, users, map0 } = init(tc, { users: 2 }) map0.set('stuff', 'stuffy') map0.set('undefined', undefined) map0.set('null', null) t.compare(map0.get('stuff'), 'stuffy') testConnector.flushAllMessages() for (let user of users) { const u = user.getMap('map') t.compare(u.get('stuff'), 'stuffy') t.assert(u.get('undefined') === undefined, 'undefined') t.compare(u.get('null'), null, 'null') } compare(users) }
export const testGetDeltaWithEmbeds = tc => { const { text0 } = init(tc, { users: 1 }) text0.applyDelta([{ insert: {linebreak: 's'} }]) t.compare(text0.toDelta(), [{ insert: {linebreak: 's'} }]) }
export const testObserversUsingObservedeep = tc => { const { users, map0 } = init(tc, { users: 2 }) /** * @type {Array<Array<string|number>>} */ const pathes = [] let calls = 0 map0.observeDeep(events => { events.forEach(event => { pathes.push(event.path) }) calls++ }) map0.set('map', new Y.Map()) map0.get('map').set('array', new Y.Array()) map0.get('map').get('array').insert(0, ['content']) t.assert(calls === 3) t.compare(pathes, [[], ['map'], ['map', 'array']]) compare(users) }
export const testGetAndSetOfMapPropertyWithConflict = tc => { const { testConnector, users, map0, map1 } = init(tc, { users: 3 }) map0.set('stuff', 'c0') map1.set('stuff', 'c1') testConnector.flushAllMessages() for (let user of users) { var u = user.getMap('map') t.compare(u.get('stuff'), 'c1') } compare(users) }
export const testGetAndSetAndDeleteOfMapProperty = tc => { const { testConnector, users, map0, map1 } = init(tc, { users: 3 }) map0.set('stuff', 'c0') map1.set('stuff', 'c1') map1.delete('stuff') testConnector.flushAllMessages() for (let user of users) { var u = user.getMap('map') t.assert(u.get('stuff') === undefined) } compare(users) }
export const testYmapEventHasCorrectValueWhenSettingAPrimitive = tc => { const { users, map0 } = init(tc, { users: 3 }) /** * @type {Object<string,any>} */ let event = {} map0.observe(e => { event = e }) map0.set('stuff', 2) t.compare(event.value, event.target.get(event.name)) compare(users) }
export const testYmapEventHasCorrectValueWhenSettingAPrimitiveFromOtherUser = tc => { const { users, map0, map1, testConnector } = init(tc, { users: 3 }) /** * @type {Object<string,any>} */ let event = {} map0.observe(e => { event = e }) map1.set('stuff', 2) testConnector.flushAllMessages() t.compare(event.value, event.target.get(event.name)) compare(users) }
export const testGetAndSetAndDeleteOfMapPropertyWithThreeConflicts = tc => { const { testConnector, users, map0, map1, map2, map3 } = init(tc, { users: 4 }) map0.set('stuff', 'c0') map1.set('stuff', 'c1') map1.set('stuff', 'c2') map2.set('stuff', 'c3') testConnector.flushAllMessages() map0.set('stuff', 'deleteme') map1.set('stuff', 'c1') map2.set('stuff', 'c2') map3.set('stuff', 'c3') map3.delete('stuff') testConnector.flushAllMessages() for (let user of users) { var u = user.getMap('map') t.assert(u.get('stuff') === undefined) } compare(users) }
export const testBasicMapTests = tc => { const { testConnector, users, map0, map1, map2 } = init(tc, { users: 3 }) users[2].disconnect() map0.set('number', 1) map0.set('string', 'hello Y') map0.set('object', { key: { key2: 'value' } }) map0.set('y-map', new Y.Map()) map0.set('boolean1', true) map0.set('boolean0', false) const map = map0.get('y-map') map.set('y-array', new Y.Array()) const array = map.get('y-array') array.insert(0, [0]) array.insert(0, [-1]) t.assert(map0.get('number') === 1, 'client 0 computed the change (number)') t.assert(map0.get('string') === 'hello Y', 'client 0 computed the change (string)') t.assert(map0.get('boolean0') === false, 'client 0 computed the change (boolean)') t.assert(map0.get('boolean1') === true, 'client 0 computed the change (boolean)') t.compare(map0.get('object'), { key: { key2: 'value' } }, 'client 0 computed the change (object)') t.assert(map0.get('y-map').get('y-array').get(0) === -1, 'client 0 computed the change (type)') users[2].connect() testConnector.flushAllMessages() t.assert(map1.get('number') === 1, 'client 1 received the update (number)') t.assert(map1.get('string') === 'hello Y', 'client 1 received the update (string)') t.assert(map1.get('boolean0') === false, 'client 1 computed the change (boolean)') t.assert(map1.get('boolean1') === true, 'client 1 computed the change (boolean)') t.compare(map1.get('object'), { key: { key2: 'value' } }, 'client 1 received the update (object)') t.assert(map1.get('y-map').get('y-array').get(0) === -1, 'client 1 received the update (type)') // compare disconnected user t.assert(map2.get('number') === 1, 'client 2 received the update (number) - was disconnected') t.assert(map2.get('string') === 'hello Y', 'client 2 received the update (string) - was disconnected') t.assert(map2.get('boolean0') === false, 'client 2 computed the change (boolean)') t.assert(map2.get('boolean1') === true, 'client 2 computed the change (boolean)') t.compare(map2.get('object'), { key: { key2: 'value' } }, 'client 2 received the update (object) - was disconnected') t.assert(map2.get('y-map').get('y-array').get(0) === -1, 'client 2 received the update (type) - was disconnected') compare(users) }
export const testBasicFormat = tc => { const { users, text0 } = init(tc, { users: 2 }) let delta text0.observe(event => { delta = event.delta }) text0.insert(0, 'abc', { bold: true }) t.assert(text0.toString() === 'abc', 'Basic insert with attributes works') t.compare(text0.toDelta(), [{ insert: 'abc', attributes: { bold: true } }]) t.compare(delta, [{ insert: 'abc', attributes: { bold: true } }]) text0.delete(0, 1) t.assert(text0.toString() === 'bc', 'Basic delete on formatted works (position 0)') t.compare(text0.toDelta(), [{ insert: 'bc', attributes: { bold: true } }]) t.compare(delta, [{ delete: 1 }]) text0.delete(1, 1) t.assert(text0.toString() === 'b', 'Basic delete works (position 1)') t.compare(text0.toDelta(), [{ insert: 'b', attributes: { bold: true } }]) t.compare(delta, [{ retain: 1 }, { delete: 1 }]) text0.insert(0, 'z', { bold: true }) t.assert(text0.toString() === 'zb') t.compare(text0.toDelta(), [{ insert: 'zb', attributes: { bold: true } }]) t.compare(delta, [{ insert: 'z', attributes: { bold: true } }]) // @ts-ignore t.assert(text0._start.right.right.right.content.str === 'b', 'Does not insert duplicate attribute marker') text0.insert(0, 'y') t.assert(text0.toString() === 'yzb') t.compare(text0.toDelta(), [{ insert: 'y' }, { insert: 'zb', attributes: { bold: true } }]) t.compare(delta, [{ insert: 'y' }]) text0.format(0, 2, { bold: null }) t.assert(text0.toString() === 'yzb') t.compare(text0.toDelta(), [{ insert: 'yz' }, { insert: 'b', attributes: { bold: true } }]) t.compare(delta, [{ retain: 1 }, { retain: 1, attributes: { bold: null } }]) compare(users) }
export const testRepeatGeneratingYmapTests100000 = tc => { t.skip(!t.production) applyRandomTests(tc, mapTransactions, 100000) }
const compareEvent = (is, should) => { for (var key in should) { t.compare(should[key], is[key]) } }