fix: prevent node:fs mock pollution in directory injector tests

Move mock.module() calls from top-level to beforeEach and restore in
afterEach to prevent readFileSync mock from leaking into other test
files. Use dynamic import with cache-busting query to get fresh modules.
This commit is contained in:
YeonGyu-Kim 2026-02-14 16:19:40 +09:00
parent f27733eae2
commit 945329e261
2 changed files with 84 additions and 34 deletions

View File

@ -1,12 +1,39 @@
import { beforeEach, describe, expect, it, mock } from "bun:test" import { beforeEach, afterEach, describe, expect, it, mock, afterAll } from "bun:test"
const readFileSyncMock = mock((_: string, __: string) => "# AGENTS") const realNodeFs = await import("node:fs")
const realFinder = await import("./finder")
const realStorage = await import("./storage")
const originalReadFileSync = realNodeFs.readFileSync
const readFileSyncMock = mock((filePath: string, encoding?: string) => {
if (String(filePath).endsWith("AGENTS.md")) {
return "# AGENTS"
}
return originalReadFileSync(filePath as never, encoding as never)
})
const findAgentsMdUpMock = mock((_: { startDir: string; rootDir: string }) => [] as string[]) const findAgentsMdUpMock = mock((_: { startDir: string; rootDir: string }) => [] as string[])
const resolveFilePathMock = mock((_: string, path: string) => path) const resolveFilePathMock = mock((_: string, path: string) => path)
const loadInjectedPathsMock = mock((_: string) => new Set<string>()) const loadInjectedPathsMock = mock((_: string) => new Set<string>())
const saveInjectedPathsMock = mock((_: string, __: Set<string>) => {}) const saveInjectedPathsMock = mock((_: string, __: Set<string>) => {})
afterAll(() => {
mock.module("node:fs", () => ({ ...realNodeFs }))
mock.module("./finder", () => ({ ...realFinder }))
mock.module("./storage", () => ({ ...realStorage }))
})
let processFilePathForAgentsInjection: typeof import("./injector").processFilePathForAgentsInjection
describe("processFilePathForAgentsInjection", () => {
beforeEach(async () => {
readFileSyncMock.mockClear()
findAgentsMdUpMock.mockClear()
resolveFilePathMock.mockClear()
loadInjectedPathsMock.mockClear()
saveInjectedPathsMock.mockClear()
mock.module("node:fs", () => ({ mock.module("node:fs", () => ({
...realNodeFs,
readFileSync: readFileSyncMock, readFileSync: readFileSyncMock,
})) }))
@ -20,15 +47,13 @@ mock.module("./storage", () => ({
saveInjectedPaths: saveInjectedPathsMock, saveInjectedPaths: saveInjectedPathsMock,
})) }))
const { processFilePathForAgentsInjection } = await import("./injector") ;({ processFilePathForAgentsInjection } = await import(`./injector?${Date.now()}`))
})
describe("processFilePathForAgentsInjection", () => { afterEach(() => {
beforeEach(() => { mock.module("node:fs", () => ({ ...realNodeFs }))
readFileSyncMock.mockClear() mock.module("./finder", () => ({ ...realFinder }))
findAgentsMdUpMock.mockClear() mock.module("./storage", () => ({ ...realStorage }))
resolveFilePathMock.mockClear()
loadInjectedPathsMock.mockClear()
saveInjectedPathsMock.mockClear()
}) })
it("does not save when all discovered paths are already cached", async () => { it("does not save when all discovered paths are already cached", async () => {

View File

@ -1,12 +1,39 @@
import { beforeEach, describe, expect, it, mock } from "bun:test" import { beforeEach, afterEach, describe, expect, it, mock, afterAll } from "bun:test"
const readFileSyncMock = mock((_: string, __: string) => "# README") const realNodeFs = await import("node:fs")
const realFinder = await import("./finder")
const realStorage = await import("./storage")
const originalReadFileSync = realNodeFs.readFileSync
const readFileSyncMock = mock((filePath: string, encoding?: string) => {
if (String(filePath).endsWith("README.md")) {
return "# README"
}
return originalReadFileSync(filePath as never, encoding as never)
})
const findReadmeMdUpMock = mock((_: { startDir: string; rootDir: string }) => [] as string[]) const findReadmeMdUpMock = mock((_: { startDir: string; rootDir: string }) => [] as string[])
const resolveFilePathMock = mock((_: string, path: string) => path) const resolveFilePathMock = mock((_: string, path: string) => path)
const loadInjectedPathsMock = mock((_: string) => new Set<string>()) const loadInjectedPathsMock = mock((_: string) => new Set<string>())
const saveInjectedPathsMock = mock((_: string, __: Set<string>) => {}) const saveInjectedPathsMock = mock((_: string, __: Set<string>) => {})
afterAll(() => {
mock.module("node:fs", () => ({ ...realNodeFs }))
mock.module("./finder", () => ({ ...realFinder }))
mock.module("./storage", () => ({ ...realStorage }))
})
let processFilePathForReadmeInjection: typeof import("./injector").processFilePathForReadmeInjection
describe("processFilePathForReadmeInjection", () => {
beforeEach(async () => {
readFileSyncMock.mockClear()
findReadmeMdUpMock.mockClear()
resolveFilePathMock.mockClear()
loadInjectedPathsMock.mockClear()
saveInjectedPathsMock.mockClear()
mock.module("node:fs", () => ({ mock.module("node:fs", () => ({
...realNodeFs,
readFileSync: readFileSyncMock, readFileSync: readFileSyncMock,
})) }))
@ -20,15 +47,13 @@ mock.module("./storage", () => ({
saveInjectedPaths: saveInjectedPathsMock, saveInjectedPaths: saveInjectedPathsMock,
})) }))
const { processFilePathForReadmeInjection } = await import("./injector") ;({ processFilePathForReadmeInjection } = await import(`./injector?${Date.now()}`))
})
describe("processFilePathForReadmeInjection", () => { afterEach(() => {
beforeEach(() => { mock.module("node:fs", () => ({ ...realNodeFs }))
readFileSyncMock.mockClear() mock.module("./finder", () => ({ ...realFinder }))
findReadmeMdUpMock.mockClear() mock.module("./storage", () => ({ ...realStorage }))
resolveFilePathMock.mockClear()
loadInjectedPathsMock.mockClear()
saveInjectedPathsMock.mockClear()
}) })
it("does not save when all discovered paths are already cached", async () => { it("does not save when all discovered paths are already cached", async () => {