mirror your GitHub repos to tangled.org automatically
1import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2import type { H3Event } from 'h3'
3import { kickWorker } from '../../server/utils/kick-worker'
4
5const ORIGINAL_SECRET = process.env.CRON_SECRET
6const ORIGINAL_URL = process.env.NUXT_PUBLIC_URL
7
8function fakeEvent() {
9 const waitUntil = vi.fn<(p: Promise<unknown>) => void>()
10 // eslint-disable-next-line ts/no-unsafe-type-assertion -- only waitUntil is exercised
11 return { event: { waitUntil } as unknown as H3Event, waitUntil }
12}
13
14describe('kickWorker', () => {
15 beforeEach(() => {
16 process.env.CRON_SECRET = 'test-secret'
17 process.env.NUXT_PUBLIC_URL = 'https://synchub.to'
18 // kick-worker reads `useRuntimeConfig().public.url`; the Nuxt auto-import
19 // isn't available in plain unit tests, so stub it to read from env.
20 vi.stubGlobal('useRuntimeConfig', () => ({ public: { url: process.env.NUXT_PUBLIC_URL ?? '' } }))
21 })
22
23 afterEach(() => {
24 if (ORIGINAL_SECRET === undefined) delete process.env.CRON_SECRET
25 else process.env.CRON_SECRET = ORIGINAL_SECRET
26 if (ORIGINAL_URL === undefined) delete process.env.NUXT_PUBLIC_URL
27 else process.env.NUXT_PUBLIC_URL = ORIGINAL_URL
28 vi.unstubAllGlobals()
29 })
30
31 it('fires a GET to the worker with the cron bearer and registers it via waitUntil', async () => {
32 const fetchMock = vi.fn<(url: string, init?: RequestInit) => Promise<Response>>(async () => new Response('{}'))
33 vi.stubGlobal('fetch', fetchMock)
34 const { event, waitUntil } = fakeEvent()
35
36 kickWorker(event)
37
38 expect(waitUntil).toHaveBeenCalledTimes(1)
39 expect(fetchMock).toHaveBeenCalledTimes(1)
40 const [url, init] = fetchMock.mock.calls[0]!
41 expect(url).toBe('https://synchub.to/api/jobs/run')
42 expect(init).toMatchObject({ method: 'GET', headers: { authorization: 'Bearer test-secret' } })
43 })
44
45 it('strips a trailing slash from the public URL', () => {
46 process.env.NUXT_PUBLIC_URL = 'https://synchub.to/'
47 const fetchMock = vi.fn<(url: string, init?: RequestInit) => Promise<Response>>(async () => new Response('{}'))
48 vi.stubGlobal('fetch', fetchMock)
49 const { event } = fakeEvent()
50
51 kickWorker(event)
52
53 expect(fetchMock.mock.calls[0]![0]).toBe('https://synchub.to/api/jobs/run')
54 })
55
56 it('no-ops when CRON_SECRET is unset', () => {
57 delete process.env.CRON_SECRET
58 const fetchMock = vi.fn<(url: string, init?: RequestInit) => Promise<Response>>()
59 vi.stubGlobal('fetch', fetchMock)
60 const { event, waitUntil } = fakeEvent()
61
62 kickWorker(event)
63
64 expect(fetchMock).not.toHaveBeenCalled()
65 expect(waitUntil).not.toHaveBeenCalled()
66 })
67
68 it('swallows a fetch rejection (cron is the safety net)', async () => {
69 const rejecting = vi.fn<(url: string, init?: RequestInit) => Promise<Response>>(async () => { throw new Error('network down') })
70 vi.stubGlobal('fetch', rejecting)
71 const captured: Promise<unknown>[] = []
72 // eslint-disable-next-line ts/no-unsafe-type-assertion -- minimal event stub
73 const event = { waitUntil: (p: Promise<unknown>) => { captured.push(p) } } as unknown as H3Event
74
75 kickWorker(event)
76
77 await expect(captured[0]).resolves.toBeUndefined()
78 })
79})