diff --git a/src/app/modules/data/data.provider.spec.ts b/src/app/modules/data/data.provider.spec.ts index 1f884e13..b5e6d475 100644 --- a/src/app/modules/data/data.provider.spec.ts +++ b/src/app/modules/data/data.provider.spec.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/ban-ts-comment,@typescript-eslint/no-explicit-any */ /* - * Copyright (C) 2018, 2019 StApps + * Copyright (C) 2018-2021 StApps * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 3. @@ -74,11 +74,11 @@ describe('DataProvider', () => { type: SCThingType.Message, uid: sampleThing.uid, }; - const otherSampleThing: SCMessage = { - ...sampleThing, - uid: 'message-456', - name: 'bar', - }; + + const fakeStorage = new Map([ + ['foo', 'Bar'], + ['bar', {foo: 'BarFoo'} as any], + ]); beforeEach(async () => { TestBed.configureTestingModule({ @@ -92,6 +92,7 @@ describe('DataProvider', () => { it('should generate data key', async () => { dataProvider.storagePrefix = 'foo.data'; + expect(dataProvider.getDataKey('123')).toBe('foo.data.123'); }); @@ -104,6 +105,7 @@ describe('DataProvider', () => { }; }); const response = await dataProvider.search(sampleQuery); + expect(response).toEqual(sampleResponse); }); @@ -116,6 +118,7 @@ describe('DataProvider', () => { }, })); const response = await dataProvider.multiSearch({a: sampleQuery}); + expect(response).toEqual({a: sampleResponse}); }); @@ -160,8 +163,8 @@ describe('DataProvider', () => { }, }), ); - const response = await dataProvider.multiSearch(request); + expect(response).toEqual(responseShould); }); @@ -173,22 +176,28 @@ describe('DataProvider', () => { providedThing.origin.created = sampleSavable.origin.created; }, ); + expect(storageProvider.put).not.toHaveBeenCalled(); expect(providedThing!).not.toBeDefined(); + await dataProvider.put(sampleThing); + expect(providedThing!).toBeDefined(); expect(providedThing!).toEqual(sampleSavable); }); it('should correctly set and get single data item from the local database (storage)', async () => { - await dataProvider.put(sampleThing); - spyOn(storageProvider, 'get').and.callThrough(); + spyOn(storageProvider, 'get').and.returnValue( + (async () => sampleSavable)(), + ); + expect(storageProvider.get).not.toHaveBeenCalled(); + const providedThing = await dataProvider.get( sampleThing.uid, DataScope.Local, ); - providedThing.origin.created = sampleSavable.origin.created; + expect(storageProvider.get).toHaveBeenCalledWith( dataProvider.getDataKey(sampleThing.uid), ); @@ -196,19 +205,20 @@ describe('DataProvider', () => { }); it('should provide all data items from the local database (storage)', async () => { - await dataProvider.put(sampleThing); - await dataProvider.put(otherSampleThing); - const result = await dataProvider.getAll(); - expect([...result.keys()].sort()).toEqual([ - dataProvider.getDataKey(sampleThing.uid), - dataProvider.getDataKey(otherSampleThing.uid), + const fakeStorage = new Map([ + ['foo', 'Bar'], + ['bar', {foo: 'BarFoo'} as any], ]); - expect(result.get(dataProvider.getDataKey(sampleThing.uid))!.data).toEqual( - sampleThing, + spyOn(storageProvider, 'search').and.callFake(async () => { + return fakeStorage; + }); + + const result = await dataProvider.getAll(); + + expect([...result.keys()].sort()).toEqual([...fakeStorage.keys()].sort()); + expect([...result.values()].sort()).toEqual( + [...fakeStorage.values()].sort(), ); - expect( - result.get(dataProvider.getDataKey(otherSampleThing.uid))!.data, - ).toEqual(otherSampleThing); }); it('should provide single data from the backend', async () => { @@ -219,11 +229,14 @@ describe('DataProvider', () => { }, }; }); + expect(Client.prototype.getThing).not.toHaveBeenCalled(); + const providedThing = await dataProvider.get( sampleThing.uid, DataScope.Remote, ); + expect(Client.prototype.getThing).toHaveBeenCalledWith(sampleThing.uid); expect(providedThing).toBe(sampleThing); }); @@ -244,39 +257,39 @@ describe('DataProvider', () => { }; }); const result = await dataProvider.get(sampleThing.uid); + expect(result.get(DataScope.Local)).toEqual(sampleSavable); expect(result.get(DataScope.Remote)).toEqual(sampleThing); }); it('should properly delete a data item from the local database (storage)', async () => { - spyOn(storageProvider, 'delete').and.callThrough(); - await dataProvider.put(sampleThing); - expect(await storageProvider.length()).toBe(1); + spyOn(storageProvider, 'delete'); + await dataProvider.delete(sampleThing.uid); + expect(storageProvider.delete).toHaveBeenCalledWith( dataProvider.getDataKey(sampleThing.uid), ); - expect(await storageProvider.length()).toBe(0); }); it('should properly delete all the data items from the local database (storage)', async () => { - spyOn(storageProvider, 'delete').and.callThrough(); - await dataProvider.put(sampleThing); - await dataProvider.put(otherSampleThing); - await storageProvider.put('some-uid', {some: 'thing'}); - expect(await storageProvider.length()).not.toBe(0); + spyOn(storageProvider, 'delete'); + spyOn(storageProvider, 'search').and.callFake(async () => { + return fakeStorage; + }); await dataProvider.deleteAll(); - expect(storageProvider.delete).toHaveBeenCalledWith( - dataProvider.getDataKey(sampleThing.uid), - dataProvider.getDataKey(otherSampleThing.uid), - ); - const result = await storageProvider.getAll(); - expect([...result.keys()]).toEqual(['some-uid']); + + expect(storageProvider.delete).toHaveBeenCalledWith('foo', 'bar'); }); it('should properly check if a data item has already been saved', async () => { - expect(await dataProvider.isSaved(sampleThing.uid)).toBeFalsy(); - await dataProvider.put(sampleThing); + spyOn(storageProvider, 'has').and.callFake(async storageKey => { + return (async () => { + return dataProvider.getDataKey(sampleThing.uid) === storageKey; + })(); + }); + + expect(await dataProvider.isSaved('some-uuid')).toBeFalsy(); expect(await dataProvider.isSaved(sampleThing.uid)).toBeTruthy(); }); }); diff --git a/src/app/modules/storage/storage.provider.spec.ts b/src/app/modules/storage/storage.provider.spec.ts index d967135b..e8951780 100644 --- a/src/app/modules/storage/storage.provider.spec.ts +++ b/src/app/modules/storage/storage.provider.spec.ts @@ -31,50 +31,65 @@ describe('StorageProvider', () => { beforeEach(async () => { TestBed.configureTestingModule({ imports: [StorageModule], - providers: [ - StorageProvider, - // { provide: Storage, useClass: StorageMock } - ], + providers: [StorageProvider], }); storageProvider = TestBed.get(StorageProvider); storage = TestBed.get(Storage); - await storage.clear(); + spyOn(storage, 'forEach').and.callFake(function_ => { + let i = 0; + for (const key of sampleEntries.keys()) { + function_(sampleEntries.get(key), key, i); + i++; + } + return (async () => { + /* just return a promise */ + })(); + }); }); it('should call ready method of storage on init', () => { spyOn(storage, 'ready'); storageProvider.init(); + expect(storage.ready).toHaveBeenCalled(); }); it('should call set method of storage to put a value', () => { spyOn(storage, 'set'); storageProvider.put('some-uid', {some: 'thing'}); + expect(storage.set).toHaveBeenCalledWith('some-uid', {some: 'thing'}); }); it('should call get method of storage to get a value', () => { spyOn(storage, 'get'); - storageProvider.get('some-uid'); + storageProvider.get('some-uid'); + expect(storage.get).toHaveBeenCalledWith('some-uid'); }); it('should properly put and get a value', async () => { + const fakeStorageSystem = new Map(); + + spyOn(storage, 'set').and.callFake((id, value) => { + return (async () => fakeStorageSystem.set(id, value))(); + }); + spyOn(storage, 'get').and.callFake(id => { + return (async () => fakeStorageSystem.get(id))(); + }); + await storageProvider.init(); await storageProvider.put('some-uid', {some: 'thing'}); - // eslint-disable-next-line @typescript-eslint/ban-types - const result: Map = await storageProvider.get< - // eslint-disable-next-line @typescript-eslint/ban-types - Map - >('some-uid'); - await expect(result).toEqual({some: 'thing'}); + const result = await storageProvider.get('some-uid'); + + expect(result).toEqual({some: 'thing'}); }); it('should throw an error when value is null', async () => { // eslint-disable-next-line unicorn/error-message let error: Error = new Error(); // eslint-disable-next-line unicorn/no-null - spyOn(storage, 'get').and.returnValue(Promise.resolve(null)); + spyOn(storage, 'get').and.returnValue((async () => null)()); try { await storageProvider.get('something-else'); } catch (error_) { @@ -86,101 +101,103 @@ describe('StorageProvider', () => { it('should put multiple values into the storage', async () => { spyOn(storageProvider, 'put'); await storageProvider.putMultiple(sampleEntries); - expect((storageProvider.put as jasmine.Spy).calls.count()).toEqual(3); - expect(storageProvider.put).toHaveBeenCalledWith('foo', 'Bar'); - expect(storageProvider.put).toHaveBeenCalledWith('bar', {foo: 'BarFoo'}); + + expect(storageProvider.put).toHaveBeenCalledTimes(sampleEntries.size); + + for (const key of sampleEntries.keys()) { + expect(storageProvider.put).toHaveBeenCalledWith( + key, + sampleEntries.get(key), + ); + } }); it('should get multiple values from the storage', async () => { - spyOn(storageProvider, 'get').and.callThrough(); - await storageProvider.putMultiple(sampleEntries); + spyOn(storageProvider, 'get').and.callFake(id => { + return (async () => sampleEntries.get(id))(); + }); const entries = await storageProvider.getMultiple(['foo', 'bar']); - expect((storageProvider.get as jasmine.Spy).calls.count()).toEqual(2); + + expect(storageProvider.get).toHaveBeenCalledTimes(2); expect(storageProvider.get).toHaveBeenCalledWith('foo'); expect(storageProvider.get).toHaveBeenCalledWith('bar'); + expect([...entries.values()]).toEqual(['Bar', {foo: 'BarFoo'}]); expect([...entries.keys()]).toEqual(['foo', 'bar']); }); it('should get all values from the storage', async () => { - spyOn(storageProvider, 'get').and.callThrough(); - await storageProvider.putMultiple(sampleEntries); - const entries = await storageProvider.getAll(); - expect( - [...entries.values()].map(item => (item.foo ? item.foo : item)).sort(), - ).toEqual( - [...sampleEntries.values()] - .map(item => (item.foo ? item.foo : item)) - .sort(), - ); - expect([...entries.keys()].sort()).toEqual(['bar', 'foo', 'foo.bar']); + const allValuesMap = await storageProvider.getAll(); + + for (const key of sampleEntries.keys()) { + expect(allValuesMap.get(key)).toEqual(sampleEntries.get(key)); + } }); it('should delete one or more entries from the storage', async () => { - spyOn(storage, 'remove').and.callThrough(); - await storageProvider.putMultiple(sampleEntries); - let entries = await storageProvider.getAll(); - expect([...entries.values()].length).toBe(3); - await storageProvider.delete('bar'); + const storageRemoveSpy = spyOn(storage, 'remove'); - expect(storage.remove).toHaveBeenCalled(); - entries = await storageProvider.getAll(); - expect([...entries.values()]).toEqual(['Bar', 123]); + await storageProvider.delete('bar'); + expect(storage.remove).toHaveBeenCalledTimes(1); + + storageRemoveSpy.calls.reset(); await storageProvider.delete('foo', 'foo.bar'); - expect(await storageProvider.length()).toBe(0); + expect(storage.remove).toHaveBeenCalledTimes(2); }); it('should delete all entries in the storage', async () => { - spyOn(storage, 'clear').and.callThrough(); - await storageProvider.putMultiple(sampleEntries); - let entries = await storageProvider.getAll(); - expect([...entries.values()].length).not.toBe(0); + spyOn(storage, 'clear'); + await storageProvider.deleteAll(); - - entries = await storageProvider.getAll(); expect(storage.clear).toHaveBeenCalled(); - expect([...entries.values()].length).toBe(0); - }); - - it('should provide number of entries', async () => { - spyOn(storage, 'length').and.callThrough(); - - expect(await storageProvider.length()).toBe(0); - expect(storage.length).toHaveBeenCalled(); - - await storageProvider.putMultiple(sampleEntries); - expect(await storageProvider.length()).toBe(3); }); it('should provide information if storage is empty', async () => { - spyOn(storage, 'length').and.callThrough(); + let n: number; + spyOn(storage, 'length').and.callFake(async () => n); - expect(await storageProvider.isEmpty()).toBeTruthy(); - expect(storage.length).toHaveBeenCalled(); + n = 0; - await storageProvider.putMultiple(sampleEntries); + const testEmpty = await storageProvider.isEmpty(); + + expect(testEmpty).toBeTruthy(); + + n = 1; expect(await storageProvider.isEmpty()).toBeFalsy(); + + expect(storage.length).toHaveBeenCalledTimes(2); + }); + + it('should provide number of entries', async () => { + const n = 5; + spyOn(storage, 'length').and.callFake(async () => n); + + expect(await storageProvider.length()).toBe(n); }); it('should provide information if storage contains a specific entry (key)', async () => { spyOn(storage, 'keys').and.returnValue( - Promise.resolve([...sampleEntries.keys()]), + (async () => [...sampleEntries.keys()])(), ); + expect(await storageProvider.has('foo')).toBeTruthy(); expect(await storageProvider.has('something-else')).toBeFalsy(); }); it('should allow search by regex', async () => { - await storageProvider.putMultiple(sampleEntries); const found: Map = await storageProvider.search(/bar/); + expect([...found.keys()].sort()).toEqual(['bar', 'foo.bar']); expect([...found.values()]).toEqual([{foo: 'BarFoo'}, 123]); }); it('should allow search by string', async () => { - await storageProvider.putMultiple(sampleEntries); + spyOn(storage, 'get').and.callFake(id => { + return (async () => sampleEntries.get(id))(); + }); const found: Map = await storageProvider.search('foo.ba'); + expect([...found.keys()]).toEqual(['foo.bar']); expect([...found.values()]).toEqual([123]); });