

























@@ -24,39 +24,43 @@ vi.mock("../infra/file-lock.js", () => ({
2424withFileLock: async (_path: string, _options: unknown, fn: () => unknown) => await fn(),
2525}));
262627-vi.mock("../plugin-sdk/json-store.js", async () => {
28-const fs = await import("node:fs/promises");
29-const path = await import("node:path");
30-31-return {
32-readJsonFileWithFallback: async <T>(filePath: string, fallback: T) => {
33-let raw: string;
34-try {
35-raw = await fs.readFile(filePath, "utf8");
36-} catch (err) {
37-if ((err as { code?: string }).code === "ENOENT") {
38-return { value: fallback, exists: false };
39-}
27+const jsonStoreMocks = vi.hoisted(() => ({
28+readJsonFileWithFallback: vi.fn(async <T>(filePath: string, fallback: T) => {
29+const fs = await import("node:fs/promises");
30+let raw: string;
31+try {
32+raw = await fs.readFile(filePath, "utf8");
33+} catch (err) {
34+if ((err as { code?: string }).code === "ENOENT") {
4035return { value: fallback, exists: false };
4136}
42-try {
43-const parsed = JSON.parse(raw) as T;
44-return {
45-value: parsed ?? fallback,
46-exists: true,
47-};
48-} catch {
49-return { value: fallback, exists: true };
50-}
51-},
52-writeJsonFileAtomically: async (filePath: string, value: unknown) => {
53-await fs.mkdir(path.dirname(filePath), { recursive: true });
54-await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
55-},
37+return { value: fallback, exists: false };
38+}
39+try {
40+const parsed = JSON.parse(raw) as T;
41+return {
42+value: parsed ?? fallback,
43+exists: true,
44+};
45+} catch {
46+return { value: fallback, exists: true };
47+}
48+}),
49+writeJsonFileAtomically: vi.fn(async (filePath: string, value: unknown) => {
50+const fs = await import("node:fs/promises");
51+const path = await import("node:path");
52+await fs.mkdir(path.dirname(filePath), { recursive: true });
53+await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
54+}),
55+}));
56+57+vi.mock("../plugin-sdk/json-store.js", () => {
58+return {
59+readJsonFileWithFallback: jsonStoreMocks.readJsonFileWithFallback,
60+writeJsonFileAtomically: jsonStoreMocks.writeJsonFileAtomically,
5661};
5762});
586359-import * as jsonStore from "../plugin-sdk/json-store.js";
6064import {
6165addChannelAllowFromStoreEntry,
6266clearPairingAllowFromReadCacheForTest,
@@ -73,6 +77,7 @@ import {
7377let fixtureRoot = "";
7478let caseId = 0;
7579type RandomIntSync = (minOrMax: number, max?: number) => number;
80+type ReadSpy = ReturnType<typeof vi.fn> | MockInstance;
76817782let randomIntSpy: MockInstance<RandomIntSync>;
7883let nextRandomInt = 0;
@@ -176,9 +181,7 @@ async function seedTelegramAllowFromFixtures(params: {
176181async function assertAllowFromCacheInvalidation(params: {
177182stateDir: string;
178183readAllowFrom: () => Promise<string[]>;
179-readSpy: {
180-mockRestore: () => void;
181-};
184+readSpy: ReadSpy;
182185}) {
183186const first = await params.readAllowFrom();
184187const second = await params.readAllowFrom();
@@ -206,9 +209,8 @@ async function expectAccountScopedEntryIsolated(entry: string, accountId = "yy")
206209207210async function withAllowFromCacheReadSpy(params: {
208211stateDir: string;
209-createReadSpy: () => {
210-mockRestore: () => void;
211-};
212+createReadSpy: () => ReadSpy;
213+cleanupReadSpy?: (readSpy: ReadSpy) => void;
212214readAllowFrom: () => Promise<string[]>;
213215}) {
214216await writeAllowFromFixture({
@@ -218,12 +220,15 @@ async function withAllowFromCacheReadSpy(params: {
218220allowFrom: ["1001"],
219221});
220222const readSpy = params.createReadSpy();
221-await assertAllowFromCacheInvalidation({
222-stateDir: params.stateDir,
223-readAllowFrom: params.readAllowFrom,
224- readSpy,
225-});
226-readSpy.mockRestore();
223+try {
224+await assertAllowFromCacheInvalidation({
225+stateDir: params.stateDir,
226+readAllowFrom: params.readAllowFrom,
227+ readSpy,
228+});
229+} finally {
230+params.cleanupReadSpy?.(readSpy);
231+}
227232}
228233229234async function seedDefaultAccountAllowFromFixture(stateDir: string) {
@@ -577,23 +582,25 @@ describe("pairing store", () => {
577582578583it("reuses cached allowFrom reads and invalidates on file updates", async () => {
579584await withTempStateDir(async (stateDir) => {
580-for (const variant of [
581-{
582-createReadSpy: () => vi.spyOn(jsonStore, "readJsonFileWithFallback"),
583-readAllowFrom: () => readChannelAllowFromStore("telegram", process.env, "yy"),
585+clearOAuthFixtures(stateDir);
586+await withAllowFromCacheReadSpy({
587+ stateDir,
588+createReadSpy: () => {
589+jsonStoreMocks.readJsonFileWithFallback.mockClear();
590+return jsonStoreMocks.readJsonFileWithFallback;
584591},
585-{
586-createReadSpy: () => vi.spyOn(fsSync, "readFileSync"),
587-readAllowFrom: async () => readChannelAllowFromStoreSync("telegram", process.env, "yy"),
592+readAllowFrom: () => readChannelAllowFromStore("telegram", process.env, "yy"),
593+});
594+595+clearOAuthFixtures(stateDir);
596+await withAllowFromCacheReadSpy({
597+ stateDir,
598+createReadSpy: () => vi.spyOn(fsSync, "readFileSync"),
599+cleanupReadSpy: (readSpy) => {
600+readSpy.mockRestore();
588601},
589-]) {
590-clearOAuthFixtures(stateDir);
591-await withAllowFromCacheReadSpy({
592- stateDir,
593-createReadSpy: variant.createReadSpy,
594-readAllowFrom: variant.readAllowFrom,
595-});
596-}
602+readAllowFrom: async () => readChannelAllowFromStoreSync("telegram", process.env, "yy"),
603+});
597604});
598605});
599606});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。