Implemented APIs

This file lists all the implemented APIs, their caveots, limitations, and example tests. Example tests are writen with vitest.

Not all APIs are implemented!

alarms

  • All alarms APIs are implemented as in production, except for onAlarm.
  • You have to manually call onAlarm.trigger() for your event listeners to be executed.

notifications

  • create, clear, and getAll are fully implemented
  • You have to manually trigger all the events (onClosed, onClicked, onButtonClicked, onShown)

Example Tests

ensureNotificationExists.test.ts
import { describe, it, beforeEach, vi, expect } from 'vitest';
import browser, { Notifications } from 'webextension-polyfill';
import { fakeBrowser } from '@webext-core/fake-browser';

async function ensureNotificationExists(
  id: string,
  notification: Notifications.CreateNotificationOptions,
): Promise<void> {
  const notifications = await browser.notifications.getAll();
  if (!notifications[id]) await browser.notifications.create(id, notification);
}

describe('ensureNotificationExists', () => {
  const id = 'some-id';
  const notification: Notifications.CreateNotificationOptions = {
    type: 'basic',
    title: 'Some Title',
    message: 'Some message...',
  };

  beforeEach(() => {
    fakeBrowser.reset();
  });

  it('should create a notification if it does not exist', async () => {
    const createSpy = vi.spyOn(browser.notifications, 'create');

    await ensureNotificationExists(id, notification);

    expect(createSpy).toBeCalledTimes(1);
    expect(createSpy).toBeCalledWith(id, notification);
  });

  it('should not create the notification if it already exists', async () => {
    await fakeBrowser.notifications.create(id, notification);
    const createSpy = vi.spyOn(browser.notifications, 'create');

    await ensureNotificationExists(id, notification);

    expect(createSpy).not.toBeCalled();
  });
});
setupNotificationShownReports.test.ts
import { describe, it, beforeEach, vi, expect } from 'vitest';
import browser from 'webextension-polyfill';
import { fakeBrowser } from '@webext-core/fake-browser';

async function setupNotificationShownReports(
  reportEvent: (notificationId: string) => void,
): Promise<void> {
  browser.notifications.onShown.addListener(id => reportEvent(id));
}

describe('setupNotificationShownReports', () => {
  beforeEach(() => {
    fakeBrowser.reset();
  });

  it('should properly report an analytics event when a notification is shown', async () => {
    const reportAnalyticsEvent = vi.fn();
    const id = 'notification-id';

    setupNotificationShownReports(reportAnalyticsEvent);
    await fakeBrowser.notifications.onShown.trigger(id);

    expect(reportAnalyticsEvent).toBeCalledTimes(1);
    expect(reportAnalyticsEvent).toBeCalledWith(id);
  });
});

runtime

  • All events have been implemented, but all of them other than onMessage must be triggered manually.
  • rutime.id is a hardcoded string. You can set this to whatever you want, but it is reset to the hardcoded value when calling reset().
  • Unlike in a real production, sendMessage will trigger onMessage listeners setup in the same JS context. This allows you to add a listener when setting up your test, then call sendMessage to trigger it.

storage

  • The local, sync, session, and managed storages are all stored separately in memory.
  • storage.onChanged, storage.{area}.onChanged events are all triggered when updating values.
  • Each storage area can be reset individually.

tabs and windows

  • Fully implemented.
  • All methods trigger corresponding tabs events AND windows events depending on what happened (ie: closing the last tab of a window would trigger both tabs.onRemoved and windows.onRemoved).

webNavigation

  • The two functions, getFrame and getAllFrames are not implemented. You will have to mock their return values yourself.
  • All the event listeners are implemented, but none are triggered automatically. They can be triggered manually by calling browser.webNavigation.{event}.trigger(...)