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:
@@ -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')
|
||||||
|
|||||||
@@ -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', () => {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
Reference in New Issue
Block a user