mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-22 20:41:39 -08:00
test: support run as electron so can use sqlite3 compiled bin for electron
This commit is contained in:
parent
e8630a993d
commit
f44c51e2c8
6 changed files with 421 additions and 24 deletions
|
|
@ -14,8 +14,8 @@
|
|||
"start:dev:debug-react": "cross-env NODE_ENV=development DEBUG_REACT=true electron-forge start",
|
||||
"build:plugin": "zx scripts/compilePlugins.mjs",
|
||||
"test": "pnpm run test:unit && pnpm run package && pnpm run test:e2e",
|
||||
"test:unit": "vitest run",
|
||||
"test:unit:coverage": "vitest run --coverage",
|
||||
"test:unit": "chcp 65001 && cross-env LANG=en_US.UTF-8 ELECTRON_RUN_AS_NODE=true ./node_modules/.bin/electron ./node_modules/vitest/vitest.mjs run",
|
||||
"test:unit:coverage": "pnpm run test:unit -- --coverage",
|
||||
"test:e2e": "cross-env NODE_ENV=test cucumber-js --config features/cucumber.config.js",
|
||||
"package": "pnpm run build:plugin && cross-env NODE_ENV=test electron-forge package",
|
||||
"make": "pnpm run build:plugin && cross-env NODE_ENV=production electron-forge make",
|
||||
|
|
@ -138,6 +138,7 @@
|
|||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/bluebird": "3.5.42",
|
||||
"@types/chai": "5.0.1",
|
||||
"@types/circular-dependency-plugin": "5.0.8",
|
||||
|
|
|
|||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
|
@ -310,6 +310,9 @@ importers:
|
|||
'@testing-library/user-event':
|
||||
specifier: ^14.6.1
|
||||
version: 14.6.1(@testing-library/dom@10.4.0)
|
||||
'@types/better-sqlite3':
|
||||
specifier: ^7.6.13
|
||||
version: 7.6.13
|
||||
'@types/bluebird':
|
||||
specifier: 3.5.42
|
||||
version: 3.5.42
|
||||
|
|
@ -2185,6 +2188,9 @@ packages:
|
|||
'@types/aria-query@5.0.4':
|
||||
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
||||
|
||||
'@types/better-sqlite3@7.6.13':
|
||||
resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==}
|
||||
|
||||
'@types/bluebird@3.5.42':
|
||||
resolution: {integrity: sha512-Jhy+MWRlro6UjVi578V/4ZGNfeCOcNCp0YaFNIUGFKlImowqwb1O/22wDVk3FDGMLqxdpOV3qQHD5fPEH4hK6A==}
|
||||
|
||||
|
|
@ -10266,6 +10272,10 @@ snapshots:
|
|||
|
||||
'@types/aria-query@5.0.4': {}
|
||||
|
||||
'@types/better-sqlite3@7.6.13':
|
||||
dependencies:
|
||||
'@types/node': 22.13.0
|
||||
|
||||
'@types/bluebird@3.5.42': {}
|
||||
|
||||
'@types/body-parser@1.19.2':
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => {
|
|||
);
|
||||
expect(historyPlugin).toBeDefined();
|
||||
expect(historyPlugin!.fullReplacementParam!.targetId).toBe('default-history'); // Real target ID
|
||||
|
||||
|
||||
// Use real prompts structure from defaultAgents.json
|
||||
const testPrompts = cloneDeep(realHandlerConfig.prompts) as IPrompt[];
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => {
|
|||
const targetId = historyPlugin!.fullReplacementParam!.targetId; // 'default-history'
|
||||
const historyPrompt = testPrompts.find(p => p.id === 'history');
|
||||
expect(historyPrompt).toBeDefined();
|
||||
|
||||
|
||||
const targetPrompt = historyPrompt!.children?.find(child => child.id === targetId);
|
||||
expect(targetPrompt).toBeDefined();
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => {
|
|||
const historyPlugin = realHandlerConfig.plugins.find(
|
||||
p => p.pluginId === 'fullReplacement' && p.fullReplacementParam?.sourceType === 'historyOfSession',
|
||||
);
|
||||
|
||||
|
||||
const messages: AgentInstanceMessage[] = [
|
||||
{
|
||||
id: 'user-msg-1',
|
||||
|
|
@ -298,7 +298,7 @@ describe('Full Replacement Plugin - Duration Mechanism', () => {
|
|||
expect(childrenText).toContain('Message 1 - no duration');
|
||||
expect(childrenText).toContain('Message 2 - duration 3');
|
||||
expect(childrenText).toContain('Message 3 - duration 1'); // roundsFromCurrent(0) < duration(1)
|
||||
|
||||
|
||||
// Last message should be removed by fullReplacement
|
||||
expect(childrenText).not.toContain('Message 4 - latest');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,368 @@
|
|||
/**
|
||||
* Deep integration tests for messageManagementPlugin with real SQLite database
|
||||
* Tests actual message persistence scenarios using defaultAgents.json configuration
|
||||
*/
|
||||
import {
|
||||
AgentDefinitionEntity,
|
||||
AgentInstanceEntity,
|
||||
AgentInstanceMessageEntity,
|
||||
} from "@services/database/schema/agent";
|
||||
import { DataSource } from "typeorm";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { AgentInstanceMessage } from "../../interface";
|
||||
import defaultAgents from "../../buildInAgentHandlers/defaultAgents.json";
|
||||
|
||||
// Mock the dependencies BEFORE importing the plugin
|
||||
vi.mock("@services/container", () => ({
|
||||
container: {
|
||||
get: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("@services/serviceIdentifier", () => ({
|
||||
default: {
|
||||
AgentInstance: Symbol.for("AgentInstance"),
|
||||
},
|
||||
}));
|
||||
|
||||
// Import plugin after mocks are set up
|
||||
import { createHandlerHooks } from "../index";
|
||||
import { messageManagementPlugin } from "../messageManagementPlugin";
|
||||
import type { ToolExecutionContext, UserMessageContext } from "../types";
|
||||
|
||||
// Use the real agent config from defaultAgents.json
|
||||
const exampleAgent = defaultAgents[0];
|
||||
|
||||
describe("Message Management Plugin - Real Database Integration", () => {
|
||||
let dataSource: DataSource;
|
||||
let testAgentId: string;
|
||||
let realAgentInstanceService: {
|
||||
saveUserMessage: (message: AgentInstanceMessage) => Promise<void>;
|
||||
debounceUpdateMessage: (
|
||||
message: AgentInstanceMessage,
|
||||
agentId?: string,
|
||||
) => void;
|
||||
updateAgent: (
|
||||
agentId: string,
|
||||
updates: Record<string, unknown>,
|
||||
) => Promise<void>;
|
||||
};
|
||||
let hooks: ReturnType<typeof createHandlerHooks>;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
testAgentId = `test-agent-${Date.now()}`;
|
||||
|
||||
// Create in-memory SQLite database
|
||||
dataSource = new DataSource({
|
||||
type: "better-sqlite3",
|
||||
database: ":memory:",
|
||||
entities: [
|
||||
AgentDefinitionEntity,
|
||||
AgentInstanceEntity,
|
||||
AgentInstanceMessageEntity,
|
||||
],
|
||||
synchronize: true,
|
||||
logging: false,
|
||||
});
|
||||
|
||||
await dataSource.initialize();
|
||||
|
||||
// Create test data using defaultAgent structure
|
||||
const agentDefRepo = dataSource.getRepository(AgentDefinitionEntity);
|
||||
await agentDefRepo.save({
|
||||
id: exampleAgent.id,
|
||||
name: exampleAgent.name,
|
||||
});
|
||||
|
||||
const agentRepo = dataSource.getRepository(AgentInstanceEntity);
|
||||
await agentRepo.save({
|
||||
id: testAgentId,
|
||||
agentDefId: exampleAgent.id,
|
||||
name: `Instance of ${exampleAgent.name}`,
|
||||
status: { state: "working", modified: new Date() },
|
||||
created: new Date(),
|
||||
closed: false,
|
||||
});
|
||||
|
||||
// Create real service with spy for database operations
|
||||
realAgentInstanceService = {
|
||||
saveUserMessage: vi.fn(async (message: AgentInstanceMessage) => {
|
||||
const messageRepo = dataSource.getRepository(
|
||||
AgentInstanceMessageEntity,
|
||||
);
|
||||
await messageRepo.save({
|
||||
id: message.id,
|
||||
agentId: message.agentId,
|
||||
role: message.role,
|
||||
content: message.content,
|
||||
contentType: message.contentType || "text/plain",
|
||||
modified: message.modified || new Date(),
|
||||
metadata: message.metadata,
|
||||
duration: message.duration ?? undefined,
|
||||
});
|
||||
}),
|
||||
debounceUpdateMessage: vi.fn(),
|
||||
updateAgent: vi.fn(),
|
||||
};
|
||||
|
||||
// Configure mock container to return our service
|
||||
const { container } = await import("@services/container");
|
||||
vi.mocked(container.get).mockReturnValue(realAgentInstanceService);
|
||||
|
||||
// Initialize plugin
|
||||
hooks = createHandlerHooks();
|
||||
messageManagementPlugin(hooks);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (dataSource.isInitialized) {
|
||||
await dataSource.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
const createHandlerContext = (messages: AgentInstanceMessage[] = []) => ({
|
||||
agent: {
|
||||
id: testAgentId,
|
||||
agentDefId: exampleAgent.id,
|
||||
status: { state: "working" as const, modified: new Date() },
|
||||
created: new Date(),
|
||||
messages,
|
||||
},
|
||||
agentDef: {
|
||||
id: exampleAgent.id,
|
||||
name: exampleAgent.name,
|
||||
version: "1.0.0",
|
||||
capabilities: [],
|
||||
handlerConfig: exampleAgent.handlerConfig,
|
||||
},
|
||||
isCancelled: () => false,
|
||||
});
|
||||
|
||||
describe("Real Wiki Search Scenario - The Missing Tool Result Bug", () => {
|
||||
it("should persist all messages in wiki search flow: user query → AI tool call → tool result → AI final response", async () => {
|
||||
const handlerContext = createHandlerContext();
|
||||
|
||||
// Step 1: User asks to search wiki
|
||||
const userMessageId = `user-msg-${Date.now()}`;
|
||||
const userContext: UserMessageContext = {
|
||||
handlerContext,
|
||||
content: { text: "搜索 wiki 中的 Index 条目并解释" },
|
||||
messageId: userMessageId,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
|
||||
await hooks.userMessageReceived.promise(userContext);
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
// Verify user message was saved
|
||||
let messageRepo = dataSource.getRepository(AgentInstanceMessageEntity);
|
||||
let allMessages = await messageRepo.find({
|
||||
where: { agentId: testAgentId },
|
||||
});
|
||||
expect(allMessages).toHaveLength(1);
|
||||
expect(allMessages[0].content).toBe("搜索 wiki 中的 Index 条目并解释");
|
||||
expect(allMessages[0].role).toBe("user");
|
||||
|
||||
// Step 2: AI generates tool call (this gets persisted via responseComplete)
|
||||
const aiToolCallMessage: AgentInstanceMessage = {
|
||||
id: `ai-tool-call-${Date.now()}`,
|
||||
agentId: testAgentId,
|
||||
role: "assistant",
|
||||
content:
|
||||
'<tool_use name="wiki-search">{ "workspaceName": "wiki", "filter": "[title[Index]]" }</tool_use>',
|
||||
contentType: "text/plain",
|
||||
modified: new Date(),
|
||||
metadata: { isComplete: true },
|
||||
duration: undefined,
|
||||
};
|
||||
|
||||
await realAgentInstanceService.saveUserMessage(aiToolCallMessage);
|
||||
handlerContext.agent.messages.push(aiToolCallMessage);
|
||||
|
||||
// Step 3: Tool result message (THIS IS THE MISSING PIECE!)
|
||||
// This simulates what wikiSearchPlugin does when tool execution completes
|
||||
const toolResultMessage: AgentInstanceMessage = {
|
||||
id: `tool-result-${Date.now()}`,
|
||||
agentId: testAgentId,
|
||||
role: "user",
|
||||
content: `<functions_result>
|
||||
Tool: wiki-search
|
||||
Result: 在wiki中找到了名为"Index"的条目。这个条目包含以下内容:
|
||||
|
||||
# Index
|
||||
这是wiki的索引页面,包含了所有重要条目的链接和分类。主要分为以下几个部分:
|
||||
- 技术文档
|
||||
- 教程指南
|
||||
- 常见问题
|
||||
- 更新日志
|
||||
|
||||
该条目创建于2024年,是导航整个wiki内容的重要入口页面。
|
||||
</functions_result>`,
|
||||
contentType: "text/plain",
|
||||
modified: new Date(),
|
||||
metadata: {
|
||||
isToolResult: true,
|
||||
toolId: "wiki-search",
|
||||
isPersisted: false, // Key: starts as false, should be marked true after persistence
|
||||
},
|
||||
duration: 10, // Tool results might have expiration
|
||||
};
|
||||
|
||||
// Add tool result to agent messages (simulating what wikiSearchPlugin does)
|
||||
handlerContext.agent.messages.push(toolResultMessage);
|
||||
|
||||
const toolContext: ToolExecutionContext = {
|
||||
handlerContext,
|
||||
toolResult: {
|
||||
success: true,
|
||||
data: "Wiki search completed successfully",
|
||||
metadata: { duration: 1500 },
|
||||
},
|
||||
toolInfo: {
|
||||
toolId: "wiki-search",
|
||||
parameters: { workspaceName: "wiki", filter: "[title[Index]]" },
|
||||
},
|
||||
};
|
||||
|
||||
// This should trigger the toolExecuted hook that saves tool result messages
|
||||
await hooks.toolExecuted.promise(toolContext);
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
// Verify tool result message was persisted
|
||||
messageRepo = dataSource.getRepository(AgentInstanceMessageEntity);
|
||||
allMessages = await messageRepo.find({
|
||||
where: { agentId: testAgentId },
|
||||
order: { modified: "ASC" },
|
||||
});
|
||||
|
||||
expect(allMessages).toHaveLength(3); // user + ai tool call + tool result
|
||||
|
||||
const savedToolResult = allMessages.find((m) => m.metadata?.isToolResult);
|
||||
expect(savedToolResult).toBeTruthy();
|
||||
expect(savedToolResult?.content).toContain("<functions_result>");
|
||||
expect(savedToolResult?.content).toContain("Tool: wiki-search");
|
||||
expect(savedToolResult?.content).toContain("Index");
|
||||
expect(savedToolResult?.metadata?.toolId).toBe("wiki-search");
|
||||
expect(savedToolResult?.duration).toBe(10);
|
||||
|
||||
// Verify isPersisted flag was updated
|
||||
const toolMessageInMemory = handlerContext.agent.messages.find(
|
||||
(m) => m.metadata?.isToolResult,
|
||||
);
|
||||
expect(toolMessageInMemory?.metadata?.isPersisted).toBe(true);
|
||||
|
||||
// Step 4: AI final response based on tool result
|
||||
const aiFinalMessage: AgentInstanceMessage = {
|
||||
id: `ai-final-${Date.now()}`,
|
||||
agentId: testAgentId,
|
||||
role: "assistant",
|
||||
content:
|
||||
'在wiki中找到了名为"Index"的条目。这个条目包含以下内容:\n\n# Index\n这是wiki的索引页面,包含了所有重要条目的链接和分类。主要分为以下几个部分:\n- 技术文档\n- 教程指南\n- 常见问题\n- 更新日志\n\n该条目创建于2024年,是导航整个wiki内容的重要入口页面。这个Index条目作为整个wiki的导航中心,为用户提供了便捷的内容访问入口。',
|
||||
contentType: "text/plain",
|
||||
modified: new Date(),
|
||||
metadata: { isComplete: true },
|
||||
duration: undefined,
|
||||
};
|
||||
|
||||
await realAgentInstanceService.saveUserMessage(aiFinalMessage);
|
||||
|
||||
// Final verification: All 4 messages should be in database
|
||||
messageRepo = dataSource.getRepository(AgentInstanceMessageEntity);
|
||||
allMessages = await messageRepo.find({
|
||||
where: { agentId: testAgentId },
|
||||
order: { modified: "ASC" },
|
||||
});
|
||||
|
||||
expect(allMessages).toHaveLength(4);
|
||||
|
||||
// Verify the complete flow
|
||||
expect(allMessages[0].role).toBe("user"); // User query
|
||||
expect(allMessages[0].content).toBe("搜索 wiki 中的 Index 条目并解释");
|
||||
|
||||
expect(allMessages[1].role).toBe("assistant"); // AI tool call
|
||||
expect(allMessages[1].content).toContain('<tool_use name="wiki-search">');
|
||||
|
||||
expect(allMessages[2].role).toBe("user"); // Tool result (THIS WAS MISSING!)
|
||||
expect(allMessages[2].content).toContain("<functions_result>");
|
||||
expect(allMessages[2].metadata?.isToolResult).toBe(true);
|
||||
|
||||
expect(allMessages[3].role).toBe("assistant"); // AI final response
|
||||
expect(allMessages[3].content).toContain(
|
||||
'在wiki中找到了名为"Index"的条目',
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle multiple tool results in one execution", async () => {
|
||||
console.log("🧪 Testing multiple tool results persistence...");
|
||||
|
||||
const handlerContext = createHandlerContext();
|
||||
|
||||
// Add multiple tool result messages
|
||||
const toolResult1: AgentInstanceMessage = {
|
||||
id: `tool-result-1-${Date.now()}`,
|
||||
agentId: testAgentId,
|
||||
role: "user",
|
||||
content:
|
||||
"<functions_result>Tool: wiki-search\nResult: Found Index page</functions_result>",
|
||||
contentType: "text/plain",
|
||||
modified: new Date(),
|
||||
metadata: {
|
||||
isToolResult: true,
|
||||
toolId: "wiki-search",
|
||||
isPersisted: false,
|
||||
},
|
||||
duration: 5,
|
||||
};
|
||||
|
||||
const toolResult2: AgentInstanceMessage = {
|
||||
id: `tool-result-2-${Date.now()}`,
|
||||
agentId: testAgentId,
|
||||
role: "user",
|
||||
content:
|
||||
"<functions_result>Tool: wiki-search\nResult: Found related pages</functions_result>",
|
||||
contentType: "text/plain",
|
||||
modified: new Date(),
|
||||
metadata: {
|
||||
isToolResult: true,
|
||||
toolId: "wiki-search",
|
||||
isPersisted: false,
|
||||
},
|
||||
duration: 3,
|
||||
};
|
||||
|
||||
handlerContext.agent.messages.push(toolResult1, toolResult2);
|
||||
|
||||
const toolContext: ToolExecutionContext = {
|
||||
handlerContext,
|
||||
toolResult: {
|
||||
success: true,
|
||||
data: "Multiple tool search completed",
|
||||
},
|
||||
toolInfo: {
|
||||
toolId: "wiki-search",
|
||||
parameters: { workspaceName: "wiki" },
|
||||
},
|
||||
};
|
||||
|
||||
await hooks.toolExecuted.promise(toolContext);
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
// Verify both tool results were persisted
|
||||
const messageRepo = dataSource.getRepository(AgentInstanceMessageEntity);
|
||||
const allMessages = await messageRepo.find({
|
||||
where: { agentId: testAgentId },
|
||||
});
|
||||
|
||||
expect(allMessages).toHaveLength(2);
|
||||
expect(allMessages.every((m) => m.metadata?.isToolResult)).toBe(true);
|
||||
expect(allMessages.every((m) => m.role === "user")).toBe(true);
|
||||
|
||||
// Verify both messages marked as persisted
|
||||
expect(toolResult1.metadata?.isPersisted).toBe(true);
|
||||
expect(toolResult2.metadata?.isPersisted).toBe(true);
|
||||
|
||||
console.log("✅ Multiple tool results test passed");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -201,33 +201,46 @@ export const messageManagementPlugin: PromptConcatPlugin = (hooks) => {
|
|||
});
|
||||
|
||||
// Handle tool result messages persistence and UI updates
|
||||
hooks.toolExecuted.tapAsync('messageManagementPlugin', (context: ToolExecutionContext, callback) => {
|
||||
hooks.toolExecuted.tapAsync('messageManagementPlugin', async (context: ToolExecutionContext, callback) => {
|
||||
try {
|
||||
const { handlerContext } = context;
|
||||
|
||||
// Update UI for any newly added messages with duration settings
|
||||
const newMessages = handlerContext.agent.messages.filter(
|
||||
(message) => message.metadata?.isToolResult && !message.metadata.uiUpdated,
|
||||
// Find newly added tool result messages that need to be persisted
|
||||
const newToolResultMessages = handlerContext.agent.messages.filter(
|
||||
(message) => message.metadata?.isToolResult && !message.metadata.isPersisted,
|
||||
);
|
||||
|
||||
for (const message of newMessages) {
|
||||
const agentInstanceService = container.get<IAgentInstanceService>(serviceIdentifier.AgentInstance);
|
||||
|
||||
// Save tool result messages to database and update UI
|
||||
for (const message of newToolResultMessages) {
|
||||
try {
|
||||
const agentInstanceService = container.get<IAgentInstanceService>(serviceIdentifier.AgentInstance);
|
||||
// Save to database using the same method as user messages
|
||||
await agentInstanceService.saveUserMessage(message);
|
||||
|
||||
// Update UI
|
||||
agentInstanceService.debounceUpdateMessage(message, handlerContext.agent.id);
|
||||
// Mark as UI updated to avoid duplicate updates
|
||||
message.metadata = { ...message.metadata, uiUpdated: true };
|
||||
|
||||
// Mark as persisted to avoid duplicate saves
|
||||
message.metadata = { ...message.metadata, isPersisted: true, uiUpdated: true };
|
||||
|
||||
logger.debug('Tool result message persisted to database', {
|
||||
messageId: message.id,
|
||||
toolId: message.metadata.toolId,
|
||||
duration: message.duration,
|
||||
});
|
||||
} catch (serviceError) {
|
||||
logger.warn('Failed to update UI for tool result message', {
|
||||
logger.error('Failed to persist tool result message', {
|
||||
error: serviceError instanceof Error ? serviceError.message : String(serviceError),
|
||||
messageId: message.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (newMessages.length > 0) {
|
||||
logger.debug('Tool result messages UI updated', {
|
||||
count: newMessages.length,
|
||||
messageIds: newMessages.map(m => m.id),
|
||||
if (newToolResultMessages.length > 0) {
|
||||
logger.debug('Tool result messages processed', {
|
||||
count: newToolResultMessages.length,
|
||||
messageIds: newToolResultMessages.map(m => m.id),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,13 +44,12 @@ export default defineConfig({
|
|||
],
|
||||
},
|
||||
|
||||
// Parallel testing configuration
|
||||
pool: 'threads',
|
||||
// Parallel testing configuration - use single fork for database consistency
|
||||
pool: 'forks',
|
||||
poolOptions: {
|
||||
threads: {
|
||||
useAtomics: true,
|
||||
forks: {
|
||||
singleFork: true, // Important for in-memory database tests
|
||||
},
|
||||
isolate: true,
|
||||
},
|
||||
|
||||
// Performance settings
|
||||
|
|
@ -67,4 +66,10 @@ export default defineConfig({
|
|||
|
||||
// Handle CSS and static assets
|
||||
assetsInclude: ['**/*.png', '**/*.jpg', '**/*.jpeg', '**/*.gif', '**/*.svg'],
|
||||
|
||||
// Set environment variables for better-sqlite3 compatibility
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'test'),
|
||||
'process.env.ELECTRON_RUN_AS_NODE': JSON.stringify(process.env.ELECTRON_RUN_AS_NODE || 'true'),
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue