@revoloo/cypress6
Version:
Cypress.io end to end testing tool
142 lines (116 loc) • 4.15 kB
JavaScript
// https://github.com/cypress-io/cypress/issues/761
describe('issue #761 - aborted XHRs from previous tests', () => {
context('aborted when complete', () => {
it('test 1 dispatches xhr, but completes in test 2', () => {
cy.window().then((win) => {
const xhr = new win.XMLHttpRequest()
xhr.open('GET', '/timeout?ms=1000')
xhr.onload = () => {
// we are in test 2 at this point
// and should not throw
xhr.abort()
}
xhr.send()
})
})
it('test 2 aborts the completed XHR', () => {
cy.wait(2000)
})
})
context('aborted before complete', () => {
let xhr = null
// TODO: we lose a reference here to the xhr in test 2
// so it shows up as "pending" forever because we reset
// the proxied XHR's as references when the next test starts
it('test 1 dispatches xhr, but completes in test 2', () => {
cy.window().then((win) => {
xhr = new win.XMLHttpRequest()
xhr.open('GET', '/timeout?ms=1000')
xhr.send()
})
})
it('test 2 aborts the incomplete XHR which is currently in flight', () => {
// we are in test 2 at this point
// and should not throw when we
// abort the incomplete xhr
expect(xhr.aborted).not.to.be.true
xhr.abort()
})
})
})
// as of chrome 71, chrome no longer fires
// readyState or abort events synchronously
// when the document unloads. instead we must
// assume they are aborting the request and
// simply check to ensure the XHR has been
// canceled internally by Cypress
// https://github.com/cypress-io/cypress/issues/3973
if (Cypress.isBrowser('chrome')) {
describe('issue #3973 - unloaded xhrs do not fire readystatechange event in chrome >= 71', () => {
it('cancels pending requests that are incomplete', () => {
const logs = []
const xhrs = []
const stub = cy.stub()
cy.on('log:added', (attrs, log) => {
if (attrs.name === 'xhr') {
logs.push(log)
}
})
cy
.server()
.route('GET', /timeout/).as('getTimeout')
.visit('http://localhost:3500/fixtures/generic.html')
.window()
.then((win) => {
const xhr = new win.XMLHttpRequest()
xhrs.push(xhr)
xhr.open('GET', '/timeout?ms=100')
xhr.send()
})
.wait('@getTimeout')
.window()
.then((win) => {
return new Promise((resolve) => {
cy.on('window:unload', resolve)
const xhr = new win.XMLHttpRequest()
xhrs.push(xhr)
xhr.open('GET', '/timeout?ms=2000')
xhr.abort = stub // this should not get called
xhr.onerror = stub // this should not fire
xhr.onload = stub // this should not fire
xhr.send()
win.location.reload()
})
})
.wait('@getTimeout')
.then((xhrProxy) => {
// after we unload we should cancel the
// pending XHR's and receive it here
// after waiting on it
expect(xhrProxy.canceled).to.be.true
const [firstXhr, secondXhr] = xhrs
const [firstLog, secondLog] = logs
// should be the same XHR here as the proxy's XHR
expect(secondXhr === xhrProxy.xhr).to.be.true
expect(firstXhr.canceled).not.to.be.true
expect(firstXhr.aborted).not.to.be.true
expect(firstXhr.readyState).to.eq(4)
expect(firstLog.get('state')).to.eq('passed')
// since we've canceled the underlying XHR
// ensure that our abort code did not run
// and that the underlying XHR was never
// completed with a status or response
expect(secondXhr.canceled).to.be.true
expect(secondXhr.aborted).not.to.be.true
expect(secondXhr.status).to.eq(0)
expect(secondXhr.responseText).to.eq('')
expect(stub).not.to.be.called
expect(secondLog.get('state')).to.eq('failed')
expect(secondLog.invoke('renderProps')).to.deep.eq({
message: 'GET (canceled) /timeout?ms=2000',
indicator: 'aborted',
})
})
})
})
}