@livetl/svelte-webext-stores
Version:
Svelte stores that synchronizes to WebExtension storage.
161 lines (139 loc) • 4.97 kB
text/typescript
import { storageLegacy } from '../storage';
import { webExtStores } from '../web-ext-stores';
import { Unsubscriber } from 'svelte/store';
const backend = storageLegacy('session');
const stores = webExtStores(backend);
const SyncStore = stores.addSyncStore;
const LookupStore = stores.addLookupStore;
afterEach(async () => await stores._clear());
describe('SyncStore', () => {
const key = 'hey';
const value1 = 'listen';
const value2 = 'watch out';
const value3 = 'take this';
test('Default value', async () => {
const store = SyncStore(key, value1);
expect(await store.get()).toBe(value1);
});
test('Get and set', async () => {
const store = SyncStore(key, value1);
await store.set(value2);
expect(await store.get()).toBe(value2);
});
test('Saves to storage', async () => {
const store = SyncStore(key, value1);
await store.ready();
expect(await backend.get(key)).toBe(value1);
await store.set(value2);
expect(await backend.get(key)).toBe(value2);
});
test('Loads from storage', async () => {
await backend.set(key, value2);
const store = SyncStore(key, value1);
expect(await store.get()).toBe(value2);
});
test('Syncs with storage changes', async () => {
const store = SyncStore(key, value1);
await backend.set(key, value2);
expect(await store.get()).toBe(value2);
});
test('Reset', async () => {
const store = SyncStore(key, value1);
await store.set(value3);
expect(await store.get()).toBe(value3);
expect(await backend.get(key)).toBe(value3);
await store.reset();
expect(await store.get()).toBe(value1);
expect(await backend.get(key)).toBe(value1);
});
test('Subscribe', (done) => {
let unSub: Unsubscriber | null = null;
function callback(v: string): void {
if (v === value1) return;
let er: unknown;
try {
expect(v).toBe(value2);
} catch (e) {
er = e;
} finally {
if (unSub !== null && typeof unSub === 'function') unSub();
if (er != null) done(er);
else done();
}
}
const store = SyncStore(key, value1);
unSub = store.subscribe(callback);
store.set(value2).catch((e) => console.error(e));
});
test('Update', async () => {
const store = SyncStore(key, value1);
const updater = (value: string): string => value + '!';
await store.update(updater);
expect(await store.get()).toBe(value1 + '!');
});
});
describe('SyncStore versioned', () => {
const key = 'arch';
const value1 = 64;
const value2 = 86;
const value3 = 'x64';
const value4 = 'x86';
const migration = (v: number): string => `x${v.toString()}`;
test('Normal SyncStore functionality', async () => {
const store = SyncStore(key, value1);
expect(await store.get()).toBe(value1);
expect(await backend.get(store.key)).toBe(value1);
await store.set(value2);
expect(await store.get()).toBe(value2);
expect(await backend.get(store.key)).toBe(value2);
});
test('Migrate to new version', async () => {
const store1 = SyncStore(
key, value1, true, { version: 0, seperator: '$$' }
);
await store1.set(value2);
const migrations = (new Map()).set(0, migration);
const store2 = SyncStore(
key, value3, true, { version: 1, seperator: '$$', migrations }
);
expect(await store2.get()).toBe(value4);
expect(await backend.get(store2.key)).toBe(value4);
expect(await backend.get(store1.key)).toBeUndefined();
});
test('Migrate from no version', async () => {
const store1 = SyncStore(key, value1);
await store1.set(value2);
const migrations = (new Map()).set(-1, migration);
const store2 = SyncStore(
key, value3, true, { version: 1, seperator: '$$', migrations }
);
expect(await store2.get()).toBe(value4);
expect(await backend.get(store2.key)).toBe(value4);
expect(await backend.get(store1.key)).toBeUndefined();
});
});
describe('LookupStore', () => {
const key = 'score';
const value1 = { a: 1, b: false, c: '3' };
const value2 = { a: 3, b: true, c: '5' };
test('Normal SyncStore functionality', async () => {
const LS = LookupStore(key, value1);
expect(await LS.get()).toStrictEqual(value1);
expect(await backend.get(LS.key)).toStrictEqual(value1);
await LS.set(value2);
expect(await LS.get()).toStrictEqual(value2);
expect(await backend.get(LS.key)).toStrictEqual(value2);
});
test('getItem()', async () => {
const LS = LookupStore(key, value1);
expect(await LS.getItem<number>('a')).toBe(1);
expect(await LS.getItem<boolean>('b')).toBe(false);
expect(await LS.getItem<string>('c')).toBe('3');
});
test('setItem()', async () => {
const LS = LookupStore(key, value1);
await LS.setItem<boolean>('b', true);
expect(await LS.getItem<boolean>('b')).toBe(true);
expect(await backend.get(LS.key)).toStrictEqual({ a: 1, b: true, c: '3' });
});
});