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      65x           65x               65x   71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 2272x 1792x 1792x 1792x 1648x 1428x   71x             71x 71x 71x 71x                     33x 33x 33x 33x 33x     33x 33x   33x             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', 'api', 'schedule', 'vikunja', 'gitea', 'github'] 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
 
    const createdAfterDate = createdAfter ? new Date(createdAfter) : null
   I const hasValidDate = createdAfterDate && !isNaN(createdAfterDate.getTime())
I
    let filtered = mockRuns.filter((run) => {
      if (allowedPhases && !allowedPhases.includes(run.phase as (typeof allPhases)[number])) return false
      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
  I    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 })
  }),
]