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      67x           67x               67x   67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 67x 2144x 1688x 1688x 1688x 1556x 1336x   67x             67x 67x 67x 67x                     32x 32x 32x 32x 32x     32x 32x   32x             11x 236x 11x 7x 7x 7x                   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 })
  }),
]