From dad16114f620f64b93de9baf91e45b11418ed54f Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 27 Aug 2024 17:54:33 +0200 Subject: [PATCH] feat: Ensure storageEngine implements correct interface In order to prevent implementation errors, we want to check that storageEngine implements the correct methods This replies to https://github.com/cozy/cozy-client/pull/1483#discussion_r1626141973 --- packages/cozy-pouch-link/src/localStorage.js | 21 ++++++++ .../cozy-pouch-link/src/localStorage.spec.js | 48 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 packages/cozy-pouch-link/src/localStorage.spec.js diff --git a/packages/cozy-pouch-link/src/localStorage.js b/packages/cozy-pouch-link/src/localStorage.js index 3fa799be0..0e213604a 100644 --- a/packages/cozy-pouch-link/src/localStorage.js +++ b/packages/cozy-pouch-link/src/localStorage.js @@ -9,6 +9,7 @@ export const LOCALSTORAGE_ADAPTERNAME = 'cozy-client-pouch-link-adaptername' export class PouchLocalStorage { constructor(storageEngine) { + checkStorageEngine(storageEngine) this.storageEngine = storageEngine } @@ -220,3 +221,23 @@ export class PouchLocalStorage { await this.storageEngine.setItem(LOCALSTORAGE_ADAPTERNAME, adapter) } } + +/** + * Throw if the given storage engine does not implement the expected Interface + * + * @param {*} storageEngine - Object containing storage access methods + */ +const checkStorageEngine = storageEngine => { + const requiredMethods = ['setItem', 'getItem', 'removeItem'] + + const missingMethods = requiredMethods.filter( + requiredMethod => !storageEngine[requiredMethod] + ) + + if (missingMethods.length > 0) { + const missingMethodsString = missingMethods.join(', ') + throw new Error( + `Provided storageEngine is missing the following methods: ${missingMethodsString}` + ) + } +} diff --git a/packages/cozy-pouch-link/src/localStorage.spec.js b/packages/cozy-pouch-link/src/localStorage.spec.js new file mode 100644 index 000000000..7d7c4ee22 --- /dev/null +++ b/packages/cozy-pouch-link/src/localStorage.spec.js @@ -0,0 +1,48 @@ +import { PouchLocalStorage } from './localStorage' + +describe('LocalStorage', () => { + describe('Type assertion', () => { + it('should throw if setItem method is missing', () => { + expect(() => { + new PouchLocalStorage({ + getItem: jest.fn(), + removeItem: jest.fn() + }) + }).toThrow( + 'Provided storageEngine is missing the following methods: setItem' + ) + }) + + it('should throw if getItem method is missing', () => { + expect(() => { + new PouchLocalStorage({ + setItem: jest.fn(), + removeItem: jest.fn() + }) + }).toThrow( + 'Provided storageEngine is missing the following methods: getItem' + ) + }) + + it('should throw if removeItem method is missing', () => { + expect(() => { + new PouchLocalStorage({ + getItem: jest.fn(), + setItem: jest.fn() + }) + }).toThrow( + 'Provided storageEngine is missing the following methods: removeItem' + ) + }) + + it('should throw if multiple methods are missing', () => { + expect(() => { + new PouchLocalStorage({ + getItem: jest.fn() + }) + }).toThrow( + 'Provided storageEngine is missing the following methods: setItem, removeItem' + ) + }) + }) +})