From 49825c5ce6a2132c788507623b09778827171b0b Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 19 Sep 2024 10:56:46 +0900 Subject: [PATCH 1/3] fix(browser): fix browser mock factory event race condition --- packages/browser/src/client/channel.ts | 3 +++ packages/browser/src/client/tester/mocker.ts | 8 +++++--- packages/browser/src/client/tester/msw.ts | 7 +++++-- packages/utils/src/index.ts | 2 ++ packages/utils/src/nanoid.ts | 12 ++++++++++++ packages/vitest/src/utils/base.ts | 15 +-------------- 6 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 packages/utils/src/nanoid.ts diff --git a/packages/browser/src/client/channel.ts b/packages/browser/src/client/channel.ts index 1eb9d9ca9228..54893c0a6ed4 100644 --- a/packages/browser/src/client/channel.ts +++ b/packages/browser/src/client/channel.ts @@ -39,16 +39,19 @@ export interface IframeMockingDoneEvent { export interface IframeMockFactoryRequestEvent { type: 'mock-factory:request' + eventId: string id: string } export interface IframeMockFactoryResponseEvent { type: 'mock-factory:response' + eventId: string exports: string[] } export interface IframeMockFactoryErrorEvent { type: 'mock-factory:error' + eventId: string error: any } diff --git a/packages/browser/src/client/tester/mocker.ts b/packages/browser/src/client/tester/mocker.ts index cc3f63bde9f4..6e15f69f3390 100644 --- a/packages/browser/src/client/tester/mocker.ts +++ b/packages/browser/src/client/tester/mocker.ts @@ -1,4 +1,4 @@ -import type { IframeChannelOutgoingEvent } from '@vitest/browser/client' +import type { IframeChannelOutgoingEvent, IframeMockFactoryErrorEvent, IframeMockFactoryResponseEvent } from '@vitest/browser/client' import { channel } from '@vitest/browser/client' import { ModuleMocker } from '@vitest/mocker/browser' import { getBrowserState } from '../utils' @@ -14,18 +14,20 @@ export class VitestBrowserClientMocker extends ModuleMocker { const exports = Object.keys(module) channel.postMessage({ type: 'mock-factory:response', + eventId: e.data.eventId, exports, - }) + } satisfies IframeMockFactoryResponseEvent) } catch (err: any) { channel.postMessage({ type: 'mock-factory:error', + eventId: e.data.eventId, error: { name: err.name, message: err.message, stack: err.stack, }, - }) + } satisfies IframeMockFactoryErrorEvent) } } }, diff --git a/packages/browser/src/client/tester/msw.ts b/packages/browser/src/client/tester/msw.ts index 997ae2ba4a7e..45c2285ad3ef 100644 --- a/packages/browser/src/client/tester/msw.ts +++ b/packages/browser/src/client/tester/msw.ts @@ -6,6 +6,7 @@ import type { import type { MockedModuleSerialized } from '@vitest/mocker' import { ManualMockedModule } from '@vitest/mocker' import { ModuleMockerMSWInterceptor } from '@vitest/mocker/browser' +import { nanoid } from '@vitest/utils' export class VitestBrowserModuleMockerInterceptor extends ModuleMockerMSWInterceptor { override async register(event: MockedModuleSerialized): Promise { @@ -42,19 +43,21 @@ export function createModuleMockerInterceptor() { } function getFactoryExports(id: string) { + const eventId = nanoid() channel.postMessage({ type: 'mock-factory:request', + eventId, id, }) return new Promise((resolve, reject) => { channel.addEventListener( 'message', function onMessage(e: MessageEvent) { - if (e.data.type === 'mock-factory:response') { + if (e.data.type === 'mock-factory:response' && e.data.eventId === eventId) { resolve(e.data.exports) channel.removeEventListener('message', onMessage) } - if (e.data.type === 'mock-factory:error') { + if (e.data.type === 'mock-factory:error' && e.data.eventId === eventId) { reject(e.data.error) channel.removeEventListener('message', onMessage) } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index ea8d8456f15d..7793578000dc 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -51,3 +51,5 @@ export type { SerializedError, TestError, } from './types' + +export { nanoid } from './nanoid' diff --git a/packages/utils/src/nanoid.ts b/packages/utils/src/nanoid.ts new file mode 100644 index 000000000000..00569c5968c0 --- /dev/null +++ b/packages/utils/src/nanoid.ts @@ -0,0 +1,12 @@ +// port from nanoid +// https://github.com/ai/nanoid +const urlAlphabet + = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' +export function nanoid(size = 21): string { + let id = '' + let i = size + while (i--) { + id += urlAlphabet[(Math.random() * 64) | 0] + } + return id +} diff --git a/packages/vitest/src/utils/base.ts b/packages/vitest/src/utils/base.ts index f165f4a931ec..8ed0c97ef5c6 100644 --- a/packages/vitest/src/utils/base.ts +++ b/packages/vitest/src/utils/base.ts @@ -1,6 +1,6 @@ import type { Arrayable, Nullable } from '../types/general' -export { notNullish, getCallLastIndex } from '@vitest/utils' +export { notNullish, getCallLastIndex, nanoid } from '@vitest/utils' export interface GlobalConstructors { Object: ObjectConstructor @@ -203,16 +203,3 @@ export function wildcardPatternToRegExp(pattern: string): RegExp { 'i', ) } - -// port from nanoid -// https://github.com/ai/nanoid -const urlAlphabet - = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' -export function nanoid(size = 21) { - let id = '' - let i = size - while (i--) { - id += urlAlphabet[(Math.random() * 64) | 0] - } - return id -} From 0f01415c19f4c2b3eb2045dbb78353e8be3c2496 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 19 Sep 2024 11:27:59 +0900 Subject: [PATCH 2/3] test: add test --- .../browser/fixtures/mocking/mocked-factory.test.ts | 13 +++++++++++++ .../fixtures/mocking/src/mocks_factory_many.ts | 4 ++++ .../fixtures/mocking/src/mocks_factory_many_dep1.ts | 1 + .../fixtures/mocking/src/mocks_factory_many_dep2.ts | 1 + 4 files changed, 19 insertions(+) create mode 100644 test/browser/fixtures/mocking/src/mocks_factory_many.ts create mode 100644 test/browser/fixtures/mocking/src/mocks_factory_many_dep1.ts create mode 100644 test/browser/fixtures/mocking/src/mocks_factory_many_dep2.ts diff --git a/test/browser/fixtures/mocking/mocked-factory.test.ts b/test/browser/fixtures/mocking/mocked-factory.test.ts index d168ba6df2e4..1f1791213e75 100644 --- a/test/browser/fixtures/mocking/mocked-factory.test.ts +++ b/test/browser/fixtures/mocking/mocked-factory.test.ts @@ -1,5 +1,6 @@ import { expect, test, vi } from 'vitest' import { calculator, mocked } from './src/mocks_factory' +import factoryMany from './src/mocks_factory_many' vi.mock(import('./src/mocks_factory'), () => { return { @@ -8,7 +9,19 @@ vi.mock(import('./src/mocks_factory'), () => { } }) +vi.mock(import('./src/mocks_factory_many_dep1'), () => ({ + dep1: "dep1-mocked" +})) +vi.mock(import('./src/mocks_factory_many_dep2'), () => ({ + dep2: "dep2-mocked" +})) + test('adds', () => { expect(mocked).toBe(true) expect(calculator('plus', 1, 2)).toBe(1166) + + expect(factoryMany).toEqual({ + "dep1": "dep1-mocked", + "dep2": "dep2-mocked", + }) }) diff --git a/test/browser/fixtures/mocking/src/mocks_factory_many.ts b/test/browser/fixtures/mocking/src/mocks_factory_many.ts new file mode 100644 index 000000000000..bfe700a27a6e --- /dev/null +++ b/test/browser/fixtures/mocking/src/mocks_factory_many.ts @@ -0,0 +1,4 @@ +import { dep1 } from "./mocks_factory_many_dep1"; +import { dep2 } from "./mocks_factory_many_dep2"; + +export default { dep1, dep2 } diff --git a/test/browser/fixtures/mocking/src/mocks_factory_many_dep1.ts b/test/browser/fixtures/mocking/src/mocks_factory_many_dep1.ts new file mode 100644 index 000000000000..d54a6606c47b --- /dev/null +++ b/test/browser/fixtures/mocking/src/mocks_factory_many_dep1.ts @@ -0,0 +1 @@ +export const dep1: string = "dep1" diff --git a/test/browser/fixtures/mocking/src/mocks_factory_many_dep2.ts b/test/browser/fixtures/mocking/src/mocks_factory_many_dep2.ts new file mode 100644 index 000000000000..de52a9d31092 --- /dev/null +++ b/test/browser/fixtures/mocking/src/mocks_factory_many_dep2.ts @@ -0,0 +1 @@ +export const dep2: string = "dep2" From 80e8e8cc8e99194c0db583466a01991093b6f366 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 19 Sep 2024 11:33:54 +0900 Subject: [PATCH 3/3] chore: tweak types --- packages/browser/src/client/tester/msw.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/browser/src/client/tester/msw.ts b/packages/browser/src/client/tester/msw.ts index 45c2285ad3ef..d41eda2b0b8a 100644 --- a/packages/browser/src/client/tester/msw.ts +++ b/packages/browser/src/client/tester/msw.ts @@ -1,6 +1,7 @@ import { channel } from '@vitest/browser/client' import type { IframeChannelEvent, + IframeMockFactoryRequestEvent, IframeMockingDoneEvent, } from '@vitest/browser/client' import type { MockedModuleSerialized } from '@vitest/mocker' @@ -48,7 +49,7 @@ function getFactoryExports(id: string) { type: 'mock-factory:request', eventId, id, - }) + } satisfies IframeMockFactoryRequestEvent) return new Promise((resolve, reject) => { channel.addEventListener( 'message',