From 4f1f2c717166fa4b3f8611cf1c60e38f1e0b40d6 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 15:01:51 -0700 Subject: [PATCH 01/22] fix: clean up comment in util.test.ts --- test/util.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/util.test.ts b/test/util.test.ts index 0de2d7ea..035272b6 100644 --- a/test/util.test.ts +++ b/test/util.test.ts @@ -22,7 +22,6 @@ import { checkForCookie, createCookieIfDoesntExist } from "./helpers" const dom = new JSDOM() global.document = dom.window.document -// global.window = (dom.window as unknown) as Window & typeof globalThis type LocationLike = Pick From 28b440a4babac4a0864c7ef32c2a894494d2fd28 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 15:02:13 -0700 Subject: [PATCH 02/22] feat: add cssStub to jest --- package.json | 5 ++++- test/cssStub.ts | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 test/cssStub.ts diff --git a/package.json b/package.json index 7f427a78..af412f5c 100644 --- a/package.json +++ b/package.json @@ -153,6 +153,9 @@ "/release-npm-package", "/release-gcp", "/release-images" - ] + ], + "moduleNameMapper": { + "^.+\\.(css|less)$": "/test/cssStub.ts" + } } } diff --git a/test/cssStub.ts b/test/cssStub.ts new file mode 100644 index 00000000..06aeb475 --- /dev/null +++ b/test/cssStub.ts @@ -0,0 +1,5 @@ +// Note: this is needed for the register.test.ts +// This is because inside src/browser/register.ts +// we import CSS files, which Jest can't handle unless we tell it how to +// See: https://stackoverflow.com/a/39434579/3015595 +module.exports = {} From 72b05cacacf433182272960d7892b2834631c35e Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 15:02:33 -0700 Subject: [PATCH 03/22] refactor: create registerServiceWorker fn --- src/browser/register.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/browser/register.ts b/src/browser/register.ts index 4f834580..c975df87 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -1,18 +1,23 @@ -import { getOptions, normalize } from "../common/util" - -const options = getOptions() +import { getOptions, Options, normalize } from "../common/util" import "./pages/error.css" import "./pages/global.css" import "./pages/login.css" -if ("serviceWorker" in navigator) { - const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) - navigator.serviceWorker - .register(path, { +export async function registerServiceWorker(navigator: Navigator, path: string, options: Options): Promise { + try { + await navigator.serviceWorker.register(path, { scope: (options.base ?? "") + "/", }) - .then(() => { - console.log("[Service Worker] registered") - }) + console.log("[Service Worker] registered") + } catch (error) { + console.error(`[Service Worker] failed to register: ${error.message}`) + } +} + +if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { + const options = getOptions() + const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) + registerServiceWorker(navigator, path, options) + } } From 06aeca0a83b67a96f4f6c6b44c9c23c84d1876e3 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 15:02:49 -0700 Subject: [PATCH 04/22] feat(testing): add register test --- test/register.test.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 test/register.test.ts diff --git a/test/register.test.ts b/test/register.test.ts new file mode 100644 index 00000000..54c8d9e4 --- /dev/null +++ b/test/register.test.ts @@ -0,0 +1,43 @@ +import { JSDOM } from "jsdom" +import { registerServiceWorker } from "../src/browser/register" +const { window } = new JSDOM() +global.window = (window as unknown) as Window & typeof globalThis +global.document = window.document +global.navigator = window.navigator + +describe("register", () => { + const spy = jest.fn() + beforeAll(() => { + // register relies on navigator to be defined globally + // this is because the code is called on the browser + // so we're sure it will be defined + // We have to cast/assert so that TS thinks it's the correct type + Object.defineProperty(global.navigator, "serviceWorker", { + value: { + register: spy, + }, + }) + // global.navigator.serviceWorker.register = (spy as unknown) as ServiceWorkerContainer["register"] + }) + + afterEach(() => { + jest.resetAllMocks() + }) + + afterAll(() => { + jest.restoreAllMocks() + }) + it("should register a ServiceWorker", () => { + // call registerServiceWorker + const path = "/hello" + const mockOptions = { + base: "", + csStaticBase: "", + logLevel: 0, + } + registerServiceWorker(navigator, path, mockOptions) + // expect spy to have been called + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + }) +}) From a9f88affa98642ab611340b0517d7ee1c18d264a Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 15:05:18 -0700 Subject: [PATCH 05/22] refactor: use logger in serviceworker --- src/browser/register.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/register.ts b/src/browser/register.ts index c975df87..607c8e92 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -1,3 +1,4 @@ +import { logger } from "@coder/logger" import { getOptions, Options, normalize } from "../common/util" import "./pages/error.css" @@ -11,7 +12,7 @@ export async function registerServiceWorker(navigator: Navigator, path: string, }) console.log("[Service Worker] registered") } catch (error) { - console.error(`[Service Worker] failed to register: ${error.message}`) + logger.error(`[Service Worker] failed to register: ${error.message}`) } } From 44b9874fbe19caa9ef8e546dd6624c67794b1d8e Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 15:23:07 -0700 Subject: [PATCH 06/22] feat: test failure to register service worker --- src/browser/register.ts | 7 ++-- test/register.test.ts | 88 +++++++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/browser/register.ts b/src/browser/register.ts index 607c8e92..c773f776 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -17,8 +17,7 @@ export async function registerServiceWorker(navigator: Navigator, path: string, } if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { - const options = getOptions() - const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) - registerServiceWorker(navigator, path, options) - } + const options = getOptions() + const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) + registerServiceWorker(navigator, path, options) } diff --git a/test/register.test.ts b/test/register.test.ts index 54c8d9e4..8f84b7eb 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -1,4 +1,7 @@ import { JSDOM } from "jsdom" +// Note: we need to import logger from the root +// because this is the logger used in logError in ../src/common/util +import { logger } from "../node_modules/@coder/logger" import { registerServiceWorker } from "../src/browser/register" const { window } = new JSDOM() global.window = (window as unknown) as Window & typeof globalThis @@ -6,38 +9,63 @@ global.document = window.document global.navigator = window.navigator describe("register", () => { - const spy = jest.fn() - beforeAll(() => { - // register relies on navigator to be defined globally - // this is because the code is called on the browser - // so we're sure it will be defined - // We have to cast/assert so that TS thinks it's the correct type - Object.defineProperty(global.navigator, "serviceWorker", { - value: { - register: spy, - }, + describe("registerServiceWorker", () => { + const spy = jest.fn() + let loggerSpy: jest.SpyInstance + + beforeAll(() => { + Object.defineProperty(global.navigator, "serviceWorker", { + value: { + register: () => { + return "hello" + }, + }, + }) }) - // global.navigator.serviceWorker.register = (spy as unknown) as ServiceWorkerContainer["register"] - }) - afterEach(() => { - jest.resetAllMocks() - }) + beforeEach(() => { + loggerSpy = jest.spyOn(logger, "error") + }) - afterAll(() => { - jest.restoreAllMocks() - }) - it("should register a ServiceWorker", () => { - // call registerServiceWorker - const path = "/hello" - const mockOptions = { - base: "", - csStaticBase: "", - logLevel: 0, - } - registerServiceWorker(navigator, path, mockOptions) - // expect spy to have been called - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledTimes(1) + afterEach(() => { + jest.resetAllMocks() + }) + + afterAll(() => { + jest.restoreAllMocks() + }) + + it("should register a ServiceWorker", () => { + global.navigator.serviceWorker.register = spy + // call registerServiceWorker + const path = "/hello" + const mockOptions = { + base: "", + csStaticBase: "", + logLevel: 0, + } + registerServiceWorker(navigator, path, mockOptions) + // expect spy to have been called + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + }) + + it("should log an error if something goes work", () => { + const message = "Can't find browser" + const path = "/hello" + const mockOptions = { + base: "", + csStaticBase: "", + logLevel: 0, + } + global.navigator.serviceWorker.register = () => { + throw new Error(message) + } + + registerServiceWorker(navigator, path, mockOptions) + expect(loggerSpy).toHaveBeenCalled() + expect(loggerSpy).toHaveBeenCalledTimes(1) + expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] failed to register: ${message}`) + }) }) }) From 21f577d471e3e90785b45ae5b02521214493e48e Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 16:51:35 -0700 Subject: [PATCH 07/22] refactor: add handleRegisterServiceWorker fn --- src/browser/register.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/browser/register.ts b/src/browser/register.ts index c773f776..76558037 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -16,8 +16,23 @@ export async function registerServiceWorker(navigator: Navigator, path: string, } } -if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { - const options = getOptions() - const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) - registerServiceWorker(navigator, path, options) +interface HandleServiceWorkerRegistration { + getOptions: () => Options + normalize: (url: string, keepTrailing?: boolean) => string + registerServiceWorker: (navigator: Navigator, path: string, options: Options) => Promise } + +export function handleServiceWorkerRegistration({ + getOptions, + normalize, + registerServiceWorker, +}: HandleServiceWorkerRegistration): void { + if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { + const options = getOptions() + const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) + registerServiceWorker(navigator, path, options) + } +} + +// Written this way so that it's easier to test +handleServiceWorkerRegistration({ getOptions, normalize, registerServiceWorker }) From 38891de0d9e9b4962a9beb949faa9369e55d395c Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 11 Feb 2021 16:51:48 -0700 Subject: [PATCH 08/22] feat(test): add test handleRegisterServiceWorker --- test/register.test.ts | 71 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/test/register.test.ts b/test/register.test.ts index 8f84b7eb..421e1d4f 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -2,7 +2,8 @@ import { JSDOM } from "jsdom" // Note: we need to import logger from the root // because this is the logger used in logError in ../src/common/util import { logger } from "../node_modules/@coder/logger" -import { registerServiceWorker } from "../src/browser/register" +import { registerServiceWorker, handleServiceWorkerRegistration } from "../src/browser/register" +import { Options } from "../src/common/util" const { window } = new JSDOM() global.window = (window as unknown) as Window & typeof globalThis global.document = window.document @@ -10,7 +11,10 @@ global.navigator = window.navigator describe("register", () => { describe("registerServiceWorker", () => { - const spy = jest.fn() + let spy: jest.MockedFunction<( + scriptURL: string, + options?: RegistrationOptions | undefined, + ) => Promise> let loggerSpy: jest.SpyInstance beforeAll(() => { @@ -25,6 +29,8 @@ describe("register", () => { beforeEach(() => { loggerSpy = jest.spyOn(logger, "error") + spy = jest.fn() + global.navigator.serviceWorker.register = spy }) afterEach(() => { @@ -37,7 +43,6 @@ describe("register", () => { it("should register a ServiceWorker", () => { global.navigator.serviceWorker.register = spy - // call registerServiceWorker const path = "/hello" const mockOptions = { base: "", @@ -50,7 +55,7 @@ describe("register", () => { expect(spy).toHaveBeenCalledTimes(1) }) - it("should log an error if something goes work", () => { + it("should log an error if something doesn't work", () => { const message = "Can't find browser" const path = "/hello" const mockOptions = { @@ -67,5 +72,63 @@ describe("register", () => { expect(loggerSpy).toHaveBeenCalledTimes(1) expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] failed to register: ${message}`) }) + + it("should work when base is undefined", () => { + const path = "/hello" + + // We want to test some code that checks if options.base is undefined + // so we leave it off mockOptions + // but assert it as Options so TS is happy + const mockOptions = { + csStaticBase: "", + logLevel: 0, + } as Options + registerServiceWorker(navigator, path, mockOptions) + // expect spy to have been called + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + }) + }) + + describe("handleServiceWorkerRegistration", () => { + let getOptionsMock: jest.MockedFunction<() => { + base: string + csStaticBase: string + logLevel: number + }> + let normalizeMock: jest.MockedFunction<(v: string) => string> + let registerServiceWorkerMock: jest.MockedFunction<( + navigator: Navigator, + path: string, + mockOptions: Options, + ) => Promise> + + beforeEach(() => { + getOptionsMock = jest.fn(() => ({ + base: "", + csStaticBase: "", + logLevel: 0, + })) + + normalizeMock = jest.fn((url: string) => "qux///") + + registerServiceWorkerMock = jest + .fn() + .mockImplementation((navigator: Navigator, path: string, mockOptions: Options) => Promise.resolve()) + }) + it("should work when called", () => { + handleServiceWorkerRegistration({ + getOptions: getOptionsMock, + normalize: normalizeMock, + registerServiceWorker: registerServiceWorkerMock, + }) + + const mocks = [getOptionsMock, normalizeMock, registerServiceWorkerMock] + + mocks.forEach((mock) => { + expect(mock).toHaveBeenCalled() + expect(mock).toHaveBeenCalledTimes(1) + }) + }) }) }) From 7ef630f7a48d16bc9f2bef0f83bc2587d310926f Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Mon, 22 Feb 2021 14:23:16 -0700 Subject: [PATCH 09/22] refactor(register): use logError instead of logger --- src/browser/register.ts | 5 ++--- test/register.test.ts | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/browser/register.ts b/src/browser/register.ts index 76558037..e430d9bf 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -1,5 +1,4 @@ -import { logger } from "@coder/logger" -import { getOptions, Options, normalize } from "../common/util" +import { getOptions, Options, normalize, logError } from "../common/util" import "./pages/error.css" import "./pages/global.css" @@ -12,7 +11,7 @@ export async function registerServiceWorker(navigator: Navigator, path: string, }) console.log("[Service Worker] registered") } catch (error) { - logger.error(`[Service Worker] failed to register: ${error.message}`) + logError(`[Service Worker] registration`, error) } } diff --git a/test/register.test.ts b/test/register.test.ts index 421e1d4f..799349a0 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -57,6 +57,7 @@ describe("register", () => { it("should log an error if something doesn't work", () => { const message = "Can't find browser" + const error = new Error(message) const path = "/hello" const mockOptions = { base: "", @@ -64,13 +65,14 @@ describe("register", () => { logLevel: 0, } global.navigator.serviceWorker.register = () => { - throw new Error(message) + throw error } registerServiceWorker(navigator, path, mockOptions) expect(loggerSpy).toHaveBeenCalled() expect(loggerSpy).toHaveBeenCalledTimes(1) - expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] failed to register: ${message}`) + // Because we use logError, it will log the prefix along with the error message + expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] registration: ${error.message} ${error.stack}`) }) it("should work when base is undefined", () => { From a44a51462cad9919d59393549dca60199d29f972 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Mon, 22 Feb 2021 15:50:26 -0700 Subject: [PATCH 10/22] refactor: use same syntax as logger spy --- src/browser/register.ts | 29 ++----- src/common/util.ts | 3 + test/register.test.ts | 164 ++++++++++++---------------------------- 3 files changed, 58 insertions(+), 138 deletions(-) diff --git a/src/browser/register.ts b/src/browser/register.ts index e430d9bf..1079d159 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -1,10 +1,12 @@ -import { getOptions, Options, normalize, logError } from "../common/util" +import { getOptions, normalize, logError } from "../common/util" import "./pages/error.css" import "./pages/global.css" import "./pages/login.css" -export async function registerServiceWorker(navigator: Navigator, path: string, options: Options): Promise { +async function registerServiceWorker(): Promise { + const options = getOptions() + const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) try { await navigator.serviceWorker.register(path, { scope: (options.base ?? "") + "/", @@ -15,23 +17,8 @@ export async function registerServiceWorker(navigator: Navigator, path: string, } } -interface HandleServiceWorkerRegistration { - getOptions: () => Options - normalize: (url: string, keepTrailing?: boolean) => string - registerServiceWorker: (navigator: Navigator, path: string, options: Options) => Promise +if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { + registerServiceWorker() +} else { + console.error(`[Service Worker] navigator is undefined`) } - -export function handleServiceWorkerRegistration({ - getOptions, - normalize, - registerServiceWorker, -}: HandleServiceWorkerRegistration): void { - if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { - const options = getOptions() - const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) - registerServiceWorker(navigator, path, options) - } -} - -// Written this way so that it's easier to test -handleServiceWorkerRegistration({ getOptions, normalize, registerServiceWorker }) diff --git a/src/common/util.ts b/src/common/util.ts index 87ca6f59..82d7cee3 100644 --- a/src/common/util.ts +++ b/src/common/util.ts @@ -114,9 +114,12 @@ export const getFirstString = (value: string | string[] | object | undefined): s } export function logError(prefix: string, err: any): void { + console.log("hey joe log error was called") if (err instanceof Error) { + console.log("it was an instance of error") logger.error(`${prefix}: ${err.message} ${err.stack}`) } else { + console.log("not an isntance errro") logger.error(`${prefix}: ${err}`) } } diff --git a/test/register.test.ts b/test/register.test.ts index 799349a0..e534fa5e 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -2,135 +2,65 @@ import { JSDOM } from "jsdom" // Note: we need to import logger from the root // because this is the logger used in logError in ../src/common/util import { logger } from "../node_modules/@coder/logger" -import { registerServiceWorker, handleServiceWorkerRegistration } from "../src/browser/register" -import { Options } from "../src/common/util" -const { window } = new JSDOM() -global.window = (window as unknown) as Window & typeof globalThis -global.document = window.document -global.navigator = window.navigator describe("register", () => { - describe("registerServiceWorker", () => { - let spy: jest.MockedFunction<( - scriptURL: string, - options?: RegistrationOptions | undefined, - ) => Promise> - let loggerSpy: jest.SpyInstance + const { window } = new JSDOM() + global.window = (window as unknown) as Window & typeof globalThis + global.document = window.document + global.navigator = window.navigator + global.location = window.location - beforeAll(() => { - Object.defineProperty(global.navigator, "serviceWorker", { - value: { - register: () => { - return "hello" - }, - }, - }) - }) + let spy: jest.SpyInstance + let loggerSpy: jest.SpyInstance + const mockRegisterFn = jest.fn(() => console.log("Mock register fn called")) - beforeEach(() => { - loggerSpy = jest.spyOn(logger, "error") - spy = jest.fn() - global.navigator.serviceWorker.register = spy - }) - - afterEach(() => { - jest.resetAllMocks() - }) - - afterAll(() => { - jest.restoreAllMocks() - }) - - it("should register a ServiceWorker", () => { - global.navigator.serviceWorker.register = spy - const path = "/hello" - const mockOptions = { - base: "", - csStaticBase: "", - logLevel: 0, - } - registerServiceWorker(navigator, path, mockOptions) - // expect spy to have been called - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledTimes(1) - }) - - it("should log an error if something doesn't work", () => { - const message = "Can't find browser" - const error = new Error(message) - const path = "/hello" - const mockOptions = { - base: "", - csStaticBase: "", - logLevel: 0, - } - global.navigator.serviceWorker.register = () => { - throw error - } - - registerServiceWorker(navigator, path, mockOptions) - expect(loggerSpy).toHaveBeenCalled() - expect(loggerSpy).toHaveBeenCalledTimes(1) - // Because we use logError, it will log the prefix along with the error message - expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] registration: ${error.message} ${error.stack}`) - }) - - it("should work when base is undefined", () => { - const path = "/hello" - - // We want to test some code that checks if options.base is undefined - // so we leave it off mockOptions - // but assert it as Options so TS is happy - const mockOptions = { - csStaticBase: "", - logLevel: 0, - } as Options - registerServiceWorker(navigator, path, mockOptions) - // expect spy to have been called - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledTimes(1) + beforeAll(() => { + Object.defineProperty(global.navigator, "serviceWorker", { + value: { + register: mockRegisterFn, + }, }) }) - describe("handleServiceWorkerRegistration", () => { - let getOptionsMock: jest.MockedFunction<() => { - base: string - csStaticBase: string - logLevel: number - }> - let normalizeMock: jest.MockedFunction<(v: string) => string> - let registerServiceWorkerMock: jest.MockedFunction<( - navigator: Navigator, - path: string, - mockOptions: Options, - ) => Promise> + beforeEach(() => { + spy = jest.spyOn(global.navigator.serviceWorker, "register") + }) - beforeEach(() => { - getOptionsMock = jest.fn(() => ({ - base: "", - csStaticBase: "", - logLevel: 0, - })) + afterEach(() => { + jest.resetModules() + }) - normalizeMock = jest.fn((url: string) => "qux///") + afterAll(() => { + jest.restoreAllMocks() + }) - registerServiceWorkerMock = jest - .fn() - .mockImplementation((navigator: Navigator, path: string, mockOptions: Options) => Promise.resolve()) + it("should register a ServiceWorker", () => { + spy = jest.spyOn(global.navigator.serviceWorker, "register") + // Load service worker like you would in the browser + require("../src/browser/register") + // Load service worker like you would in the browser + // expect spy to have been called + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + spy.mockClear() + }) + + it("should log an error if something doesn't work", () => { + loggerSpy = jest.spyOn(logger, "error") + const message = "Can't find browser" + const error = new Error(message) + + mockRegisterFn.mockImplementation(() => { + throw error }) - it("should work when called", () => { - handleServiceWorkerRegistration({ - getOptions: getOptionsMock, - normalize: normalizeMock, - registerServiceWorker: registerServiceWorkerMock, - }) - const mocks = [getOptionsMock, normalizeMock, registerServiceWorkerMock] + // Load service worker like you would in the browser + require("../src/browser/register") - mocks.forEach((mock) => { - expect(mock).toHaveBeenCalled() - expect(mock).toHaveBeenCalledTimes(1) - }) - }) + expect(spy).toHaveBeenCalled() + expect(loggerSpy).toHaveBeenCalled() + // expect(loggerSpy).toHaveBeenCalledTimes(1) + // Because we use logError, it will log the prefix along with the error message + // expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] registration: ${error.message} ${error.stack}`) }) }) From 027e8e5adfa973b1986df50b8aaef07b0b45b99d Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 12:30:48 -0700 Subject: [PATCH 11/22] refactor: use LogModule from Asher in tests --- src/common/util.ts | 3 --- test/register.test.ts | 37 +++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/common/util.ts b/src/common/util.ts index 82d7cee3..87ca6f59 100644 --- a/src/common/util.ts +++ b/src/common/util.ts @@ -114,12 +114,9 @@ export const getFirstString = (value: string | string[] | object | undefined): s } export function logError(prefix: string, err: any): void { - console.log("hey joe log error was called") if (err instanceof Error) { - console.log("it was an instance of error") logger.error(`${prefix}: ${err.message} ${err.stack}`) } else { - console.log("not an isntance errro") logger.error(`${prefix}: ${err}`) } } diff --git a/test/register.test.ts b/test/register.test.ts index e534fa5e..1d45293b 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -1,7 +1,5 @@ +import { field, Level } from "@coder/logger" import { JSDOM } from "jsdom" -// Note: we need to import logger from the root -// because this is the logger used in logError in ../src/common/util -import { logger } from "../node_modules/@coder/logger" describe("register", () => { const { window } = new JSDOM() @@ -10,9 +8,18 @@ describe("register", () => { global.navigator = window.navigator global.location = window.location - let spy: jest.SpyInstance - let loggerSpy: jest.SpyInstance - const mockRegisterFn = jest.fn(() => console.log("Mock register fn called")) + const mockRegisterFn = jest.fn() + const loggerModule = { + field, + level: Level.Info, + logger: { + debug: jest.fn(), + error: jest.fn(), + info: jest.fn(), + trace: jest.fn(), + warn: jest.fn(), + }, + } beforeAll(() => { Object.defineProperty(global.navigator, "serviceWorker", { @@ -23,10 +30,11 @@ describe("register", () => { }) beforeEach(() => { - spy = jest.spyOn(global.navigator.serviceWorker, "register") + jest.mock("@coder/logger", () => loggerModule) }) afterEach(() => { + mockRegisterFn.mockClear() jest.resetModules() }) @@ -35,18 +43,14 @@ describe("register", () => { }) it("should register a ServiceWorker", () => { - spy = jest.spyOn(global.navigator.serviceWorker, "register") // Load service worker like you would in the browser require("../src/browser/register") // Load service worker like you would in the browser - // expect spy to have been called - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledTimes(1) - spy.mockClear() + expect(mockRegisterFn).toHaveBeenCalled() + expect(mockRegisterFn).toHaveBeenCalledTimes(1) }) it("should log an error if something doesn't work", () => { - loggerSpy = jest.spyOn(logger, "error") const message = "Can't find browser" const error = new Error(message) @@ -57,10 +61,7 @@ describe("register", () => { // Load service worker like you would in the browser require("../src/browser/register") - expect(spy).toHaveBeenCalled() - expect(loggerSpy).toHaveBeenCalled() - // expect(loggerSpy).toHaveBeenCalledTimes(1) - // Because we use logError, it will log the prefix along with the error message - // expect(loggerSpy).toHaveBeenCalledWith(`[Service Worker] registration: ${error.message} ${error.stack}`) + expect(mockRegisterFn).toHaveBeenCalled() + expect(loggerModule.logger.error).toHaveBeenCalled() }) }) From 711abd8d840e40c19e9ca5ba1cb8996c4ce2f6e7 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 13:54:22 -0700 Subject: [PATCH 12/22] refactor: move loggerModule into helpers --- test/constants.test.ts | 14 +++++++++----- test/register.test.ts | 17 +++++------------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/test/constants.test.ts b/test/constants.test.ts index 457f57fa..4d4d327e 100644 --- a/test/constants.test.ts +++ b/test/constants.test.ts @@ -1,14 +1,16 @@ // Note: we need to import logger from the root // because this is the logger used in logError in ../src/common/util -import { logger } from "../node_modules/@coder/logger" +// import { logger } from "../node_modules/@coder/logger" import { commit, getPackageJson, version } from "../src/node/constants" +import { loggerModule } from "./helpers" describe("constants", () => { describe("getPackageJson", () => { - let spy: jest.SpyInstance + // let spy: jest.SpyInstance beforeEach(() => { - spy = jest.spyOn(logger, "warn") + // spy = jest.spyOn(logger, "warn") + jest.mock("@coder/logger", () => loggerModule) }) afterEach(() => { @@ -24,8 +26,10 @@ describe("constants", () => { getPackageJson("./package.json") - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledWith(expectedErrorMessage) + // expect(spy).toHaveBeenCalled() + // expect(spy).toHaveBeenCalledWith(expectedErrorMessage) + expect(loggerModule.logger.warn).toHaveBeenCalled() + expect(loggerModule.logger.warn).toHaveBeenCalledWith(expectedErrorMessage) }) it("should find the package.json", () => { diff --git a/test/register.test.ts b/test/register.test.ts index 1d45293b..6ae30376 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -1,5 +1,5 @@ -import { field, Level } from "@coder/logger" import { JSDOM } from "jsdom" +import { loggerModule } from "./helpers" describe("register", () => { const { window } = new JSDOM() @@ -9,17 +9,6 @@ describe("register", () => { global.location = window.location const mockRegisterFn = jest.fn() - const loggerModule = { - field, - level: Level.Info, - logger: { - debug: jest.fn(), - error: jest.fn(), - info: jest.fn(), - trace: jest.fn(), - warn: jest.fn(), - }, - } beforeAll(() => { Object.defineProperty(global.navigator, "serviceWorker", { @@ -63,5 +52,9 @@ describe("register", () => { expect(mockRegisterFn).toHaveBeenCalled() expect(loggerModule.logger.error).toHaveBeenCalled() + expect(loggerModule.logger.error).toHaveBeenCalledTimes(1) + expect(loggerModule.logger.error).toHaveBeenCalledWith( + `[Service Worker] registration: ${error.message} ${error.stack}`, + ) }) }) From 1470ff203a53d9f9b20f916424c4c038ea577009 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 15:58:54 -0700 Subject: [PATCH 13/22] refactor: dont use actual logger in helper --- test/helpers.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/helpers.ts b/test/helpers.ts index 193fd0ca..2aeb82df 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -33,3 +33,15 @@ export function createCookieIfDoesntExist(cookies: Array, cookieToStore: } return cookies } + +export const loggerModule = { + field: jest.fn(), + level: 2, + logger: { + debug: jest.fn(), + error: jest.fn(), + info: jest.fn(), + trace: jest.fn(), + warn: jest.fn(), + }, +} From 1c737f1f938871e37fbc34450d2dcc0f36336e94 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 15:59:17 -0700 Subject: [PATCH 14/22] refactor: hoist jest.mock in constants --- test/constants.test.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/constants.test.ts b/test/constants.test.ts index 4d4d327e..7751ec53 100644 --- a/test/constants.test.ts +++ b/test/constants.test.ts @@ -4,15 +4,11 @@ import { commit, getPackageJson, version } from "../src/node/constants" import { loggerModule } from "./helpers" +// jest.mock is hoisted above the imports so we must use `require` here. +jest.mock("@coder/logger", () => require("./helpers").loggerModule) + describe("constants", () => { describe("getPackageJson", () => { - // let spy: jest.SpyInstance - - beforeEach(() => { - // spy = jest.spyOn(logger, "warn") - jest.mock("@coder/logger", () => loggerModule) - }) - afterEach(() => { jest.clearAllMocks() }) From cb4185b360af0058e3730d9b502f7db5b605247c Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 16:01:11 -0700 Subject: [PATCH 15/22] refactor: use loggerModule in util --- test/constants.test.ts | 2 -- test/util.test.ts | 23 ++++++++--------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/test/constants.test.ts b/test/constants.test.ts index 7751ec53..64514981 100644 --- a/test/constants.test.ts +++ b/test/constants.test.ts @@ -22,8 +22,6 @@ describe("constants", () => { getPackageJson("./package.json") - // expect(spy).toHaveBeenCalled() - // expect(spy).toHaveBeenCalledWith(expectedErrorMessage) expect(loggerModule.logger.warn).toHaveBeenCalled() expect(loggerModule.logger.warn).toHaveBeenCalledWith(expectedErrorMessage) }) diff --git a/test/util.test.ts b/test/util.test.ts index 035272b6..2681d877 100644 --- a/test/util.test.ts +++ b/test/util.test.ts @@ -1,8 +1,4 @@ import { JSDOM } from "jsdom" -import { Cookie } from "playwright" -// Note: we need to import logger from the root -// because this is the logger used in logError in ../src/common/util -import { logger } from "../node_modules/@coder/logger" import { arrayify, generateUuid, @@ -18,13 +14,16 @@ import { import { Cookie as CookieEnum } from "../src/node/routes/login" import { hash } from "../src/node/util" import { PASSWORD } from "./constants" -import { checkForCookie, createCookieIfDoesntExist } from "./helpers" +import { checkForCookie, createCookieIfDoesntExist, loggerModule, Cookie } from "./helpers" const dom = new JSDOM() global.document = dom.window.document type LocationLike = Pick +// jest.mock is hoisted above the imports so we must use `require` here. +jest.mock("@coder/logger", () => require("./helpers").loggerModule) + describe("util", () => { describe("normalize", () => { it("should remove multiple slashes", () => { @@ -228,12 +227,6 @@ describe("util", () => { }) describe("logError", () => { - let spy: jest.SpyInstance - - beforeEach(() => { - spy = jest.spyOn(logger, "error") - }) - afterEach(() => { jest.clearAllMocks() }) @@ -248,15 +241,15 @@ describe("util", () => { logError("ui", error) - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledWith(`ui: ${error.message} ${error.stack}`) + expect(loggerModule.logger.error).toHaveBeenCalled() + expect(loggerModule.logger.error).toHaveBeenCalledWith(`ui: ${error.message} ${error.stack}`) }) it("should log an error, even if not an instance of error", () => { logError("api", "oh no") - expect(spy).toHaveBeenCalled() - expect(spy).toHaveBeenCalledWith("api: oh no") + expect(loggerModule.logger.error).toHaveBeenCalled() + expect(loggerModule.logger.error).toHaveBeenCalledWith("api: oh no") }) }) From e6a324b48410b33471fc874f97efa85cd7380c57 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 16:11:04 -0700 Subject: [PATCH 16/22] refactor: update mocking logger in register test --- test/register.test.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/register.test.ts b/test/register.test.ts index 6ae30376..dc024697 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -1,6 +1,9 @@ import { JSDOM } from "jsdom" import { loggerModule } from "./helpers" +// jest.mock is hoisted above the imports so we must use `require` here. +jest.mock("@coder/logger", () => require("./helpers").loggerModule) + describe("register", () => { const { window } = new JSDOM() global.window = (window as unknown) as Window & typeof globalThis @@ -18,10 +21,6 @@ describe("register", () => { }) }) - beforeEach(() => { - jest.mock("@coder/logger", () => loggerModule) - }) - afterEach(() => { mockRegisterFn.mockClear() jest.resetModules() From b232dcbd4a2bd38d2515ad12fbbd3863ac2b172b Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Tue, 23 Feb 2021 16:20:18 -0700 Subject: [PATCH 17/22] feat(register): add test when navigator undefined --- test/constants.test.ts | 3 -- test/register.test.ts | 117 +++++++++++++++++++++++++---------------- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/test/constants.test.ts b/test/constants.test.ts index 64514981..0cb33f2f 100644 --- a/test/constants.test.ts +++ b/test/constants.test.ts @@ -1,6 +1,3 @@ -// Note: we need to import logger from the root -// because this is the logger used in logError in ../src/common/util -// import { logger } from "../node_modules/@coder/logger" import { commit, getPackageJson, version } from "../src/node/constants" import { loggerModule } from "./helpers" diff --git a/test/register.test.ts b/test/register.test.ts index dc024697..4fd00b3d 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -1,59 +1,88 @@ import { JSDOM } from "jsdom" import { loggerModule } from "./helpers" -// jest.mock is hoisted above the imports so we must use `require` here. -jest.mock("@coder/logger", () => require("./helpers").loggerModule) - describe("register", () => { - const { window } = new JSDOM() - global.window = (window as unknown) as Window & typeof globalThis - global.document = window.document - global.navigator = window.navigator - global.location = window.location + describe("when navigator and serviceWorker are defined", () => { + const mockRegisterFn = jest.fn() - const mockRegisterFn = jest.fn() + beforeAll(() => { + const { window } = new JSDOM() + global.window = (window as unknown) as Window & typeof globalThis + global.document = window.document + global.navigator = window.navigator + global.location = window.location - beforeAll(() => { - Object.defineProperty(global.navigator, "serviceWorker", { - value: { - register: mockRegisterFn, - }, + Object.defineProperty(global.navigator, "serviceWorker", { + value: { + register: mockRegisterFn, + }, + }) + }) + + beforeEach(() => { + jest.mock("@coder/logger", () => loggerModule) + }) + + afterEach(() => { + mockRegisterFn.mockClear() + jest.resetModules() + }) + + afterAll(() => { + jest.restoreAllMocks() + + // We don't want these to stay around because it can affect other tests + global.window = (undefined as unknown) as Window & typeof globalThis + global.document = (undefined as unknown) as Document & typeof globalThis + global.navigator = (undefined as unknown) as Navigator & typeof globalThis + global.location = (undefined as unknown) as Location & typeof globalThis + }) + + it("should register a ServiceWorker", () => { + // Load service worker like you would in the browser + require("../src/browser/register") + // Load service worker like you would in the browser + expect(mockRegisterFn).toHaveBeenCalled() + expect(mockRegisterFn).toHaveBeenCalledTimes(1) + }) + + it("should log an error if something doesn't work", () => { + const message = "Can't find browser" + const error = new Error(message) + + mockRegisterFn.mockImplementation(() => { + throw error + }) + + // Load service worker like you would in the browser + require("../src/browser/register") + + expect(mockRegisterFn).toHaveBeenCalled() + expect(loggerModule.logger.error).toHaveBeenCalled() + expect(loggerModule.logger.error).toHaveBeenCalledTimes(1) + expect(loggerModule.logger.error).toHaveBeenCalledWith( + `[Service Worker] registration: ${error.message} ${error.stack}`, + ) }) }) - afterEach(() => { - mockRegisterFn.mockClear() - jest.resetModules() - }) + describe("when navigator and serviceWorker are NOT defined", () => { + let spy: jest.SpyInstance - afterAll(() => { - jest.restoreAllMocks() - }) - - it("should register a ServiceWorker", () => { - // Load service worker like you would in the browser - require("../src/browser/register") - // Load service worker like you would in the browser - expect(mockRegisterFn).toHaveBeenCalled() - expect(mockRegisterFn).toHaveBeenCalledTimes(1) - }) - - it("should log an error if something doesn't work", () => { - const message = "Can't find browser" - const error = new Error(message) - - mockRegisterFn.mockImplementation(() => { - throw error + beforeEach(() => { + spy = jest.spyOn(console, "error") }) - // Load service worker like you would in the browser - require("../src/browser/register") + afterAll(() => { + jest.restoreAllMocks() + }) - expect(mockRegisterFn).toHaveBeenCalled() - expect(loggerModule.logger.error).toHaveBeenCalled() - expect(loggerModule.logger.error).toHaveBeenCalledTimes(1) - expect(loggerModule.logger.error).toHaveBeenCalledWith( - `[Service Worker] registration: ${error.message} ${error.stack}`, - ) + it("should log an error to the console", () => { + // Load service worker like you would in the browser + require("../src/browser/register") + expect(spy).toHaveBeenCalled() + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith("[Service Worker] navigator is undefined") + }) }) }) From 80a180079e47c6c0b28a95d2b33e677a640bea77 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Wed, 10 Feb 2021 15:37:43 -0700 Subject: [PATCH 18/22] feat: add test for catching errors in Emitter --- test/emitter.test.ts | 22 +++++++++++++++++++++- test/serviceWorker.test.ts | 9 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test/serviceWorker.test.ts diff --git a/test/emitter.test.ts b/test/emitter.test.ts index 8ff5106a..001b13e0 100644 --- a/test/emitter.test.ts +++ b/test/emitter.test.ts @@ -1,9 +1,10 @@ // Note: we need to import logger from the root // because this is the logger used in logError in ../src/common/util import { logger } from "../node_modules/@coder/logger" + import { Emitter } from "../src/common/emitter" -describe("Emitter", () => { +describe("emitter", () => { let spy: jest.SpyInstance beforeEach(() => { @@ -59,6 +60,25 @@ describe("Emitter", () => { emitter.dispose() }) + it("should log an error if something goes wrong", async () => { + const HELLO_WORLD = "HELLO_WORLD" + const mockCallback = jest.fn(() => "Mock function called") + const message = "You don't have access to that folder." + + const emitter = new Emitter<{ event: string; callback: () => void }>() + + const onHelloWorld = ({ event, callback }: { event: string; callback: () => void }): void => { + if (event === HELLO_WORLD) { + callback() + throw new Error(message) + } + } + + emitter.event(onHelloWorld) + + await emitter.emit({ event: HELLO_WORLD, callback: mockCallback }) + }) + it("should log an error if something goes wrong", async () => { const HELLO_WORLD = "HELLO_WORLD" const mockCallback = jest.fn(() => "Mock function called") diff --git a/test/serviceWorker.test.ts b/test/serviceWorker.test.ts new file mode 100644 index 00000000..32e6effd --- /dev/null +++ b/test/serviceWorker.test.ts @@ -0,0 +1,9 @@ +describe("serviceWorker", () => { + it("should add the proper eventListeners", () => { + // make sure install, active and fetch were added as event listeners + }) + + it("should call the proper callbacks", () => { + // somehow test Line 8 with the events waitUntil.. + }) +}) \ No newline at end of file From 46226ea26b1d9bfb2d46cc982fb1b1d0d0f0d3a9 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 18 Feb 2021 14:35:15 -0700 Subject: [PATCH 19/22] chore(testing): add service-worker-mock --- test/package.json | 2 ++ test/yarn.lock | 86 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/test/package.json b/test/package.json index 4a408464..9640d195 100644 --- a/test/package.json +++ b/test/package.json @@ -4,11 +4,13 @@ "@types/jest": "^26.0.20", "@types/jsdom": "^16.2.6", "@types/node-fetch": "^2.5.8", + "@types/service-worker-mock": "^2.0.1", "@types/supertest": "^2.0.10", "jest": "^26.6.3", "jsdom": "^16.4.0", "node-fetch": "^2.6.1", "playwright": "^1.8.0", + "service-worker-mock": "^2.0.5", "supertest": "^6.1.1", "ts-jest": "^26.4.4" } diff --git a/test/yarn.lock b/test/yarn.lock index 4f6ae7ab..559e3c07 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -588,6 +588,11 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.6.tgz#f4b1efa784e8db479cdb8b14403e2144b1e9ff03" integrity sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA== +"@types/service-worker-mock@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/service-worker-mock/-/service-worker-mock-2.0.1.tgz#4857b2024318c395294a02eda5050ac083f41e56" + integrity sha512-LqaP0QmgppRF7YEaqx4amoazHNXaX5bIFDAu62LnWIc5ku0HbgqlPKroQstAu8WsdmWIqEfI9VGlP8Skkq+m5A== + "@types/stack-utils@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" @@ -1232,6 +1237,13 @@ diff-sequences@^26.6.2: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== +dom-urls@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e" + integrity sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4= + dependencies: + urijs "^1.16.1" + domexception@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" @@ -2486,6 +2498,38 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash._basefor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + integrity sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI= + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + +lodash.isplainobject@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + integrity sha1-moI4rhayAEMpYM1zRlEtASP79MU= + dependencies: + lodash._basefor "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.keysin "^3.0.0" + +lodash.keysin@^3.0.0: + version "3.0.8" + resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + integrity sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8= + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -3016,6 +3060,13 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +realistic-structured-clone@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-1.0.1.tgz#1abe82af0b80cd7b109fdaf5d29308032852d45d" + integrity sha1-Gr6CrwuAzXsQn9r10pMIAyhS1F0= + dependencies: + lodash.isplainobject "^3.0.2" + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -3199,6 +3250,16 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +service-worker-mock@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/service-worker-mock/-/service-worker-mock-2.0.5.tgz#89d47ec1571130114d4deed66d69bdcfee4a4545" + integrity sha512-yk6NCFnRWGfbOlP+IS4hEbJnGU8dVgtodAAKLxhkTPsOmaES44XVSWTNozK6KwI+p/0PDRrFsb2RjTMhvXiNkA== + dependencies: + dom-urls "^1.1.0" + shelving-mock-indexeddb "^1.1.0" + url-search-params "^0.10.0" + w3c-hr-time "^1.0.1" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -3243,6 +3304,19 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== +shelving-mock-event@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/shelving-mock-event/-/shelving-mock-event-1.0.12.tgz#401dc90b3b49cbf2a817ecf2dd5a83eff4de2e14" + integrity sha512-2F+IZ010rwV3sA/Kd2hnC1vGNycsxeBJmjkXR8+4IOlv5e+Wvj+xH+A8Cv8/Z0lUyCut/HcxSpeDccYTVtnuaQ== + +shelving-mock-indexeddb@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shelving-mock-indexeddb/-/shelving-mock-indexeddb-1.1.0.tgz#e065a8d7987d182d058e2b55f0f79a52d48a38f1" + integrity sha512-akHJAmGL/dplJ4FZNxPxVbOxMw8Ey6wAnB9+3+GCUNqPUcJaskS55GijxZtarTfAYB4XQyu+FLtjcq2Oa3e2Lg== + dependencies: + realistic-structured-clone "^1.0.1" + shelving-mock-event "^1.0.12" + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -3674,11 +3748,21 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urijs@^1.16.1: + version "1.19.6" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.6.tgz#51f8cb17ca16faefb20b9a31ac60f84aa2b7c870" + integrity sha512-eSXsXZ2jLvGWeLYlQA3Gh36BcjF+0amo92+wHPyN1mdR8Nxf75fuEuYTd9c0a+m/vhCjRK0ESlE9YNLW+E1VEw== + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +url-search-params@^0.10.0: + version "0.10.2" + resolved "https://registry.yarnpkg.com/url-search-params/-/url-search-params-0.10.2.tgz#e9da69646e48c6140c6732e1f07fb669525f5a4e" + integrity sha512-d6GYsr992Bo9rzTZFc9BUw3UFAAg3prE9JGVBgW2TLTbI3rSvg4VDa0BFXHMzKkWbAuhrmaFWpucpRJl+3W7Jg== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -3725,7 +3809,7 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -w3c-hr-time@^1.0.2: +w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== From ee0973c05a545bc1495aed63727d453f8b81e7c1 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 18 Feb 2021 14:35:30 -0700 Subject: [PATCH 20/22] feat: add logs to serviceWorker --- src/browser/serviceWorker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/serviceWorker.ts b/src/browser/serviceWorker.ts index 1bee59bf..25765a1a 100644 --- a/src/browser/serviceWorker.ts +++ b/src/browser/serviceWorker.ts @@ -1,11 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ self.addEventListener("install", () => { - console.log("[Service Worker] install") + console.log("[Service Worker] installed") }) self.addEventListener("activate", (event: any) => { event.waitUntil((self as any).clients.claim()) + console.log("[Service Worker] activated") }) self.addEventListener("fetch", () => { From 6b56e6572d028eecf7d10d8b7293b1185518e912 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Thu, 18 Feb 2021 14:35:41 -0700 Subject: [PATCH 21/22] feat(testing): add serviceWorker tests --- ci/dev/lint.sh | 2 +- test/package.json | 3 ++ test/patches/service-worker-mock-fetch.patch | 15 +++++++ .../service-worker-mock-response.patch | 9 ++++ test/patches/service-worker-types.patch | 14 ++++++ test/scripts/patch.sh | 26 +++++++++++ test/serviceWorker.test.ts | 45 ++++++++++++++++--- 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 test/patches/service-worker-mock-fetch.patch create mode 100644 test/patches/service-worker-mock-response.patch create mode 100644 test/patches/service-worker-types.patch create mode 100755 test/scripts/patch.sh diff --git a/ci/dev/lint.sh b/ci/dev/lint.sh index c4875ff1..9ba576e0 100755 --- a/ci/dev/lint.sh +++ b/ci/dev/lint.sh @@ -6,7 +6,7 @@ main() { eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js" | grep -v "lib/vscode") stylelint $(git ls-files "*.css" | grep -v "lib/vscode") - tsc --noEmit + tsc --noEmit --skipLibCheck shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh" | grep -v "lib/vscode") if command -v helm && helm kubeval --help > /dev/null; then helm kubeval ci/helm-chart diff --git a/test/package.json b/test/package.json index 9640d195..1738e80d 100644 --- a/test/package.json +++ b/test/package.json @@ -1,5 +1,8 @@ { "#": "We must put jest in a sub-directory otherwise VS Code somehow picks up the types and generates conflicts with mocha.", + "scripts": { + "postinstall": "./scripts/patch.sh" + }, "devDependencies": { "@types/jest": "^26.0.20", "@types/jsdom": "^16.2.6", diff --git a/test/patches/service-worker-mock-fetch.patch b/test/patches/service-worker-mock-fetch.patch new file mode 100644 index 00000000..f3008c31 --- /dev/null +++ b/test/patches/service-worker-mock-fetch.patch @@ -0,0 +1,15 @@ +--- node_modules/service-worker-mock/fetch.js 2021-02-18 13:47:55.000000000 -0700 ++++ patches/service-worker-mock-fixed.js 2021-02-18 15:49:47.000000000 -0700 +@@ -1,8 +1,11 @@ + module.exports = async (request) => { ++ const Response = require('./models/Response'); + const response = new Response('Response from service-worker-mock/fetch.js', { + status: 200, + statusText: 'ok.' + }); +- response.url = request.url; ++ if (request && request.url) { ++ response.url = request.url; ++ } + return response; + }; diff --git a/test/patches/service-worker-mock-response.patch b/test/patches/service-worker-mock-response.patch new file mode 100644 index 00000000..16ed6fd8 --- /dev/null +++ b/test/patches/service-worker-mock-response.patch @@ -0,0 +1,9 @@ +--- node_modules/service-worker-mock/models/Response.js 2021-02-18 13:47:55.000000000 -0700 ++++ patches/service-worker-mock-response.js 2021-02-18 15:57:12.000000000 -0700 +@@ -1,5 +1,6 @@ + // stubs https://developer.mozilla.org/en-US/docs/Web/API/Response + const Body = require('./Body'); ++const Blob = require('./Blob'); + const Headers = require('./Headers'); + + const isSupportedBodyType = (body) => diff --git a/test/patches/service-worker-types.patch b/test/patches/service-worker-types.patch new file mode 100644 index 00000000..16870822 --- /dev/null +++ b/test/patches/service-worker-types.patch @@ -0,0 +1,14 @@ +--- node_modules/@types/service-worker-mock/index.d.ts 2021-02-18 13:51:50.000000000 -0700 ++++ patches/service-workertypes.d.ts 2021-02-18 16:30:01.000000000 -0700 +@@ -3,6 +3,11 @@ + // Definitions by: Remco Haszing + // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + // TypeScript Version: 2.8 ++// https://gist.github.com/shqld/32df51a4a4ed429f2c76e4e2cfdf6f96#gistcomment-2793376 ++// excludes default libs such as 'dom' conflicting with 'webworker' ++/// ++/// ++/// + + export = makeServiceWorkerEnv; + declare function makeServiceWorkerEnv(): WorkerGlobalScope; diff --git a/test/scripts/patch.sh b/test/scripts/patch.sh new file mode 100755 index 00000000..48f099ac --- /dev/null +++ b/test/scripts/patch.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +apply_service_worker_mock_patches() { + # The `service-worker-mock` package is no longer maintained + # so we have to apply patches ourselves + + # This patch fixes an undefined error in fetch.js and adds a missing import + patch --forward node_modules/service-worker-mock/fetch.js < patches/service-worker-mock-fetch.patch + + # This patch adds a missing import + patch --forward node_modules/service-worker-mock/models/Response.js < patches/service-worker-mock-response.patch + + # This patch fixes the types declaration file + # See discussion: + patch --forward node_modules/@types/service-worker-mock/index.d.ts < patches/service-worker-types.patch +} + +main() { + echo -e "🔨 Applying patches..." + apply_service_worker_mock_patches + + echo -e "✅ Patches applied successfully." +} + +main "$@" diff --git a/test/serviceWorker.test.ts b/test/serviceWorker.test.ts index 32e6effd..7b76f2c4 100644 --- a/test/serviceWorker.test.ts +++ b/test/serviceWorker.test.ts @@ -1,9 +1,44 @@ +import makeServiceWorkerEnv = require("service-worker-mock") +const makeFetchMock = require("service-worker-mock/fetch") + describe("serviceWorker", () => { - it("should add the proper eventListeners", () => { - // make sure install, active and fetch were added as event listeners + let spy: jest.SpyInstance + beforeEach(() => { + Object.assign( + global, + makeServiceWorkerEnv(), + makeFetchMock(), + // If you're using sinon ur similar you'd probably use below instead of makeFetchMock + // fetch: sinon.stub().returns(Promise.resolve()) + ) + jest.resetModules() + + spy = jest.spyOn(console, "log") }) - it("should call the proper callbacks", () => { - // somehow test Line 8 with the events waitUntil.. + afterEach(() => { + jest.restoreAllMocks() + spy.mockRestore() }) -}) \ No newline at end of file + + it("should add listeners", () => { + require("../src/browser/serviceWorker.ts") + const _self = (self as unknown) as WorkerGlobalScope + expect(_self.listeners.get("install")).toBeDefined() + expect(_self.listeners.get("activate")).toBeDefined() + expect(_self.listeners.get("fetch")).toBeDefined() + }) + + it("should call the proper callbacks for 'install'", async () => { + require("../src/browser/serviceWorker.ts") + await self.trigger("install") + expect(spy).toHaveBeenCalledWith("[Service Worker] installed") + }) + it("should call the proper callbacks for 'activate'", async () => { + require("../src/browser/serviceWorker.ts") + await self.trigger("activate") + + // Activate serviceWorker + expect(spy).toHaveBeenCalledWith("[Service Worker] activated") + }) +}) From 8c14799797f3ef67bbececccb0de15c527ce27cf Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Wed, 24 Feb 2021 10:50:08 -0700 Subject: [PATCH 22/22] refactor: add custom mock for serviceWorker test --- test/emitter.test.ts | 19 ---- test/package.json | 5 -- test/patches/service-worker-mock-fetch.patch | 15 ---- .../service-worker-mock-response.patch | 9 -- test/patches/service-worker-types.patch | 14 --- test/register.test.ts | 1 - test/scripts/patch.sh | 26 ------ test/serviceWorker.test.ts | 86 +++++++++++++++---- test/yarn.lock | 86 +------------------ 9 files changed, 68 insertions(+), 193 deletions(-) delete mode 100644 test/patches/service-worker-mock-fetch.patch delete mode 100644 test/patches/service-worker-mock-response.patch delete mode 100644 test/patches/service-worker-types.patch delete mode 100755 test/scripts/patch.sh diff --git a/test/emitter.test.ts b/test/emitter.test.ts index 001b13e0..3ea72ae2 100644 --- a/test/emitter.test.ts +++ b/test/emitter.test.ts @@ -60,25 +60,6 @@ describe("emitter", () => { emitter.dispose() }) - it("should log an error if something goes wrong", async () => { - const HELLO_WORLD = "HELLO_WORLD" - const mockCallback = jest.fn(() => "Mock function called") - const message = "You don't have access to that folder." - - const emitter = new Emitter<{ event: string; callback: () => void }>() - - const onHelloWorld = ({ event, callback }: { event: string; callback: () => void }): void => { - if (event === HELLO_WORLD) { - callback() - throw new Error(message) - } - } - - emitter.event(onHelloWorld) - - await emitter.emit({ event: HELLO_WORLD, callback: mockCallback }) - }) - it("should log an error if something goes wrong", async () => { const HELLO_WORLD = "HELLO_WORLD" const mockCallback = jest.fn(() => "Mock function called") diff --git a/test/package.json b/test/package.json index 1738e80d..4a408464 100644 --- a/test/package.json +++ b/test/package.json @@ -1,19 +1,14 @@ { "#": "We must put jest in a sub-directory otherwise VS Code somehow picks up the types and generates conflicts with mocha.", - "scripts": { - "postinstall": "./scripts/patch.sh" - }, "devDependencies": { "@types/jest": "^26.0.20", "@types/jsdom": "^16.2.6", "@types/node-fetch": "^2.5.8", - "@types/service-worker-mock": "^2.0.1", "@types/supertest": "^2.0.10", "jest": "^26.6.3", "jsdom": "^16.4.0", "node-fetch": "^2.6.1", "playwright": "^1.8.0", - "service-worker-mock": "^2.0.5", "supertest": "^6.1.1", "ts-jest": "^26.4.4" } diff --git a/test/patches/service-worker-mock-fetch.patch b/test/patches/service-worker-mock-fetch.patch deleted file mode 100644 index f3008c31..00000000 --- a/test/patches/service-worker-mock-fetch.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- node_modules/service-worker-mock/fetch.js 2021-02-18 13:47:55.000000000 -0700 -+++ patches/service-worker-mock-fixed.js 2021-02-18 15:49:47.000000000 -0700 -@@ -1,8 +1,11 @@ - module.exports = async (request) => { -+ const Response = require('./models/Response'); - const response = new Response('Response from service-worker-mock/fetch.js', { - status: 200, - statusText: 'ok.' - }); -- response.url = request.url; -+ if (request && request.url) { -+ response.url = request.url; -+ } - return response; - }; diff --git a/test/patches/service-worker-mock-response.patch b/test/patches/service-worker-mock-response.patch deleted file mode 100644 index 16ed6fd8..00000000 --- a/test/patches/service-worker-mock-response.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- node_modules/service-worker-mock/models/Response.js 2021-02-18 13:47:55.000000000 -0700 -+++ patches/service-worker-mock-response.js 2021-02-18 15:57:12.000000000 -0700 -@@ -1,5 +1,6 @@ - // stubs https://developer.mozilla.org/en-US/docs/Web/API/Response - const Body = require('./Body'); -+const Blob = require('./Blob'); - const Headers = require('./Headers'); - - const isSupportedBodyType = (body) => diff --git a/test/patches/service-worker-types.patch b/test/patches/service-worker-types.patch deleted file mode 100644 index 16870822..00000000 --- a/test/patches/service-worker-types.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- node_modules/@types/service-worker-mock/index.d.ts 2021-02-18 13:51:50.000000000 -0700 -+++ patches/service-workertypes.d.ts 2021-02-18 16:30:01.000000000 -0700 -@@ -3,6 +3,11 @@ - // Definitions by: Remco Haszing - // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - // TypeScript Version: 2.8 -+// https://gist.github.com/shqld/32df51a4a4ed429f2c76e4e2cfdf6f96#gistcomment-2793376 -+// excludes default libs such as 'dom' conflicting with 'webworker' -+/// -+/// -+/// - - export = makeServiceWorkerEnv; - declare function makeServiceWorkerEnv(): WorkerGlobalScope; diff --git a/test/register.test.ts b/test/register.test.ts index 4fd00b3d..a80c2034 100644 --- a/test/register.test.ts +++ b/test/register.test.ts @@ -41,7 +41,6 @@ describe("register", () => { it("should register a ServiceWorker", () => { // Load service worker like you would in the browser require("../src/browser/register") - // Load service worker like you would in the browser expect(mockRegisterFn).toHaveBeenCalled() expect(mockRegisterFn).toHaveBeenCalledTimes(1) }) diff --git a/test/scripts/patch.sh b/test/scripts/patch.sh deleted file mode 100755 index 48f099ac..00000000 --- a/test/scripts/patch.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -apply_service_worker_mock_patches() { - # The `service-worker-mock` package is no longer maintained - # so we have to apply patches ourselves - - # This patch fixes an undefined error in fetch.js and adds a missing import - patch --forward node_modules/service-worker-mock/fetch.js < patches/service-worker-mock-fetch.patch - - # This patch adds a missing import - patch --forward node_modules/service-worker-mock/models/Response.js < patches/service-worker-mock-response.patch - - # This patch fixes the types declaration file - # See discussion: - patch --forward node_modules/@types/service-worker-mock/index.d.ts < patches/service-worker-types.patch -} - -main() { - echo -e "🔨 Applying patches..." - apply_service_worker_mock_patches - - echo -e "✅ Patches applied successfully." -} - -main "$@" diff --git a/test/serviceWorker.test.ts b/test/serviceWorker.test.ts index 7b76f2c4..7933d1f4 100644 --- a/test/serviceWorker.test.ts +++ b/test/serviceWorker.test.ts @@ -1,44 +1,92 @@ -import makeServiceWorkerEnv = require("service-worker-mock") -const makeFetchMock = require("service-worker-mock/fetch") +interface MockEvent { + claim: jest.Mock + waitUntil?: jest.Mock +} + +interface Listener { + event: string + cb: (event?: MockEvent) => void +} describe("serviceWorker", () => { + let listeners: Listener[] = [] let spy: jest.SpyInstance - beforeEach(() => { - Object.assign( - global, - makeServiceWorkerEnv(), - makeFetchMock(), - // If you're using sinon ur similar you'd probably use below instead of makeFetchMock - // fetch: sinon.stub().returns(Promise.resolve()) - ) - jest.resetModules() + let claimSpy: jest.Mock + let waitUntilSpy: jest.Mock + function emit(event: string) { + listeners + .filter((listener) => listener.event === event) + .forEach((listener) => { + switch (event) { + case "activate": + listener.cb({ + claim: jest.fn(), + waitUntil: jest.fn(() => waitUntilSpy()), + }) + break + default: + listener.cb() + } + }) + } + + beforeEach(() => { + claimSpy = jest.fn() spy = jest.spyOn(console, "log") + waitUntilSpy = jest.fn() + + Object.assign(global, { + self: global, + addEventListener: (event: string, cb: () => void) => { + listeners.push({ event, cb }) + }, + clients: { + claim: claimSpy.mockResolvedValue("claimed"), + }, + }) }) afterEach(() => { jest.restoreAllMocks() - spy.mockRestore() + jest.resetModules() + spy.mockClear() + claimSpy.mockClear() + + // Clear all the listeners + listeners = [] }) - it("should add listeners", () => { + it("should add 3 listeners: install, activate and fetch", () => { require("../src/browser/serviceWorker.ts") - const _self = (self as unknown) as WorkerGlobalScope - expect(_self.listeners.get("install")).toBeDefined() - expect(_self.listeners.get("activate")).toBeDefined() - expect(_self.listeners.get("fetch")).toBeDefined() + const listenerEventNames = listeners.map((listener) => listener.event) + + expect(listeners).toHaveLength(3) + expect(listenerEventNames).toContain("install") + expect(listenerEventNames).toContain("activate") + expect(listenerEventNames).toContain("fetch") }) it("should call the proper callbacks for 'install'", async () => { require("../src/browser/serviceWorker.ts") - await self.trigger("install") + emit("install") expect(spy).toHaveBeenCalledWith("[Service Worker] installed") + expect(spy).toHaveBeenCalledTimes(1) }) + + it("should do nothing when 'fetch' is called", async () => { + require("../src/browser/serviceWorker.ts") + emit("fetch") + expect(spy).not.toHaveBeenCalled() + }) + it("should call the proper callbacks for 'activate'", async () => { require("../src/browser/serviceWorker.ts") - await self.trigger("activate") + emit("activate") // Activate serviceWorker expect(spy).toHaveBeenCalledWith("[Service Worker] activated") + expect(waitUntilSpy).toHaveBeenCalled() + expect(claimSpy).toHaveBeenCalled() }) }) diff --git a/test/yarn.lock b/test/yarn.lock index 559e3c07..4f6ae7ab 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -588,11 +588,6 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.6.tgz#f4b1efa784e8db479cdb8b14403e2144b1e9ff03" integrity sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA== -"@types/service-worker-mock@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/service-worker-mock/-/service-worker-mock-2.0.1.tgz#4857b2024318c395294a02eda5050ac083f41e56" - integrity sha512-LqaP0QmgppRF7YEaqx4amoazHNXaX5bIFDAu62LnWIc5ku0HbgqlPKroQstAu8WsdmWIqEfI9VGlP8Skkq+m5A== - "@types/stack-utils@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" @@ -1237,13 +1232,6 @@ diff-sequences@^26.6.2: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== -dom-urls@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e" - integrity sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4= - dependencies: - urijs "^1.16.1" - domexception@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" @@ -2498,38 +2486,6 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lodash._basefor@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" - integrity sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI= - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= - -lodash.isplainobject@^3.0.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" - integrity sha1-moI4rhayAEMpYM1zRlEtASP79MU= - dependencies: - lodash._basefor "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.keysin "^3.0.0" - -lodash.keysin@^3.0.0: - version "3.0.8" - resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" - integrity sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8= - dependencies: - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -3060,13 +3016,6 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -realistic-structured-clone@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-1.0.1.tgz#1abe82af0b80cd7b109fdaf5d29308032852d45d" - integrity sha1-Gr6CrwuAzXsQn9r10pMIAyhS1F0= - dependencies: - lodash.isplainobject "^3.0.2" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -3250,16 +3199,6 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -service-worker-mock@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/service-worker-mock/-/service-worker-mock-2.0.5.tgz#89d47ec1571130114d4deed66d69bdcfee4a4545" - integrity sha512-yk6NCFnRWGfbOlP+IS4hEbJnGU8dVgtodAAKLxhkTPsOmaES44XVSWTNozK6KwI+p/0PDRrFsb2RjTMhvXiNkA== - dependencies: - dom-urls "^1.1.0" - shelving-mock-indexeddb "^1.1.0" - url-search-params "^0.10.0" - w3c-hr-time "^1.0.1" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -3304,19 +3243,6 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -shelving-mock-event@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/shelving-mock-event/-/shelving-mock-event-1.0.12.tgz#401dc90b3b49cbf2a817ecf2dd5a83eff4de2e14" - integrity sha512-2F+IZ010rwV3sA/Kd2hnC1vGNycsxeBJmjkXR8+4IOlv5e+Wvj+xH+A8Cv8/Z0lUyCut/HcxSpeDccYTVtnuaQ== - -shelving-mock-indexeddb@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shelving-mock-indexeddb/-/shelving-mock-indexeddb-1.1.0.tgz#e065a8d7987d182d058e2b55f0f79a52d48a38f1" - integrity sha512-akHJAmGL/dplJ4FZNxPxVbOxMw8Ey6wAnB9+3+GCUNqPUcJaskS55GijxZtarTfAYB4XQyu+FLtjcq2Oa3e2Lg== - dependencies: - realistic-structured-clone "^1.0.1" - shelving-mock-event "^1.0.12" - signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -3748,21 +3674,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urijs@^1.16.1: - version "1.19.6" - resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.6.tgz#51f8cb17ca16faefb20b9a31ac60f84aa2b7c870" - integrity sha512-eSXsXZ2jLvGWeLYlQA3Gh36BcjF+0amo92+wHPyN1mdR8Nxf75fuEuYTd9c0a+m/vhCjRK0ESlE9YNLW+E1VEw== - urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-search-params@^0.10.0: - version "0.10.2" - resolved "https://registry.yarnpkg.com/url-search-params/-/url-search-params-0.10.2.tgz#e9da69646e48c6140c6732e1f07fb669525f5a4e" - integrity sha512-d6GYsr992Bo9rzTZFc9BUw3UFAAg3prE9JGVBgW2TLTbI3rSvg4VDa0BFXHMzKkWbAuhrmaFWpucpRJl+3W7Jg== - use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -3809,7 +3725,7 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2: +w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==