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      144x           144x               144x   165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 165x 5280x 4128x 4128x 4128x 3900x 3372x   165x             165x 165x 165x 165x                     58x 58x 58x 58x 58x     58x 58x   58x             20x 408x 20x 12x 12x 12x                   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', '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 })
  }),
]