From a0cf7c4a5721291e4e1e1d5e1301eb3b1c4ecf3d Mon Sep 17 00:00:00 2001 From: lama <1774550500@qq.com> Date: Mon, 1 Jun 2026 21:50:08 +0800 Subject: [PATCH] test(adapters): cover runtime delegation --- test/unit/app-structure.test.js | 81 ++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/test/unit/app-structure.test.js b/test/unit/app-structure.test.js index 4a152fb..09dc58b 100644 --- a/test/unit/app-structure.test.js +++ b/test/unit/app-structure.test.js @@ -1,4 +1,4 @@ -import { describe, expect, it } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import apiHandler, { config as vercelConfig } from '../../adapters/functions/api/index.js'; import { handler as denoHandler } from '../../adapters/functions/deno.js'; @@ -7,6 +7,24 @@ import { createRequestContext } from '../../src/app/request-context.js'; import { PLATFORM_CATALOG } from '../../src/config/platform-catalog.js'; import { normalizeEffectivePath, resolveTarget } from '../../src/routing/resolve-target.js'; +afterEach(() => { + vi.unstubAllGlobals(); + vi.restoreAllMocks(); +}); + +/** + * Mocks the upstream fetch used by adapter smoke tests. + * @returns {ReturnType} Fetch spy. + */ +function mockUpstreamFetch() { + return vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response('adapter-ok', { + status: 200, + headers: { 'Content-Type': 'text/plain' } + }) + ); +} + describe('Application structure', () => { it('builds a shared request context for protocol-aware routing', () => { const request = new Request('https://example.com/ip/openai/v1/chat/completions', { @@ -49,4 +67,65 @@ describe('Application structure', () => { expect(typeof onRequest).toBe('function'); expect(vercelConfig).toEqual({ runtime: 'edge' }); }); + + it('delegates Cloudflare Pages requests through the shared handler with env overrides', async () => { + const fetchSpy = mockUpstreamFetch(); + const waitUntil = vi.fn(); + + const response = await onRequest({ + request: new Request('https://pages.example.com/gh/user/repo/pages-file.txt'), + env: { CACHE_DURATION: '42' }, + params: {}, + waitUntil, + next: async () => new Response('next'), + data: {} + }); + + expect(fetchSpy).toHaveBeenCalledWith( + 'https://github.com/user/repo/pages-file.txt', + expect.objectContaining({ method: 'GET' }) + ); + expect(await response.text()).toBe('adapter-ok'); + expect(response.headers.get('Cache-Control')).toContain('s-maxage=42'); + }); + + it('delegates Netlify/Vercel function requests through the shared handler with env overrides', async () => { + const fetchSpy = mockUpstreamFetch(); + + const response = await apiHandler( + new Request('https://functions.example.com/gh/user/repo/functions-file.txt'), + { + env: { CACHE_DURATION: '43' }, + geo: {}, + waitUntil: vi.fn() + } + ); + + expect(fetchSpy).toHaveBeenCalledWith( + 'https://github.com/user/repo/functions-file.txt', + expect.objectContaining({ method: 'GET' }) + ); + expect(await response.text()).toBe('adapter-ok'); + expect(response.headers.get('Cache-Control')).toContain('s-maxage=43'); + }); + + it('delegates Deno requests through the shared handler with env overrides', async () => { + const fetchSpy = mockUpstreamFetch(); + vi.stubGlobal('Deno', { + env: { + get: vi.fn(name => (name === 'CACHE_DURATION' ? '44' : undefined)) + } + }); + + const response = await denoHandler( + new Request('https://deno.example.com/gh/user/repo/deno-file.txt') + ); + + expect(fetchSpy).toHaveBeenCalledWith( + 'https://github.com/user/repo/deno-file.txt', + expect.objectContaining({ method: 'GET' }) + ); + expect(await response.text()).toBe('adapter-ok'); + expect(response.headers.get('Cache-Control')).toContain('s-maxage=44'); + }); });