feat: refactor tests and improve mocking for file-service and GitHub polling

- Updated mocking strategy for node:fs and node:fs/promises in file-service tests.
- Removed redundant test files and improved test implementations for better clarity.
- Enhanced GitHub polling service tests with rate limiter integration.
This commit is contained in:
gsxdsm
2026-04-01 22:44:44 -07:00
parent 59a236adbd
commit dc442cf391
18 changed files with 28 additions and 1142 deletions

View File

@@ -17,6 +17,8 @@ vi.mock("lucide-react", () => ({
Lightbulb: () => null,
ListTree: () => null,
Zap: () => null,
ChevronDown: () => null,
ChevronUp: () => null,
}));
// Mock the api module
@@ -28,6 +30,7 @@ vi.mock("../../api", () => ({
defaultPresetBySize: {},
}),
uploadAttachment: vi.fn(),
updateGlobalSettings: vi.fn(),
}));
const MOCK_MODELS: ModelInfo[] = [

View File

@@ -1,69 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Use vi.mock with __mocks__ pattern
vi.mock("node:fs/promises", () => {
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", () => {
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import file-service
import { listProjectFiles } from "../file-service";
describe("debug", () => {
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/project");
mocks.mockStat.mockResolvedValue({
isDirectory: () => true,
isFile: () => false,
});
mocks.mockReaddir.mockResolvedValue([]);
console.log("Calling listProjectFiles...");
try {
const result = await listProjectFiles(mockStore, "./src");
console.log("Result:", result);
console.log("mockStat calls:", mocks.mockStat.mock.calls);
expect(result.path).toBe("src");
expect(result.entries).toEqual([]);
} catch (e) {
console.log("Error:", e);
console.log("mockStat calls:", mocks.mockStat.mock.calls);
throw e;
}
});
});

View File

@@ -1,80 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
import { dirname, resolve } from "path";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
const basePath = resolve("/test/project");
const filePath = "file.txt/sub.txt";
const resolvedPath = resolve(basePath, filePath);
const parentDir = dirname(resolvedPath);
// Test the mock directly
mocks.mockStat.mockResolvedValue({
isDirectory: () => false,
isFile: () => true,
});
const result = await mocks.mockStat("/test/some/path");
console.log("Direct mock result:", result);
console.log("Direct mock isDirectory():", result.isDirectory());
// Now test writeProjectFile
try {
await writeProjectFile(mockStore, filePath, "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,93 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
import { dirname, resolve } from "path";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// Track all stat calls
let callCount = 0;
mocks.mockStat.mockImplementation(async (path: string) => {
callCount++;
console.log(`stat call #${callCount}:`, path);
if (callCount === 1) {
// First call - file doesn't exist
throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
}
if (callCount === 2) {
// Second call - parent is a file
return {
isDirectory: () => false,
isFile: () => true,
};
}
if (callCount === 3) {
// Third call - after write
return {
isDirectory: () => false,
isFile: () => true,
size: 100,
mtime: new Date(),
};
}
throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,81 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
import { dirname, resolve } from "path";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
let callCount = 0;
mocks.mockStat.mockImplementation(async (path: string) => {
callCount++;
console.log(`stat call #${callCount}:`, path);
// Return a simple object
const result = {
isDirectory: () => path.includes("/file.txt"),
isFile: () => !path.includes("/file.txt"),
};
console.log(`stat #${callCount} returning:`, result);
console.log(`stat #${callCount} isDirectory():`, result.isDirectory());
return result;
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,80 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test - parent is not a directory", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// First call: file doesn't exist (throw ENOENT)
// Second call: parent is a file, not a directory (return object with isDirectory: false)
// Third call: after write, get file stats
mocks.mockStat
.mockRejectedValueOnce({ code: "ENOENT" }) // First: file doesn't exist
.mockResolvedValueOnce({ // Second: parent is a file
isDirectory: () => false,
isFile: () => true,
})
.mockResolvedValueOnce({ // Third: after write
isDirectory: () => false,
isFile: () => true,
size: 100,
mtime: new Date(),
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
expect(e.message).toContain("Parent is not a directory");
}
});
});

View File

@@ -1,79 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
mocks.mockStat.mockImplementation(async (path: string) => {
console.log("stat called:", path);
throw { code: "ENOENT" };
});
});
it("test - parent is not a directory", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// First call: file doesn't exist (throw ENOENT)
// Second call: parent is a file, not a directory (return object with isDirectory: false)
mocks.mockStat
.mockRejectedValueOnce({ code: "ENOENT" }) // First: file doesn't exist
.mockImplementation(async (path: string) => { // Subsequent calls
console.log("Second stat call:", path);
return {
isDirectory: () => false,
isFile: () => true,
};
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,63 +0,0 @@
import { describe, it, expect, vi } from "vitest";
import { writeProjectFile } from "../file-service";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
vi.mock("node:fs/promises", () => {
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", () => {
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
describe("debug", () => {
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
mocks.mockStat
.mockRejectedValueOnce({ code: "ENOENT" }) // File doesn't exist
.mockResolvedValueOnce({
isDirectory: () => false,
isFile: () => true,
}); // Parent is a file
console.log("mockStat calls before:", mocks.mockStat.mock.calls);
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
} catch (e) {
console.log("Error:", e);
console.log("mockStat calls after:", mocks.mockStat.mock.calls);
}
});
});

View File

@@ -1,68 +0,0 @@
import { describe, it, expect, vi } from "vitest";
import { writeProjectFile } from "../file-service";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
vi.mock("node:fs/promises", () => {
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", () => {
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
describe("debug", () => {
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// Setup mock to return specific values for each call
mocks.mockStat.mockImplementation((path: string) => {
console.log("stat called with:", path);
if (path === "/test/project/file.txt/sub.txt") {
return Promise.reject({ code: "ENOENT" });
}
if (path === "/test/project/file.txt") {
return Promise.resolve({
isDirectory: () => false,
isFile: () => true,
});
}
return Promise.reject({ code: "ENOENT" });
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
} catch (e) {
console.log("Error:", e);
}
});
});

View File

@@ -1,78 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// Setup mock to return specific values for each call
mocks.mockStat.mockImplementation((path: string) => {
console.log("stat called with:", path);
if (path === "/test/project/file.txt/sub.txt") {
return Promise.reject({ code: "ENOENT" });
}
if (path === "/test/project/file.txt") {
return Promise.resolve({
isDirectory: () => false,
isFile: () => true,
});
}
return Promise.reject({ code: "ENOENT" });
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,77 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
mocks.mockStat.mockImplementation((path: string) => {
console.log("stat called with:", path);
if (path === "/test/project/file.txt/sub.txt") {
return Promise.reject({ code: "ENOENT" });
}
if (path === "/test/project/file.txt") {
return Promise.resolve({
isDirectory: () => false,
isFile: () => true,
});
}
return Promise.reject({ code: "ENOENT" });
});
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
expect(e.message).toContain("Parent is not a directory");
}
});
});

View File

@@ -1,74 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// Setup mock
mocks.mockStat
.mockRejectedValueOnce({ code: "ENOENT" }) // First call - file doesn't exist
.mockResolvedValueOnce({ // Second call - parent is a file
isDirectory: () => false,
isFile: () => true,
});
console.log("Before call");
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
console.log("mockStat calls:", mocks.mockStat.mock.calls);
}
});
});

