Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add mock redirect response tests for "axios" and "follow-redirects" #581

Merged
merged 7 commits into from
Sep 8, 2024
131 changes: 119 additions & 12 deletions test/third-party/follow-redirect-http.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
// @vitest-environment jsdom
// @vitest-environment node
import { vi, it, expect, beforeAll, afterEach, afterAll } from 'vitest'
import { https } from 'follow-redirects'
import { HttpServer } from '@open-draft/test-server/http'
import { ClientRequestInterceptor } from '../../src/interceptors/ClientRequest'
import type { HttpRequestEventMap } from '../../src/glossary'
import { waitForClientRequest } from '../helpers'

const resolver = vi.fn<HttpRequestEventMap['request']>()

const interceptor = new ClientRequestInterceptor()
interceptor.on('request', resolver)

const server = new HttpServer((app) => {
app.post('/resource', (req, res) => {
@@ -24,6 +20,14 @@ const server = new HttpServer((app) => {
app.post('/user', (req, res) => {
res.status(200).send('hello from the server')
})

app.get('/original', (req, res) => {
res.writeHead(307, { Location: server.https.url('/redirected') })
})

app.get('/redirected', (req, res) => {
res.status(200).send('redirected response')
})
})

beforeAll(async () => {
@@ -33,19 +37,23 @@ beforeAll(async () => {

afterEach(() => {
vi.resetAllMocks()
interceptor.removeAllListeners()
})

afterAll(async () => {
interceptor.dispose()
await server.close()
})

it('intercepts a POST request issued by "follow-redirects"', async () => {
it('intercepts a request issued by "follow-redirects"', async () => {
const requestListener = vi.fn<[Request]>()
interceptor.on('request', ({ request }) => requestListener(request))

const { address } = server.https
const payload = JSON.stringify({ todo: 'Buy the milk' })

const catchResponseUrl = vi.fn()
const req = https.request(
const request = https.request(
{
method: 'POST',
hostname: address.host,
@@ -62,14 +70,16 @@ it('intercepts a POST request issued by "follow-redirects"', async () => {
}
)

req.end(payload)
request.end(payload)

const { text } = await waitForClientRequest(req as any)
const { text } = await waitForClientRequest(request as any)

expect(resolver).toHaveBeenCalledTimes(2)
await vi.waitFor(() => {
expect(requestListener).toHaveBeenCalledTimes(2)
})

// Intercepted initial request.
const [{ request: initialRequest }] = resolver.mock.calls[0]
const [initialRequest] = requestListener.mock.calls[0]

expect(initialRequest.method).toBe('POST')
expect(initialRequest.url).toBe(server.https.url('/resource'))
@@ -79,7 +89,7 @@ it('intercepts a POST request issued by "follow-redirects"', async () => {
expect(await initialRequest.json()).toEqual({ todo: 'Buy the milk' })

// Intercepted redirect request (issued by "follow-redirects").
const [{ request: redirectedRequest }] = resolver.mock.calls[1]
const [redirectedRequest] = requestListener.mock.calls[1]

expect(redirectedRequest.method).toBe('POST')
expect(redirectedRequest.url).toBe(server.https.url('/user'))
@@ -92,3 +102,100 @@ it('intercepts a POST request issued by "follow-redirects"', async () => {
expect(catchResponseUrl).toHaveBeenCalledWith(server.https.url('/user'))
expect(await text()).toBe('hello from the server')
})

it('supports mocking a redirect response to the original response', async () => {
const requestListener = vi.fn<[Request]>()

interceptor.once('request', ({ request, controller }) => {
requestListener(request)

if (request.url.endsWith('/original')) {
controller.respondWith(
Response.redirect(server.https.url('/redirected'), 307)
)
}
})

const catchResponseUrl = vi.fn()
const request = https.request(
{
method: 'GET',
hostname: server.https.address.host,
port: server.https.address.port,
path: '/original',
rejectUnauthorized: false,
},
(res) => {
catchResponseUrl(res.responseUrl)
}
)

request.end()

const { text } = await waitForClientRequest(request as any)

// Intercepted redirect request (issued by "follow-redirects").
const [redirectedRequest] = requestListener.mock.calls[0]

expect(redirectedRequest.method).toBe('GET')
expect(redirectedRequest.url).toBe(server.https.url('/original'))

// Response (original).
expect(catchResponseUrl).toHaveBeenCalledWith(server.https.url('/redirected'))
expect(await text()).toBe('redirected response')
})

/**
* @note `follow-redirects` requires `http` and `https` before the interceptor
* can patch them.
*/
it.skip('supports mocking a redirect response to a mocked response', async () => {
const requestListener = vi.fn<[Request]>()
kettanaito marked this conversation as resolved.
Show resolved Hide resolved

interceptor.once('request', ({ request, controller }) => {
requestListener(request)

if (request.url.endsWith('/original')) {
return controller.respondWith(
Response.redirect('https://localhost:3000/redirected', 307)
)
}

if (request.url.endsWith('/redirected')) {
return controller.respondWith(new Response('mocked response'))
}
})

const catchResponseUrl = vi.fn()
const request = followRedirects.https.request(
{
method: 'GET',
hostname: server.https.address.host,
port: server.https.address.port,
path: '/original',
rejectUnauthorized: false,
agents: {
http: new http.Agent(),
https: https.globalAgent,
},
},

(res) => {
catchResponseUrl(res.responseUrl)
}
)

request.end()

const { text } = await waitForClientRequest(request as any)

// Intercepted redirect request (issued by "follow-redirects").
const [redirectedRequest] = requestListener.mock.calls[0]

expect(redirectedRequest.method).toBe('GET')
expect(redirectedRequest.url).toBe(server.https.url('/original'))

// Response (original).
expect(catchResponseUrl).toHaveBeenCalledWith('http://localhost/redirected')
expect(await text()).toBe('mocked response')
})