diff --git a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts index 990cd60f4c..59e412a9c4 100644 --- a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts +++ b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts @@ -928,6 +928,22 @@ describe('network stubbing', function () { .wait('@dest') }) + // @see https://github.com/cypress-io/cypress/issues/7967 + it('can skip redirects via followRedirect', function () { + const href = `/fixtures/generic.html?t=${Date.now()}` + const url = `/redirect?href=${encodeURIComponent(href)}` + + cy.route2('/redirect', (req) => { + req.followRedirect = true + req.reply((res) => { + expect(res.body).to.include('Some generic content') + expect(res.statusCode).to.eq(200) + res.send() + }) + }) + .then(() => fetch(url)) + }) + it('intercepts cached responses as expected', { browser: '!firefox', // TODO: why does firefox behave differently? transparently returns cached response }, function () { diff --git a/packages/net-stubbing/lib/external-types.ts b/packages/net-stubbing/lib/external-types.ts index bd5807e104..8c2d1ab88d 100644 --- a/packages/net-stubbing/lib/external-types.ts +++ b/packages/net-stubbing/lib/external-types.ts @@ -39,6 +39,11 @@ export namespace CyHttpMessages { export type IncomingRequest = BaseMessage & { responseTimeout?: number + /** + * Set if redirects should be followed when this request is made. By default, requests will + * not follow redirects before yielding the response (the 3xx redirect is yielded) + */ + followRedirect?: boolean } export interface IncomingHttpRequest extends IncomingRequest { diff --git a/packages/net-stubbing/lib/internal-types.ts b/packages/net-stubbing/lib/internal-types.ts index 98a4c282f0..ee2d9cadd1 100644 --- a/packages/net-stubbing/lib/internal-types.ts +++ b/packages/net-stubbing/lib/internal-types.ts @@ -19,6 +19,7 @@ export const SERIALIZABLE_REQ_PROPS = [ 'method', 'httpVersion', 'responseTimeout', + 'followRedirect', ] export const SERIALIZABLE_RES_PROPS = _.concat( @@ -89,6 +90,7 @@ export declare namespace NetEventFrames { // Millisecond timestamp for when the response should continue continueResponseAt?: number throttleKbps?: number + followRedirect?: boolean } // fired when a response has been sent completely by the server to an intercepted request diff --git a/packages/proxy/lib/http/request-middleware.ts b/packages/proxy/lib/http/request-middleware.ts index 40633b20e8..f68d2254b4 100644 --- a/packages/proxy/lib/http/request-middleware.ts +++ b/packages/proxy/lib/http/request-middleware.ts @@ -103,7 +103,7 @@ const SendRequestOutgoing: RequestMiddleware = function () { const requestOptions = { timeout: this.req.responseTimeout, strictSSL: false, - followRedirect: false, + followRedirect: this.req.followRedirect || false, retryIntervals: [0, 100, 200, 200], url: this.req.proxiedUrl, } diff --git a/packages/proxy/lib/types.ts b/packages/proxy/lib/types.ts index e0b3255cc2..05977a326b 100644 --- a/packages/proxy/lib/types.ts +++ b/packages/proxy/lib/types.ts @@ -10,6 +10,7 @@ export type CypressIncomingRequest = Request & { requestId: string body?: string responseTimeout?: number + followRedirect?: boolean } /**