View File

@@ -1,80 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// Setup mock to return specific values
mocks.mockStat.mockImplementation(async (path: string) => {
console.log("stat called:", path);
if (path === "/test/project/file.txt/sub.txt") {
throw { code: "ENOENT" };
}
if (path === "/test/project/file.txt") {
const result = {
isDirectory: () => false,
isFile: () => true,
};
console.log("Returning for parent:", result);
return result;
}
throw { code: "ENOENT" };
});
try {
await writeProjectFile(mockStore, "file.txt/sub.txt", "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,93 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
import { join, resolve, dirname } from "path";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
// Log what paths will be used
const basePath = resolve("/test/project");
const filePath = "file.txt/sub.txt";
const resolvedPath = resolve(basePath, filePath);
const parentDir = dirname(resolvedPath);
console.log("basePath:", basePath);
console.log("filePath:", filePath);
console.log("resolvedPath:", resolvedPath);
console.log("parentDir:", parentDir);
// Setup mock to return specific values
mocks.mockStat.mockImplementation(async (path: string) => {
console.log("stat called:", path);
if (path === resolvedPath) {
console.log("File path match!");
throw { code: "ENOENT" };
}
if (path === parentDir) {
console.log("Parent dir match!");
return {
isDirectory: () => false,
isFile: () => true,
};
}
console.log("No match for:", path);
throw { code: "ENOENT" };
});
try {
await writeProjectFile(mockStore, filePath, "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -1,93 +0,0 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { TaskStore } from "@fusion/core";
import { dirname, resolve } from "path";
// Create mock functions that can be configured in tests
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Hoist mocks alongside vi.mock
vi.mock("node:fs/promises", async () => {
const actual = await import("node:fs/promises");
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
};
});
vi.mock("node:fs", async () => {
const actual = await import("node:fs");
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
};
});
// Import AFTER mocks are set up
import { writeProjectFile } from "../file-service";
describe("debug", () => {
beforeEach(() => {
mocks.mockStat.mockReset();
});
it("test", async () => {
const mockGetRootDir = vi.fn();
const mockStore = {
getRootDir: mockGetRootDir,
} as unknown as TaskStore;
mockGetRootDir.mockReturnValue("/test/project");
const basePath = resolve("/test/project");
const filePath = "file.txt/sub.txt";
const resolvedPath = resolve(basePath, filePath);
const parentDir = dirname(resolvedPath);
// Create a proper stats object
const fileNotDirStats = {
isDirectory: () => false,
isFile: () => true,
size: 100,
mtime: new Date(),
};
// Setup mock - note: use .mockResolvedValue for promises
mocks.mockStat.mockImplementation(async (path: string) => {
console.log("stat called:", path);
if (path === resolvedPath) {
console.log("File path - throwing ENOENT");
throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
}
if (path === parentDir) {
console.log("Parent dir - returning file stats");
console.log("Returning:", fileNotDirStats);
console.log("isDirectory():", fileNotDirStats.isDirectory());
return fileNotDirStats;
}
throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
});
try {
await writeProjectFile(mockStore, filePath, "content");
console.log("Success!");
} catch (e: any) {
console.log("Error:", e.message);
}
});
});

View File

@@ -14,44 +14,34 @@ import {
} from "../file-service.js";
import type { TaskStore } from "@fusion/core";
// Create mock functions that can be configured in tests
// Use vi.hoisted to hoist alongside vi.mock
const mocks = vi.hoisted(() => ({
mockReaddir: vi.fn(),
mockReadFile: vi.fn(),
mockWriteFile: vi.fn(),
mockStat: vi.fn(),
mockExistsSync: vi.fn(),
}));
// Mock node:fs/promises
const mockReaddir = vi.fn();
const mockReadFile = vi.fn();
const mockWriteFile = vi.fn();
const mockStat = vi.fn();
// Hoist mocks alongside vi.mock - must include default export
vi.mock("node:fs/promises", () => {
vi.mock("node:fs/promises", async (importOriginal) => {
const actual = await importOriginal<typeof import("node:fs/promises")>();
return {
default: {
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
},
readdir: mocks.mockReaddir,
readFile: mocks.mockReadFile,
writeFile: mocks.mockWriteFile,
stat: mocks.mockStat,
...actual,
readdir: (...args: any[]) => mockReaddir(...args),
readFile: (...args: any[]) => mockReadFile(...args),
writeFile: (...args: any[]) => mockWriteFile(...args),
stat: (...args: any[]) => mockStat(...args),
};
});
vi.mock("node:fs", () => {
// Mock node:fs
const mockExistsSync = vi.fn();
vi.mock("node:fs", async (importOriginal) => {
const actual = await importOriginal<typeof import("node:fs")>();
return {
default: {
existsSync: mocks.mockExistsSync,
},
existsSync: mocks.mockExistsSync,
...actual,
existsSync: (...args: any[]) => mockExistsSync(...args),
};
});
// Export mocks for use in tests
export const { mockReaddir, mockReadFile, mockWriteFile, mockStat, mockExistsSync } = mocks;
describe("FileServiceError", () => {
it("constructor sets code and name correctly", () => {
const error = new FileServiceError("Test message", "ETEST");

View File

@@ -118,6 +118,7 @@ describe("GitHubPollingService", () => {
store: mockStore,
token: "test-token",
pollingIntervalMs: 60_000,
rateLimiter: new GitHubRateLimiter(),
});
mockGetBadgeStatusesBatch.mockReset();