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      134x           134x           134x   152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 152x 4864x 3784x 3784x 3784x 3520x 3036x   152x             152x 152x 152x 152x                     63x 63x 63x 63x 63x     63x 63x   63x             21x 440x 21x 13x 13x 13x                   2x 2x                        
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 })
  }),
]