import { Hono } from 'hono' import * as Timing from './Timing.js' describe('middleware', () => { test('emits request and operation server timings', async () => { const app = new Hono<{ Variables: Timing.Variables }>() app.use('*', Timing.middleware()) app.get('/', async (c) => { await Timing.time(c, 'example.work', () => Promise.resolve()) return c.text('ok') }) const response = await app.request('/') const timing = response.headers.get('server-timing') expect(response.status).toMatchInlineSnapshot(`200`) expect(response.headers.get('content-type')).toMatchInlineSnapshot(`"text/plain;charset=UTF-8"`) expect(timing?.includes('example.work;dur=')).toMatchInlineSnapshot(`true`) expect(timing?.includes('request;dur=')).toMatchInlineSnapshot(`true`) }) test('appends outer timings without replacing app timings', () => { const response = new Response('ok', { headers: { 'Server-Timing': 'request;dur=10' } }) expect( Timing.append(response, [ { duration: 2.25, name: 'edge rate limit' }, { duration: 12.5, name: 'worker' }, ]), ).toBe(response) expect(response.headers.get('server-timing')).toBe( 'request;dur=10, edge_rate_limit;dur=2.3, worker;dur=12.5', ) }) test('merges timings seeded before the app receives the request', async () => { const app = new Hono<{ Variables: Timing.Variables }>() app.use('*', Timing.middleware()) app.get('/', (c) => c.text('ok')) const request = new Request('http://localhost/') Timing.seed(request, { active: [{ name: 'worker', start: performance.now() }], metrics: [{ duration: 3, name: 'edge_rate_limit' }], }) const response = await app.fetch(request) expect(response.headers.get('server-timing')).toContain('edge_rate_limit;dur=3.0') expect(response.headers.get('server-timing')).toContain('request;dur=') expect(response.headers.get('server-timing')).toContain('worker;dur=') }) test('accumulates repeated work under one server timing metric', async () => { vi.useFakeTimers() try { const app = new Hono<{ Variables: Timing.Variables }>() app.use('*', Timing.middleware()) app.get('/', async (c) => { await Timing.sum(c, 'page_work', () => vi.advanceTimersByTime(20)) await Timing.sum(c, 'page_work', () => vi.advanceTimersByTime(5)) return c.text('ok') }) const response = await app.request('/') const timing = response.headers.get('server-timing') expect(timing?.match(/page_work/g)).toHaveLength(1) expect(timing).toContain('page_work;dur=25.0') } finally { vi.useRealTimers() } }) test('counts overlapping work once', async () => { vi.useFakeTimers() try { const app = new Hono<{ Variables: Timing.Variables }>() app.use('*', Timing.middleware()) app.get('/', async (c) => { const releases: (() => void)[] = [] const work = () => new Promise((resolve) => releases.push(resolve)) const pending = [Timing.sum(c, 'parallel_work', work), Timing.sum(c, 'parallel_work', work)] vi.advanceTimersByTime(20) for (const release of releases) release() await Promise.all(pending) return c.text('ok') }) const response = await app.request('/') const timing = response.headers.get('server-timing') expect(timing?.match(/parallel_work/g)).toHaveLength(1) expect(timing).toContain('parallel_work;dur=20.0') } finally { vi.useRealTimers() } }) })