test: Phase 2 - Create test infrastructure
- Create comprehensive test directory structure - Implement better-sqlite3 mock for Vitest - Add node factory using fishery for test data generation - Create workflow builder with fluent API - Add infrastructure validation tests - Update testing checklist to reflect progress All Phase 2 tasks completed successfully with 7 tests passing. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
53
tests/unit/database/__mocks__/better-sqlite3.ts
Normal file
53
tests/unit/database/__mocks__/better-sqlite3.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export class MockDatabase {
|
||||
private data = new Map<string, any[]>();
|
||||
private prepared = new Map<string, any>();
|
||||
|
||||
constructor() {
|
||||
this.data.set('nodes', []);
|
||||
this.data.set('templates', []);
|
||||
this.data.set('tools_documentation', []);
|
||||
}
|
||||
|
||||
prepare(sql: string) {
|
||||
const key = this.extractTableName(sql);
|
||||
|
||||
return {
|
||||
all: vi.fn(() => this.data.get(key) || []),
|
||||
get: vi.fn((id: string) => {
|
||||
const items = this.data.get(key) || [];
|
||||
return items.find(item => item.id === id);
|
||||
}),
|
||||
run: vi.fn((params: any) => {
|
||||
const items = this.data.get(key) || [];
|
||||
items.push(params);
|
||||
this.data.set(key, items);
|
||||
return { changes: 1, lastInsertRowid: items.length };
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
exec(sql: string) {
|
||||
// Mock schema creation
|
||||
return true;
|
||||
}
|
||||
|
||||
close() {
|
||||
// Mock close
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper to extract table name from SQL
|
||||
private extractTableName(sql: string): string {
|
||||
const match = sql.match(/FROM\s+(\w+)|INTO\s+(\w+)|UPDATE\s+(\w+)/i);
|
||||
return match ? (match[1] || match[2] || match[3]) : 'nodes';
|
||||
}
|
||||
|
||||
// Test helper to seed data
|
||||
_seedData(table: string, data: any[]) {
|
||||
this.data.set(table, data);
|
||||
}
|
||||
}
|
||||
|
||||
export default vi.fn(() => new MockDatabase());
|
||||
149
tests/unit/database/__mocks__/database.mock.ts
Normal file
149
tests/unit/database/__mocks__/database.mock.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { vi } from 'vitest';
|
||||
import type { Database } from 'better-sqlite3';
|
||||
|
||||
export interface MockDatabase extends Partial<Database> {
|
||||
prepare: ReturnType<typeof vi.fn>;
|
||||
exec: ReturnType<typeof vi.fn>;
|
||||
close: ReturnType<typeof vi.fn>;
|
||||
transaction: ReturnType<typeof vi.fn>;
|
||||
pragma: ReturnType<typeof vi.fn>;
|
||||
backup: ReturnType<typeof vi.fn>;
|
||||
serialize: ReturnType<typeof vi.fn>;
|
||||
function: ReturnType<typeof vi.fn>;
|
||||
aggregate: ReturnType<typeof vi.fn>;
|
||||
table: ReturnType<typeof vi.fn>;
|
||||
loadExtension: ReturnType<typeof vi.fn>;
|
||||
defaultSafeIntegers: ReturnType<typeof vi.fn>;
|
||||
unsafeMode: ReturnType<typeof vi.fn>;
|
||||
}
|
||||
|
||||
export interface MockStatement {
|
||||
run: ReturnType<typeof vi.fn>;
|
||||
get: ReturnType<typeof vi.fn>;
|
||||
all: ReturnType<typeof vi.fn>;
|
||||
iterate: ReturnType<typeof vi.fn>;
|
||||
pluck: ReturnType<typeof vi.fn>;
|
||||
expand: ReturnType<typeof vi.fn>;
|
||||
raw: ReturnType<typeof vi.fn>;
|
||||
columns: ReturnType<typeof vi.fn>;
|
||||
bind: ReturnType<typeof vi.fn>;
|
||||
safeIntegers: ReturnType<typeof vi.fn>;
|
||||
}
|
||||
|
||||
export function createMockDatabase(): MockDatabase {
|
||||
const mockDb: MockDatabase = {
|
||||
prepare: vi.fn(),
|
||||
exec: vi.fn(),
|
||||
close: vi.fn(),
|
||||
transaction: vi.fn(),
|
||||
pragma: vi.fn(),
|
||||
backup: vi.fn(),
|
||||
serialize: vi.fn(),
|
||||
function: vi.fn(),
|
||||
aggregate: vi.fn(),
|
||||
table: vi.fn(),
|
||||
loadExtension: vi.fn(),
|
||||
defaultSafeIntegers: vi.fn(),
|
||||
unsafeMode: vi.fn(),
|
||||
memory: false,
|
||||
readonly: false,
|
||||
name: ':memory:',
|
||||
open: true,
|
||||
inTransaction: false,
|
||||
};
|
||||
|
||||
// Setup default behavior
|
||||
mockDb.transaction.mockImplementation((fn: Function) => {
|
||||
return (...args: any[]) => fn(...args);
|
||||
});
|
||||
|
||||
mockDb.pragma.mockReturnValue(undefined);
|
||||
|
||||
return mockDb;
|
||||
}
|
||||
|
||||
export function createMockStatement(defaultResults: any = []): MockStatement {
|
||||
const mockStmt: MockStatement = {
|
||||
run: vi.fn().mockReturnValue({ changes: 1, lastInsertRowid: 1 }),
|
||||
get: vi.fn().mockReturnValue(defaultResults[0] || undefined),
|
||||
all: vi.fn().mockReturnValue(defaultResults),
|
||||
iterate: vi.fn().mockReturnValue(defaultResults[Symbol.iterator]()),
|
||||
pluck: vi.fn().mockReturnThis(),
|
||||
expand: vi.fn().mockReturnThis(),
|
||||
raw: vi.fn().mockReturnThis(),
|
||||
columns: vi.fn().mockReturnValue([]),
|
||||
bind: vi.fn().mockReturnThis(),
|
||||
safeIntegers: vi.fn().mockReturnThis(),
|
||||
};
|
||||
|
||||
return mockStmt;
|
||||
}
|
||||
|
||||
export function setupDatabaseMock(mockDb: MockDatabase, queryResults: Record<string, any> = {}) {
|
||||
mockDb.prepare.mockImplementation((query: string) => {
|
||||
// Match queries to results
|
||||
for (const [pattern, result] of Object.entries(queryResults)) {
|
||||
if (query.includes(pattern)) {
|
||||
return createMockStatement(Array.isArray(result) ? result : [result]);
|
||||
}
|
||||
}
|
||||
// Default mock statement
|
||||
return createMockStatement();
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to create a mock node repository
|
||||
export function createMockNodeRepository() {
|
||||
return {
|
||||
getNodeByType: vi.fn(),
|
||||
searchNodes: vi.fn(),
|
||||
listNodes: vi.fn(),
|
||||
getNodeEssentials: vi.fn(),
|
||||
getNodeDocumentation: vi.fn(),
|
||||
getNodeInfo: vi.fn(),
|
||||
searchNodeProperties: vi.fn(),
|
||||
listAITools: vi.fn(),
|
||||
getNodeForTask: vi.fn(),
|
||||
listTasks: vi.fn(),
|
||||
getDatabaseStatistics: vi.fn(),
|
||||
close: vi.fn(),
|
||||
};
|
||||
}
|
||||
|
||||
// Helper to create mock node data
|
||||
export function createMockNode(overrides: any = {}) {
|
||||
return {
|
||||
id: 1,
|
||||
package_name: 'n8n-nodes-base',
|
||||
node_type: 'n8n-nodes-base.webhook',
|
||||
display_name: 'Webhook',
|
||||
description: 'Starts the workflow when a webhook is called',
|
||||
version: 2,
|
||||
defaults: JSON.stringify({ name: 'Webhook' }),
|
||||
properties: JSON.stringify([]),
|
||||
credentials: JSON.stringify([]),
|
||||
inputs: JSON.stringify(['main']),
|
||||
outputs: JSON.stringify(['main']),
|
||||
type_version: 2,
|
||||
is_trigger: 1,
|
||||
is_regular: 0,
|
||||
is_webhook: 1,
|
||||
webhook_path: '/webhook',
|
||||
full_metadata: JSON.stringify({}),
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
// Helper to create mock query results
|
||||
export function createMockQueryResults() {
|
||||
return {
|
||||
'SELECT * FROM nodes WHERE node_type = ?': createMockNode(),
|
||||
'SELECT COUNT(*) as count FROM nodes': { count: 525 },
|
||||
'SELECT * FROM nodes WHERE display_name LIKE ?': [
|
||||
createMockNode({ node_type: 'n8n-nodes-base.slack', display_name: 'Slack' }),
|
||||
createMockNode({ node_type: 'n8n-nodes-base.webhook', display_name: 'Webhook' }),
|
||||
],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user