diff --git a/src/add-elements.ts b/src/add-elements.ts index 6bba3d6..1e5db88 100644 --- a/src/add-elements.ts +++ b/src/add-elements.ts @@ -8,7 +8,7 @@ import { Storage } from './jest-chrome' * @template T Type of namespace member */ interface SchemaData< - T extends 'event' | 'function' | 'property' + T extends 'event' | 'function' | 'property', > { name: string type: T @@ -62,11 +62,30 @@ export const addEvent = ( return event } +/** As of Manifest v3, all the Chrome API functions that accepted a callback + * now return promises when the callback is not supplied. + */ +const makeAsyncMock = (callbackArgIndex: number) => + jest + .fn() + .mockImplementation( + (...args: any[]): Promise | void => { + if (!args[callbackArgIndex]) { + return Promise.resolve() + } + }, + ) + export const addFunction = ( - { name }: SchemaData<'function'>, + { name, parameters }: SchemaData<'function'>, target: any, ) => { - const fn = jest.fn() + const fn = + parameters?.length && + parameters[parameters.length - 1]?.name === 'callback' && + parameters[parameters.length - 1]?.type === 'function' + ? makeAsyncMock(parameters.length - 1) + : jest.fn() Object.assign(target, { [name]: fn }) return fn @@ -93,10 +112,10 @@ export const addProperty = ( export function addStorageArea(): Storage.StorageArea { return { - clear: jest.fn(), - get: jest.fn(), + clear: makeAsyncMock(0), + get: makeAsyncMock(1), getBytesInUse: jest.fn(), - remove: jest.fn(), - set: jest.fn(), + remove: makeAsyncMock(1), + set: makeAsyncMock(1), } } diff --git a/src/index.test.ts b/src/index.test.ts index 5138bfc..55ab78d 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -36,6 +36,16 @@ test('get: function', () => { expect(chrome.runtime.getManifest).toBeCalled() }) +test('async: undefined with callback', () => { + expect(chrome.runtime.openOptionsPage(() => 1)).toBeUndefined() +}) + +test('async: promise without callback', () => { + expect(chrome.runtime.openOptionsPage()).toBeInstanceOf( + Promise, + ) +}) + test('get: event', () => { expect(chrome.runtime.onMessage).toMatchObject< CallableEvent< @@ -77,6 +87,16 @@ test('ownKeys: storage', () => { }) }) +test('storage: undefined with callback', () => { + expect( + chrome.storage.local.get('key', () => 1), + ).toBeUndefined() +}) + +test('storage: promise without callback', () => { + expect(chrome.storage.local.get('key')).toBeInstanceOf(Promise) +}) + test('set: lastError correctly', () => { const lastErrorSpy = jest.fn(() => 'test') const lastError = { @@ -92,7 +112,7 @@ test('set: lastError correctly', () => { }) test('set: lastError incorrectly', () => { - const lastError = ('error' as unknown) as Runtime.LastError + const lastError = 'error' as unknown as Runtime.LastError const setter = () => (chrome.runtime.lastError = lastError)