Files
BIPMaterialManager/tests/unit/data-importer.test.ts
Misaka_Company 63ea81e0d6 feat: add automatic database import after ERP data extraction
- Add DataImportService for reading Excel and importing to database
- Extend DiscreteMaterialPlanDAO with deleteBySourceNumbers and batchInsert
- Auto-trigger database write after successful Excel merge
- Support batch delete by SourceNumber and batch insert (1000/batch)
- Update ExtractorPage UI to show import results
- Fix SQL Server query to handle undefined recordset for DELETE/INSERT

Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
2026-03-04 12:50:27 +08:00

119 lines
3.2 KiB
TypeScript

/**
* Unit tests for DataImportService
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { DataImportService } from '../../../src/main/services/database/data-importer'
// Mock the logger
vi.mock('../../../src/main/services/logger', () => ({
createLogger: () => ({
info: vi.fn(),
debug: vi.fn(),
warn: vi.fn(),
error: vi.fn()
})
}))
// Mock the database factory
vi.mock('../../../src/main/services/database', () => ({
create: vi.fn().mockResolvedValue({
type: 'mysql',
isConnected: () => true,
query: vi.fn().mockResolvedValue({ rows: [], rowCount: 0 }),
disconnect: vi.fn().mockResolvedValue(undefined)
})
}))
// Create mock worksheet
const mockWorksheet = {
getRow: vi.fn().mockReturnValue({
eachCell: vi.fn((callback) => {
callback({ text: '工厂' }, 1)
callback({ text: '来源单号' }, 2)
callback({ text: '备料计划单号' }, 3)
})
}),
eachRow: vi.fn((callback) => {
// Skip header row (rowNumber 1)
// Add data rows
callback(
{
eachCell: vi.fn((cellCallback) => {
cellCallback({ text: '工厂A', value: '工厂A' }, 1)
cellCallback({ text: 'PO-001', value: 'PO-001' }, 2)
cellCallback({ text: 'PLAN-001', value: 'PLAN-001' }, 3)
}),
text: '工厂A,PO-001,PLAN-001'
},
2
)
callback(
{
eachCell: vi.fn((cellCallback) => {
cellCallback({ text: '工厂A', value: '工厂A' }, 1)
cellCallback({ text: 'PO-002', value: 'PO-002' }, 2)
cellCallback({ text: 'PLAN-002', value: 'PLAN-002' }, 3)
}),
text: '工厂A,PO-002,PLAN-002'
},
3
)
})
}
// Mock ExcelJS with a proper class constructor
class MockWorkbook {
worksheets = [mockWorksheet]
xlsx = {
readFile: vi.fn().mockResolvedValue(undefined)
}
}
vi.mock('exceljs', () => {
return {
default: {
Workbook: MockWorkbook
},
Workbook: MockWorkbook
}
})
describe('DataImportService', () => {
let service: DataImportService
beforeEach(() => {
service = new DataImportService()
vi.clearAllMocks()
})
afterEach(() => {
vi.restoreAllMocks()
})
describe('importFromExcel', () => {
it('should return result with expected structure', async () => {
const result = await service.importFromExcel('/path/to/test.xlsx', 1000)
// Check that we got a result with expected structure
expect(result).toHaveProperty('success')
expect(result).toHaveProperty('recordsRead')
expect(result).toHaveProperty('recordsDeleted')
expect(result).toHaveProperty('recordsImported')
expect(result).toHaveProperty('uniqueSourceNumbers')
expect(result).toHaveProperty('errors')
})
it('should return records read count', async () => {
const result = await service.importFromExcel('/path/to/test.xlsx', 1000)
expect(result.recordsRead).toBeGreaterThanOrEqual(0)
})
it('should return unique source numbers count', async () => {
const result = await service.importFromExcel('/path/to/test.xlsx', 1000)
expect(result.uniqueSourceNumbers).toBeGreaterThanOrEqual(0)
})
})
})