From e7493557e1c4d9ecece11cd45d29472c90c28426 Mon Sep 17 00:00:00 2001 From: Artem Zakharchenko Date: Sat, 16 Mar 2024 14:09:47 +0100 Subject: [PATCH] fix: improve the worker integrity warning (#2091) --- src/browser/setupWorker/glossary.ts | 5 ++- .../setupWorker/start/createStartHandler.ts | 28 +++++---------- src/browser/utils/checkWorkerIntegrity.ts | 34 +++++++++++++++++++ src/browser/utils/requestIntegrityCheck.ts | 23 ------------- src/mockServiceWorker.js | 8 +++-- test/browser/msw-api/integrity-check.test.ts | 9 ++++- 6 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 src/browser/utils/checkWorkerIntegrity.ts delete mode 100644 src/browser/utils/requestIntegrityCheck.ts diff --git a/src/browser/setupWorker/glossary.ts b/src/browser/setupWorker/glossary.ts index f9c1b66ab..a51d0f73c 100644 --- a/src/browser/setupWorker/glossary.ts +++ b/src/browser/setupWorker/glossary.ts @@ -54,7 +54,10 @@ export type ServiceWorkerIncomingResponse = Pick< */ export interface ServiceWorkerIncomingEventsMap { MOCKING_ENABLED: boolean - INTEGRITY_CHECK_RESPONSE: string + INTEGRITY_CHECK_RESPONSE: { + packageVersion: string + checksum: string + } KEEPALIVE_RESPONSE: never REQUEST: ServiceWorkerIncomingRequest RESPONSE: ServiceWorkerIncomingResponse diff --git a/src/browser/setupWorker/start/createStartHandler.ts b/src/browser/setupWorker/start/createStartHandler.ts index 04bbe5154..dd9c35ebb 100644 --- a/src/browser/setupWorker/start/createStartHandler.ts +++ b/src/browser/setupWorker/start/createStartHandler.ts @@ -1,10 +1,9 @@ -import { until } from '@open-draft/until' import { devUtils } from '~/core/utils/internal/devUtils' import { getWorkerInstance } from './utils/getWorkerInstance' import { enableMocking } from './utils/enableMocking' import { SetupWorkerInternalContext, StartHandler } from '../glossary' import { createRequestListener } from './createRequestListener' -import { requestIntegrityCheck } from '../../utils/requestIntegrityCheck' +import { checkWorkerIntegrity } from '../../utils/checkWorkerIntegrity' import { createResponseListener } from './createResponseListener' import { validateWorkerScope } from './utils/validateWorkerScope' @@ -74,23 +73,14 @@ Please consider using a custom "serviceWorker.url" option to point to the actual window.clearInterval(context.keepAliveInterval) }) - // Check if the active Service Worker is the latest published one - const integrityCheckResult = await until(() => - requestIntegrityCheck(context, worker), - ) - - if (integrityCheckResult.error) { - devUtils.warn(`\ -Detected outdated Service Worker: ${integrityCheckResult.error.message} - -The mocking is still enabled, but it's highly recommended that you update your Service Worker by running: - -$ npx msw init - -This is necessary to ensure that the Service Worker is in sync with the library to guarantee its stability. -If this message still persists after updating, please report an issue: https://github.com/open-draft/msw/issues\ - `) - } + // Check if the active Service Worker has been generated + // by the currently installed version of MSW. + await checkWorkerIntegrity(context).catch((error) => { + devUtils.error( + 'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues), including the original error below.', + ) + console.error(error) + }) context.keepAliveInterval = window.setInterval( () => context.workerChannel.send('KEEPALIVE_REQUEST'), diff --git a/src/browser/utils/checkWorkerIntegrity.ts b/src/browser/utils/checkWorkerIntegrity.ts new file mode 100644 index 000000000..6a7a0073f --- /dev/null +++ b/src/browser/utils/checkWorkerIntegrity.ts @@ -0,0 +1,34 @@ +import { devUtils } from '~/core/utils/internal/devUtils' +import type { SetupWorkerInternalContext } from '../setupWorker/glossary' + +/** + * Check whether the registered Service Worker has been + * generated by the installed version of the library. + * Prints a warning message if the worker scripts mismatch. + */ +export async function checkWorkerIntegrity( + context: SetupWorkerInternalContext, +): Promise { + // Request the integrity checksum from the registered worker. + context.workerChannel.send('INTEGRITY_CHECK_REQUEST') + + const { payload } = await context.events.once('INTEGRITY_CHECK_RESPONSE') + + // Compare the response from the Service Worker and the + // global variable set during the build. + + // The integrity is validated based on the worker script's checksum + // that's derived from its minified content during the build. + // The "SERVICE_WORKER_CHECKSUM" global variable is injected by the build. + if (payload.checksum !== SERVICE_WORKER_CHECKSUM) { + devUtils.warn( + `The currently registered Service Worker has been generated by a different version of MSW (${payload.packageVersion}) and may not be fully compatible with the installed version. + +It's recommended you update your worker script by running this command: + + \u2022 npx msw init + +You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`, + ) + } +} diff --git a/src/browser/utils/requestIntegrityCheck.ts b/src/browser/utils/requestIntegrityCheck.ts deleted file mode 100644 index 67e1b4144..000000000 --- a/src/browser/utils/requestIntegrityCheck.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { SetupWorkerInternalContext } from '../setupWorker/glossary' - -export async function requestIntegrityCheck( - context: SetupWorkerInternalContext, - serviceWorker: ServiceWorker, -): Promise { - // Signal Service Worker to report back its integrity - context.workerChannel.send('INTEGRITY_CHECK_REQUEST') - - const { payload: actualChecksum } = await context.events.once( - 'INTEGRITY_CHECK_RESPONSE', - ) - - // Compare the response from the Service Worker and the - // global variable set during the build. - if (actualChecksum !== SERVICE_WORKER_CHECKSUM) { - throw new Error( - `Currently active Service Worker (${actualChecksum}) is behind the latest published one (${SERVICE_WORKER_CHECKSUM}).`, - ) - } - - return serviceWorker -} diff --git a/src/mockServiceWorker.js b/src/mockServiceWorker.js index bece48c8d..6e6f415c9 100644 --- a/src/mockServiceWorker.js +++ b/src/mockServiceWorker.js @@ -2,12 +2,13 @@ /* tslint:disable */ /** - * Mock Service Worker (). + * Mock Service Worker. * @see https://github.com/mswjs/msw * - Please do NOT modify this file. * - Please do NOT serve this file on production. */ +const PACKAGE_VERSION = '' const INTEGRITY_CHECKSUM = '' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() @@ -48,7 +49,10 @@ self.addEventListener('message', async function (event) { case 'INTEGRITY_CHECK_REQUEST': { sendToClient(client, { type: 'INTEGRITY_CHECK_RESPONSE', - payload: INTEGRITY_CHECKSUM, + payload: { + packageVersion: PACKAGE_VERSION, + checksum: INTEGRITY_CHECKSUM, + }, }) break } diff --git a/test/browser/msw-api/integrity-check.test.ts b/test/browser/msw-api/integrity-check.test.ts index 8d4d324f0..86ea3b2b2 100644 --- a/test/browser/msw-api/integrity-check.test.ts +++ b/test/browser/msw-api/integrity-check.test.ts @@ -2,6 +2,7 @@ import * as fs from 'fs' import * as path from 'path' import { test, expect } from '../playwright.extend' import copyServiceWorker from '../../../config/copyServiceWorker' +import { version } from '../../../package.json' const { SERVICE_WORKER_SOURCE_PATH } = require('../../../config/constants') @@ -67,7 +68,13 @@ test('errors when activating the worker with an outdated integrity', async ({ // Produces a meaningful error in the browser's console. expect(consoleSpy.get('warning')).toEqual( expect.arrayContaining([ - expect.stringContaining('[MSW] Detected outdated Service Worker'), + `[MSW] The currently registered Service Worker has been generated by a different version of MSW (${version}) and may not be fully compatible with the installed version. + +It's recommended you update your worker script by running this command: + + \u2022 npx msw init + +You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`, ]), ) })