On a site, I have a caching infrastructure like this:
After a deploy, I would like to receive a 'fresh' and uncached version of the site for my Cypress-tests. I don't want to clear the cache for all visitors. I just want my Cypress-tests to see an uncached version, after a deploy.
My idea was add a header to all my cy.visit
and cy.request
, and then setting up my Varnish-cache settings, to look for that. And handling it in Redis as well.
It appears to be quite cumbersome, but doable, to actually do this 'bypass-cache'-setup in Varnish and Redis. If anyone has a better/simpler way of doing this, I'm all ears.
What the core of this question is: 'How do I send a header with all my cy.visit
and cy.request
, without having to type it out like this, every time (see below)?
cy.request({
method: 'GET',
url: 'https://example.org',
headers: {
'x-my-custom-header': 'myValue'
}
}).then((response) => {
// ...
});
cy.visit('/', {
headers: {
'x-my-custom-header': 'myValue'
}});
I considered building my own custom command on top of this. But it gets long-tailed and clumbsy quickly.
I also considered, if I could intercept all requests and add the header to it, in beforeEach
in my e2e.js
. I couldn't get this to work, though. This was my attempt:
beforeEach(() => {
cy.intercept('*', (req) => {
req.headers['x-foo'] = 'bar';
});
});
Requests issued from the test (handled with intercept)
You haven't mentioned the problem with the intercept, just that there is one. If there are other intercepts in the pipeline, the middleware
option ensures the headers are added before those other intercepts are called.
Passing a request to the next request handler
// you could have a top-level middleware handler that
// sets an auth token on all requests
// but remember setting `middleware: true` will
// cause this to always be called first
cy.intercept('http://api.company.com/',
{ middleware: true }, <-- don't block the intercepts in the tests
(req) => {
req.headers['authorization'] = `token ${token}`
}
)
Example
beforeEach(() => {
cy.intercept('*', { middleware: true }, (req) => {
req.headers['x-nocache'] = '123'
}).as('header-added')
})
it('/todos/1 with additional header', () => {
cy.intercept('https://jsonplaceholder.typicode.com/todos/1')
.as('wait-for-response')
cy.window().then(win => win.fetch('https://jsonplaceholder.typicode.com/todos/1'))
cy.wait('@wait-for-response')
.its('request')
.its('headers')
.its('x-nocache')
.should('eq', '123')
})
it('/todos/2 with additional header', () => {
cy.window().then(win => win.fetch('https://jsonplaceholder.typicode.com/todos/2'))
cy.wait('@header-added')
.its('request')
.its('headers')
.its('x-nocache')
.should('eq', '123')
})
Requests issued from the test (not handled by intercept)
Using a custom command to add header to all cy.request()
Cypress.Commands.overwrite("request", (originalFn, ...args) => {
const {_} = Cypress
const isMethod = (a) => ['GET','POST','PUT','PATCH','DELETE'].includes(a)
let options = { headers: {} }
if (_.isObject(args[0])) {
_.extend(options, args[0])
} else if (args.length === 1) {
options.url = args[0]
} else if (args.length === 2 && isMethod(args[0])) {
options.method = args[0]
options.url = args[1]
} else if (args.length === 2 && _.isObject(args[1])) {
options.url = args[0]
options.body = args[1]
} else if (args.length === 3) {
options.method = args[0]
options.url = args[1]
options.body = args[2]
}
options.headers['x-nocache'] = '123'
return originalFn(options)
})
cy.request('https://jsonplaceholder.typicode.com/todos/3')
.its('requestHeaders').should('have.property', 'x-nocache', '123')
cy.request({url: 'https://jsonplaceholder.typicode.com/todos/3', headers:{'x-other': 'abc'}})
.its('requestHeaders')
.should(requestHeaders => {
expect(requestHeaders['x-nocache']).to.eq('123')
expect(requestHeaders['x-other']).to.eq('abc')
})