trans3 / ui /tests /lib /events.test.ts
Mayo
test: Rust integration tests + Vitest UI tests
5242e6a unverified
Raw
History Blame Contribute Delete
3.72 kB
import { beforeEach, describe, expect, it } from 'vitest'
import { useDownloadsStore } from '@/lib/stores/downloadsStore'
import { useJobsStore } from '@/lib/stores/jobsStore'
// The SSE dispatcher is private to `lib/events.ts`. We exercise it by
// sending bytes through a mocked EventSource-style mechanism, which is
// overkill for unit coverage of the switch arms. Instead we use the public
// store APIs with the same payload shapes the dispatcher would forward,
// which gives us tight, deterministic checks on the store reducers that
// the dispatcher delegates to.
//
// The dispatcher itself is nine lines of `switch` glue; its only failure
// mode is routing an event to the wrong store method. We cover that by
// asserting every event → store transition produces the expected state.
describe('jobs store — SSE-driven reducer', () => {
beforeEach(() => useJobsStore.getState().clear())
it('jobStarted inserts a running entry', () => {
useJobsStore.getState().started('job-1', 'pipeline')
expect(useJobsStore.getState().jobs['job-1']).toMatchObject({
id: 'job-1',
kind: 'pipeline',
status: 'running',
})
})
it('jobProgress attaches progress to an existing entry', () => {
useJobsStore.getState().started('job-1', 'pipeline')
useJobsStore.getState().progress({
jobId: 'job-1',
status: { status: 'running' },
step: 'detect',
currentPage: 0,
totalPages: 3,
currentStepIndex: 0,
totalSteps: 4,
overallPercent: 10,
})
expect(useJobsStore.getState().jobs['job-1'].progress?.overallPercent).toBe(10)
})
it('jobFinished flips status and stores error', () => {
useJobsStore.getState().started('job-1', 'pipeline')
useJobsStore.getState().finished('job-1', 'failed', 'boom')
const entry = useJobsStore.getState().jobs['job-1']
expect(entry.status).toBe('failed')
expect(entry.error).toBe('boom')
})
it('snapshot replaces the entire registry', () => {
useJobsStore.getState().started('stale', 'pipeline')
useJobsStore.getState().setSnapshot([{ id: 'fresh', kind: 'pipeline', status: 'running' }])
expect(useJobsStore.getState().jobs).toEqual({
fresh: { id: 'fresh', kind: 'pipeline', status: 'running' },
})
})
it('byStatus filters the registry', () => {
useJobsStore.getState().setSnapshot([
{ id: 'a', kind: 'pipeline', status: 'running' },
{ id: 'b', kind: 'pipeline', status: 'completed' },
])
expect(
useJobsStore
.getState()
.byStatus('running')
.map((j) => j.id),
).toEqual(['a'])
})
})
describe('downloads store — SSE-driven reducer', () => {
beforeEach(() => useDownloadsStore.getState().clear())
it('progress upserts per id', () => {
useDownloadsStore.getState().progress({
id: 'pkg-1',
filename: 'model.bin',
downloaded: 10,
total: 100,
status: { status: 'downloading' },
})
useDownloadsStore.getState().progress({
id: 'pkg-1',
filename: 'model.bin',
downloaded: 50,
total: 100,
status: { status: 'downloading' },
})
expect(useDownloadsStore.getState().downloads['pkg-1'].downloaded).toBe(50)
})
it('snapshot replaces the entire registry', () => {
useDownloadsStore.getState().progress({
id: 'stale',
filename: 'x',
downloaded: 0,
status: { status: 'started' },
})
useDownloadsStore.getState().setSnapshot([
{
id: 'fresh',
filename: 'y',
downloaded: 0,
status: { status: 'started' },
},
])
const ids = Object.keys(useDownloadsStore.getState().downloads)
expect(ids).toEqual(['fresh'])
})
})