test: fix mock configuration and lint errors in unit tests

- Fix logger mock missing default export in extractor.test.ts
- Fix performance-monitor mock configuration
- Fix prefer-const in validation-database.test.ts
- Fix no-unsafe-function-type in cleaner-handler.test.ts
- Fix no-empty-function in cleaner-application-service.test.ts
- Run prettier format on test files

All 622 tests now passing (59 files, 3 skipped)
This commit is contained in:
Misaka
2026-04-05 22:04:32 +08:00
parent c6f67e49a4
commit fb3bdbc493
5 changed files with 57 additions and 25 deletions

View File

@@ -305,6 +305,7 @@
``` ```
3. **错误处理验证** 3. **错误处理验证**
```typescript ```typescript
it('should handle errors in batch download gracefully', async () => { it('should handle errors in batch download gracefully', async () => {
vi.spyOn(extractorCore as any, 'downloadBatch') vi.spyOn(extractorCore as any, 'downloadBatch')

View File

@@ -18,7 +18,7 @@ vi.mock('../../../src/main/services/logger/error-utils', () => ({
})) }))
// In-memory storage for registered IPC handlers // In-memory storage for registered IPC handlers
const registeredHandlers: Map<string, Function> = new Map() const registeredHandlers: Map<string, (...args: any[]) => any> = new Map()
// Mock Electron's ipcMain to capture registered handlers // Mock Electron's ipcMain to capture registered handlers
vi.mock('electron', () => { vi.mock('electron', () => {

View File

@@ -23,7 +23,7 @@ vi.mock('../../../../src/main/services/config/config-manager', () => {
vi.mock('../../../../src/main/services/erp/order-resolver', () => { vi.mock('../../../../src/main/services/erp/order-resolver', () => {
return { return {
OrderNumberResolver: class { OrderNumberResolver: class {
constructor(_dbService: any) {} constructor(_dbService: any) {} // eslint-disable-line @typescript-eslint/no-empty-function
async resolve(orderNumbers: string[]) { async resolve(orderNumbers: string[]) {
return orderNumbers return orderNumbers
} }
@@ -71,7 +71,7 @@ let erpAuthCloseCalled = false
vi.mock('../../../../src/main/services/erp/erp-auth', () => { vi.mock('../../../../src/main/services/erp/erp-auth', () => {
return { return {
ErpAuthService: class { ErpAuthService: class {
constructor(_config: any) {} constructor(_config: any) {} // eslint-disable-line @typescript-eslint/no-empty-function
async login() { async login() {
return Promise.resolve(undefined) return Promise.resolve(undefined)
} }
@@ -157,10 +157,16 @@ describe('CleanerApplicationService', () => {
it('should increase materialsDeleted when dryRun is false vs true', async () => { it('should increase materialsDeleted when dryRun is false vs true', async () => {
const eventSender: any = { send: vi.fn() } const eventSender: any = { send: vi.fn() }
const resDry = await service.runCleaner(eventSender, makeInput({ dryRun: true, orderNumbers: ['SC1', 'SC2', 'SC3'] })) const resDry = await service.runCleaner(
eventSender,
makeInput({ dryRun: true, orderNumbers: ['SC1', 'SC2', 'SC3'] })
)
expect(resDry.materialsDeleted).toBe(0) expect(resDry.materialsDeleted).toBe(0)
const resActual = await service.runCleaner(eventSender, makeInput({ dryRun: false, orderNumbers: ['SC1', 'SC2', 'SC3'] })) const resActual = await service.runCleaner(
eventSender,
makeInput({ dryRun: false, orderNumbers: ['SC1', 'SC2', 'SC3'] })
)
expect(resActual.materialsDeleted).toBe(3) expect(resActual.materialsDeleted).toBe(3)
expect(lastCleanerInput?.dryRun).toBe(false) expect(lastCleanerInput?.dryRun).toBe(false)
}) })
@@ -168,7 +174,10 @@ describe('CleanerApplicationService', () => {
it('should handle different order counts independently across invocations', async () => { it('should handle different order counts independently across invocations', async () => {
const eventSender: any = { send: vi.fn() } const eventSender: any = { send: vi.fn() }
const res1 = await service.runCleaner(eventSender, makeInput({ orderNumbers: ['SC1', 'SC2'] })) const res1 = await service.runCleaner(
eventSender,
makeInput({ orderNumbers: ['SC1', 'SC2'] })
)
expect(res1.ordersProcessed).toBe(2) expect(res1.ordersProcessed).toBe(2)
const res2 = await service.runCleaner(eventSender, makeInput({ orderNumbers: ['SC3'] })) const res2 = await service.runCleaner(eventSender, makeInput({ orderNumbers: ['SC3'] }))
@@ -178,9 +187,9 @@ describe('CleanerApplicationService', () => {
it('should reject when ERP config fetch fails', async () => { it('should reject when ERP config fetch fails', async () => {
;(service as any).getErpConfig = vi.fn().mockRejectedValue(new Error('ERP config error')) ;(service as any).getErpConfig = vi.fn().mockRejectedValue(new Error('ERP config error'))
await expect( await expect(service.runCleaner({ send: vi.fn() } as any, makeInput())).rejects.toThrow(
service.runCleaner({ send: vi.fn() } as any, makeInput()) 'ERP config error'
).rejects.toThrow('ERP config error') )
}) })
it('should reject with DatabaseQueryError when database connection fails', async () => { it('should reject with DatabaseQueryError when database connection fails', async () => {
@@ -218,10 +227,13 @@ describe('CleanerApplicationService', () => {
it('should handle processConcurrency=0 gracefully', async () => { it('should handle processConcurrency=0 gracefully', async () => {
const eventSender: any = { send: vi.fn() } const eventSender: any = { send: vi.fn() }
const result = await service.runCleaner(eventSender, makeInput({ const result = await service.runCleaner(
orderNumbers: ['SC1'], eventSender,
processConcurrency: 0 makeInput({
})) orderNumbers: ['SC1'],
processConcurrency: 0
})
)
expect(result.ordersProcessed).toBe(1) expect(result.ordersProcessed).toBe(1)
}) })
@@ -236,9 +248,9 @@ describe('CleanerApplicationService', () => {
cleanerShouldThrow = true cleanerShouldThrow = true
cleanerError = new Error('cleaner crashed') cleanerError = new Error('cleaner crashed')
await expect( await expect(service.runCleaner({ send: vi.fn() } as any, makeInput())).rejects.toThrow(
service.runCleaner({ send: vi.fn() } as any, makeInput()) 'cleaner crashed'
).rejects.toThrow('cleaner crashed') )
expect(erpAuthCloseCalled).toBe(true) expect(erpAuthCloseCalled).toBe(true)
}) })
@@ -271,9 +283,9 @@ describe('CleanerApplicationService', () => {
cleanerShouldThrow = true cleanerShouldThrow = true
cleanerError = new Error('boom') cleanerError = new Error('boom')
await expect( await expect(service.runCleaner({ send: vi.fn() } as any, makeInput())).rejects.toThrow(
service.runCleaner({ send: vi.fn() } as any, makeInput()) 'boom'
).rejects.toThrow('boom') )
expect(mockDisconnect).toHaveBeenCalled() expect(mockDisconnect).toHaveBeenCalled()
}) })
@@ -282,8 +294,24 @@ describe('CleanerApplicationService', () => {
describe('exportResults', () => { describe('exportResults', () => {
it('should export results successfully for non-empty items', async () => { it('should export results successfully for non-empty items', async () => {
const items = [ const items = [
{ materialCode: 'M1', materialName: 'Mat A', specification: '', model: '', managerName: 'Mgr', isMarkedForDeletion: false, isSelected: true }, {
{ materialCode: 'M2', materialName: 'Mat B', specification: '', model: '', managerName: 'Mgr', isMarkedForDeletion: true, isSelected: false } materialCode: 'M1',
materialName: 'Mat A',
specification: '',
model: '',
managerName: 'Mgr',
isMarkedForDeletion: false,
isSelected: true
},
{
materialCode: 'M2',
materialName: 'Mat B',
specification: '',
model: '',
managerName: 'Mgr',
isMarkedForDeletion: true,
isSelected: false
}
] ]
const result = await service.exportResults(items as any) const result = await service.exportResults(items as any)

View File

@@ -25,15 +25,18 @@ vi.mock('../../../../src/main/services/logger', () => {
} }
return { return {
default: mockLogger,
createLogger: vi.fn(() => mockLogger), createLogger: vi.fn(() => mockLogger),
withRequestContext: vi.fn(async (fn) => fn()), withRequestContext: vi.fn(async (fn) => fn()),
getRequestId: vi.fn(() => 'test-request-id') getRequestId: vi.fn(() => 'test-request-id')
} }
}) })
vi.mock('../../../../src/main/services/logger/performance-monitor', () => ({ vi.mock('../../../../src/main/services/logger/performance-monitor', () => {
trackDuration: vi.fn(async (fn) => ({ result: await fn() })) return {
})) trackDuration: vi.fn(async (fn) => ({ result: await fn() }))
}
})
// Mock ExcelParser - reset in beforeEach // Mock ExcelParser - reset in beforeEach
let mockExcelParserInstance: any let mockExcelParserInstance: any

View File

@@ -9,7 +9,7 @@ let lastPgOpts: any = null
let pgConnectCalled = false let pgConnectCalled = false
let currentDbType: string = 'mysql' let currentDbType: string = 'mysql'
let currentDbConfig: any = { const currentDbConfig: any = {
database: { database: {
mysql: { host: 'db', port: 3306, username: 'user', password: 'pass', database: 'erp' }, mysql: { host: 'db', port: 3306, username: 'user', password: 'pass', database: 'erp' },
sqlserver: { sqlserver: {