Ctrl K
ComunidadGuías…

tests/background-task.unit.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { afterEach, describe, expect, it, vi } from 'vitest'
import { backgroundTask, WAIT_FOR_COMPLETION_HEADER } from '../supabase/functions/_backend/utils/utils.ts'

const runtimeKey = vi.hoisted(() => ({ value: 'node' }))

vi.mock('hono/adapter', async importOriginal => ({
  ...(await importOriginal<typeof import('hono/adapter')>()),
  getRuntimeKey: () => runtimeKey.value,
}))

interface EdgeRuntimeLike {
  waitUntil?: (promise: Promise<unknown>) => void
}

const runtime = globalThis as typeof globalThis & { EdgeRuntime?: EdgeRuntimeLike }
const originalEdgeRuntime = runtime.EdgeRuntime

function createContext({ apiSecret, completionHeader = false, executionCtx }: {
  apiSecret?: string
  completionHeader?: boolean
  executionCtx?: { waitUntil: (promise: Promise<unknown>) => void }
} = {}) {
  return {
    env: {},
    get(key: string) {
      return key === 'APISecret' ? apiSecret : undefined
    },
    req: {
      header(key: string) {
        return completionHeader && key === WAIT_FOR_COMPLETION_HEADER ? 'true' : undefined
      },
    },
    get executionCtx() {
      if (!executionCtx)
        throw new Error('This context has no ExecutionContext')
      return executionCtx
    },
  } as any
}

afterEach(() => {
  vi.unstubAllEnvs()
  runtimeKey.value = 'node'
  if (originalEdgeRuntime === undefined)
    delete runtime.EdgeRuntime
  else
    runtime.EdgeRuntime = originalEdgeRuntime
})

async function expectAwaited(result: unknown, task: Promise<unknown>) {
  expect(result).toBe(task)
  await expect(result).resolves.toBe('completed')
}

describe('backgroundTask on Supabase Edge Runtime', () => {
  it('awaits each request task when the test runtime disables background functions', async () => {
    vi.stubEnv('CAPGO_PREVENT_BACKGROUND_FUNCTIONS', 'true')
    const waitUntil = vi.fn()
    runtime.EdgeRuntime = { waitUntil }
    const task = Promise.resolve('completed')

    await expectAwaited(backgroundTask(createContext(), task), task)
    expect(waitUntil).not.toHaveBeenCalled()
  })

  it.each([
    ['the EdgeRuntime global is absent', undefined],
    ['EdgeRuntime has no waitUntil hook', {}],
  ])('awaits the task when %s', async (_label, edgeRuntime) => {
    if (edgeRuntime === undefined)
      delete runtime.EdgeRuntime
    else
      runtime.EdgeRuntime = edgeRuntime
    const task = Promise.resolve('completed')

    await expectAwaited(backgroundTask(createContext({ completionHeader: true }), task), task)
  })

  it('keeps an untrusted completion header in the background', async () => {
    const waitUntil = vi.fn()
    runtime.EdgeRuntime = { waitUntil }
    const task = Promise.resolve('completed')

    const result = backgroundTask(createContext({ completionHeader: true }), task)

    await expect(result).resolves.toBeNull()
    expect(waitUntil).toHaveBeenCalledWith(task)
  })

  it('awaits a completion header only after internal secret validation', async () => {
    const waitUntil = vi.fn()
    runtime.EdgeRuntime = { waitUntil }
    const task = Promise.resolve('completed')

    await expectAwaited(backgroundTask(createContext({ apiSecret: 'verified-secret', completionHeader: true }), task), task)
    expect(waitUntil).not.toHaveBeenCalled()
  })
})

describe('backgroundTask on workerd', () => {
  it('uses waitUntil when the context has an ExecutionContext', async () => {
    runtimeKey.value = 'workerd'
    const waitUntil = vi.fn()
    const task = Promise.resolve('completed')

    const result = backgroundTask(createContext({ executionCtx: { waitUntil } }), task)

    await expect(result).resolves.toBeNull()
    expect(waitUntil).toHaveBeenCalledWith(task)
  })

  it('returns the task instead of throwing when no ExecutionContext exists (Durable Object router)', async () => {
    runtimeKey.value = 'workerd'
    const task = Promise.resolve('completed')

    await expectAwaited(backgroundTask(createContext(), task), task)
  })
})