1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
/*!
* VisualEditor tests for ve.init.ConflictableStorage.
*
* @copyright See AUTHORS.txt
*/
/* eslint-disable camelcase */
QUnit.module( 've.init.ConflictableStorage', {
beforeEach: function () {
// Fake time in seconds
const mockNow = 1000000;
this.now = Date.now;
this.mockNow = mockNow;
Date.now = function () {
return mockNow * 1000;
};
},
afterEach: function () {
Date.now = this.now;
}
} );
QUnit.test( 'Basic methods', ( assert ) => {
const store = {},
storage = ve.init.platform.createSessionStorage( store );
// Basic methods still work
storage.set( 'foo', 'bar' );
assert.strictEqual( store.foo, 'bar', 'String stored' );
assert.strictEqual( storage.get( 'foo' ), 'bar', 'String fetched' );
storage.remove( 'foo' );
assert.false( 'foo' in store, 'String removed' );
storage.setObject( 'foo', { x: 1 } );
assert.strictEqual( store.foo, '{"x":1}', 'Object stored' );
assert.deepEqual( storage.getObject( 'foo' ), { x: 1 }, 'Object fetched' );
storage.remove( 'foo' );
assert.false( 'foo' in store, 'Object removed' );
} );
QUnit.test( 'Conflict handling', function ( assert ) {
const store = {},
conflictableKeys = {
foo: true,
bar: true,
baz: true
},
storageA = ve.init.platform.createSessionStorage( store, true ),
storageB = ve.init.platform.createSessionStorage( store, true );
function getData( s ) {
const copy = ve.copy( s );
// eslint-disable-next-line no-underscore-dangle
delete copy.__conflictId;
return copy;
}
storageA.addConflictableKeys( conflictableKeys );
storageB.addConflictableKeys( conflictableKeys );
storageA.set( 'foo', 'hello' );
assert.deepEqual( getData( store ), { foo: 'hello' }, 'String stored in A' );
storageB.set( 'bar', 'world' );
assert.deepEqual( getData( store ), { bar: 'world' }, 'String stored in B overwrites store in A' );
storageA.set( 'baz', 'world!' );
assert.deepEqual(
getData( store ),
{ foo: 'hello', baz: 'world!' },
'Storage A overwrites storage B, and keeps first key set'
);
storageB.set( 'unmanagedKey', 'data' );
// Trigger conflict check with get
storageA.get( '_' );
assert.deepEqual(
getData( store ),
{ foo: 'hello', baz: 'world!', unmanagedKey: 'data' },
'Storage A overwrites storage B, but keeps unmanagedKey'
);
storageA.remove( 'foo' );
storageA.remove( 'bar' );
storageA.remove( 'baz' );
storageB.get( '_' );
assert.deepEqual(
getData( store ),
{ bar: 'world', unmanagedKey: 'data' },
'"bar" in B not removed by A'
);
storageA.get( '_' );
assert.deepEqual(
getData( store ),
{ unmanagedKey: 'data' },
'keys in A removed when A is restored'
);
// Cleanup
storageB.remove( 'bar' );
storageB.set( 'bar', 'expires', 1000 );
assert.deepEqual(
getData( store ),
{
_EXPIRY_bar: String( this.mockNow + 1000 ),
bar: 'expires',
unmanagedKey: 'data'
},
'expiry key set'
);
storageA.get( '_' );
assert.deepEqual(
getData( store ),
{
unmanagedKey: 'data'
},
'expiry key cleared when A is restored'
);
storageB.get( '_' );
assert.deepEqual(
getData( store ),
{
_EXPIRY_bar: String( this.mockNow + 1000 ),
bar: 'expires',
unmanagedKey: 'data'
},
'expiry key restored when B is restored'
);
// Cleanup
storageB.remove( 'bar' );
storageB.set( 'existing', 'expires', 2000 );
storageB.addConflictableKeys( { existing: true } );
storageA.get( '_' );
storageB.get( '_' );
assert.deepEqual(
getData( store ),
{
_EXPIRY_existing: String( this.mockNow + 2000 ),
existing: 'expires',
unmanagedKey: 'data'
},
'expiry key restored with conflictableKey registered on existing data'
);
} );
|