fix(testing): preserve parallel module evaluation mocks
This commit is contained in:
@@ -113,6 +113,49 @@ describe("installModuleMockLifecycle active-test tracking", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("treats module-evaluation mocks from another file as persistent while a different test is active", () => {
|
||||||
|
// given
|
||||||
|
const events: string[] = []
|
||||||
|
let callerStack = "Error\n at file:///repo/tests/first.test.ts:5:1\n at test (native:1:11)"
|
||||||
|
let callerUrl = "file:///repo/tests/first.test.ts"
|
||||||
|
const mockApi = {
|
||||||
|
module: (specifier: string, factory: () => Record<string, unknown>) => {
|
||||||
|
events.push(`module:${specifier}:${String(factory().named)}`)
|
||||||
|
},
|
||||||
|
restore: mock(() => {
|
||||||
|
events.push("delegate:restore")
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
const { beginTestMockTracking, endTestMockTracking } = installModuleMockLifecycle(mockApi, {
|
||||||
|
getCallerStack: () => callerStack,
|
||||||
|
getCallerUrl: () => callerUrl,
|
||||||
|
trackOnlyDuringActiveTest: true,
|
||||||
|
isPersistentModuleMockOwner: () => true,
|
||||||
|
resolveSpecifier: (specifier, ownerUrl) => `resolved:${ownerUrl}:${specifier}`,
|
||||||
|
loadOriginalModule: () => ({ ok: true, value: { named: "original" } }),
|
||||||
|
})
|
||||||
|
|
||||||
|
beginTestMockTracking()
|
||||||
|
callerStack = "Error\n at file:///repo/tests/second.test.ts:5:1\n at moduleEvaluation (native:1:11)"
|
||||||
|
callerUrl = "file:///repo/tests/second.test.ts"
|
||||||
|
mockApi.module("./dependency", () => ({ named: "top-level second" }))
|
||||||
|
|
||||||
|
// when
|
||||||
|
callerStack = "Error\n at file:///repo/tests/first.test.ts:10:1\n at cleanup (native:1:11)"
|
||||||
|
callerUrl = "file:///repo/tests/first.test.ts"
|
||||||
|
mockApi.restore()
|
||||||
|
endTestMockTracking()
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(events).toEqual([
|
||||||
|
"module:./dependency:top-level second",
|
||||||
|
"delegate:restore",
|
||||||
|
"module:./dependency:top-level second",
|
||||||
|
"module:resolved:file:///repo/tests/second.test.ts:./dependency:top-level second",
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
test("clears persistent module-evaluation snapshots when restore runs while inactive", () => {
|
test("clears persistent module-evaluation snapshots when restore runs while inactive", () => {
|
||||||
// given
|
// given
|
||||||
const events: string[] = []
|
const events: string[] = []
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createRequire } from "node:module"
|
import { createRequire } from "node:module"
|
||||||
import { fileURLToPath } from "node:url"
|
import { fileURLToPath } from "node:url"
|
||||||
import { defaultGetCallerStack, resolveCallerUrlFromStack } from "./module-mock-stack"
|
import { defaultGetCallerStack, isModuleEvaluationStack, resolveCallerUrlFromStack } from "./module-mock-stack"
|
||||||
import { createRestoreExports } from "./module-mock-restore-exports"
|
import { createRestoreExports } from "./module-mock-restore-exports"
|
||||||
|
|
||||||
type MockModuleFactory = () => Record<string, unknown>
|
type MockModuleFactory = () => Record<string, unknown>
|
||||||
@@ -98,6 +98,7 @@ export function installModuleMockLifecycle(
|
|||||||
let lastRestoredSnapshots: ModuleSnapshot[] = []
|
let lastRestoredSnapshots: ModuleSnapshot[] = []
|
||||||
let isActiveTest = !options.trackOnlyDuringActiveTest
|
let isActiveTest = !options.trackOnlyDuringActiveTest
|
||||||
let hasStartedTest = false
|
let hasStartedTest = false
|
||||||
|
let activeTestOwnerUrl: string | null = null
|
||||||
const delegateModule = mockApi.module.bind(mockApi)
|
const delegateModule = mockApi.module.bind(mockApi)
|
||||||
const delegateRestore = mockApi.restore.bind(mockApi)
|
const delegateRestore = mockApi.restore.bind(mockApi)
|
||||||
const getCallerStack = options.getCallerStack ?? defaultGetCallerStack
|
const getCallerStack = options.getCallerStack ?? defaultGetCallerStack
|
||||||
@@ -200,18 +201,27 @@ export function installModuleMockLifecycle(
|
|||||||
function beginTestMockTracking(): void {
|
function beginTestMockTracking(): void {
|
||||||
hasStartedTest = true
|
hasStartedTest = true
|
||||||
isActiveTest = true
|
isActiveTest = true
|
||||||
|
const callerStack = getCallerStack()
|
||||||
|
activeTestOwnerUrl = getCallerUrl(callerStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
function endTestMockTracking(): void {
|
function endTestMockTracking(): void {
|
||||||
isActiveTest = !options.trackOnlyDuringActiveTest
|
isActiveTest = !options.trackOnlyDuringActiveTest
|
||||||
|
activeTestOwnerUrl = null
|
||||||
}
|
}
|
||||||
|
|
||||||
mockApi.module = (specifier: string, factory: MockModuleFactory): unknown => {
|
mockApi.module = (specifier: string, factory: MockModuleFactory): unknown => {
|
||||||
lastRestoredSnapshots = []
|
lastRestoredSnapshots = []
|
||||||
const callerStack = getCallerStack()
|
const callerStack = getCallerStack()
|
||||||
const callerUrl = getCallerUrl(callerStack)
|
const callerUrl = getCallerUrl(callerStack)
|
||||||
|
const isParallelFileEvaluationMock =
|
||||||
|
isActiveTest &&
|
||||||
|
options.trackOnlyDuringActiveTest === true &&
|
||||||
|
activeTestOwnerUrl !== null &&
|
||||||
|
callerUrl !== activeTestOwnerUrl &&
|
||||||
|
isModuleEvaluationStack(callerStack)
|
||||||
|
|
||||||
if (!isActiveTest && isPersistentModuleMockOwner(callerUrl)) {
|
if ((!isActiveTest || isParallelFileEvaluationMock) && isPersistentModuleMockOwner(callerUrl)) {
|
||||||
const resolvedSpecifier = resolveSpecifier(specifier, callerUrl)
|
const resolvedSpecifier = resolveSpecifier(specifier, callerUrl)
|
||||||
const snapshotsByOwner = persistentSnapshots.get(resolvedSpecifier) ?? new Map<string, PersistentModuleSnapshot>()
|
const snapshotsByOwner = persistentSnapshots.get(resolvedSpecifier) ?? new Map<string, PersistentModuleSnapshot>()
|
||||||
const existingSnapshot = snapshotsByOwner.get(callerUrl)
|
const existingSnapshot = snapshotsByOwner.get(callerUrl)
|
||||||
|
|||||||
Reference in New Issue
Block a user