mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 12:08:00 +01:00
93 lines
3.1 KiB
TypeScript
93 lines
3.1 KiB
TypeScript
import { MockInstance } from 'vitest';
|
|
|
|
type MockStorageKeys = 'getItem' | 'setItem' | 'removeItem';
|
|
|
|
export function mockStorage<Keys extends MockStorageKeys>(
|
|
options: Pick<Storage, Keys>,
|
|
): { [k in `${Keys}Spy`]: MockInstance } {
|
|
const getItemSpy = 'getItem' in options ? vi.spyOn(Storage.prototype, 'getItem') : undefined;
|
|
const setItemSpy = 'setItem' in options ? vi.spyOn(Storage.prototype, 'setItem') : undefined;
|
|
const removeItemSpy = 'removeItem' in options ? vi.spyOn(Storage.prototype, 'removeItem') : undefined;
|
|
|
|
beforeAll(() => {
|
|
getItemSpy && getItemSpy.mockImplementation((options as Storage).getItem);
|
|
setItemSpy && setItemSpy.mockImplementation((options as Storage).setItem);
|
|
removeItemSpy && removeItemSpy.mockImplementation((options as Storage).removeItem);
|
|
});
|
|
|
|
afterEach(() => {
|
|
getItemSpy && getItemSpy.mockClear();
|
|
setItemSpy && setItemSpy.mockClear();
|
|
removeItemSpy && removeItemSpy.mockClear();
|
|
});
|
|
|
|
afterAll(() => {
|
|
getItemSpy && getItemSpy.mockRestore();
|
|
setItemSpy && setItemSpy.mockRestore();
|
|
removeItemSpy && removeItemSpy.mockRestore();
|
|
});
|
|
|
|
return { getItemSpy, setItemSpy, removeItemSpy } as ReturnType<typeof mockStorage>;
|
|
}
|
|
|
|
type MockStorageImplApi = { [k in `${MockStorageKeys}Spy`]: MockInstance } & {
|
|
/**
|
|
* Forces the mock storage back to its default (empty) state
|
|
* @param value
|
|
*/
|
|
clearStorage: VoidFunction;
|
|
/**
|
|
* Forces the mock storage to be in the specific state provided as the parameter
|
|
* @param value
|
|
*/
|
|
setStorageValue: (value: Record<string, string>) => void;
|
|
/**
|
|
* Forces the mock storage to throw an error for the duration of the provided function's execution,
|
|
* or in case a promise is returned by the function, until that promise is resolved.
|
|
*/
|
|
forceStorageError: <Args, Return>(func: (...args: Args[]) => Return | Promise<Return>) => void;
|
|
};
|
|
|
|
export function mockStorageImpl(): MockStorageImplApi {
|
|
let shouldThrow = false;
|
|
let tempStorage: Record<string, string> = {};
|
|
const mockStorageSpies = mockStorage({
|
|
setItem(key, value) {
|
|
if (shouldThrow) throw new Error('Mock error thrown by mockStorageImpl.setItem');
|
|
|
|
tempStorage[key] = String(value);
|
|
},
|
|
getItem(key: string): string | null {
|
|
if (shouldThrow) throw new Error('Mock error thrown by mockStorageImpl.getItem');
|
|
|
|
return key in tempStorage ? tempStorage[key] : null;
|
|
},
|
|
removeItem(key: string) {
|
|
if (shouldThrow) throw new Error('Mock error thrown by mockStorageImpl.removeItem');
|
|
|
|
delete tempStorage[key];
|
|
},
|
|
});
|
|
const forceStorageError: MockStorageImplApi['forceStorageError'] = func => {
|
|
shouldThrow = true;
|
|
const value = func();
|
|
if (!(value instanceof Promise)) {
|
|
shouldThrow = false;
|
|
return;
|
|
}
|
|
|
|
value.then(() => {
|
|
shouldThrow = false;
|
|
});
|
|
};
|
|
const setStorageValue: MockStorageImplApi['setStorageValue'] = value => {
|
|
tempStorage = value;
|
|
};
|
|
const clearStorage = () => setStorageValue({});
|
|
|
|
afterEach(() => {
|
|
clearStorage();
|
|
});
|
|
|
|
return { ...mockStorageSpies, clearStorage, forceStorageError, setStorageValue };
|
|
}
|