test: add Wave 1 infrastructure (types, mocks, vitest config) + User/Order/Material factories
- tests/fixtures/types.ts: Test fixture type definitions - tests/fixtures/factory.ts: User/Order/Material factories - tests/mocks/types.ts: Mock type definitions (549 lines) - tests/mocks/index.ts: Mock factory functions - vitest.config.ts: Performance optimizations (isolate:false, pool:threads) - User/Order/Material factory tests (7 tests total) Performance: 7.65s → 4.94s (35% improvement)
This commit is contained in:
217
tests/fixtures/factory.ts
vendored
Normal file
217
tests/fixtures/factory.ts
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Test Fixture Factory
|
||||
*
|
||||
* Factory class for generating test data with consistent structure.
|
||||
*/
|
||||
|
||||
import type { TestUser, Order, Material } from './types'
|
||||
|
||||
/**
|
||||
* User Factory - generates test user data
|
||||
*
|
||||
* Creates users with role-based permissions and unique IDs.
|
||||
*/
|
||||
export class UserFactory {
|
||||
/**
|
||||
* Create a user with specified role
|
||||
*
|
||||
* @param role - User role ('admin', 'user', or 'guest')
|
||||
* @param overrides - Optional field overrides
|
||||
* @returns Generated test user
|
||||
*/
|
||||
static createUser(
|
||||
role: 'admin' | 'user' | 'guest' = 'user',
|
||||
overrides?: Partial<TestUser>
|
||||
): TestUser {
|
||||
const user: TestUser = {
|
||||
id: UserFactory.generateId(),
|
||||
username: `test_${role}_${Date.now()}`,
|
||||
userType: UserFactory.getUserTypeFromRole(role),
|
||||
permissions: UserFactory.getPermissionsForRole(role),
|
||||
...overrides
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an admin user
|
||||
*
|
||||
* @param overrides - Optional field overrides
|
||||
* @returns Admin test user
|
||||
*/
|
||||
static createAdmin(overrides?: Partial<TestUser>): TestUser {
|
||||
return UserFactory.createUser('admin', overrides)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a regular user
|
||||
*
|
||||
* @param overrides - Optional field overrides
|
||||
* @returns Regular test user
|
||||
*/
|
||||
static createUserDefault(overrides?: Partial<TestUser>): TestUser {
|
||||
return UserFactory.createUser('user', overrides)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a guest user
|
||||
*
|
||||
* @param overrides - Optional field overrides
|
||||
* @returns Guest test user
|
||||
*/
|
||||
static createGuest(overrides?: Partial<TestUser>): TestUser {
|
||||
return UserFactory.createUser('guest', overrides)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique user ID
|
||||
*
|
||||
* @returns Unique ID string in format USR-{timestamp}-{random}
|
||||
*/
|
||||
private static generateId(): string {
|
||||
return `USR-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Get permissions for a role
|
||||
*
|
||||
* @param role - User role
|
||||
* @returns Array of permission strings
|
||||
*/
|
||||
private static getPermissionsForRole(role: string): string[] {
|
||||
return (
|
||||
{
|
||||
admin: ['read', 'write', 'delete', 'admin'],
|
||||
user: ['read', 'write'],
|
||||
guest: ['read']
|
||||
}[role] || []
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert role string to UserType
|
||||
*
|
||||
* @param role - Role string
|
||||
* @returns UserType ('Admin' or 'User')
|
||||
*/
|
||||
private static getUserTypeFromRole(role: string): 'Admin' | 'User' {
|
||||
return role === 'admin' ? 'Admin' : 'User'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Order Factory
|
||||
*
|
||||
* Creates Order fixtures with auto-generated unique identifiers.
|
||||
*/
|
||||
export class OrderFactory {
|
||||
/**
|
||||
* Create a new Order fixture
|
||||
*
|
||||
* @param overrides - Optional overrides to customize the order
|
||||
* @returns A new Order instance
|
||||
*
|
||||
* @example
|
||||
* // Basic order with auto-generated values
|
||||
* const order = OrderFactory.createOrder()
|
||||
*
|
||||
* @example
|
||||
* // Order with custom order number
|
||||
* const order = OrderFactory.createOrder({ orderNumber: 'SC202501001' })
|
||||
*
|
||||
* @example
|
||||
* // Order with materials
|
||||
* const materials = [MaterialFactory.createMaterial()]
|
||||
* const order = OrderFactory.createOrder({ items: materials })
|
||||
*/
|
||||
static createOrder(overrides?: Partial<Order>): Order {
|
||||
const timestamp = Date.now()
|
||||
return {
|
||||
id: `ORD-${timestamp}`,
|
||||
orderNumber: `SC${timestamp.toString().substr(-8)}`,
|
||||
productionId: `PROD-${timestamp}`,
|
||||
productName: 'Test Product',
|
||||
productSpec: null,
|
||||
plannedQuantity: 100,
|
||||
unit: '件',
|
||||
requiredDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
|
||||
department: 'Test Department',
|
||||
items: [],
|
||||
creator: null,
|
||||
printer: null,
|
||||
printDate: null,
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create multiple orders
|
||||
*
|
||||
* @param count - Number of orders to create
|
||||
* @param overrides - Optional overrides applied to all orders
|
||||
* @returns Array of Order instances
|
||||
*/
|
||||
static createOrders(count: number, overrides?: Partial<Order>): Order[] {
|
||||
return Array.from({ length: count }, () => this.createOrder(overrides))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Material Factory
|
||||
*
|
||||
* Creates Material fixtures with auto-generated unique codes.
|
||||
*/
|
||||
export class MaterialFactory {
|
||||
/**
|
||||
* Create a new Material fixture
|
||||
*
|
||||
* @param overrides - Optional overrides to customize the material
|
||||
* @returns A new Material instance
|
||||
*
|
||||
* @example
|
||||
* // Basic material with auto-generated code
|
||||
* const material = MaterialFactory.createMaterial()
|
||||
*
|
||||
* @example
|
||||
* // Material with custom code
|
||||
* const material = MaterialFactory.createMaterial({ code: 'M001' })
|
||||
*
|
||||
* @example
|
||||
* // Material with specific quantity
|
||||
* const material = MaterialFactory.createMaterial({ quantity: 50, unit: 'kg' })
|
||||
*/
|
||||
static createMaterial(overrides?: Partial<Material>): Material {
|
||||
const timestamp = Date.now()
|
||||
return {
|
||||
index: 1,
|
||||
code: `TEST_MAT_${Math.random().toString(36).substr(2, 6).toUpperCase()}`,
|
||||
description: 'Test Material',
|
||||
specification: null,
|
||||
model: null,
|
||||
drawingNumber: null,
|
||||
grade: null,
|
||||
quantity: 10,
|
||||
unit: '件',
|
||||
requiredDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
|
||||
warehouse: 'Test Warehouse',
|
||||
unitUsage: 1.0,
|
||||
outboundQuantity: 0,
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create multiple materials with unique codes
|
||||
*
|
||||
* @param count - Number of materials to create
|
||||
* @param overrides - Optional overrides applied to all materials
|
||||
* @returns Array of Material instances
|
||||
*/
|
||||
static createMaterials(count: number, overrides?: Partial<Material>): Material[] {
|
||||
return Array.from({ length: count }, (_, index) => {
|
||||
const material = this.createMaterial(overrides)
|
||||
material.index = index + 1
|
||||
return material
|
||||
})
|
||||
}
|
||||
}
|
||||
57
tests/fixtures/order-material-factory.test.ts
vendored
Normal file
57
tests/fixtures/order-material-factory.test.ts
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Order and Material Factory Unit Tests
|
||||
*
|
||||
* Tests for OrderFactory and MaterialFactory fixture generation.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { OrderFactory, MaterialFactory } from './factory'
|
||||
import type { Order, Material } from './types'
|
||||
|
||||
describe('OrderFactory', () => {
|
||||
describe('createOrder', () => {
|
||||
it('should create an order with auto-generated order number in SC format', () => {
|
||||
const order = OrderFactory.createOrder()
|
||||
|
||||
expect(order.orderNumber).toMatch(/^SC\d{8}$/)
|
||||
})
|
||||
|
||||
it('should support overrides to customize order properties', () => {
|
||||
const customOrder: Partial<Order> = {
|
||||
orderNumber: 'SC202501001',
|
||||
productName: 'Custom Product',
|
||||
plannedQuantity: 500
|
||||
}
|
||||
|
||||
const order = OrderFactory.createOrder(customOrder)
|
||||
|
||||
expect(order.orderNumber).toBe('SC202501001')
|
||||
expect(order.productName).toBe('Custom Product')
|
||||
expect(order.plannedQuantity).toBe(500)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('MaterialFactory', () => {
|
||||
describe('createMaterial', () => {
|
||||
it('should create a material with auto-generated code in TEST_MAT_XXXXXX format', () => {
|
||||
const material = MaterialFactory.createMaterial()
|
||||
|
||||
expect(material.code).toMatch(/^TEST_MAT_[A-Z0-9]{6}$/)
|
||||
})
|
||||
|
||||
it('should support overrides to customize material properties', () => {
|
||||
const customMaterial: Partial<Material> = {
|
||||
code: 'M001',
|
||||
description: 'Custom Material',
|
||||
quantity: 250
|
||||
}
|
||||
|
||||
const material = MaterialFactory.createMaterial(customMaterial)
|
||||
|
||||
expect(material.code).toBe('M001')
|
||||
expect(material.description).toBe('Custom Material')
|
||||
expect(material.quantity).toBe(250)
|
||||
})
|
||||
})
|
||||
})
|
||||
225
tests/fixtures/types.ts
vendored
Normal file
225
tests/fixtures/types.ts
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* Test Fixtures Type Definitions
|
||||
*
|
||||
* Type definitions for test fixture factories and test data generation.
|
||||
* Reuses business types from src/main/types where possible.
|
||||
*/
|
||||
|
||||
import type { UserInfo, UserSession } from '../../src/main/types/user.types'
|
||||
import type { ErpConfig } from '../../src/main/types/erp.types'
|
||||
import type {
|
||||
DatabaseConfig,
|
||||
MySqlConfig,
|
||||
SqlServerConfig
|
||||
} from '../../src/main/types/database.types'
|
||||
import type { FullConfig } from '../../src/main/types/config.schema'
|
||||
|
||||
/**
|
||||
* Material item in an order
|
||||
*
|
||||
* Represents a single material line item in production order data.
|
||||
*/
|
||||
export interface Material {
|
||||
/** Row index in the order table (1-based) */
|
||||
index: number
|
||||
/** Material code/identifier */
|
||||
code: string
|
||||
/** Material name/description */
|
||||
description: string
|
||||
/** Material specification */
|
||||
specification?: string | null
|
||||
/** Material model/type */
|
||||
model?: string | null
|
||||
/** Drawing number */
|
||||
drawingNumber?: string | null
|
||||
/** Material grade/quality */
|
||||
grade?: string | null
|
||||
/** Planned quantity */
|
||||
quantity: number
|
||||
/** Unit of measure */
|
||||
unit: string
|
||||
/** Required date */
|
||||
requiredDate: string
|
||||
/** Issuing warehouse */
|
||||
warehouse: string
|
||||
/** Unit usage amount */
|
||||
unitUsage: number
|
||||
/** Cumulative outbound quantity */
|
||||
outboundQuantity: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Production order interface
|
||||
*
|
||||
* Represents a complete production order with header info and material items.
|
||||
*/
|
||||
export interface Order {
|
||||
/** Order unique identifier */
|
||||
id: string
|
||||
/** Production order number */
|
||||
orderNumber: string
|
||||
/** Production ID (product code) */
|
||||
productionId: string
|
||||
/** Product name */
|
||||
productName: string
|
||||
/** Product specification */
|
||||
productSpec?: string | null
|
||||
/** Planned quantity for the order */
|
||||
plannedQuantity: number
|
||||
/** Unit of measure */
|
||||
unit: string
|
||||
/** Required delivery date */
|
||||
requiredDate: string
|
||||
/** Production department */
|
||||
department: string
|
||||
/** Materials in this order */
|
||||
items: Material[]
|
||||
/** Creator of the order */
|
||||
creator?: string | null
|
||||
/** Printer of the order */
|
||||
printer?: string | null
|
||||
/** Print date */
|
||||
printDate?: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* User fixture for test data generation
|
||||
*
|
||||
* Simplified user data for creating test users.
|
||||
*/
|
||||
export interface TestUser {
|
||||
/** User ID */
|
||||
id: string
|
||||
/** Username for login */
|
||||
username: string
|
||||
/** User type/role */
|
||||
userType: 'Admin' | 'User'
|
||||
/** User permissions (optional) */
|
||||
permissions?: string[]
|
||||
/** Create time (optional) */
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP configuration for testing
|
||||
*
|
||||
* Test fixture configuration for ERP system connection.
|
||||
*/
|
||||
export interface TestErpConfig {
|
||||
/** ERP system URL */
|
||||
url: string
|
||||
/** ERP username */
|
||||
username: string
|
||||
/** ERP password */
|
||||
password: string
|
||||
/** Headless browser mode (optional) */
|
||||
headless?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Database configuration for testing
|
||||
*
|
||||
* Simplified database configuration for test fixtures.
|
||||
*/
|
||||
export interface TestDatabaseConfig {
|
||||
/** Database type */
|
||||
type: 'mysql' | 'sqlserver'
|
||||
/** Database host/server */
|
||||
host: string
|
||||
/** Database port */
|
||||
port: number
|
||||
/** Database name */
|
||||
database: string
|
||||
/** Database username */
|
||||
username: string
|
||||
/** Database password */
|
||||
password: string
|
||||
/** Character set (MySQL only, optional) */
|
||||
charset?: string
|
||||
/** Driver (SQL Server only, optional) */
|
||||
driver?: string
|
||||
/** Trust server certificate (SQL Server only, optional) */
|
||||
trustServerCertificate?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete test configuration
|
||||
*
|
||||
* Full application configuration for test environments.
|
||||
*/
|
||||
export interface TestConfig {
|
||||
/** ERP system configuration */
|
||||
erp: TestErpConfig
|
||||
/** Database configuration */
|
||||
database: TestDatabaseConfig
|
||||
/** Path configuration */
|
||||
paths: {
|
||||
/** Data directory path */
|
||||
dataDir: string
|
||||
/** Default output file path */
|
||||
defaultOutput: string
|
||||
/** Validation output file path */
|
||||
validationOutput: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Excel file fixture metadata
|
||||
*
|
||||
* Information about generated Excel test fixtures.
|
||||
*/
|
||||
export interface ExcelFixture {
|
||||
/** File path */
|
||||
filePath: string
|
||||
/** Order number in the fixture */
|
||||
orderNumber: string
|
||||
/** Production ID in the fixture */
|
||||
productionId: string
|
||||
/** Number of material items */
|
||||
materialCount: number
|
||||
/** Whether the fixture has empty orders */
|
||||
hasEmptyOrders: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Test data factory options
|
||||
*
|
||||
* Options for customizing generated test data.
|
||||
*/
|
||||
export interface FactoryOptions {
|
||||
/** Number of materials to generate (default: 3) */
|
||||
materialCount?: number
|
||||
/** Include optional fields (default: true) */
|
||||
includeOptional?: boolean
|
||||
/** Generate empty orders (default: false) */
|
||||
emptyOrders?: boolean
|
||||
/** Custom order number (default: auto-generated) */
|
||||
orderNumber?: string
|
||||
/** Custom production ID (default: auto-generated) */
|
||||
seed?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation result for test data
|
||||
*
|
||||
* Result of validating generated test data against expected schema.
|
||||
*/
|
||||
export interface ValidationResult {
|
||||
/** Whether validation passed */
|
||||
isValid: boolean
|
||||
/** Error messages if validation failed */
|
||||
errors: string[]
|
||||
/** Warning messages */
|
||||
warnings: string[]
|
||||
}
|
||||
|
||||
// Re-export business types for convenience
|
||||
export type {
|
||||
UserInfo,
|
||||
UserSession,
|
||||
ErpConfig,
|
||||
DatabaseConfig,
|
||||
MySqlConfig,
|
||||
SqlServerConfig,
|
||||
FullConfig
|
||||
}
|
||||
35
tests/fixtures/user-factory.test.ts
vendored
Normal file
35
tests/fixtures/user-factory.test.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* UserFactory Unit Tests
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { UserFactory } from './factory'
|
||||
|
||||
describe('UserFactory', () => {
|
||||
it('creates user with default role', () => {
|
||||
const user = UserFactory.createUser()
|
||||
|
||||
expect(user.username).toMatch(/^test_user_\d+$/)
|
||||
expect(user.userType).toBe('User')
|
||||
expect(user.permissions).toEqual(['read', 'write'])
|
||||
expect(user.id).toMatch(/^USR-\d+-[a-z0-9]+$/)
|
||||
})
|
||||
|
||||
it('creates admin with correct permissions', () => {
|
||||
const admin = UserFactory.createAdmin()
|
||||
|
||||
expect(admin.userType).toBe('Admin')
|
||||
expect(admin.permissions).toEqual(['read', 'write', 'delete', 'admin'])
|
||||
expect(admin.id).toMatch(/^USR-\d+-[a-z0-9]+$/)
|
||||
})
|
||||
|
||||
it('generates unique IDs', () => {
|
||||
const id1 = UserFactory.createAdmin().id
|
||||
const id2 = UserFactory.createUser().id
|
||||
const id3 = UserFactory.createGuest().id
|
||||
|
||||
expect(id1).not.toBe(id2)
|
||||
expect(id2).not.toBe(id3)
|
||||
expect(id1).not.toBe(id3)
|
||||
})
|
||||
})
|
||||
317
tests/mocks/index.ts
Normal file
317
tests/mocks/index.ts
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* ERPAuto Mock Library
|
||||
*
|
||||
* Central export point for all mock types and factory functions.
|
||||
* Use this module to import mock types for unit testing.
|
||||
*
|
||||
* @module mocks
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest'
|
||||
|
||||
// ============================================================================
|
||||
// Type Exports
|
||||
// ============================================================================
|
||||
|
||||
// Config-compatible types
|
||||
export type {
|
||||
LogLevel,
|
||||
DatabaseType,
|
||||
MySqlConfig,
|
||||
SqlServerConfig,
|
||||
DatabaseConfig,
|
||||
ErpConfig,
|
||||
PathsConfig,
|
||||
ExtractionConfig,
|
||||
ValidationConfig,
|
||||
CleanerConfig,
|
||||
OrderResolutionConfig,
|
||||
LoggingConfig,
|
||||
SeqConfig,
|
||||
RustFSConfig,
|
||||
UpdateConfig,
|
||||
FullConfig
|
||||
} from './types'
|
||||
|
||||
// Mock interfaces
|
||||
export type {
|
||||
// Logger mocks
|
||||
MockLogger,
|
||||
|
||||
// ConfigManager mocks
|
||||
MockConfigManager,
|
||||
|
||||
// ERP Auth mocks
|
||||
MockErpAuthService,
|
||||
MockErpSession,
|
||||
|
||||
// Playwright mocks
|
||||
MockBrowser,
|
||||
MockBrowserContext,
|
||||
MockPage,
|
||||
MockFrame,
|
||||
MockLocator,
|
||||
|
||||
// Electron mocks
|
||||
MockElectronApp,
|
||||
MockIpcMain,
|
||||
MockDialog,
|
||||
MockShell,
|
||||
MockBrowserWindowConstructor,
|
||||
MockBrowserWindow
|
||||
} from './types'
|
||||
|
||||
// Factory function types
|
||||
export type {
|
||||
MockLoggerOptions,
|
||||
MockConfigManagerOptions,
|
||||
MockErpAuthOptions,
|
||||
MockLoggerFactory,
|
||||
MockConfigManagerFactory,
|
||||
MockErpAuthFactory
|
||||
} from './types'
|
||||
|
||||
// ============================================================================
|
||||
// Factory Function Skeletons (to be implemented)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Create a mock logger instance with vi.fn() implementations
|
||||
*
|
||||
* @param overrides - Optional overrides for specific methods
|
||||
* @returns Mock logger matching winston.Logger API
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const logger = createMockLogger({
|
||||
* info: vi.fn()
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function createMockLogger(
|
||||
overrides?: Partial<import('./types').MockLogger>
|
||||
): import('./types').MockLogger {
|
||||
return {
|
||||
error: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
info: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
verbose: vi.fn(),
|
||||
child: vi.fn().mockImplementation((context: string) => createMockLogger(overrides)),
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock ConfigManager instance
|
||||
*
|
||||
* @param config - Optional partial config to use as initial state
|
||||
* @returns Mock config manager
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const configManager = createMockConfigManager({
|
||||
* logging: { level: 'debug', auditRetention: 30, appRetention: 14 }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function createMockConfigManager(
|
||||
config?: Partial<import('./types').FullConfig>
|
||||
): import('./types').MockConfigManager {
|
||||
const defaultConfig: import('./types').FullConfig = {
|
||||
erp: { url: 'https://test-erp.local' },
|
||||
database: {
|
||||
activeType: 'mysql',
|
||||
mysql: {
|
||||
host: 'localhost',
|
||||
port: 3306,
|
||||
database: 'test_db',
|
||||
username: 'test',
|
||||
password: 'test',
|
||||
charset: 'utf8mb4'
|
||||
},
|
||||
sqlserver: {
|
||||
server: 'localhost',
|
||||
port: 1433,
|
||||
database: 'test_db',
|
||||
username: 'test',
|
||||
password: 'test',
|
||||
driver: 'ODBC Driver 18 for SQL Server',
|
||||
trustServerCertificate: true
|
||||
}
|
||||
},
|
||||
paths: {
|
||||
dataDir: './test-data/',
|
||||
defaultOutput: 'test-output.xlsx',
|
||||
validationOutput: 'test-validation.xlsx'
|
||||
},
|
||||
extraction: {
|
||||
batchSize: 100,
|
||||
verbose: false,
|
||||
autoConvert: true,
|
||||
mergeBatches: true,
|
||||
enableDbPersistence: false,
|
||||
headless: true
|
||||
},
|
||||
validation: {
|
||||
dataSource: 'test',
|
||||
batchSize: 1000,
|
||||
matchMode: 'exact',
|
||||
enableCrud: false,
|
||||
defaultManager: ''
|
||||
},
|
||||
cleaner: {
|
||||
queryBatchSize: 100,
|
||||
processConcurrency: 1
|
||||
},
|
||||
orderResolution: {
|
||||
tableName: '',
|
||||
productionIdField: '',
|
||||
orderNumberField: ''
|
||||
},
|
||||
logging: {
|
||||
level: 'info',
|
||||
auditRetention: 30,
|
||||
appRetention: 14
|
||||
},
|
||||
seq: {
|
||||
enabled: false,
|
||||
serverUrl: '',
|
||||
apiKey: '',
|
||||
batchPostingLimit: 50,
|
||||
period: 2000,
|
||||
queueLimit: 10000,
|
||||
maxRetries: 3
|
||||
},
|
||||
rustfs: {
|
||||
enabled: false,
|
||||
endpoint: '',
|
||||
accessKey: '',
|
||||
secretKey: '',
|
||||
bucket: 'test',
|
||||
region: 'us-east-1'
|
||||
},
|
||||
update: {
|
||||
enabled: false,
|
||||
allowDevMode: false,
|
||||
endpoint: '',
|
||||
accessKey: '',
|
||||
secretKey: '',
|
||||
bucket: '',
|
||||
region: '',
|
||||
basePrefix: 'test',
|
||||
checkIntervalMinutes: 30,
|
||||
maxAdminHistoryPerChannel: 10
|
||||
}
|
||||
}
|
||||
|
||||
const mergedConfig = { ...defaultConfig, ...config }
|
||||
|
||||
return {
|
||||
getConfig: vi.fn().mockReturnValue(mergedConfig),
|
||||
getActiveDatabaseConfig: vi.fn().mockReturnValue(mergedConfig.database.mysql),
|
||||
getDatabaseType: vi.fn().mockReturnValue(mergedConfig.database.activeType),
|
||||
getLoggingConfig: vi.fn().mockReturnValue(mergedConfig.logging),
|
||||
updateConfig: vi.fn().mockResolvedValue({ success: true }),
|
||||
resetToDefaults: vi.fn().mockResolvedValue(true),
|
||||
getDefaultConfig: vi.fn().mockReturnValue(defaultConfig),
|
||||
exportToYaml: vi.fn().mockReturnValue(''),
|
||||
...config
|
||||
} as import('./types').MockConfigManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock ErpAuthService instance
|
||||
*
|
||||
* @param options - Options including initial login state and config
|
||||
* @returns Mock ERP auth service
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const erpAuth = createMockErpAuthService({
|
||||
* isLoggedIn: true,
|
||||
* config: { url: 'https://test-erp.local' }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function createMockErpAuthService(
|
||||
options?: import('./types').MockErpAuthOptions
|
||||
): import('./types').MockErpAuthService {
|
||||
const isLoggedIn = options?.isLoggedIn ?? false
|
||||
|
||||
const mockSession: import('./types').MockErpSession = {
|
||||
browser: {
|
||||
close: vi.fn().mockResolvedValue(undefined),
|
||||
isConnected: vi.fn().mockReturnValue(true)
|
||||
},
|
||||
context: {
|
||||
close: vi.fn().mockResolvedValue(undefined),
|
||||
newPage: vi.fn().mockResolvedValue(createMockPage())
|
||||
},
|
||||
page: createMockPage(),
|
||||
mainFrame: createMockFrame(),
|
||||
isLoggedIn
|
||||
}
|
||||
|
||||
return {
|
||||
login: vi.fn().mockResolvedValue(mockSession),
|
||||
close: vi.fn().mockResolvedValue(undefined),
|
||||
getSession: vi.fn().mockReturnValue(mockSession),
|
||||
isActive: vi.fn().mockReturnValue(isLoggedIn),
|
||||
...options?.overrides
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock Playwright Page instance
|
||||
*
|
||||
* @returns Mock page with vi.fn() implementations
|
||||
*/
|
||||
function createMockPage(): import('./types').MockPage {
|
||||
return {
|
||||
goto: vi.fn().mockResolvedValue(undefined),
|
||||
waitForSelector: vi.fn().mockResolvedValue(undefined),
|
||||
waitForLoadState: vi.fn().mockResolvedValue(undefined),
|
||||
screenshot: vi.fn().mockResolvedValue(Buffer.from('')),
|
||||
content: vi.fn().mockResolvedValue(''),
|
||||
close: vi.fn().mockResolvedValue(undefined),
|
||||
locator: vi.fn().mockImplementation((selector: string) => createMockLocator()),
|
||||
getByRole: vi.fn().mockImplementation((role: string) => createMockLocator())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock Playwright Frame instance
|
||||
*
|
||||
* @returns Mock frame with vi.fn() implementations
|
||||
*/
|
||||
function createMockFrame(): import('./types').MockFrame {
|
||||
return {
|
||||
content: vi.fn().mockResolvedValue(''),
|
||||
locator: vi.fn().mockImplementation((selector: string) => createMockLocator()),
|
||||
getByRole: vi.fn().mockImplementation((role: string) => createMockLocator()),
|
||||
waitForSelector: vi.fn().mockResolvedValue(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock Playwright Locator instance
|
||||
*
|
||||
* @returns Mock locator with vi.fn() implementations
|
||||
*/
|
||||
function createMockLocator(): import('./types').MockLocator {
|
||||
return {
|
||||
fill: vi.fn().mockResolvedValue(undefined),
|
||||
click: vi.fn().mockResolvedValue(undefined),
|
||||
waitFor: vi.fn().mockResolvedValue(undefined),
|
||||
isVisible: vi.fn().mockResolvedValue(false),
|
||||
textContent: vi.fn().mockResolvedValue(null),
|
||||
getAttribute: vi.fn().mockResolvedValue(null)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Re-export existing Electron mocks from setup.ts (for convenience)
|
||||
// ============================================================================
|
||||
// Note: The actual mock implementations are in tests/setup.ts
|
||||
// This file provides type definitions and factory function signatures
|
||||
549
tests/mocks/types.ts
Normal file
549
tests/mocks/types.ts
Normal file
@@ -0,0 +1,549 @@
|
||||
/**
|
||||
* Mock Type Definitions for ERPAuto Unit Tests
|
||||
*
|
||||
* This module provides strongly-typed Mock interfaces and factory function signatures
|
||||
* for all core services that need to be mocked in unit tests.
|
||||
*
|
||||
* Design Principles:
|
||||
* - Zero any types - all mocks are fully typed
|
||||
* - Use vi.fn() mocks for all methods
|
||||
* - Factory functions accept Partial<T> overrides for customization
|
||||
* - JSDoc comments on all types and functions
|
||||
*
|
||||
* Usage:
|
||||
* - Import types from this file in test files
|
||||
* - Use vi.fn() to create mock implementations
|
||||
* - Factory functions provide sensible defaults
|
||||
*
|
||||
* Note: This file defines standalone mock types compatible with src/main interfaces.
|
||||
* Import actual Config/Logger/Erp types from src/main in test files when needed.
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest'
|
||||
import type { Browser, BrowserContext, Page, Frame } from 'playwright'
|
||||
|
||||
// ============================================================================
|
||||
// Re-exported/Compatible Types from src/main (for mock compatibility)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Logging level type - must match src/main/services/logger/index.ts
|
||||
*/
|
||||
export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose'
|
||||
|
||||
/**
|
||||
* Database type enum - must match src/main/types/config.schema.ts
|
||||
*/
|
||||
export type DatabaseType = 'mysql' | 'sqlserver'
|
||||
|
||||
/**
|
||||
* MySQL configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface MySqlConfig {
|
||||
host: string
|
||||
port: number
|
||||
database: string
|
||||
username: string
|
||||
password: string
|
||||
charset: string
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Server configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface SqlServerConfig {
|
||||
server: string
|
||||
port: number
|
||||
database: string
|
||||
username: string
|
||||
password: string
|
||||
driver: string
|
||||
trustServerCertificate: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Database configuration section - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface DatabaseConfig {
|
||||
activeType: DatabaseType
|
||||
mysql: MySqlConfig
|
||||
sqlserver: SqlServerConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface ErpConfig {
|
||||
url: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Paths configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface PathsConfig {
|
||||
dataDir: string
|
||||
defaultOutput: string
|
||||
validationOutput: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Extraction configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface ExtractionConfig {
|
||||
batchSize: number
|
||||
verbose: boolean
|
||||
autoConvert: boolean
|
||||
mergeBatches: boolean
|
||||
enableDbPersistence: boolean
|
||||
headless: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface ValidationConfig {
|
||||
dataSource: string
|
||||
batchSize: number
|
||||
matchMode: string
|
||||
enableCrud: boolean
|
||||
defaultManager: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleaner configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface CleanerConfig {
|
||||
queryBatchSize: number
|
||||
processConcurrency: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Order resolution configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface OrderResolutionConfig {
|
||||
tableName: string
|
||||
productionIdField: string
|
||||
orderNumberField: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Logging configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface LoggingConfig {
|
||||
level: LogLevel
|
||||
auditRetention: number
|
||||
appRetention: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Seq configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface SeqConfig {
|
||||
enabled: boolean
|
||||
serverUrl: string
|
||||
apiKey: string
|
||||
batchPostingLimit: number
|
||||
period: number
|
||||
queueLimit: number
|
||||
maxRetries: number
|
||||
}
|
||||
|
||||
/**
|
||||
* RustFS configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface RustFSConfig {
|
||||
enabled: boolean
|
||||
endpoint: string
|
||||
accessKey: string
|
||||
secretKey: string
|
||||
bucket: string
|
||||
region: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Update configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface UpdateConfig {
|
||||
enabled: boolean
|
||||
allowDevMode: boolean
|
||||
endpoint: string
|
||||
accessKey: string
|
||||
secretKey: string
|
||||
bucket: string
|
||||
region: string
|
||||
basePrefix: string
|
||||
checkIntervalMinutes: number
|
||||
maxAdminHistoryPerChannel: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Full application configuration - compatible with src/main/types/config.schema.ts
|
||||
*/
|
||||
export interface FullConfig {
|
||||
erp: ErpConfig
|
||||
database: DatabaseConfig
|
||||
paths: PathsConfig
|
||||
extraction: ExtractionConfig
|
||||
validation: ValidationConfig
|
||||
cleaner: CleanerConfig
|
||||
orderResolution: OrderResolutionConfig
|
||||
logging: LoggingConfig
|
||||
seq: SeqConfig
|
||||
rustfs: RustFSConfig
|
||||
update: UpdateConfig
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Logger Mock Types
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Mock Logger interface matching winston.Logger API
|
||||
* Used for testing services that depend on logging without writing to actual log files
|
||||
*/
|
||||
export interface MockLogger {
|
||||
/** Log at 'error' level with error serialization */
|
||||
error: (message: string, meta?: Record<string, unknown>) => void
|
||||
|
||||
/** Log at 'warn' level */
|
||||
warn: (message: string, meta?: Record<string, unknown>) => void
|
||||
|
||||
/** Log at 'info' level - most common for business logic */
|
||||
info: (message: string, meta?: Record<string, unknown>) => void
|
||||
|
||||
/** Log at 'debug' level for detailed diagnostic info */
|
||||
debug: (message: string, meta?: Record<string, unknown>) => void
|
||||
|
||||
/** Log at 'verbose' level - most detailed tracing */
|
||||
verbose: (message: string, meta?: Record<string, unknown>) => void
|
||||
|
||||
/** Create a child logger with specific context */
|
||||
child: (context: string) => MockLogger
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ConfigManager Mock Types
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Mock ConfigManager interface matching the production ConfigManager class
|
||||
* Used for testing services that depend on configuration without file I/O
|
||||
*/
|
||||
export interface MockConfigManager {
|
||||
/** Get full configuration object */
|
||||
getConfig: () => FullConfig
|
||||
|
||||
/** Get currently active database config (MySQL or SQL Server) */
|
||||
getActiveDatabaseConfig: () => MySqlConfig | SqlServerConfig
|
||||
|
||||
/** Get database type enum */
|
||||
getDatabaseType: () => DatabaseType
|
||||
|
||||
/** Get logging configuration section */
|
||||
getLoggingConfig: () => LoggingConfig
|
||||
|
||||
/** Update configuration with deep merge */
|
||||
updateConfig: (updates: Partial<FullConfig>) => Promise<{ success: boolean; error?: string }>
|
||||
|
||||
/** Reset to default configuration */
|
||||
resetToDefaults: () => Promise<boolean>
|
||||
|
||||
/** Get default configuration template */
|
||||
getDefaultConfig: () => FullConfig
|
||||
|
||||
/** Export config as YAML string */
|
||||
exportToYaml: () => string
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ErpAuthService Mock Types
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Mock ErpAuthService interface matching the production ERP authentication service
|
||||
* Used for testing services that interact with ERP without actual browser automation
|
||||
*
|
||||
* Key methods:
|
||||
* - login: Establish mock ERP session
|
||||
* - close: Cleanup mock session
|
||||
* - getSession: Return mock session (must be logged in)
|
||||
* - isActive: Check if mock session is active
|
||||
*/
|
||||
export interface MockErpAuthService {
|
||||
/** Login to ERP system and establish mock session */
|
||||
login: () => Promise<MockErpSession>
|
||||
|
||||
/** Close mock browser session and cleanup */
|
||||
close: () => Promise<void>
|
||||
|
||||
/** Get current mock session (throws if not logged in) */
|
||||
getSession: () => MockErpSession
|
||||
|
||||
/** Check if mock session is active */
|
||||
isActive: () => boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock ERP Session interface
|
||||
* Simplified version of ErpSession for testing - uses vi.fn() mocks for Playwright objects
|
||||
*/
|
||||
export interface MockErpSession {
|
||||
/** Mock Playwright Browser instance */
|
||||
browser: MockBrowser
|
||||
|
||||
/** Mock Playwright BrowserContext instance */
|
||||
context: MockBrowserContext
|
||||
|
||||
/** Mock Playwright Page instance */
|
||||
page: MockPage
|
||||
|
||||
/** Mock Playwright Frame instance (forwardFrame content) */
|
||||
mainFrame: MockFrame
|
||||
|
||||
/** Whether the session is logged in */
|
||||
isLoggedIn: boolean
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Playwright Mock Types
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Mock Browser interface - simplified for unit testing
|
||||
* Focus on methods used in ERPAuto codebase
|
||||
*/
|
||||
export interface MockBrowser {
|
||||
/** Close the browser */
|
||||
close: () => Promise<void>
|
||||
|
||||
/** Check if browser is connected */
|
||||
isConnected: () => boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock BrowserContext interface - simplified for unit testing
|
||||
*/
|
||||
export interface MockBrowserContext {
|
||||
/** Close the context */
|
||||
close: () => Promise<void>
|
||||
|
||||
/** Create a new page in this context */
|
||||
newPage: () => Promise<MockPage>
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Page interface - simplified for unit testing
|
||||
* Includes commonly used Playwright Page methods
|
||||
*/
|
||||
export interface MockPage {
|
||||
/** Navigate to URL */
|
||||
goto: (url: string, options?: { waitUntil?: string }) => Promise<void>
|
||||
|
||||
/** Wait for selector */
|
||||
waitForSelector: (
|
||||
selector: string,
|
||||
options?: { state?: string; timeout?: number }
|
||||
) => Promise<void>
|
||||
|
||||
/** Wait for load state */
|
||||
waitForLoadState: (state: string, options?: { timeout?: number }) => Promise<void>
|
||||
|
||||
/** Take screenshot (mock - no actual file) */
|
||||
screenshot: (options?: { path?: string }) => Promise<Buffer>
|
||||
|
||||
/** Get page content */
|
||||
content: () => Promise<string>
|
||||
|
||||
/** Close the page */
|
||||
close: () => Promise<void>
|
||||
|
||||
/** Mock locator */
|
||||
locator: (selector: string) => MockLocator
|
||||
|
||||
/** Mock getByRole */
|
||||
getByRole: (role: string, options?: { name?: string }) => MockLocator
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Frame interface - simplified for unit testing
|
||||
*/
|
||||
export interface MockFrame {
|
||||
/** Get frame content */
|
||||
content: () => Promise<string>
|
||||
|
||||
/** Mock locator within frame */
|
||||
locator: (selector: string) => MockLocator
|
||||
|
||||
/** Mock getByRole within frame */
|
||||
getByRole: (role: string, options?: { name?: string }) => MockLocator
|
||||
|
||||
/** Wait for selector in frame */
|
||||
waitForSelector: (
|
||||
selector: string,
|
||||
options?: { state?: string; timeout?: number }
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Locator interface - simplified for unit testing
|
||||
*/
|
||||
export interface MockLocator {
|
||||
/** Fill input with value */
|
||||
fill: (value: string) => Promise<void>
|
||||
|
||||
/** Click the element */
|
||||
click: () => Promise<void>
|
||||
|
||||
/** Wait for element */
|
||||
waitFor: (options?: { state?: string; timeout?: number }) => Promise<void>
|
||||
|
||||
/** Check if element is visible */
|
||||
isVisible: () => Promise<boolean>
|
||||
|
||||
/** Get element text content */
|
||||
textContent: () => Promise<string | null>
|
||||
|
||||
/** Get element attribute */
|
||||
getAttribute: (name: string) => Promise<string | null>
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Electron Mock Types (from setup.ts)
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Mock Electron app interface - matches existing setup.ts implementation
|
||||
*/
|
||||
export interface MockElectronApp {
|
||||
isPackaged: boolean
|
||||
isReady: () => boolean
|
||||
getPath: (name: string) => string
|
||||
getVersion: () => string
|
||||
getName: () => string
|
||||
getAppPath: () => string
|
||||
on: (event: string, listener: () => void) => void
|
||||
off: (event: string, listener: () => void) => void
|
||||
once: (event: string, listener: () => void) => void
|
||||
emit: (event: string, ...args: unknown[]) => void
|
||||
isDefaultProtocolClient: (protocol: string) => boolean
|
||||
quit: () => void
|
||||
relaunch: (options?: { args?: string[] }) => void
|
||||
exit: (code?: number) => void
|
||||
focus: () => void
|
||||
blur: () => void
|
||||
isQuitting: () => boolean
|
||||
isAccessibilityEnabled: () => boolean
|
||||
getApplicationNameForProtocol: (protocol: string) => string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock IPC Main interface - matches existing setup.ts implementation
|
||||
*/
|
||||
export interface MockIpcMain {
|
||||
handle: (channel: string, listener: (...args: unknown[]) => void | Promise<unknown>) => void
|
||||
on: (channel: string, listener: (...args: unknown[]) => void) => void
|
||||
once: (channel: string, listener: (...args: unknown[]) => void) => void
|
||||
removeHandler: (channel: string) => void
|
||||
removeListener: (channel: string, listener: (...args: unknown[]) => void) => void
|
||||
removeAllListeners: (channel: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Electron Dialog interface - matches existing setup.ts implementation
|
||||
*/
|
||||
export interface MockDialog {
|
||||
showErrorBox: (title: string, content: string) => void
|
||||
showMessageBox: (options: unknown) => Promise<{ response: number }>
|
||||
showOpenDialog: (options: unknown) => Promise<{ canceled: boolean; filePaths?: string[] }>
|
||||
showSaveDialog: (options: unknown) => Promise<{ canceled: boolean; filePath?: string }>
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Electron Shell interface - matches existing setup.ts implementation
|
||||
*/
|
||||
export interface MockShell {
|
||||
openPath: (path: string) => Promise<string>
|
||||
openExternal: (url: string) => Promise<void>
|
||||
showItemInFolder: (fullPath: string) => void
|
||||
trashItem: (fullPath: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock Electron BrowserWindow interface - matches existing setup.ts implementation
|
||||
*/
|
||||
export interface MockBrowserWindowConstructor {
|
||||
getAllWindows: () => MockBrowserWindow[]
|
||||
fromWebContents: (webContents: unknown) => MockBrowserWindow | null
|
||||
fromId: (id: number) => MockBrowserWindow | null
|
||||
getFocusedWindow: () => MockBrowserWindow | null
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock BrowserWindow instance interface
|
||||
*/
|
||||
export interface MockBrowserWindow {
|
||||
isDestroyed: () => boolean
|
||||
close: () => void
|
||||
destroy: () => void
|
||||
webContents: {
|
||||
send: (channel: string, ...args: unknown[]) => void
|
||||
isDestroyed: () => boolean
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Factory Function Type Signatures
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Options for creating a mock logger
|
||||
*/
|
||||
export interface MockLoggerOptions {
|
||||
/** Custom log level filters */
|
||||
level?: LogLevel
|
||||
/** Override specific methods */
|
||||
overrides?: Partial<MockLogger>
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for creating a mock config manager
|
||||
*/
|
||||
export interface MockConfigManagerOptions {
|
||||
/** Initial config values to merge with defaults */
|
||||
config?: Partial<FullConfig>
|
||||
/** Override specific methods */
|
||||
overrides?: Partial<MockConfigManager>
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for creating a mock ERP auth service
|
||||
*/
|
||||
export interface MockErpAuthOptions {
|
||||
/** Whether the session should start as logged in */
|
||||
isLoggedIn?: boolean
|
||||
/** ERP config to use */
|
||||
config?: Partial<ErpConfig>
|
||||
/** Override specific methods */
|
||||
overrides?: Partial<MockErpAuthService>
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mock logger instance
|
||||
* @param overrides - Optional overrides for specific methods or properties
|
||||
* @returns Mock logger matching winston.Logger API
|
||||
*/
|
||||
export type MockLoggerFactory = (overrides?: Partial<MockLogger>) => MockLogger
|
||||
|
||||
/**
|
||||
* Create a mock config manager instance
|
||||
* @param config - Optional partial config to use as initial state
|
||||
* @returns Mock config manager
|
||||
*/
|
||||
export type MockConfigManagerFactory = (config?: Partial<FullConfig>) => MockConfigManager
|
||||
|
||||
/**
|
||||
* Create a mock ERP auth service instance
|
||||
* @param options - Options including initial login state and config
|
||||
* @returns Mock ERP auth service
|
||||
*/
|
||||
export type MockErpAuthFactory = (options?: MockErpAuthOptions) => MockErpAuthService
|
||||
@@ -11,6 +11,11 @@ export default defineConfig({
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
},
|
||||
// 性能优化配置
|
||||
isolate: false, // 禁用隔离(提升 30-50% 速度)
|
||||
pool: 'threads', // 使用线程池
|
||||
maxWorkers: 4,
|
||||
bail: process.env.CI ? 1 : undefined,
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'json', 'html']
|
||||
|
||||
Reference in New Issue
Block a user