fix(test): improve logger mock path and add behavior-based repository tests
- Fix logger-performance test mock path to use bare module specifier - Replace meaningless "should be defined" assertions in repositories test with behavior-based tests covering upsert, batch operations, queries, deletes, and error handling for both MaterialsToBeDeletedRepository and DiscreteMaterialPlanRepository Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
||||
import logger from '../../src/main/services/logger/index'
|
||||
|
||||
// Mock the logger to avoid noisy output during tests
|
||||
vi.mock('../../src/main/services/logger/index', () => ({
|
||||
vi.mock('../../src/main/services/logger', () => ({
|
||||
default: {
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
|
||||
@@ -1,59 +1,45 @@
|
||||
/**
|
||||
* Repository Unit Tests
|
||||
*
|
||||
* Tests for TypeORM repository patterns.
|
||||
* Note: These tests mock the database connections.
|
||||
* Behavior-based tests for MaterialsToBeDeletedRepository and DiscreteMaterialPlanRepository.
|
||||
* Verifies correct delegation to TypeORM methods, return values, and safe defaults on error.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { createMockRepository, createMockQueryBuilder } from '../mocks'
|
||||
|
||||
// Mock TypeORM
|
||||
// --- Shared mock state ---
|
||||
|
||||
let mockRepo: ReturnType<typeof createMockRepository>
|
||||
|
||||
// Mock TypeORM decorators (entities still need them)
|
||||
vi.mock('typeorm', () => {
|
||||
// Create mock decorator functions
|
||||
const Entity = vi.fn()
|
||||
const PrimaryGeneratedColumn = vi.fn()
|
||||
const Column = vi.fn()
|
||||
const ManyToOne = vi.fn()
|
||||
const OneToMany = vi.fn()
|
||||
const ManyToMany = vi.fn()
|
||||
const JoinColumn = vi.fn()
|
||||
const JoinTable = vi.fn()
|
||||
const CreateDateColumn = vi.fn()
|
||||
const UpdateDateColumn = vi.fn()
|
||||
const DeleteDateColumn = vi.fn()
|
||||
const Index = vi.fn()
|
||||
const Unique = vi.fn()
|
||||
const Check = vi.fn()
|
||||
const Exclusion = vi.fn()
|
||||
const Generated = vi.fn()
|
||||
|
||||
const decorator = vi.fn()
|
||||
return {
|
||||
DataSource: vi.fn(() => ({
|
||||
initialize: vi.fn().mockResolvedValue({}),
|
||||
isInitialized: false,
|
||||
getRepository: vi.fn(),
|
||||
initialize: vi.fn().mockResolvedValue(undefined),
|
||||
isInitialized: true,
|
||||
getRepository: vi.fn(() => mockRepo),
|
||||
destroy: vi.fn()
|
||||
})),
|
||||
Repository: vi.fn(),
|
||||
In: vi.fn((arr) => arr),
|
||||
// Add all the decorators that entities use
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
ManyToMany,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
DeleteDateColumn,
|
||||
Index,
|
||||
Unique,
|
||||
Check,
|
||||
Exclusion,
|
||||
Generated,
|
||||
// Other TypeORM exports
|
||||
In: vi.fn((arr: unknown[]) => arr),
|
||||
Entity: decorator,
|
||||
PrimaryGeneratedColumn: decorator,
|
||||
Column: decorator,
|
||||
ManyToOne: decorator,
|
||||
OneToMany: decorator,
|
||||
ManyToMany: decorator,
|
||||
JoinColumn: decorator,
|
||||
JoinTable: decorator,
|
||||
CreateDateColumn: decorator,
|
||||
UpdateDateColumn: decorator,
|
||||
DeleteDateColumn: decorator,
|
||||
Index: decorator,
|
||||
Unique: decorator,
|
||||
Check: decorator,
|
||||
Exclusion: decorator,
|
||||
Generated: decorator,
|
||||
Between: vi.fn(),
|
||||
LessThan: vi.fn(),
|
||||
LessThanOrEqual: vi.fn(),
|
||||
@@ -76,40 +62,577 @@ vi.mock('../../src/main/services/logger', () => ({
|
||||
}))
|
||||
}))
|
||||
|
||||
vi.mock('../../src/main/services/database/data-source', () => ({
|
||||
getDataSource: vi.fn(() => ({
|
||||
isInitialized: true,
|
||||
initialize: vi.fn().mockResolvedValue(undefined),
|
||||
getRepository: vi.fn(() => mockRepo)
|
||||
}))
|
||||
}))
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MaterialsToBeDeletedRepository
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('MaterialsToBeDeletedRepository', () => {
|
||||
beforeEach(() => {
|
||||
let MaterialsToBeDeletedRepository: typeof import(
|
||||
'../../src/main/services/database/repositories/MaterialsToBeDeletedRepository'
|
||||
).MaterialsToBeDeletedRepository
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks()
|
||||
mockRepo = createMockRepository()
|
||||
const mod = await import(
|
||||
'../../src/main/services/database/repositories/MaterialsToBeDeletedRepository'
|
||||
)
|
||||
MaterialsToBeDeletedRepository = mod.MaterialsToBeDeletedRepository
|
||||
})
|
||||
|
||||
it('should be defined', async () => {
|
||||
const { MaterialsToBeDeletedRepository } =
|
||||
await import('../../src/main/services/database/repositories/MaterialsToBeDeletedRepository')
|
||||
expect(MaterialsToBeDeletedRepository).toBeDefined()
|
||||
afterEach(() => {
|
||||
vi.resetModules()
|
||||
})
|
||||
|
||||
it('should create repository instance', async () => {
|
||||
const { MaterialsToBeDeletedRepository } =
|
||||
await import('../../src/main/services/database/repositories/MaterialsToBeDeletedRepository')
|
||||
// --- upsert ---
|
||||
|
||||
it('upsert: creates new entity when not found', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
expect(repo).toBeDefined()
|
||||
mockRepo.findOne!.mockResolvedValue(null)
|
||||
mockRepo.create!.mockReturnValue({ materialCode: 'MAT01', managerName: 'Alice' })
|
||||
|
||||
const result = await repo.upsert('MAT01', 'Alice')
|
||||
|
||||
expect(result).toBe(true)
|
||||
expect(mockRepo.findOne).toHaveBeenCalledWith({ where: { materialCode: 'MAT01' } })
|
||||
expect(mockRepo.create).toHaveBeenCalledWith({ materialCode: 'MAT01', managerName: 'Alice' })
|
||||
expect(mockRepo.save).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('upsert: updates existing entity', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
const existing = { materialCode: 'MAT01', managerName: 'Bob' }
|
||||
mockRepo.findOne!.mockResolvedValue(existing)
|
||||
|
||||
const result = await repo.upsert('MAT01', 'Alice')
|
||||
|
||||
expect(result).toBe(true)
|
||||
expect(existing.managerName).toBe('Alice')
|
||||
expect(mockRepo.save).toHaveBeenCalledWith(existing)
|
||||
})
|
||||
|
||||
it('upsert: returns false on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.findOne!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.upsert('MAT01', 'Alice')
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
// --- upsertBatch ---
|
||||
|
||||
it('upsertBatch: processes valid materials', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.findOne!.mockResolvedValue(null)
|
||||
mockRepo.create!.mockImplementation((data) => data)
|
||||
|
||||
const stats = await repo.upsertBatch([
|
||||
{ materialCode: 'M1', managerName: 'A' },
|
||||
{ materialCode: 'M2', managerName: 'B' }
|
||||
])
|
||||
|
||||
expect(stats.total).toBe(2)
|
||||
expect(stats.success).toBe(2)
|
||||
expect(stats.failed).toBe(0)
|
||||
})
|
||||
|
||||
it('upsertBatch: skips empty materialCodes', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
|
||||
const stats = await repo.upsertBatch([
|
||||
{ materialCode: '', managerName: 'A' },
|
||||
{ materialCode: ' ', managerName: 'B' },
|
||||
{ materialCode: 'M1', managerName: 'C' }
|
||||
])
|
||||
|
||||
expect(stats.total).toBe(3)
|
||||
expect(stats.success).toBe(1)
|
||||
expect(stats.failed).toBe(2)
|
||||
})
|
||||
|
||||
it('upsertBatch: returns stats with partial failures', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.findOne!.mockRejectedValue(new Error('fail'))
|
||||
|
||||
const stats = await repo.upsertBatch([{ materialCode: 'M1', managerName: 'A' }])
|
||||
|
||||
expect(stats.total).toBe(1)
|
||||
expect(stats.failed).toBe(1)
|
||||
})
|
||||
|
||||
// --- getAllMaterialCodes ---
|
||||
|
||||
it('getAllMaterialCodes: returns Set via QueryBuilder', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
const qb = createMockQueryBuilder({
|
||||
result: [{ materialCode: 'M1' }, { materialCode: 'M2' }]
|
||||
})
|
||||
mockRepo.createQueryBuilder!.mockReturnValue(qb)
|
||||
|
||||
const result = await repo.getAllMaterialCodes()
|
||||
|
||||
expect(result).toBeInstanceOf(Set)
|
||||
expect(result.size).toBe(2)
|
||||
expect(result.has('M1')).toBe(true)
|
||||
expect(result.has('M2')).toBe(true)
|
||||
})
|
||||
|
||||
it('getAllMaterialCodes: returns empty Set on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.createQueryBuilder!.mockImplementation(() => {
|
||||
throw new Error('db fail')
|
||||
})
|
||||
|
||||
const result = await repo.getAllMaterialCodes()
|
||||
|
||||
expect(result).toBeInstanceOf(Set)
|
||||
expect(result.size).toBe(0)
|
||||
})
|
||||
|
||||
// --- getAllRecords ---
|
||||
|
||||
it('getAllRecords: returns ordered records', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
const records = [{ materialCode: 'M1' }, { materialCode: 'M2' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.getAllRecords()
|
||||
|
||||
expect(result).toEqual(records)
|
||||
expect(mockRepo.find).toHaveBeenCalledWith({
|
||||
order: { managerName: 'ASC', materialCode: 'ASC' }
|
||||
})
|
||||
})
|
||||
|
||||
it('getAllRecords: returns empty array on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.getAllRecords()
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- getByManager ---
|
||||
|
||||
it('getByManager: filters by managerName', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
const records = [{ materialCode: 'M1', managerName: 'Alice' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.getByManager('Alice')
|
||||
|
||||
expect(result).toEqual(records)
|
||||
expect(mockRepo.find).toHaveBeenCalledWith({
|
||||
where: { managerName: 'Alice' },
|
||||
order: { materialCode: 'ASC' }
|
||||
})
|
||||
})
|
||||
|
||||
it('getByManager: returns empty array on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.getByManager('Alice')
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- getManagers ---
|
||||
|
||||
it('getManagers: returns distinct names via QueryBuilder', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
const qb = createMockQueryBuilder({
|
||||
result: [{ managerName: 'Alice' }, { managerName: 'Bob' }]
|
||||
})
|
||||
mockRepo.createQueryBuilder!.mockReturnValue(qb)
|
||||
|
||||
const result = await repo.getManagers()
|
||||
|
||||
expect(result).toEqual(['Alice', 'Bob'])
|
||||
})
|
||||
|
||||
it('getManagers: returns empty array on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.createQueryBuilder!.mockImplementation(() => {
|
||||
throw new Error('db fail')
|
||||
})
|
||||
|
||||
const result = await repo.getManagers()
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- deleteByMaterialCode ---
|
||||
|
||||
it('deleteByMaterialCode: returns true when affected > 0', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.delete!.mockResolvedValue({ affected: 1 })
|
||||
|
||||
const result = await repo.deleteByMaterialCode('M1')
|
||||
|
||||
expect(result).toBe(true)
|
||||
expect(mockRepo.delete).toHaveBeenCalledWith({ materialCode: 'M1' })
|
||||
})
|
||||
|
||||
it('deleteByMaterialCode: returns false when affected is 0', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.delete!.mockResolvedValue({ affected: 0 })
|
||||
|
||||
const result = await repo.deleteByMaterialCode('M1')
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('deleteByMaterialCode: returns false on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.delete!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.deleteByMaterialCode('M1')
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
// --- deleteByMaterialCodes ---
|
||||
|
||||
it('deleteByMaterialCodes: returns 0 for empty array', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
|
||||
const result = await repo.deleteByMaterialCodes([])
|
||||
|
||||
expect(result).toBe(0)
|
||||
expect(mockRepo.delete).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('deleteByMaterialCodes: returns affected count', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.delete!.mockResolvedValue({ affected: 3 })
|
||||
|
||||
const result = await repo.deleteByMaterialCodes(['M1', 'M2', 'M3'])
|
||||
|
||||
expect(result).toBe(3)
|
||||
})
|
||||
|
||||
it('deleteByMaterialCodes: returns 0 on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.delete!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.deleteByMaterialCodes(['M1'])
|
||||
|
||||
expect(result).toBe(0)
|
||||
})
|
||||
|
||||
// --- exists ---
|
||||
|
||||
it('exists: returns true when count > 0', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.count!.mockResolvedValue(1)
|
||||
|
||||
const result = await repo.exists('M1')
|
||||
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it('exists: returns false when count is 0', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.count!.mockResolvedValue(0)
|
||||
|
||||
const result = await repo.exists('M1')
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it('exists: returns false on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.count!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.exists('M1')
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
// --- countAll ---
|
||||
|
||||
it('countAll: returns count', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.count!.mockResolvedValue(42)
|
||||
|
||||
const result = await repo.countAll()
|
||||
|
||||
expect(result).toBe(42)
|
||||
})
|
||||
|
||||
it('countAll: returns 0 on error', async () => {
|
||||
const repo = new MaterialsToBeDeletedRepository()
|
||||
mockRepo.count!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.countAll()
|
||||
|
||||
expect(result).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// DiscreteMaterialPlanRepository
|
||||
// ---------------------------------------------------------------------------
|
||||
describe('DiscreteMaterialPlanRepository', () => {
|
||||
beforeEach(() => {
|
||||
let DiscreteMaterialPlanRepository: typeof import(
|
||||
'../../src/main/services/database/repositories/DiscreteMaterialPlanRepository'
|
||||
).DiscreteMaterialPlanRepository
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks()
|
||||
mockRepo = createMockRepository()
|
||||
const mod = await import(
|
||||
'../../src/main/services/database/repositories/DiscreteMaterialPlanRepository'
|
||||
)
|
||||
DiscreteMaterialPlanRepository = mod.DiscreteMaterialPlanRepository
|
||||
})
|
||||
|
||||
it('should be defined', async () => {
|
||||
const { DiscreteMaterialPlanRepository } =
|
||||
await import('../../src/main/services/database/repositories/DiscreteMaterialPlanRepository')
|
||||
expect(DiscreteMaterialPlanRepository).toBeDefined()
|
||||
afterEach(() => {
|
||||
vi.resetModules()
|
||||
})
|
||||
|
||||
it('should create repository instance', async () => {
|
||||
const { DiscreteMaterialPlanRepository } =
|
||||
await import('../../src/main/services/database/repositories/DiscreteMaterialPlanRepository')
|
||||
// --- queryAll ---
|
||||
|
||||
it('queryAll: returns find results', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
expect(repo).toBeDefined()
|
||||
const records = [{ sourceNumber: 'S1' }, { sourceNumber: 'S2' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.queryAll()
|
||||
|
||||
expect(result).toEqual(records)
|
||||
})
|
||||
|
||||
it('queryAll: returns empty array on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.queryAll()
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- queryAllDistinctByMaterialCode ---
|
||||
|
||||
it('queryAllDistinctByMaterialCode: calls repo.query() with raw SQL', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
const mockQueryResult = [{ MaterialCode: 'M1', rn: 1 }]
|
||||
mockRepo = { ...createMockRepository(), query: vi.fn().mockResolvedValue(mockQueryResult) }
|
||||
// Re-import to pick up new mockRepo
|
||||
vi.resetModules()
|
||||
const mod = await import(
|
||||
'../../src/main/services/database/repositories/DiscreteMaterialPlanRepository'
|
||||
)
|
||||
const freshRepo = new mod.DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await freshRepo.queryAllDistinctByMaterialCode()
|
||||
|
||||
expect(result).toEqual(mockQueryResult)
|
||||
})
|
||||
|
||||
it('queryAllDistinctByMaterialCode: returns empty array on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo = {
|
||||
...createMockRepository(),
|
||||
query: vi.fn().mockRejectedValue(new Error('db fail'))
|
||||
}
|
||||
vi.resetModules()
|
||||
const mod = await import(
|
||||
'../../src/main/services/database/repositories/DiscreteMaterialPlanRepository'
|
||||
)
|
||||
const freshRepo = new mod.DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await freshRepo.queryAllDistinctByMaterialCode()
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- queryBySourceNumbers ---
|
||||
|
||||
it('queryBySourceNumbers: returns empty array for empty input', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await repo.queryBySourceNumbers([])
|
||||
|
||||
expect(result).toEqual([])
|
||||
expect(mockRepo.find).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('queryBySourceNumbers: batches in groups of 2000', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
// Create 2500 source numbers to trigger 2 batches
|
||||
const sourceNumbers = Array.from({ length: 2500 }, (_, i) => `S${i}`)
|
||||
mockRepo.find!.mockResolvedValue([])
|
||||
|
||||
await repo.queryBySourceNumbers(sourceNumbers)
|
||||
|
||||
// Should be called twice: once for 2000, once for 500
|
||||
expect(mockRepo.find).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('queryBySourceNumbers: returns combined results', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
const records = [{ sourceNumber: 'S1' }, { sourceNumber: 'S2' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.queryBySourceNumbers(['S1', 'S2'])
|
||||
|
||||
expect(result).toEqual(records)
|
||||
})
|
||||
|
||||
it('queryBySourceNumbers: returns empty array on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.queryBySourceNumbers(['S1'])
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- queryBySourceNumbersDistinct ---
|
||||
|
||||
it('queryBySourceNumbersDistinct: returns empty array for empty input', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await repo.queryBySourceNumbersDistinct([])
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
it('queryBySourceNumbersDistinct: calls repo.query() per batch', async () => {
|
||||
mockRepo = { ...createMockRepository(), query: vi.fn().mockResolvedValue([{ M: 'X' }]) }
|
||||
vi.resetModules()
|
||||
const mod = await import(
|
||||
'../../src/main/services/database/repositories/DiscreteMaterialPlanRepository'
|
||||
)
|
||||
const repo = new mod.DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await repo.queryBySourceNumbersDistinct(['S1', 'S2'])
|
||||
|
||||
expect(result.length).toBeGreaterThan(0)
|
||||
expect((mockRepo as Record<string, unknown>).query).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('queryBySourceNumbersDistinct: returns empty array on error', async () => {
|
||||
mockRepo = {
|
||||
...createMockRepository(),
|
||||
query: vi.fn().mockRejectedValue(new Error('db fail'))
|
||||
}
|
||||
vi.resetModules()
|
||||
const mod = await import(
|
||||
'../../src/main/services/database/repositories/DiscreteMaterialPlanRepository'
|
||||
)
|
||||
const repo = new mod.DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await repo.queryBySourceNumbersDistinct(['S1'])
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- queryBySourceNumber ---
|
||||
|
||||
it('queryBySourceNumber: calls find with where clause', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
const records = [{ sourceNumber: 'S1', planNumber: 'P1' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.queryBySourceNumber('S1')
|
||||
|
||||
expect(result).toEqual(records)
|
||||
expect(mockRepo.find).toHaveBeenCalledWith({ where: { sourceNumber: 'S1' } })
|
||||
})
|
||||
|
||||
it('queryBySourceNumber: returns empty array on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.queryBySourceNumber('S1')
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- queryByPlanNumber ---
|
||||
|
||||
it('queryByPlanNumber: calls find with where clause', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
const records = [{ sourceNumber: 'S1', planNumber: 'P1' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.queryByPlanNumber('P1')
|
||||
|
||||
expect(result).toEqual(records)
|
||||
expect(mockRepo.find).toHaveBeenCalledWith({ where: { planNumber: 'P1' } })
|
||||
})
|
||||
|
||||
it('queryByPlanNumber: returns empty array on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.queryByPlanNumber('P1')
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- queryByPlanNumbers ---
|
||||
|
||||
it('queryByPlanNumbers: returns empty array for empty input', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
|
||||
const result = await repo.queryByPlanNumbers([])
|
||||
|
||||
expect(result).toEqual([])
|
||||
expect(mockRepo.find).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('queryByPlanNumbers: calls find with In()', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
const records = [{ planNumber: 'P1' }, { planNumber: 'P2' }]
|
||||
mockRepo.find!.mockResolvedValue(records)
|
||||
|
||||
const result = await repo.queryByPlanNumbers(['P1', 'P2'])
|
||||
|
||||
expect(result).toEqual(records)
|
||||
expect(mockRepo.find).toHaveBeenCalledWith({
|
||||
where: { planNumber: ['P1', 'P2'] } // In() mock returns the array as-is
|
||||
})
|
||||
})
|
||||
|
||||
it('queryByPlanNumbers: returns empty array on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.find!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.queryByPlanNumbers(['P1'])
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
// --- countAll ---
|
||||
|
||||
it('countAll: returns count', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.count!.mockResolvedValue(99)
|
||||
|
||||
const result = await repo.countAll()
|
||||
|
||||
expect(result).toBe(99)
|
||||
})
|
||||
|
||||
it('countAll: returns 0 on error', async () => {
|
||||
const repo = new DiscreteMaterialPlanRepository()
|
||||
mockRepo.count!.mockRejectedValue(new Error('db fail'))
|
||||
|
||||
const result = await repo.countAll()
|
||||
|
||||
expect(result).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user