All files / msw / handlers runs.ts

86.88% Statements 53/61
64.28% Branches 36/56
72.72% Functions 8/11
90.38% Lines 47/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108      45x           45x           45x   58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 58x 1856x 1400x 1400x 1400x 1304x 1106x   58x             58x 58x 58x 58x                     13x 13x 13x 13x 13x     13x 13x   13x             10x 204x 10x 6x 6x 6x                   1x 1x                        
import { http, HttpResponse } from 'msw'
import { mockRuns, mockProjects } from '@/msw/mock-data'
import { createMockRun } from '@/msw/data'
 
const allPhases = ['pending', 'running', 'succeeded', 'failed'] as const
const allSources = ['manual', 'webhook', 'api', 'schedule'] as const
 
export const runHandlers = [
  http.get('/api/v1/runs', ({ request }) => {
    const url = new URL(request.url)
    const phaseParam = url.searchParams.get('phase')
    const projectIdParam = url.searchParams.get('project_id')
    const sourceTypeParam = url.searchParams.get('source_type')
    const sourceParam = url.searchParams.get('source')
    const createdAfter = url.searchParams.get('created_after')
    const sort = url.searchParams.get('sort')
    const order = url.searchParams.get('order')
    const limit = parseInt(url.searchParams.get('limit') ?? '50')
    const offset = parseInt(url.searchParams.get('offset') ?? '0')
 
    const allowedPhases = phaseParam
      ? phaseParam.split('|').filter((p): p is (typeof allPhases)[number] =>
          allPhases.includes(p as (typeof allPhases)[number]),
        )
      : undefined
 
    const allowedSourcesByType = sourceTypeParam
      ? sourceTypeParam.split('|').filter((s): s is (typeof allSources)[number] =>
          allSources.includes(s as (typeof allSources)[number]),
        )
      : undefined
 
    const allowedSourcesByMeta = sourceParam ? sourceParam.split('|') : undefined
 
    const projectIds = projectIdParam ? projectIdParam.split('|') : undefined
I
   I const createdAfterDate = createdAfter ? new Date(createdAfter) : null
    const hasValidDate = createdAfterDate && !isNaN(createdAfterDate.getTime())
 
    let filtered = mockRuns.filter((run) => {
      if (allowedPhases && !allowedPhases.includes(run.phase as (typeof allPhases)[number])) return false
  I    if (allowedSourcesByType && !allowedSourcesByType.includes(run.source_type as (typeof allSources)[number])) return false
      if (allowedSourcesByMeta && run.source_metadata?.source && !allowedSourcesByMeta.includes(run.source_metadata.source)) return false
      if (projectIds && !projectIds.includes(run.project_id!)) return false
      if (hasValidDate && run.created_at && new Date(run.created_at) < createdAfterDate!) return false
      return true
    })
 
    if (sort === 'tokens') {
      filtered.sort((a, b) => {
        const aTotal = (a.token_input ?? 0) + (a.token_output ?? 0)
        const bTotal = (b.token_input ?? 0) + (b.token_output ?? 0)
        return order === 'asc' ? aTotal - bTotal : bTotal - aTotal
      })
    }
 
    const total = filtered.length
    const paginated = filtered.slice(offset, offset + limit)
    const hasMore = offset + limit < total
 
    return HttpResponse.json({
      data: paginated,
      meta: { limit, returned: paginated.length, has_more: hasMore, total_estimate: total },
    })
  }),
 
  http.get('/api/v1/runs/events', () => {
    const stream = new ReadableStream({
      start(controller) {
        const encoder = new TextEncoder()
        controller.enqueue(encoder.encode('event: run.created\ndata: {"run_id":"run-live-1","phase":"running"}\n\n'))
        controller.enqueue(encoder.encode('event: run.updated\ndata: {"run_id":"run-live-1","phase":"succeeded"}\n\n'))
        const _interval: ReturnType<typeof setInterval> = setInterval(() => {
          controller.enqueue(encoder.encode('event: heartbeat\n\n'))
        }, 30000)
        void _interval
        controller.enqueue(encoder.encode('event: run.created\ndata: {"run_id":"run-live-2","phase":"pending"}\n\n'))
      },
    })
    return new HttpResponse(stream, {
      headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' },
    })
  }),
 
  http.get('/api/v1/runs/:id', ({ params }) => {
    const id = params.id as string
    const run = mockRuns.find((r) => r.run_id === id)
    if (run) return HttpResponse.json(run)
    const proj = mockProjects[Math.floor(Math.random() * 3)]
    const isRunning = id === 'run-running'
    return HttpResponse.json(
      createMockRun({
        run_id: id,
        project_id: proj.id,
        project_name: proj.name,
        phase: isRunning ? 'running' : 'succeeded',
        started_at: new Date(Date.now() - 120000).toISOString(),
        completed_at: isRunning ? null : new Date().toISOString(),
      }),
    )
  }),
 
  http.post('/api/v1/runs', () => {
    const proj = mockProjects[Math.floor(Math.random() * 3)]
    return HttpResponse.json(createMockRun({ project_id: proj.id, project_name: proj.name }), { status: 201 })
  }),
]