fix(testing): preserve mock restore export identity

This commit is contained in:
YeonGyu-Kim
2026-05-30 12:19:08 +09:00
parent d32caf3d87
commit 68f02e61ef
2 changed files with 19 additions and 14 deletions
+10 -9
View File
@@ -4,8 +4,9 @@ import { describe, expect, mock, test } from "bun:test"
import { installModuleMockLifecycle } from "./module-mock-lifecycle" import { installModuleMockLifecycle } from "./module-mock-lifecycle"
describe("installModuleMockLifecycle", () => { describe("installModuleMockLifecycle", () => {
test("restores the original module exports on mock.restore", () => { test("restores the original module export object instead of a cloned snapshot", () => {
// given // given
const originalExports = { named: "original" }
const moduleCalls: Array<{ specifier: string; value: Record<string, unknown> }> = [] const moduleCalls: Array<{ specifier: string; value: Record<string, unknown> }> = []
const mockApi = { const mockApi = {
module: (specifier: string, factory: () => Record<string, unknown>) => { module: (specifier: string, factory: () => Record<string, unknown>) => {
@@ -17,7 +18,7 @@ describe("installModuleMockLifecycle", () => {
installModuleMockLifecycle(mockApi, { installModuleMockLifecycle(mockApi, {
getCallerUrl: () => "file:///repo/tests/example.test.ts", getCallerUrl: () => "file:///repo/tests/example.test.ts",
resolveSpecifier: (specifier) => `resolved:${specifier}`, resolveSpecifier: (specifier) => `resolved:${specifier}`,
loadOriginalModule: () => ({ ok: true, value: { named: "original" } }), loadOriginalModule: () => ({ ok: true, value: originalExports }),
}) })
// when // when
@@ -25,13 +26,12 @@ describe("installModuleMockLifecycle", () => {
mockApi.restore() mockApi.restore()
// then // then
expect(moduleCalls).toEqual([ expect(moduleCalls.map((call) => call.specifier)).toEqual(["./dependency", "resolved:./dependency"])
{ specifier: "./dependency", value: { named: "mocked" } }, const restoreCall = moduleCalls.find((call) => call.specifier === "resolved:./dependency")
{ specifier: "resolved:./dependency", value: { named: "original" } }, expect(restoreCall?.value).toBe(originalExports)
])
}) })
test("restores original exports after the delegate restore runs", () => { test("clears tracked snapshots after the delegate restore runs", () => {
// given // given
const events: string[] = [] const events: string[] = []
const mockApi = { const mockApi = {
@@ -43,7 +43,7 @@ describe("installModuleMockLifecycle", () => {
}), }),
} }
installModuleMockLifecycle(mockApi, { const { restoreModuleMocks } = installModuleMockLifecycle(mockApi, {
getCallerUrl: () => "file:///repo/tests/example.test.ts", getCallerUrl: () => "file:///repo/tests/example.test.ts",
resolveSpecifier: (specifier) => `resolved:${specifier}`, resolveSpecifier: (specifier) => `resolved:${specifier}`,
loadOriginalModule: () => ({ ok: true, value: { named: "original" } }), loadOriginalModule: () => ({ ok: true, value: { named: "original" } }),
@@ -52,6 +52,7 @@ describe("installModuleMockLifecycle", () => {
// when // when
mockApi.module("./dependency", () => ({ named: "mocked" })) mockApi.module("./dependency", () => ({ named: "mocked" }))
mockApi.restore() mockApi.restore()
restoreModuleMocks()
// then // then
expect(events).toEqual([ expect(events).toEqual([
@@ -65,7 +66,7 @@ describe("installModuleMockLifecycle", () => {
// given // given
let loadCount = 0 let loadCount = 0
const mockApi = { const mockApi = {
module: mock(() => {}), module: mock((_specifier: string, _factory: () => Record<string, unknown>) => {}),
restore: mock(() => {}), restore: mock(() => {}),
} }
+9 -5
View File
@@ -31,7 +31,11 @@ function toError(error: unknown): Error {
return new Error(String(error)) return new Error(String(error))
} }
function cloneModuleExports(moduleValue: unknown): Record<string, unknown> { function isModuleExports(moduleValue: unknown): moduleValue is Record<string, unknown> {
return moduleValue !== null && typeof moduleValue === "object"
}
function createRestoreExports(moduleValue: unknown): Record<string, unknown> {
if (typeof moduleValue === "function") { if (typeof moduleValue === "function") {
const functionExports = Object.assign({}, moduleValue) const functionExports = Object.assign({}, moduleValue)
return { return {
@@ -40,8 +44,8 @@ function cloneModuleExports(moduleValue: unknown): Record<string, unknown> {
} }
} }
if (moduleValue && typeof moduleValue === "object") { if (isModuleExports(moduleValue)) {
return { ...(moduleValue as Record<string, unknown>) } return moduleValue
} }
return { default: moduleValue } return { default: moduleValue }
@@ -123,10 +127,10 @@ export function installModuleMockLifecycle(
const originalModule = loadOriginalModule(specifier, callerUrl) const originalModule = loadOriginalModule(specifier, callerUrl)
if (originalModule.ok) { if (originalModule.ok) {
const clonedExports = cloneModuleExports(originalModule.value) const restoreExports = createRestoreExports(originalModule.value)
snapshots.set(restoreSpecifier, { snapshots.set(restoreSpecifier, {
restoreSpecifier, restoreSpecifier,
restoreFactory: () => ({ ...clonedExports }), restoreFactory: () => restoreExports,
}) })
} }
} }