mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-14 01:36:14 +00:00
test: harden flaky unit tests to reduce CI timeout failures
- executionStore eviction tests: replace O(MAX_PROGRESS_JOBS) event loops with direct state pre-population, reducing event fires from 1000+ to ≤10 - assetsStore Memory Management tests: add explicit 15s timeout to cover O(n²) sorted insertion across 1200 items - modelToNodeStore performance test: widen wall-clock threshold from 10ms to 1000ms to tolerate shared CI runner load - workflowDraftStoreV2 FSM test: reduce fast-check numRuns from 200 to 50 to fit within the 30s timeout on slower CI machines
This commit is contained in:
@@ -367,7 +367,7 @@ describe('workflowDraftStoreV2 FSM', () => {
|
||||
}
|
||||
fc.modelRun(() => ({ model, real }), cmds)
|
||||
}),
|
||||
{ numRuns: 200 }
|
||||
{ numRuns: 50 }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -485,56 +485,64 @@ describe('assetsStore - Refactored (Option A)', () => {
|
||||
})
|
||||
|
||||
describe('Memory Management', () => {
|
||||
it('should cleanup when exceeding MAX_HISTORY_ITEMS', async () => {
|
||||
// Load 1200 items (exceeds 1000 limit)
|
||||
const batches = 6
|
||||
it(
|
||||
'should cleanup when exceeding MAX_HISTORY_ITEMS',
|
||||
{ timeout: 15_000 },
|
||||
async () => {
|
||||
// Load 1200 items (exceeds 1000 limit)
|
||||
const batches = 6
|
||||
|
||||
for (let batch = 0; batch < batches; batch++) {
|
||||
const items = Array.from({ length: 200 }, (_, i) =>
|
||||
createMockJobItem(batch * 200 + i)
|
||||
)
|
||||
vi.mocked(api.getHistory).mockResolvedValueOnce(items)
|
||||
for (let batch = 0; batch < batches; batch++) {
|
||||
const items = Array.from({ length: 200 }, (_, i) =>
|
||||
createMockJobItem(batch * 200 + i)
|
||||
)
|
||||
vi.mocked(api.getHistory).mockResolvedValueOnce(items)
|
||||
|
||||
if (batch === 0) {
|
||||
await store.updateHistory()
|
||||
} else {
|
||||
await store.loadMoreHistory()
|
||||
if (batch === 0) {
|
||||
await store.updateHistory()
|
||||
} else {
|
||||
await store.loadMoreHistory()
|
||||
}
|
||||
}
|
||||
|
||||
// Should be limited to 1000
|
||||
expect(store.historyAssets).toHaveLength(1000)
|
||||
|
||||
// All items should be unique (Set cleanup works)
|
||||
const assetIds = store.historyAssets.map((a) => a.id)
|
||||
const uniqueAssetIds = new Set(assetIds)
|
||||
expect(uniqueAssetIds.size).toBe(1000)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should maintain correct state after cleanup',
|
||||
{ timeout: 15_000 },
|
||||
async () => {
|
||||
// Load items beyond limit
|
||||
for (let batch = 0; batch < 6; batch++) {
|
||||
const items = Array.from({ length: 200 }, (_, i) =>
|
||||
createMockJobItem(batch * 200 + i)
|
||||
)
|
||||
vi.mocked(api.getHistory).mockResolvedValueOnce(items)
|
||||
|
||||
if (batch === 0) {
|
||||
await store.updateHistory()
|
||||
} else {
|
||||
await store.loadMoreHistory()
|
||||
}
|
||||
}
|
||||
|
||||
expect(store.historyAssets).toHaveLength(1000)
|
||||
|
||||
// Should still maintain sorting
|
||||
for (let i = 1; i < store.historyAssets.length; i++) {
|
||||
const prevDate = new Date(store.historyAssets[i - 1].created_at ?? 0)
|
||||
const currDate = new Date(store.historyAssets[i].created_at ?? 0)
|
||||
expect(prevDate.getTime()).toBeGreaterThanOrEqual(currDate.getTime())
|
||||
}
|
||||
}
|
||||
|
||||
// Should be limited to 1000
|
||||
expect(store.historyAssets).toHaveLength(1000)
|
||||
|
||||
// All items should be unique (Set cleanup works)
|
||||
const assetIds = store.historyAssets.map((a) => a.id)
|
||||
const uniqueAssetIds = new Set(assetIds)
|
||||
expect(uniqueAssetIds.size).toBe(1000)
|
||||
})
|
||||
|
||||
it('should maintain correct state after cleanup', async () => {
|
||||
// Load items beyond limit
|
||||
for (let batch = 0; batch < 6; batch++) {
|
||||
const items = Array.from({ length: 200 }, (_, i) =>
|
||||
createMockJobItem(batch * 200 + i)
|
||||
)
|
||||
vi.mocked(api.getHistory).mockResolvedValueOnce(items)
|
||||
|
||||
if (batch === 0) {
|
||||
await store.updateHistory()
|
||||
} else {
|
||||
await store.loadMoreHistory()
|
||||
}
|
||||
}
|
||||
|
||||
expect(store.historyAssets).toHaveLength(1000)
|
||||
|
||||
// Should still maintain sorting
|
||||
for (let i = 1; i < store.historyAssets.length; i++) {
|
||||
const prevDate = new Date(store.historyAssets[i - 1].created_at ?? 0)
|
||||
const currDate = new Date(store.historyAssets[i].created_at ?? 0)
|
||||
expect(prevDate.getTime()).toBeGreaterThanOrEqual(currDate.getTime())
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
describe('jobDetailView Support', () => {
|
||||
|
||||
@@ -358,14 +358,23 @@ describe('useExecutionStore - nodeProgressStatesByJob eviction', () => {
|
||||
expect(Object.keys(store.nodeProgressStatesByJob)).toHaveLength(5)
|
||||
})
|
||||
|
||||
function makeFullState(): Record<string, Record<string, NodeProgressState>> {
|
||||
const state: Record<string, Record<string, NodeProgressState>> = {}
|
||||
for (let i = 0; i < MAX_PROGRESS_JOBS; i++) {
|
||||
state[`job-${i}`] = makeProgressNodes(`${i}`, `job-${i}`)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
it('should evict oldest entries when exceeding MAX_PROGRESS_JOBS', () => {
|
||||
for (let i = 0; i < MAX_PROGRESS_JOBS + 10; i++) {
|
||||
store.nodeProgressStatesByJob = makeFullState()
|
||||
|
||||
for (let i = MAX_PROGRESS_JOBS; i < MAX_PROGRESS_JOBS + 10; i++) {
|
||||
fireProgressState(`job-${i}`, makeProgressNodes(`${i}`, `job-${i}`))
|
||||
}
|
||||
|
||||
const keys = Object.keys(store.nodeProgressStatesByJob)
|
||||
expect(keys).toHaveLength(MAX_PROGRESS_JOBS)
|
||||
// Oldest jobs (0-9) should be evicted; newest should remain
|
||||
expect(keys).not.toContain('job-0')
|
||||
expect(keys).not.toContain('job-9')
|
||||
expect(keys).toContain(`job-${MAX_PROGRESS_JOBS + 9}`)
|
||||
@@ -373,23 +382,23 @@ describe('useExecutionStore - nodeProgressStatesByJob eviction', () => {
|
||||
})
|
||||
|
||||
it('should keep the most recently added job after eviction', () => {
|
||||
for (let i = 0; i < MAX_PROGRESS_JOBS + 1; i++) {
|
||||
fireProgressState(`job-${i}`, makeProgressNodes(`${i}`, `job-${i}`))
|
||||
}
|
||||
store.nodeProgressStatesByJob = makeFullState()
|
||||
|
||||
const lastJobId = `job-${MAX_PROGRESS_JOBS}`
|
||||
fireProgressState(
|
||||
lastJobId,
|
||||
makeProgressNodes(`${MAX_PROGRESS_JOBS}`, lastJobId)
|
||||
)
|
||||
|
||||
expect(store.nodeProgressStatesByJob).toHaveProperty(lastJobId)
|
||||
})
|
||||
|
||||
it('should not evict when updating an existing job', () => {
|
||||
for (let i = 0; i < MAX_PROGRESS_JOBS; i++) {
|
||||
fireProgressState(`job-${i}`, makeProgressNodes(`${i}`, `job-${i}`))
|
||||
}
|
||||
store.nodeProgressStatesByJob = makeFullState()
|
||||
expect(Object.keys(store.nodeProgressStatesByJob)).toHaveLength(
|
||||
MAX_PROGRESS_JOBS
|
||||
)
|
||||
|
||||
// Update an existing job — should not trigger eviction
|
||||
fireProgressState('job-0', makeProgressNodes('0', 'job-0'))
|
||||
expect(Object.keys(store.nodeProgressStatesByJob)).toHaveLength(
|
||||
MAX_PROGRESS_JOBS
|
||||
|
||||
@@ -589,15 +589,13 @@ describe('useModelToNodeStore', () => {
|
||||
const modelToNodeStore = useModelToNodeStore()
|
||||
modelToNodeStore.registerDefaults()
|
||||
|
||||
// Measure performance without assuming implementation
|
||||
const start = performance.now()
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
modelToNodeStore.getCategoryForNodeType('CheckpointLoaderSimple')
|
||||
}
|
||||
const end = performance.now()
|
||||
|
||||
// Should be fast enough for UI responsiveness
|
||||
expect(end - start).toBeLessThan(10)
|
||||
expect(end - start).toBeLessThan(1000)
|
||||
})
|
||||
|
||||
it('should handle invalid input types gracefully', () => {
|
||||
|
||||
Reference in New Issue
Block a user