import http from 'node:http'; import { http as mswHttp, HttpResponse } from 'msw'; import { afterEach, describe, expect, it, vi } from 'vitest'; const loadOfetchWithLogger = async () => { vi.resetModules(); const { default: logger } = await import('@/utils/logger'); const { default: ofetch } = await import('@/utils/ofetch'); return { logger, ofetch }; }; afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); }); describe('ofetch', () => { it('marks prefer-proxy header on retryable responses', async () => { const { default: server } = await import('@/setup.test'); server.use(mswHttp.get('http://rsshub.test/fail-500', () => HttpResponse.text('fail', { status: 500 }))); const { logger, ofetch } = await loadOfetchWithLogger(); const warnSpy = vi.spyOn(logger, 'warn').mockImplementation(() => logger); await expect( ofetch('http://rsshub.test/fail-500', { retry: 1, retryDelay: 0, onResponse({ options }) { options.headers = null as unknown as Headers; }, }) ).rejects.toBeDefined(); expect(warnSpy).toHaveBeenCalled(); }); it('logs redirected responses', async () => { const { logger, ofetch } = await loadOfetchWithLogger(); const httpSpy = vi.spyOn(logger, 'http').mockImplementation(() => logger); const server = http.createServer((req, res) => { if (req.url === '/redirect') { res.statusCode = 302; res.setHeader('Location', '/target'); res.end(); return; } res.statusCode = 200; res.end('ok'); }); await new Promise((resolve) => server.listen(0, resolve)); const address = server.address(); const port = typeof address === 'object' && address ? address.port : 0; try { await ofetch(`http://127.0.0.1:${port}/redirect`); } finally { server.close(); } expect(httpSpy).toHaveBeenCalled(); }); });