Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/driver/src/cy/commands/xhr.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ module.exports = (Commands, Cypress, cy, state, config) ->
## reset the existing server
reset()

## reset any state on the backend
Cypress.backend('reset:xhr:server')

## create the server before each test run
## its possible for this to fail if the
## last test we ran ended with an invalid
Expand Down
4 changes: 0 additions & 4 deletions packages/runner/src/lib/event-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,6 @@ const eventManager = {
})
})

Cypress.on('test:before:run:async', () => {
Cypress.backend('reset:xhr:server')
})

Cypress.on('script:error', (err) => {
Cypress.stop()
localBus.emit('script:error', err)
Expand Down
1 change: 1 addition & 0 deletions packages/server/lib/server.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Socket = require("./socket")
Request = require("./request")
fileServer = require("./file_server")
XhrServer = require("./xhr_ws_server")
templateEngine = require("./template_engine")

DEFAULT_DOMAIN_NAME = "localhost"
fullyQualifiedRe = /^https?:\/\//
Expand Down
4 changes: 1 addition & 3 deletions packages/server/lib/socket.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ class Socket

_.defaults options,
socketId: null
onBeforeTestRun: ->
onIncomingXhr: ->
onResetXhrServer: ->
onSetRunnables: ->
onMocha: ->
onConnect: ->
Expand Down Expand Up @@ -341,8 +341,6 @@ class Socket
socket.on "external:open", (url) ->
require("electron").shell.openExternal(url)

socket.on "test:before:run:async", options.onBeforeTestRun

reporterEvents.forEach (event) =>
socket.on event, (data) =>
@toRunner(event, data)
Expand Down
53 changes: 37 additions & 16 deletions packages/server/lib/xhr_ws_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,76 @@ function trunc (str) {
})
}

type DeferredPromise<T> = {
resolve: Function
reject: Function
p: Bluebird<T>
}

export function create () {
let incomingXhrs: any = {}
let incomingXhrResponses: {
[key: string]: string | DeferredPromise<string>
} = {}

function onIncomingXhr (id, data) {
function onIncomingXhr (id: string, data: string) {
debug('onIncomingXhr %o', { id, res: trunc(data) })
const deferred = incomingXhrs[id]
const deferred = incomingXhrResponses[id]

if (deferred) {
if (deferred && typeof deferred !== 'string') {
// request came before response, resolve with it
return deferred.resolve({
data,
})
}

incomingXhrs[id] = data
// response came before request, cache the data
incomingXhrResponses[id] = data
}

function getDeferredResponse (id) {
debug('getDeferredResponse %o', { id })
// if we already have it, send it
const res = incomingXhrs[id]
const res = incomingXhrResponses[id]

if (res) {
if (res.then) {
debug('returning existing deferred promise for %o', { id })
if (typeof res === 'object') {
debug('returning existing deferred promise for %o', { id, res })

return res.p
}

debug('already have deferred response %o', { id, res: trunc(res) })
delete incomingXhrs[id]
delete incomingXhrResponses[id]

return res
}

return new Bluebird((resolve, reject) => {
let deferred: Partial<DeferredPromise<string>> = {}

deferred.p = new Bluebird((resolve, reject) => {
debug('do not have response, waiting %o', { id })
incomingXhrs[id] = { resolve, reject }
deferred.resolve = resolve
deferred.reject = reject
})
.tap((res) => {
debug('deferred response found %o', { id, res: trunc(res) })
})
}) as Bluebird<string>

incomingXhrResponses[id] = deferred as DeferredPromise<string>

return deferred.p
}

function reset () {
debug('resetting incomingXhrs %o', { length: incomingXhrs.length })
debug('resetting incomingXhrs')

_.forEach(incomingXhrs, ({ reject }) => {
reject(new Error('This stubbed XHR was pending on a stub response object from the driver, but the test ended before that happened.'))
_.forEach(incomingXhrResponses, (res) => {
if (typeof res !== 'string') {
res.reject(new Error('This stubbed XHR was pending on a stub response object from the driver, but the test ended before that happened.'))
}
})

incomingXhrs = {}
incomingXhrResponses = {}
}

return {
Expand Down
6 changes: 4 additions & 2 deletions packages/server/test/unit/xhr_ws_server_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ describe('lib/xhr_ws_server', function () {
expect(xhrServer.getDeferredResponse('foo')).to.eq('bar')
})

it('resolves a response when incomingXhr is received after request', function () {
it('resolves a response when incomingXhr is received after request', async function () {
const p = xhrServer.getDeferredResponse('foo')
const q = xhrServer.getDeferredResponse('foo')

xhrServer.onIncomingXhr('foo', 'bar')

return expect(p).to.eventually.deep.eq({ data: 'bar' })
await expect(p).to.eventually.deep.eq({ data: 'bar' })
await expect(q).to.eventually.deep.eq({ data: 'bar' })
})

it('rejects a response when incomingXhr is received and test gets reset', function () {
Expand Down