diff --git a/packages/driver/cypress/fixtures/isolated-runner-inner.html b/packages/driver/cypress/fixtures/isolated-runner-inner.html
new file mode 100644
index 000000000000..895fc7379f48
--- /dev/null
+++ b/packages/driver/cypress/fixtures/isolated-runner-inner.html
@@ -0,0 +1,24 @@
+
+
+
+ Isolated Runner Fixture
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/driver/cypress/integration/commands/actions/click_spec.js b/packages/driver/cypress/integration/commands/actions/click_spec.js
index 93ff851c272a..7fd96b610db7 100644
--- a/packages/driver/cypress/integration/commands/actions/click_spec.js
+++ b/packages/driver/cypress/integration/commands/actions/click_spec.js
@@ -3711,7 +3711,8 @@ describe('shadow dom', () => {
it('does not hang when experimentalShadowDomSupport is false and clicking on custom element', () => {
Cypress.config('experimentalShadowDomSupport', false)
// needs some size or it's considered invisible and click will fail its prerequisites
- cy.$$('#shadow-element-1').css({ padding: 2 })
+ // so we make it display: block so its getClientRects() contains only a single
+ cy.$$('#shadow-element-1').css({ display: 'block' })
cy.get('#shadow-element-1').click()
})
diff --git a/packages/driver/cypress/integration/commands/actions/type_spec.js b/packages/driver/cypress/integration/commands/actions/type_spec.js
index 120c9b59b49d..d22a6642f258 100644
--- a/packages/driver/cypress/integration/commands/actions/type_spec.js
+++ b/packages/driver/cypress/integration/commands/actions/type_spec.js
@@ -3051,7 +3051,7 @@ describe('src/cy/commands/actions/type - #type', () => {
const spyTableName = cy.spy(top.console, 'groupCollapsed')
const spyTableData = cy.spy(top.console, 'table')
- const commandLogEl = getCommandLogWithText('foo')
+ const commandLogEl = getCommandLogWithText('foo', 'message-text')
const reactCommandInstance = findReactInstance(commandLogEl[0])
diff --git a/packages/driver/cypress/integration/e2e/dom_hitbox.spec.js b/packages/driver/cypress/integration/e2e/dom_hitbox.spec.js
index a5d0fb2561c3..cd4fba07b7b6 100644
--- a/packages/driver/cypress/integration/e2e/dom_hitbox.spec.js
+++ b/packages/driver/cypress/integration/e2e/dom_hitbox.spec.js
@@ -127,7 +127,7 @@ const ensureCorrectHighlightPositions = (sel) => {
const getAndPin = (sel) => {
cy.get(sel)
- clickCommandLog(sel)
+ clickCommandLog(sel, 'message-text')
}
const clickAndPin = (sel, ...args) => {
diff --git a/packages/driver/cypress/support/utils.js b/packages/driver/cypress/support/utils.js
index 149ecfd51a88..bd37b8414ca8 100644
--- a/packages/driver/cypress/support/utils.js
+++ b/packages/driver/cypress/support/utils.js
@@ -1,14 +1,12 @@
const { $, _, Promise } = Cypress
-export const getCommandLogWithText = (text) => {
+export const getCommandLogWithText = (command, type = 'method') => {
// Open current test if not already open, so we can find the command log
cy.$$('.runnable-active .runnable-wrapper:not(.is-open)', top.document).click()
return cy
- .$$(`.runnable-active .command-wrapper:contains(${text})`, top.document)
- .parentsUntil('li')
- .last()
- .parent()
+ .$$(`.runnable-active .command-${type}:contains(${command})`, top.document)
+ .closest('.command')
}
export const findReactInstance = function (dom) {
@@ -22,12 +20,11 @@ export const findReactInstance = function (dom) {
: internalInstance.return.stateNode
}
-export const clickCommandLog = (sel) => {
+export const clickCommandLog = (sel, type) => {
return cy.wait(10)
.then(() => {
return withMutableReporterState(() => {
- const commandLogEl = getCommandLogWithText(sel)
-
+ const commandLogEl = getCommandLogWithText(sel, type)
const reactCommandInstance = findReactInstance(commandLogEl[0])
if (!reactCommandInstance) {
diff --git a/packages/driver/src/cy/errors.js b/packages/driver/src/cy/errors.js
index 5f50742d4a3f..7d10e1bc6298 100644
--- a/packages/driver/src/cy/errors.js
+++ b/packages/driver/src/cy/errors.js
@@ -14,6 +14,8 @@ const create = (state, config, log) => {
snapshot: true,
error: err,
consoleProps () {
+ if (!current) return
+
const obj = {}
const prev = current.get('prev')
diff --git a/packages/driver/src/dom/coordinates.js b/packages/driver/src/dom/coordinates.js
index 2de5b81b6508..f115fcb8faba 100644
--- a/packages/driver/src/dom/coordinates.js
+++ b/packages/driver/src/dom/coordinates.js
@@ -1,3 +1,4 @@
+const _ = require('lodash')
const $window = require('./window')
const $elements = require('./elements')
@@ -7,6 +8,13 @@ const getElementAtPointFromViewport = (doc, x, y) => {
const isAutIframe = (win) => !$elements.getNativeProp(win.parent, 'frameElement')
+const getFirstValidSizedRect = (el) => {
+ return _.find(el.getClientRects(), (rect) => {
+ // use the first rect that has a nonzero width and height
+ return rect.width && rect.height
+ }) || el.getBoundingClientRect() // otherwise fall back to the parent client rect
+}
+
/**
* @param {JQuery} $el
*/
@@ -32,7 +40,7 @@ const getElementPositioning = ($el) => {
// returns a zero length DOMRectList in that case, which becomes undefined.
// so we fallback to getBoundingClientRect() so that we get an actual DOMRect
// with all properties 0'd out
- const rect = [...el.getClientRects()].find((e) => e.width && e.height) || el.getBoundingClientRect()
+ const rect = getFirstValidSizedRect(el)
// we want to return the coordinates from the autWindow to the element
// which handles a situation in which the element is inside of a nested
diff --git a/packages/runner/cypress/fixtures/errors/assertions_spec.js b/packages/runner/cypress/fixtures/errors/assertions_spec.js
new file mode 100644
index 000000000000..5651e2c274ab
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/assertions_spec.js
@@ -0,0 +1,15 @@
+import './setup'
+
+describe('assertion failures', () => {
+ it('with expect().', () => {
+ expect('actual').to.equal('expected')
+ })
+
+ it('with assert()', () => {
+ assert(false, 'should be true')
+ })
+
+ it('with assert.()', () => {
+ assert.equal('actual', 'expected')
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/commands_spec.js b/packages/runner/cypress/fixtures/errors/commands_spec.js
new file mode 100644
index 000000000000..2f509a585350
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/commands_spec.js
@@ -0,0 +1,11 @@
+import './setup'
+
+describe('commands', { defaultCommandTimeout: 0 }, () => {
+ it('failure', () => {
+ cy.get('#does-not-exist')
+ })
+
+ it('chained failure', () => {
+ cy.get('body').find('#does-not-exist')
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/custom_commands_spec.js b/packages/runner/cypress/fixtures/errors/custom_commands_spec.js
new file mode 100644
index 000000000000..919a23d68f6c
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/custom_commands_spec.js
@@ -0,0 +1,27 @@
+import './setup'
+
+Cypress.Commands.add('failAssertion', () => {
+ expect('actual').to.equal('expected')
+})
+
+Cypress.Commands.add('failException', () => {
+ ({}).bar()
+})
+
+Cypress.Commands.add('failCommand', () => {
+ cy.get('#does-not-exist')
+})
+
+describe('custom commands', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ cy.failAssertion()
+ })
+
+ it('exception', () => {
+ cy.failException()
+ })
+
+ it('command failure', () => {
+ cy.failCommand()
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/docs_url_spec.js b/packages/runner/cypress/fixtures/errors/docs_url_spec.js
new file mode 100644
index 000000000000..f5806c950ec7
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/docs_url_spec.js
@@ -0,0 +1,13 @@
+import './setup'
+
+describe('docs url', () => {
+ it('displays as button in interactive mode', () => {
+ Cypress.config('isInteractive', true)
+ cy.viewport()
+ })
+
+ it('is text in error message in run mode', () => {
+ Cypress.config('isInteractive', false)
+ cy.viewport()
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/each_spec.js b/packages/runner/cypress/fixtures/errors/each_spec.js
new file mode 100644
index 000000000000..e95785680ddf
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/each_spec.js
@@ -0,0 +1,21 @@
+import './setup'
+
+describe('cy.each', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ cy.wrap([1]).each(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('exception', () => {
+ cy.wrap([1]).each(() => {
+ ({}).bar()
+ })
+ })
+
+ it('command failure', () => {
+ cy.wrap([1]).each(() => {
+ cy.get('#does-not-exist')
+ })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/events_spec.js b/packages/runner/cypress/fixtures/errors/events_spec.js
new file mode 100644
index 000000000000..855dd08d5516
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/events_spec.js
@@ -0,0 +1,35 @@
+import './setup'
+
+describe('event handlers', { defaultCommandTimeout: 0 }, () => {
+ it('event assertion failure', () => {
+ cy.on('window:load', () => {
+ expect('actual').to.equal('expected')
+ })
+
+ cy.visit('http://localhost:1919')
+ })
+
+ it('event exception', () => {
+ cy.on('window:load', () => {
+ ({}).bar()
+ })
+
+ cy.visit('http://localhost:1919')
+ })
+
+ it('fail handler assertion failure', () => {
+ cy.on('fail', () => {
+ expect('actual').to.equal('expected')
+ })
+
+ cy.get('#does-not-exist')
+ })
+
+ it('fail handler exception', () => {
+ cy.on('fail', () => {
+ ({}).bar()
+ })
+
+ cy.get('#does-not-exist')
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/exceptions_spec.js b/packages/runner/cypress/fixtures/errors/exceptions_spec.js
new file mode 100644
index 000000000000..ec61175d6b1c
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/exceptions_spec.js
@@ -0,0 +1,13 @@
+import './setup'
+
+const outsideError = require('../../../../server/test/support/fixtures/projects/todos/throws-error')
+
+describe('exception failures', () => {
+ it('in spec file', () => {
+ ({}).bar()
+ })
+
+ it('in file outside project', () => {
+ outsideError()
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/readfile_spec.js b/packages/runner/cypress/fixtures/errors/readfile_spec.js
new file mode 100644
index 000000000000..141e89113e3c
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/readfile_spec.js
@@ -0,0 +1,7 @@
+import './setup'
+
+describe('cy.readFile', () => {
+ it('existence failure', () => {
+ cy.readFile('does-not-exist', { timeout: 0 })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/route_spec.js b/packages/runner/cypress/fixtures/errors/route_spec.js
new file mode 100644
index 000000000000..889e2be067d2
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/route_spec.js
@@ -0,0 +1,85 @@
+import { abortXhr, sendXhr } from './setup'
+
+describe('cy.route', { defaultCommandTimeout: 0 }, () => {
+ it('callback assertion failure', () => {
+ cy.server().route(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('callback exception', () => {
+ cy.server().route(() => {
+ ({}).bar()
+ })
+ })
+
+ it('command failure', () => {
+ cy.server().route(() => {
+ cy.get('#does-not-exist')
+
+ return '/foo'
+ })
+ })
+
+ it('onAbort assertion failure', () => {
+ cy.server().route({
+ url: '/foo',
+ onAbort () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ .window().then(abortXhr('/foo'))
+ })
+
+ it('onAbort exception', () => {
+ cy.server().route({
+ url: '/foo',
+ onAbort () {
+ ({}).bar()
+ },
+ })
+ .window().then(abortXhr('/foo'))
+ })
+
+ it('onRequest assertion failure', () => {
+ cy.server().route({
+ url: '/foo',
+ onRequest () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ .window().then(sendXhr('/foo'))
+ })
+
+ it('onRequest exception', () => {
+ cy.server().route({
+ url: '/foo',
+ onRequest () {
+ ({}).bar()
+ },
+ })
+ .window().then(sendXhr('/foo'))
+ })
+
+ it('onResponse assertion failure', () => {
+ cy.server().route({
+ url: '/json-content-type',
+ onResponse () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ .window().then(sendXhr('/json-content-type'))
+ .wait(10000)
+ })
+
+ it('onResponse exception', () => {
+ cy.server().route({
+ url: '/json-content-type',
+ onResponse () {
+ ({}).bar()
+ },
+ })
+ .window().then(sendXhr('/json-content-type'))
+ .wait(10000)
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/server_spec.js b/packages/runner/cypress/fixtures/errors/server_spec.js
new file mode 100644
index 000000000000..5f6677520e9f
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/server_spec.js
@@ -0,0 +1,65 @@
+import { abortXhr, sendXhr } from './setup'
+
+describe('cy.server', { defaultCommandTimeout: 0 }, () => {
+ it('onAbort assertion failure', () => {
+ cy.server({
+ onAbort () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ .route('/foo')
+ .window().then(abortXhr('/foo'))
+ })
+
+ it('onAbort exception', () => {
+ cy.server({
+ onAbort () {
+ ({}).bar()
+ },
+ })
+ .route('/foo')
+ .window().then(abortXhr('/foo'))
+ })
+
+ it('onRequest assertion failure', () => {
+ cy.server({
+ onRequest () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ .route('/foo')
+ .window().then(sendXhr('/foo'))
+ })
+
+ it('onRequest exception', () => {
+ cy.server({
+ onRequest () {
+ ({}).bar()
+ },
+ })
+ .route('/foo')
+ .window().then(sendXhr('/foo'))
+ })
+
+ it('onResponse assertion failure', () => {
+ cy.server({
+ onResponse () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ .route('/json-content-type')
+ .window().then(sendXhr('/json-content-type'))
+ .wait(10000)
+ })
+
+ it('onResponse exception', () => {
+ cy.server({
+ onResponse () {
+ ({}).bar()
+ },
+ })
+ .route('/json-content-type')
+ .window().then(sendXhr('/json-content-type'))
+ .wait(10000)
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/setup.js b/packages/runner/cypress/fixtures/errors/setup.js
new file mode 100644
index 000000000000..f6d5fb0b83bc
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/setup.js
@@ -0,0 +1,29 @@
+const testToRun = window.testToRun
+const originalIt = window.it
+
+window.it = (title, ...args) => {
+ const itFn = title === testToRun ? originalIt : () => {}
+
+ return itFn(title, ...args)
+}
+
+window.it.only = () => {
+ throw new Error('Instead of putting .only in the spec-under-test, put it in the corresponding test in the parent spec (reporter.error.spec.js, etc)')
+}
+
+// eslint-disable-next-line
+export const sendXhr = (route) => (win) => {
+ const xhr = new win.XMLHttpRequest()
+
+ xhr.open('GET', route)
+ xhr.send()
+
+ return xhr
+}
+
+// eslint-disable-next-line
+export const abortXhr = (route) => (win) => {
+ const xhr = sendXhr(route)(win)
+
+ xhr.abort()
+}
diff --git a/packages/runner/cypress/fixtures/errors/should_spec.js b/packages/runner/cypress/fixtures/errors/should_spec.js
new file mode 100644
index 000000000000..5d7158333497
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/should_spec.js
@@ -0,0 +1,58 @@
+import './setup'
+
+describe('cy.should', { defaultCommandTimeout: 0 }, () => {
+ it('callback assertion failure', () => {
+ cy.wrap({}).should(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('callback exception', () => {
+ cy.wrap({}).should(() => {
+ ({}).bar()
+ })
+ })
+
+ it('standard assertion failure', () => {
+ cy.wrap({})
+ .should('have.property', 'foo')
+ })
+
+ it('after multiple', () => {
+ cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
+ .should('equal', 'bar')
+ })
+
+ it('after multiple callbacks exception', () => {
+ cy.wrap({ foo: 'foo' })
+ .should(() => {
+ expect(true).to.be.true
+ })
+ .should(() => {
+ ({}).bar()
+ })
+ })
+
+ it('after multiple callbacks assertion failure', () => {
+ cy.wrap({ foo: 'foo' })
+ .should(() => {
+ expect(true).to.be.true
+ })
+ .should(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('after callback success assertion failure', () => {
+ cy.wrap({})
+ .should(() => {
+ expect(true).to.be.true
+ })
+ .should('have.property', 'foo')
+ })
+
+ it('command failure after success', () => {
+ cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
+ cy.get('#does-not-exist')
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/spread_spec.js b/packages/runner/cypress/fixtures/errors/spread_spec.js
new file mode 100644
index 000000000000..b6dd1a51bf1c
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/spread_spec.js
@@ -0,0 +1,21 @@
+import './setup'
+
+describe('cy.spread', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ cy.wrap([1, 2, 3]).spread(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('exception', () => {
+ cy.wrap([1, 2, 3]).spread(() => {
+ ({}).bar()
+ })
+ })
+
+ it('command failure', () => {
+ cy.wrap([1, 2, 3]).spread(() => {
+ cy.get('#does-not-exist')
+ })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/then_spec.js b/packages/runner/cypress/fixtures/errors/then_spec.js
new file mode 100644
index 000000000000..00c45d4bb431
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/then_spec.js
@@ -0,0 +1,21 @@
+import './setup'
+
+describe('cy.then', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ cy.wrap({}).then(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('exception', () => {
+ cy.wrap({}).then(() => {
+ ({}).bar()
+ })
+ })
+
+ it('command failure', () => {
+ cy.wrap({}).then(() => {
+ cy.get('#does-not-exist')
+ })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/typescript_spec.ts b/packages/runner/cypress/fixtures/errors/typescript_spec.ts
new file mode 100644
index 000000000000..285c310e6404
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/typescript_spec.ts
@@ -0,0 +1,21 @@
+import './setup'
+
+// simple example of typescript types
+type Foo = {
+ something: string
+}
+
+describe('typescript', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ expect('actual').to.equal('expected')
+ })
+
+ it('exception', () => {
+ // @ts-ignore
+ ({}).bar()
+ })
+
+ it('command failure', () => {
+ cy.get('#does-not-exist')
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/uncaught_spec.js b/packages/runner/cypress/fixtures/errors/uncaught_spec.js
new file mode 100644
index 000000000000..8edadd6daf9d
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/uncaught_spec.js
@@ -0,0 +1,28 @@
+import './setup'
+
+describe('uncaught errors', { defaultCommandTimeout: 0 }, () => {
+ it('sync app exception', () => {
+ cy.visit('/index.html')
+ cy.get('.trigger-sync-error').click()
+ })
+
+ it('async app exception', () => {
+ cy.visit('/index.html')
+ cy.get('.trigger-async-error').click()
+ cy.wait(10000)
+ })
+
+ it('async exception', () => {
+ setTimeout(() => {
+ ({}).bar()
+ })
+
+ cy.wait(10000)
+ })
+
+ it('async exception with done', (done) => {
+ setTimeout(() => {
+ ({}).bar()
+ })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/unexpected_spec.js b/packages/runner/cypress/fixtures/errors/unexpected_spec.js
new file mode 100644
index 000000000000..18f869f5b97c
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/unexpected_spec.js
@@ -0,0 +1,30 @@
+import './setup'
+
+describe('unexpected errors', { defaultCommandTimeout: 0 }, () => {
+ let originalIsSpecialKeyword
+ let orignalCyExpect
+
+ beforeEach(() => {
+ originalIsSpecialKeyword = Cypress.LocalStorage._isSpecialKeyword
+ orignalCyExpect = cy.expect
+ })
+
+ afterEach(() => {
+ Cypress.LocalStorage._isSpecialKeyword = originalIsSpecialKeyword
+ cy.expect = orignalCyExpect
+ })
+
+ it('Cypress method error', () => {
+ Cypress.LocalStorage.setStorages({ foo: 'foo' })
+
+ window.autWindow.eval(`Cypress.LocalStorage._isSpecialKeyword = () => { throw new Error('thrown in Cypress-LocalStorage-_isSpecialKeyword') }`)
+
+ Cypress.LocalStorage.clear()
+ })
+
+ it('internal cy error', () => {
+ window.autWindow.eval(`cy.expect = () => { throw new Error('thrown in cy-expect') }`)
+
+ cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/validation_spec.js b/packages/runner/cypress/fixtures/errors/validation_spec.js
new file mode 100644
index 000000000000..21d2e48ad3bc
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/validation_spec.js
@@ -0,0 +1,15 @@
+import './setup'
+
+describe('validation errors', { defaultCommandTimeout: 0 }, () => {
+ it('from cypress', () => {
+ cy.viewport()
+ })
+
+ it('from chai expect', () => {
+ expect(true).to.be.nope
+ })
+
+ it('from chai assert', () => {
+ assert.deepInclude()
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/visit_spec.js b/packages/runner/cypress/fixtures/errors/visit_spec.js
new file mode 100644
index 000000000000..f2b727082670
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/visit_spec.js
@@ -0,0 +1,35 @@
+import './setup'
+
+describe('cy.visit', () => {
+ it('onBeforeLoad assertion failure', () => {
+ cy.visit('/index.html', {
+ onBeforeLoad () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ })
+
+ it('onBeforeLoad exception', () => {
+ cy.visit('/index.html', {
+ onBeforeLoad () {
+ ({}).bar()
+ },
+ })
+ })
+
+ it('onLoad assertion failure', () => {
+ cy.visit('/index.html', {
+ onLoad () {
+ expect('actual').to.equal('expected')
+ },
+ })
+ })
+
+ it('onLoad exception', () => {
+ cy.visit('/index.html', {
+ onLoad () {
+ ({}).bar()
+ },
+ })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/within_spec.js b/packages/runner/cypress/fixtures/errors/within_spec.js
new file mode 100644
index 000000000000..d7ca3f342351
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/within_spec.js
@@ -0,0 +1,21 @@
+import './setup'
+
+describe('cy.within', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ cy.get('body').within(() => {
+ expect('actual').to.equal('expected')
+ })
+ })
+
+ it('exception', () => {
+ cy.get('body').within(() => {
+ ({}).bar()
+ })
+ })
+
+ it('command failure', () => {
+ cy.get('body').within(() => {
+ cy.get('#does-not-exist')
+ })
+ })
+})
diff --git a/packages/runner/cypress/fixtures/errors/wrap_spec.js b/packages/runner/cypress/fixtures/errors/wrap_spec.js
new file mode 100644
index 000000000000..f566fc572c27
--- /dev/null
+++ b/packages/runner/cypress/fixtures/errors/wrap_spec.js
@@ -0,0 +1,21 @@
+import './setup'
+
+describe('cy.wrap', { defaultCommandTimeout: 0 }, () => {
+ it('assertion failure', () => {
+ cy.wrap(() => {
+ expect('actual').to.equal('expected')
+ }).then((fn) => fn())
+ })
+
+ it('exception', () => {
+ cy.wrap(() => {
+ ({}).bar()
+ }).then((fn) => fn())
+ })
+
+ it('command failure', () => {
+ cy.wrap(() => {
+ cy.get('#does-not-exist')
+ }).then((fn) => fn())
+ })
+})
diff --git a/packages/runner/cypress/integration/reporter.errors.spec.js b/packages/runner/cypress/integration/reporter.errors.spec.js
new file mode 100644
index 000000000000..c5af93b1ffc1
--- /dev/null
+++ b/packages/runner/cypress/integration/reporter.errors.spec.js
@@ -0,0 +1,708 @@
+const helpers = require('../support/helpers')
+
+const _ = Cypress._
+const { runIsolatedCypress } = helpers.createCypress()
+
+export const verifyFailure = (options) => {
+ const {
+ hasCodeFrame = true,
+ verifyOpenInIde = true,
+ column,
+ codeFrameText,
+ message,
+ stack,
+ file,
+ win,
+ } = options
+ let { regex, line } = options
+
+ regex = regex || new RegExp(`${file}:${line || '\\d+'}:${column}`)
+
+ const testOpenInIde = () => {
+ expect(win.runnerWs.emit.withArgs('open:file').lastCall.args[1].file).to.include(file)
+ }
+
+ win.runnerWs.emit.withArgs('get:user:editor')
+ .yields({
+ preferredOpener: {
+ id: 'foo-editor',
+ name: 'Foo',
+ openerId: 'foo-editor',
+ isOther: false,
+ },
+ })
+
+ win.runnerWs.emit.withArgs('open:file')
+
+ cy.contains('View stack trace').click()
+
+ _.each([].concat(message), (msg) => {
+ cy.get('.runnable-err-message')
+ .should('include.text', msg)
+
+ cy.get('.runnable-err-stack-trace')
+ .should('not.include.text', msg)
+ })
+
+ cy.get('.runnable-err-stack-trace')
+ .invoke('text')
+ .should('match', regex)
+
+ if (stack) {
+ _.each([].concat(stack), (stackLine) => {
+ cy.get('.runnable-err-stack-trace')
+ .should('include.text', stackLine)
+ })
+ }
+
+ cy.get('.runnable-err-stack-trace')
+ .should('not.include.text', '__stackReplacementMarker')
+
+ if (verifyOpenInIde) {
+ cy.contains('.runnable-err-stack-trace .runnable-err-file-path a', file)
+ .click()
+ .should(() => {
+ testOpenInIde()
+ })
+ }
+
+ if (!hasCodeFrame) return
+
+ cy
+ .get('.test-err-code-frame .runnable-err-file-path')
+ .invoke('text')
+ .should('match', regex)
+
+ cy.get('.test-err-code-frame pre span').should('include.text', codeFrameText)
+
+ if (verifyOpenInIde) {
+ cy.contains('.test-err-code-frame .runnable-err-file-path a', file)
+ .click()
+ .should(() => {
+ expect(win.runnerWs.emit.withArgs('open:file')).to.be.calledTwice
+ testOpenInIde()
+ })
+ }
+}
+
+const verifyInternalFailure = (props) => {
+ const { method } = props
+
+ cy.get('.runnable-err-message')
+ .should('include.text', `thrown in ${method.replace(/\./g, '-')}`)
+
+ cy.get('.runnable-err-stack-trace')
+ .should('include.text', method)
+
+ cy.get('.test-err-code-frame')
+ .should('not.exist')
+}
+
+// eslint-disable-next-line
+const createVerifyTest = (modifier) => (title, props) => {
+ const verifyFn = props.verifyFn || verifyFailure
+
+ ;(modifier ? it[modifier] : it)(title, () => {
+ return runIsolatedCypress(`cypress/fixtures/errors/${props.file}`, {
+ onBeforeRun ({ specWindow, win, autCypress }) {
+ specWindow.testToRun = title
+ specWindow.autWindow = win
+ specWindow.autCypress = autCypress
+
+ if (props.onBeforeRun) {
+ props.onBeforeRun({ specWindow, win })
+ }
+ },
+ })
+ .then(({ win }) => {
+ props.codeFrameText = props.codeFrameText || title
+ props.win = win
+
+ verifyFn(props)
+ })
+ })
+}
+
+const verify = {
+ it: createVerifyTest(),
+}
+
+verify.it['only'] = createVerifyTest('only')
+verify.it['skip'] = createVerifyTest('skip')
+
+describe('errors ui', () => {
+ describe('assertion failures', () => {
+ const file = 'assertions_spec.js'
+
+ verify.it('with expect().', {
+ file,
+ column: 25,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('with assert()', {
+ file,
+ column: '(5|12)',
+ message: `should be true`,
+ })
+
+ verify.it('with assert.()', {
+ file,
+ column: 12,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+ })
+
+ describe('exception failures', () => {
+ const file = 'exceptions_spec.js'
+
+ verify.it('in spec file', {
+ file,
+ column: 10,
+ message: 'bar is not a function',
+ })
+
+ verify.it('in file outside project', {
+ file,
+ message: 'An outside error',
+ regex: /todos\/throws\-error\.js:5:9/,
+ codeFrameText: `thrownewError('An outside error')`,
+ verifyOpenInIde: false,
+ })
+ })
+
+ describe('commands', () => {
+ const file = 'commands_spec.js'
+
+ verify.it('failure', {
+ file,
+ column: 8,
+ message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
+ })
+
+ verify.it('chained failure', {
+ file,
+ column: 20,
+ message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.then', () => {
+ const file = 'then_spec.js'
+
+ verify.it('assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 10,
+ message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.should', () => {
+ const file = 'should_spec.js'
+
+ verify.it('callback assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('callback exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('standard assertion failure', {
+ file,
+ column: 6,
+ message: 'Timed out retrying: expected {} to have property \'foo\'',
+ })
+
+ verify.it('after multiple', {
+ file,
+ column: 6,
+ message: 'Timed out retrying: expected \'foo\' to equal \'bar\'',
+ })
+
+ verify.it('after multiple callbacks exception', {
+ file,
+ column: 12,
+ codeFrameText: '({}).bar()',
+ message: 'bar is not a function',
+ })
+
+ verify.it('after multiple callbacks assertion failure', {
+ file,
+ column: 27,
+ codeFrameText: '.should(()=>',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('after callback success assertion failure', {
+ file,
+ column: 6,
+ codeFrameText: '.should(\'have.property',
+ message: `expected {} to have property 'foo'`,
+ })
+
+ verify.it('command failure after success', {
+ file,
+ column: 8,
+ message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.each', () => {
+ const file = 'each_spec.js'
+
+ verify.it('assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 10,
+ message: 'Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.spread', () => {
+ const file = 'spread_spec.js'
+
+ verify.it('assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 10,
+ message: 'Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.within', () => {
+ const file = 'within_spec.js'
+
+ verify.it('assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 10,
+ message: 'Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.wrap', () => {
+ const file = 'wrap_spec.js'
+
+ verify.it('assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 10,
+ message: 'Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('cy.visit', () => {
+ const file = 'visit_spec.js'
+
+ verify.it('onBeforeLoad assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onBeforeLoad',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('onBeforeLoad exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onBeforeLoad',
+ message: 'bar is not a function',
+ })
+
+ verify.it('onLoad assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onLoad',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('onLoad exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onLoad',
+ message: 'bar is not a function',
+ })
+ })
+
+ describe('cy.route', () => {
+ const file = 'route_spec.js'
+
+ verify.it('callback assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('callback exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 10,
+ message: 'Expected to find element: #does-not-exist, but never found it',
+ })
+
+ verify.it('onAbort assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onAbort',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('onAbort exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onAbort',
+ message: 'bar is not a function',
+ })
+
+ verify.it('onRequest assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onRequest',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('onRequest exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onRequest',
+ message: 'bar is not a function',
+ })
+
+ // FIXME: in isolated runner, the error ends up uncaught for
+ // some reason, which throws off the test
+ verify.it.skip('onResponse assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onResponse',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ // FIXME: in isolated runner, the error ends up uncaught for
+ // some reason, which throws off the test
+ verify.it.skip('onResponse exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onResponse',
+ message: 'bar is not a function',
+ })
+ })
+
+ describe('cy.server', () => {
+ const file = 'server_spec.js'
+
+ verify.it('onAbort assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onAbort',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('onAbort exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onAbort',
+ message: 'bar is not a function',
+ })
+
+ verify.it('onRequest assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onRequest',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('onRequest exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onRequest',
+ message: 'bar is not a function',
+ })
+
+ // FIXME: in isolated runner, the error ends up uncaught for
+ // some reason, which throws off the test
+ verify.it.skip('onResponse assertion failure', {
+ file,
+ column: 29,
+ codeFrameText: 'onResponse',
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ // FIXME: in isolated runner, the error ends up uncaught for
+ // some reason, which throws off the test
+ verify.it.skip('onResponse exception', {
+ file,
+ column: 14,
+ codeFrameText: 'onResponse',
+ message: 'bar is not a function',
+ })
+ })
+
+ describe('cy.readFile', () => {
+ const file = 'readfile_spec.js'
+
+ verify.it('existence failure', {
+ onBeforeRun ({ win }) {
+ win.runnerWs.emit.withArgs('backend:request', 'read:file')
+ .yields({ error: { code: 'ENOENT' } })
+ },
+ file,
+ column: 8,
+ message: 'failed because the file does not exist',
+ })
+ })
+
+ describe('validation errors', () => {
+ const file = 'validation_spec.js'
+
+ verify.it('from cypress', {
+ file,
+ column: 8,
+ message: 'can only accept a string preset or',
+ stack: ['throwErrBadArgs', 'From Your Spec Code:'],
+ })
+
+ verify.it('from chai expect', {
+ file,
+ column: '(5|12)', // different between chrome & firefox
+ message: 'Invalid Chai property: nope',
+ stack: ['proxyGetter', 'From Your Spec Code:'],
+ })
+
+ verify.it('from chai assert', {
+ file,
+ column: 12,
+ message: 'object tested must be an array',
+ })
+ })
+
+ describe('event handlers', () => {
+ const file = 'events_spec.js'
+
+ verify.it('event assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('event exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+
+ verify.it('fail handler assertion failure', {
+ file,
+ column: 27,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('fail handler exception', {
+ file,
+ column: 12,
+ message: 'bar is not a function',
+ })
+ })
+
+ describe('uncaught errors', () => {
+ const file = 'uncaught_spec.js'
+
+ verify.it('sync app exception', {
+ file,
+ message: [
+ 'The following error originated from your application code',
+ 'syncReference is not defined',
+ ],
+ regex: /localhost\:\d+\/fixtures\/isolated-runner-inner.html:\d+:\d+/,
+ hasCodeFrame: false,
+ verifyOpenInIde: false,
+ })
+
+ // FIXME: does not get caught and wrapped like it does in real cypress
+ verify.it.skip('async app exception', {
+ file,
+ message: [
+ 'The following error originated from your application code',
+ 'asyncReference is not defined',
+ ],
+ regex: /localhost\:\d+\/fixtures\/isolated-runner-inner.html:\d+:\d+/,
+ hasCodeFrame: false,
+ verifyOpenInIde: false,
+ })
+
+ verify.it('async exception', {
+ file,
+ column: 12,
+ message: [
+ 'bar is not a function',
+ 'The following error originated from your test code',
+ ],
+ })
+
+ verify.it('async exception with done', {
+ file,
+ column: 12,
+ message: [
+ 'bar is not a function',
+ 'The following error originated from your test code',
+ ],
+ })
+ })
+
+ describe('custom commands', () => {
+ const file = 'custom_commands_spec.js'
+
+ verify.it('assertion failure', {
+ file,
+ column: 23,
+ message: `expected 'actual' to equal 'expected'`,
+ codeFrameText: `add('failAssertion'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 8,
+ message: 'bar is not a function',
+ codeFrameText: `add('failException'`,
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 6,
+ message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
+ codeFrameText: `add('failCommand'`,
+ })
+ })
+
+ describe('typescript', () => {
+ const file = 'typescript_spec.ts'
+
+ verify.it('assertion failure', {
+ file,
+ column: 25,
+ message: `expected 'actual' to equal 'expected'`,
+ })
+
+ verify.it('exception', {
+ file,
+ column: 10,
+ message: 'bar is not a function',
+ })
+
+ verify.it('command failure', {
+ file,
+ column: 8,
+ message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
+ })
+ })
+
+ describe('docs url', () => {
+ const file = 'docs_url_spec.js'
+ const docsUrl = 'https://on.cypress.io/viewport'
+
+ verify.it('displays as button in interactive mode', {
+ file,
+ verifyFn () {
+ cy
+ .get('.runnable-err-message')
+ .should('not.contain', docsUrl)
+ .contains('Learn more')
+ .should('have.attr', 'href', docsUrl)
+ },
+ })
+
+ verify.it('is text in error message in run mode', {
+ file,
+ verifyFn () {
+ cy
+ .get('.runnable-err-message')
+ .should('contain', docsUrl)
+ .contains('Learn more')
+ .should('not.exist')
+ },
+ })
+ })
+
+ // cases where there is a bug in Cypress and we should show cypress internals
+ // instead of the invocation stack. we do this by monkey-patching internal
+ // methods to make them throw an error
+ describe('unexpected errors', () => {
+ const file = 'unexpected_spec.js'
+
+ verify.it('Cypress method error', {
+ file,
+ verifyFn: verifyInternalFailure,
+ method: 'Cypress.LocalStorage._isSpecialKeyword',
+ })
+
+ verify.it('internal cy error', {
+ file,
+ verifyFn: verifyInternalFailure,
+ method: 'cy.expect',
+ })
+ })
+})
diff --git a/packages/runner/cypress/plugins/index.js b/packages/runner/cypress/plugins/index.js
index 62be55014b82..e5158967e1ca 100644
--- a/packages/runner/cypress/plugins/index.js
+++ b/packages/runner/cypress/plugins/index.js
@@ -5,9 +5,7 @@ const { getSnapshot, saveSnapshot } = require('./snapshot/snapshotPlugin')
/**
* @type {Cypress.PluginConfig}
*/
-module.exports = (on, config) => {
- // `on` is used to hook into various events Cypress emits
- // `config` is the resolved Cypress config
+module.exports = (on) => {
on('task', {
getSnapshot,
saveSnapshot,
diff --git a/packages/runner/cypress/support/helpers.js b/packages/runner/cypress/support/helpers.js
index de6c2cc15285..26e178ac001f 100644
--- a/packages/runner/cypress/support/helpers.js
+++ b/packages/runner/cypress/support/helpers.js
@@ -91,13 +91,14 @@ function createCypress () {
/**
* Spawns an isolated Cypress runner as the AUT, with provided spec/fixture and optional state/config
- * @param {()=>void | {[key:string]: any}} mochaTests
+ * @param {string | ()=>void | {[key:string]: any}} mochaTestsOrFile
* @param {{state?: any, config?: any}} opts
*/
- const runIsolatedCypress = (mochaTests, opts = {}) => {
+ const runIsolatedCypress = (mochaTestsOrFile, opts = {}) => {
_.defaultsDeep(opts, {
state: {},
config: { video: false },
+ onBeforeRun () {},
})
return cy.visit('/fixtures/isolated-runner.html#/tests/cypress/fixtures/empty_spec.js')
@@ -193,7 +194,7 @@ function createCypress () {
onInitializedListeners = []
autCypress.run((failed) => {
- resolve({ failed, mochaStubs, autCypress })
+ resolve({ failed, mochaStubs, autCypress, win })
})
}
@@ -208,15 +209,22 @@ function createCypress () {
cy.stub(autCypress, 'onSpecWindow').snapshot(enableStubSnapshots).callsFake((specWindow) => {
autCypress.onSpecWindow.restore()
+ opts.onBeforeRun({ specWindow, win, autCypress })
+
+ const testsInOwnFile = _.isString(mochaTestsOrFile)
+ const relativeFile = testsInOwnFile ? mochaTestsOrFile : 'cypress/fixtures/empty_spec.js'
+
autCypress.onSpecWindow(specWindow, [
{
- absolute: 'cypress/fixtures/empty_spec.js',
- relative: 'cypress/fixtures/empty_spec.js',
- relativeUrl: '/__cypress/tests?p=cypress/fixtures/empty_spec.js',
+ absolute: relativeFile,
+ relative: relativeFile,
+ relativeUrl: `/__cypress/tests?p=${relativeFile}`,
},
])
- generateMochaTestsForWin(specWindow, mochaTests)
+ if (testsInOwnFile) return
+
+ generateMochaTestsForWin(specWindow, mochaTestsOrFile)
specWindow.before = () => {}
specWindow.beforeEach = () => {}
specWindow.afterEach = () => {}
@@ -241,7 +249,7 @@ function createCypress () {
.yieldsAsync({ response: {
isOkStatusCode: true,
isHtml: true,
- url: 'http://localhost:3500/fixtures/generic.html',
+ url: 'http://localhost:3500/fixtures/isolated-runner-inner.html',
} })
.withArgs('set:runnables')
@@ -278,7 +286,6 @@ function createCypress () {
snapshotMochaEvents,
onInitialized,
getAutCypress,
-
}
}
diff --git a/packages/server/test/e2e/8_error_ui_spec.ts b/packages/server/test/e2e/8_error_ui_spec.ts
index 43ac85af8da3..df2eafa9d363 100644
--- a/packages/server/test/e2e/8_error_ui_spec.ts
+++ b/packages/server/test/e2e/8_error_ui_spec.ts
@@ -1,65 +1,24 @@
-import bodyParser from 'body-parser'
import e2e, { expect } from '../support/helpers/e2e'
import Fixtures from '../support/helpers/fixtures'
-const WEBPACK_PREPROCESSOR_PROJECTS = [
- 'webpack-preprocessor',
- 'webpack-preprocessor-ts-loader',
- 'webpack-preprocessor-ts-loader-compiler-options',
- 'webpack-preprocessor-awesome-typescript-loader',
-]
-
-const onServer = function (app) {
- app.use(bodyParser.json())
-
- return app.get('/response', (req, res) => res.json({ ok: true }))
-}
-
-const VARIOUS_FAILURES_EXPECTED_FAILURES = 63
-
const verifyPassedAndFailedAreSame = (expectedFailures) => {
return ({ stdout }) => {
const passes = stdout.match(/✓ ✓ VERIFY/g)
- expect(passes.length, 'number of passes should equal the number of failures').to.equal(expectedFailures)
+ expect(passes?.length || 0, 'number of passes should equal the number of failures').to.equal(expectedFailures)
}
}
describe('e2e error ui', function () {
- e2e.setup({
- port: 1919,
- onServer,
- })
-
- e2e.it('displays correct UI for errors', {
- spec: 'various_failures_spec.js',
- expectedExitCode: VARIOUS_FAILURES_EXPECTED_FAILURES,
- timeout: 240000, // 4 minutes
- noTypeScript: true,
- onRun (exec) {
- return exec().then(verifyPassedAndFailedAreSame(VARIOUS_FAILURES_EXPECTED_FAILURES))
- },
- })
-
- e2e.it('displays correct UI for errors in custom commands', {
- spec: 'various_failures_custom_commands_spec.js',
- expectedExitCode: VARIOUS_FAILURES_EXPECTED_FAILURES,
- timeout: 240000, // 4 minutes
- noTypeScript: true,
- onRun (exec) {
- return exec().then(verifyPassedAndFailedAreSame(VARIOUS_FAILURES_EXPECTED_FAILURES))
- },
- })
-
- e2e.it('displays correct UI for typescript errors', {
- spec: 'various_failures_spec.ts',
- expectedExitCode: 2,
- onRun (exec) {
- return exec().then(verifyPassedAndFailedAreSame(2))
- },
- })
-
- WEBPACK_PREPROCESSOR_PROJECTS.forEach((project) => {
+ e2e.setup()
+
+ ;[
+ 'webpack-preprocessor',
+ 'webpack-preprocessor-ts-loader',
+ 'webpack-preprocessor-ts-loader-compiler-options',
+ 'webpack-preprocessor-awesome-typescript-loader',
+ ]
+ .forEach((project) => {
e2e.it(`handles sourcemaps in webpack for project: ${project}`, {
project: Fixtures.projectPath(project),
spec: 'failing_spec.*',
diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_custom_commands_spec.js b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_custom_commands_spec.js
deleted file mode 100644
index 8dbd3b4ed10e..000000000000
--- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_custom_commands_spec.js
+++ /dev/null
@@ -1,833 +0,0 @@
-/**
- * See comment at top of various_failures_spec.js for more info
- * This covers the same errors but inside custom commands
- */
-
-import outsideError from '../../../todos/throws-error'
-import { setup, fail, verify, verifyInternalError } from '../support/util'
-
-setup({
- idePath: {
- relative: 'cypress/support/commands.js',
- absolute: /\/[^\/]+\/cypress\/support\/commands\.js/,
- },
- verifyStackLineIsSpecFile: false,
-})
-
-context('assertion failures', function () {
- describe('with expect().', function () {
- fail(this, () => {
- cy.failExpect()
- })
-
- verify(this, {
- column: 23,
- codeFrameText: 'add(\'failExpect\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('with assert()', function () {
- fail(this, () => {
- cy.failAssert()
- })
-
- verify(this, {
- column: '(3|10)', // different between chrome & firefox
- codeFrameText: 'add(\'failAssert\'',
- message: 'should be true',
- })
- })
-
- describe('with assert.()', function () {
- fail(this, () => {
- cy.failAssertMethod()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failAssertMethod\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-})
-
-context('exceptions', function () {
- describe('in commands file', function () {
- fail(this, () => {
- cy.failException()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'add(\'failException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('in file outside project', function () {
- fail(this, () => {
- outsideError()
- })
-
- verify(this, {
- message: 'An outside error',
- regex: /todos\/throws\-error\.js:5:9/,
- codeFrameText: `thrownewError('An outside error')`,
- verifyOpenInIde: false,
- })
- })
-})
-
-context('commands', function () {
- describe('failure', function () {
- fail(this, () => {
- cy.failCommand()
- })
-
- verify(this, {
- column: 6,
- codeFrameText: 'add(\'failCommand\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-
- describe('chained failure', function () {
- fail(this, () => {
- cy.failChainedCommand()
- })
-
- verify(this, {
- column: 18,
- codeFrameText: 'add(\'failChainedCommand\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.then', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.failThenAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'add(\'failThenAssertion\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.failThenException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failThenException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.failThenCommandFailure()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'add(\'failThenCommandFailure\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.should', function () {
- describe('callback assertion failure', function () {
- fail(this, () => {
- cy.failShouldCallbackAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'add(\'failShouldCallbackAssertion\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('callback exception', function () {
- fail(this, () => {
- cy.failShouldCallbackException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failShouldCallbackException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('assertion failure', function () {
- fail(this, () => {
- cy.failShouldAssertion()
- })
-
- verify(this, {
- column: 4,
- codeFrameText: 'add(\'failShouldAssertion\'',
- message: 'Timed out retrying: expected {} to have property \'foo\'',
- })
- })
-
- describe('after multiple', function () {
- fail(this, () => {
- cy.failAfterMultipleShoulds()
- })
-
- verify(this, {
- column: 4,
- codeFrameText: 'add(\'failAfterMultipleShoulds\'',
- message: 'Timed out retrying: expected \'foo\' to equal \'bar\'',
- })
- })
-
- describe('after multiple callbacks exception', function () {
- fail(this, () => {
- cy.failAfterMultipleShouldCallbacksException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: '({}).bar()',
- message: 'bar is not a function',
- })
- })
-
- describe('after multiple callbacks assertion failure', function () {
- fail(this, () => {
- cy.failAfterMultipleShouldCallbacksAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: '.should(()=>',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('after callback success assertion failure', function () {
- fail(this, () => {
- cy.failAfterCallbackSuccessAssertion()
- })
-
- verify(this, {
- column: 4,
- codeFrameText: '.should(\'have.property\',\'foo\')',
- message: `expected {} to have property 'foo'`,
- })
- })
-
- describe('command failure after success', function () {
- fail(this, () => {
- cy.failCommandAfterShouldSuccess()
- })
-
- verify(this, {
- column: 6,
- codeFrameText: 'add(\'failCommandAfterShouldSuccess\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.each', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.failEachAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'add(\'failEachAssertion\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.failEachException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failEachException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.failEachCommandFailure()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'add(\'failEachCommandFailure\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.spread', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.failSpreadAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'add(\'failSpreadAssertion\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.failSpreadException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failSpreadException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.failSpreadCommandFailure()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'add(\'failSpreadCommandFailure\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.within', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.failWithinAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'add(\'failWithinAssertion\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.failWithinException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failWithinException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.failWithinCommandFailure()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'add(\'failWithinCommandFailure\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.wrap', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.failWrapAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'add(\'failWrapAssertion\'',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.failWrapException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'failWrapException\'',
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.failWrapCommandFailure()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'add(\'failWrapCommandFailure\'',
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.visit', function () {
- describe('onBeforeLoad assertion failure', function () {
- fail(this, () => {
- cy.failVisitBeforeLoadAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onBeforeLoad',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onBeforeLoad exception', function () {
- fail(this, () => {
- cy.failVisitBeforeLoadException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onBeforeLoad',
- message: 'bar is not a function',
- })
- })
-
- describe('onLoad assertion failure', function () {
- fail(this, () => {
- cy.failVisitLoadAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onLoad',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onLoad exception', function () {
- fail(this, () => {
- cy.failVisitLoadException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onLoad',
- message: 'bar is not a function',
- })
- })
-})
-
-context('cy.route', function () {
- describe('callback assertion failure', function () {
- fail(this, () => {
- cy.failRouteCallbackAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'failRouteCallbackAssertion',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('callback exception', function () {
- fail(this, () => {
- cy.failRouteCallbackException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'failRouteCallbackException',
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.failRouteCallbackCommandFailure()
- })
-
- verify(this, {
- column: 8,
- codeFrameText: 'failRouteCallbackCommandFailure',
- message: 'Expected to find element: #does-not-exist, but never found it',
- })
- })
-
- describe('onAbort assertion failure', function (done) {
- fail(this, () => {
- cy.failRouteOnAbortAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onAbort',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onAbort exception', function (done) {
- fail(this, () => {
- cy.failRouteOnAbortException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onAbort',
- message: 'bar is not a function',
- })
- })
-
- describe('onRequest assertion failure', function (done) {
- fail(this, () => {
- cy.failRouteOnRequestAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onRequest',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onRequest exception', function (done) {
- fail(this, () => {
- cy.failRouteOnRequestException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onRequest',
- message: 'bar is not a function',
- })
- })
-
- describe('onResponse assertion failure', function (done) {
- fail(this, () => {
- cy.failRouteOnResponseAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onResponse',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onResponse exception', function (done) {
- fail(this, () => {
- cy.failRouteOnResponseException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onResponse',
- message: 'bar is not a function',
- })
- })
-})
-
-context('cy.server', function () {
- describe('onAbort assertion failure', function (done) {
- fail(this, () => {
- cy.failServerOnAbortAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onAbort',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onAbort exception', function (done) {
- fail(this, () => {
- cy.failServerOnAbortException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onAbort',
- message: 'bar is not a function',
- })
- })
-
- describe('onRequest assertion failure', function (done) {
- fail(this, () => {
- cy.failServerOnRequestAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onRequest',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onRequest exception', function (done) {
- fail(this, () => {
- cy.failServerOnRequestException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onRequest',
- message: 'bar is not a function',
- })
- })
-
- describe('onResponse assertion failure', function (done) {
- fail(this, () => {
- cy.failServerOnResponseAssertion()
- })
-
- verify(this, {
- column: 27,
- codeFrameText: 'onResponse',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onResponse exception', function (done) {
- fail(this, () => {
- cy.failServerOnResponseException()
- })
-
- verify(this, {
- column: 12,
- codeFrameText: 'onResponse',
- message: 'bar is not a function',
- })
- })
-})
-
-context('cy.readFile', function () {
- describe('existence failure', function () {
- fail(this, () => {
- cy.failReadFileExistence()
- })
-
- verify(this, {
- column: 6,
- codeFrameText: 'failReadFileExistence',
- message: 'failed because the file does not exist',
- })
- })
-})
-
-context('validation errors', function () {
- describe('from cypress', function () {
- fail(this, () => {
- cy.cypressValidationError()
- })
-
- verify(this, {
- column: 6,
- codeFrameText: 'add(\'cypressValidationError\'',
- message: 'can only accept a string preset or',
- stack: ['throwErrBadArgs', 'From Your Spec Code:'],
- })
- })
-
- describe('from chai expect', function () {
- fail(this, () => {
- cy.chaiExpectValidationError()
- })
-
- verify(this, {
- column: '(3|10)', // different between chrome & firefox
- codeFrameText: 'add(\'chaiExpectValidationError\'',
- message: 'Invalid Chai property: nope',
- stack: ['proxyGetter', 'From Your Spec Code:'],
- })
- })
-
- describe('from chai assert', function () {
- fail(this, () => {
- cy.chaiAssertValidationError()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'add(\'chaiAssertValidationError\'',
- message: 'object tested must be an array',
- })
- })
-})
-
-context('event handlers', function () {
- describe('event assertion failure', function () {
- fail(this, () => {
- cy.failEventHandlerAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'failEventHandlerAssertion',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('event exception', function () {
- fail(this, () => {
- cy.failEventHandlerException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'failEventHandlerException',
- message: 'bar is not a function',
- })
- })
-
- describe('fail handler assertion failure', function () {
- fail(this, () => {
- cy.failFailHandlerAssertion()
- })
-
- verify(this, {
- column: 25,
- codeFrameText: 'failFailHandlerAssertion',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('fail handler exception', function () {
- fail(this, () => {
- cy.failFailHandlerException()
- })
-
- verify(this, {
- column: 10,
- codeFrameText: 'failFailHandlerException',
- message: 'bar is not a function',
- })
- })
-})
-
-context('uncaught errors', () => {
- describe('sync app exception', function () {
- fail(this, () => {
- cy.failSyncAppException()
- })
-
- verify(this, {
- message: [
- 'The following error originated from your application code',
- 'qux is not defined',
- ],
- regex: /localhost\:\d+\/js_errors.html:\d+:\d+/,
- hasCodeFrame: false,
- verifyOpenInIde: false,
- })
- })
-
- describe('async app exception', function () {
- fail(this, () => {
- cy.failAsyncAppException()
- })
-
- verify(this, {
- message: [
- 'The following error originated from your application code',
- 'qax is not defined',
- ],
- regex: /localhost\:\d+\/js_errors.html:\d+:\d+/,
- hasCodeFrame: false,
- verifyOpenInIde: false,
- })
- })
-
- describe('async exception', function () {
- fail(this, () => {
- cy.failAsyncException()
- })
-
- verify(this, {
- column: 10,
- message: [
- 'bar is not a function',
- 'The following error originated from your test code',
- ],
- codeFrameText: 'failAsyncException',
- })
- })
-
- describe('async exception with done', function () {
- fail(this, (done) => {
- cy.failAsyncException()
- })
-
- verify(this, {
- column: 10,
- message: [
- 'bar is not a function',
- 'The following error originated from your test code',
- ],
- codeFrameText: 'failAsyncException',
- })
- })
-})
-
-// covering cases where there is a bug in Cypress and we shouldn't show
-// the invocation stack. it should show the original stack even if it is
-// thrown within a command
-context('unexpected errors', () => {
- describe('Cypress method error', function () {
- const isJquery = Cypress.dom.isJquery
-
- beforeEach(() => {
- Cypress.dom.isJquery = isJquery
- })
-
- fail(this, () => {
- cy.failInternalCypressMethod()
- })
-
- verifyInternalError(this, {
- method: 'Cypress.dom.isJquery',
- })
- })
-
- describe('cy method error', function () {
- const cyExpect = cy.expect
-
- beforeEach(() => {
- cy.expect = cyExpect
- })
-
- fail(this, () => {
- cy.failInternalCyMethod()
- })
-
- verifyInternalError(this, {
- method: 'cy.expect',
- })
- })
-})
diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_spec.js b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_spec.js
deleted file mode 100644
index 3e0721b3ce8a..000000000000
--- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_spec.js
+++ /dev/null
@@ -1,981 +0,0 @@
-/**
- * This tests various failure scenarios where an error and code frame is displayed
- * It does this by having a test fail and then a subsequent test run that
- * tests the appearance of the command log
- * Because of this, the test order is important
- * There should be the same number of failing tests as there are passing
- * tests, because each failure has a verification test (e.g. 11 fail, 11 pass)
- */
-import outsideError from '../../../todos/throws-error'
-import {
- fail,
- verify,
- verifyInternalError,
- setup,
- sendXhr,
- abortXhr,
-} from '../support/util'
-
-setup({ verifyStackLineIsSpecFile: true })
-
-context('assertion failures', function () {
- describe('with expect().', function () {
- fail(this, () => {
- expect('actual').to.equal('expected')
- })
-
- verify(this, {
- column: 27,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('with assert()', function () {
- fail(this, () => {
- assert(false, 'should be true')
- })
-
- verify(this, {
- column: '(7|14)', // different between chrome & firefox
- message: 'should be true',
- })
- })
-
- describe('with assert.()', function () {
- fail(this, () => {
- assert.equal('actual', 'expected')
- })
-
- verify(this, {
- column: 14,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-})
-
-context('exceptions', function () {
- describe('in spec file', function () {
- fail(this, () => {
- ({}).bar()
- })
-
- verify(this, {
- column: 12,
- message: 'bar is not a function',
- })
- })
-
- describe('in file outside project', function () {
- fail(this, () => {
- outsideError()
- })
-
- verify(this, {
- message: 'An outside error',
- regex: /todos\/throws\-error\.js:5:9/,
- codeFrameText: `thrownewError('An outside error')`,
- verifyOpenInIde: false,
- })
- })
-})
-
-context('commands', function () {
- describe('failure', function () {
- fail(this, () => {
- cy.get('#does-not-exist')
- })
-
- verify(this, {
- column: 10,
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-
- describe('chained failure', function () {
- fail(this, () => {
- cy.get('body').find('#does-not-exist')
- })
-
- verify(this, {
- column: 22,
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.then', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.wrap({}).then(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.wrap({}).then(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.wrap({}).then(() => {
- cy.get('#does-not-exist')
- })
- })
-
- verify(this, {
- column: 12,
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.should', function () {
- describe('callback assertion failure', function () {
- fail(this, () => {
- cy.wrap({}).should(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('callback exception', function () {
- fail(this, () => {
- cy.wrap({}).should(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('assertion failure', function () {
- fail(this, () => {
- cy.wrap({})
- .should('have.property', 'foo')
- })
-
- verify(this, {
- column: 8,
- message: 'Timed out retrying: expected {} to have property \'foo\'',
- })
- })
-
- describe('after multiple', function () {
- fail(this, () => {
- cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
- .should('equal', 'bar')
- })
-
- verify(this, {
- column: 8,
- message: 'Timed out retrying: expected \'foo\' to equal \'bar\'',
- })
- })
-
- describe('after multiple callbacks exception', function () {
- fail(this, () => {
- cy.wrap({ foo: 'foo' })
- .should(() => {
- expect(true).to.be.true
- })
- .should(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- codeFrameText: '({}).bar()',
- message: 'bar is not a function',
- })
- })
-
- describe('after multiple callbacks assertion failure', function () {
- fail(this, () => {
- cy.wrap({ foo: 'foo' })
- .should(() => {
- expect(true).to.be.true
- })
- .should(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- codeFrameText: '.should(()=>',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('after callback success assertion failure', function () {
- fail(this, () => {
- cy.wrap({})
- .should(() => {
- expect(true).to.be.true
- })
- .should('have.property', 'foo')
- })
-
- verify(this, {
- column: 8,
- codeFrameText: '.should(\'have.property',
- message: `expected {} to have property 'foo'`,
- })
- })
-
- describe('command failure after success', function () {
- fail(this, () => {
- cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
- cy.get('#does-not-exist')
- })
-
- verify(this, {
- column: 10,
- message: 'Timed out retrying: Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.each', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.wrap([1]).each(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.wrap([1]).each(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.wrap([1]).each(() => {
- cy.get('#does-not-exist')
- })
- })
-
- verify(this, {
- column: 12,
- message: 'Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.spread', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.wrap([1, 2, 3]).spread(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.wrap([1, 2, 3]).spread(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.wrap([1, 2, 3]).spread(() => {
- cy.get('#does-not-exist')
- })
- })
-
- verify(this, {
- column: 12,
- message: 'Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.within', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.get('body').within(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.get('body').within(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.get('body').within(() => {
- cy.get('#does-not-exist')
- })
- })
-
- verify(this, {
- column: 12,
- message: 'Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.wrap', function () {
- describe('assertion failure', function () {
- fail(this, () => {
- cy.wrap(() => {
- expect('actual').to.equal('expected')
- }).then((fn) => fn())
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('exception', function () {
- fail(this, () => {
- cy.wrap(() => {
- ({}).bar()
- }).then((fn) => fn())
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.wrap(() => {
- cy.get('#does-not-exist')
- }).then((fn) => fn())
- })
-
- verify(this, {
- column: 12,
- message: 'Expected to find element: #does-not-exist, but never found it',
- })
- })
-})
-
-context('cy.visit', () => {
- describe('onBeforeLoad assertion failure', function () {
- fail(this, () => {
- cy.visit('/index.html', {
- onBeforeLoad () {
- expect('actual').to.equal('expected')
- },
- })
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onBeforeLoad',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onBeforeLoad exception', function () {
- fail(this, () => {
- cy.visit('/index.html', {
- onBeforeLoad () {
- ({}).bar()
- },
- })
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onBeforeLoad',
- message: 'bar is not a function',
- })
- })
-
- describe('onLoad assertion failure', function () {
- fail(this, () => {
- cy.visit('/index.html', {
- onLoad () {
- expect('actual').to.equal('expected')
- },
- })
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onLoad',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onLoad exception', function () {
- fail(this, () => {
- cy.visit('/index.html', {
- onLoad () {
- ({}).bar()
- },
- })
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onLoad',
- message: 'bar is not a function',
- })
- })
-})
-
-context('cy.route', () => {
- describe('callback assertion failure', function () {
- fail(this, () => {
- cy.server().route(() => {
- expect('actual').to.equal('expected')
- })
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('callback exception', function () {
- fail(this, () => {
- cy.server().route(() => {
- ({}).bar()
- })
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('command failure', function () {
- fail(this, () => {
- cy.server().route(() => {
- cy.get('#does-not-exist')
-
- return '/foo'
- })
- })
-
- verify(this, {
- column: 12,
- message: 'Expected to find element: #does-not-exist, but never found it',
- })
- })
-
- describe('onAbort assertion failure', function (done) {
- fail(this, () => {
- cy.server().route({
- url: '/foo',
- onAbort () {
- expect('actual').to.equal('expected')
- },
- })
- .window().then(abortXhr)
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onAbort',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onAbort exception', function (done) {
- fail(this, () => {
- cy.server().route({
- url: '/foo',
- onAbort () {
- ({}).bar()
- },
- })
- .window().then(abortXhr)
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onAbort',
- message: 'bar is not a function',
- })
- })
-
- describe('onRequest assertion failure', function (done) {
- fail(this, () => {
- cy.server().route({
- url: '/foo',
- onRequest () {
- expect('actual').to.equal('expected')
- },
- })
- .window().then(sendXhr)
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onRequest',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onRequest exception', function (done) {
- fail(this, () => {
- cy.server().route({
- url: '/foo',
- onRequest () {
- ({}).bar()
- },
- })
- .window().then(sendXhr)
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onRequest',
- message: 'bar is not a function',
- })
- })
-
- describe('onResponse assertion failure', function (done) {
- fail(this, () => {
- cy.server().route({
- url: '/users',
- onResponse () {
- expect('actual').to.equal('expected')
- },
- })
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onResponse',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onResponse exception', function (done) {
- fail(this, () => {
- cy.server().route({
- url: '/users',
- onResponse () {
- ({}).bar()
- },
- })
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onResponse',
- message: 'bar is not a function',
- })
- })
-})
-
-context('cy.server', () => {
- describe('onAbort assertion failure', function (done) {
- fail(this, () => {
- cy.server({
- onAbort () {
- expect('actual').to.equal('expected')
- },
- })
- .route('/foo')
- .window().then(abortXhr)
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onAbort',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onAbort exception', function (done) {
- fail(this, () => {
- cy.server({
- onAbort () {
- ({}).bar()
- },
- })
- .route('/foo')
- .window().then(abortXhr)
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onAbort',
- message: 'bar is not a function',
- })
- })
-
- describe('onRequest assertion failure', function (done) {
- fail(this, () => {
- cy.server({
- onRequest () {
- expect('actual').to.equal('expected')
- },
- })
- .route('/foo')
- .window().then(sendXhr)
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onRequest',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onRequest exception', function (done) {
- fail(this, () => {
- cy.server({
- onRequest () {
- ({}).bar()
- },
- })
- .route('/foo')
- .window().then(sendXhr)
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onRequest',
- message: 'bar is not a function',
- })
- })
-
- describe('onResponse assertion failure', function (done) {
- fail(this, () => {
- cy.server({
- onResponse () {
- expect('actual').to.equal('expected')
- },
- })
- .route('/users')
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
- })
-
- verify(this, {
- column: 31,
- codeFrameText: 'onResponse',
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('onResponse exception', function (done) {
- fail(this, () => {
- cy.server({
- onResponse () {
- ({}).bar()
- },
- })
- .route('/users')
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
- })
-
- verify(this, {
- column: 16,
- codeFrameText: 'onResponse',
- message: 'bar is not a function',
- })
- })
-})
-
-context('cy.readFile', function () {
- describe('existence failure', function () {
- fail(this, () => {
- cy.readFile('does-not-exist', { timeout: 0 })
- })
-
- verify(this, {
- column: 10,
- message: 'failed because the file does not exist',
- })
- })
-})
-
-context('validation errors', function () {
- describe('from cypress', function () {
- fail(this, () => {
- cy.viewport()
- })
-
- verify(this, {
- column: 10,
- message: 'can only accept a string preset or',
- stack: ['throwErrBadArgs', 'From Your Spec Code:'],
- })
- })
-
- describe('from chai expect', function () {
- fail(this, () => {
- expect(true).to.be.nope
- })
-
- verify(this, {
- column: '(7|14)', // different between chrome & firefox
- message: 'Invalid Chai property: nope',
- stack: ['proxyGetter', 'From Your Spec Code:'],
- })
- })
-
- describe('from chai assert', function () {
- fail(this, () => {
- assert.deepInclude()
- })
-
- verify(this, {
- column: 14,
- message: 'object tested must be an array',
- })
- })
-})
-
-context('event handlers', function () {
- describe('event assertion failure', function () {
- fail(this, () => {
- cy.on('window:load', () => {
- expect('actual').to.equal('expected')
- })
-
- cy.visit('http://localhost:1919')
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('event exception', function () {
- fail(this, () => {
- cy.on('window:load', () => {
- ({}).bar()
- })
-
- cy.visit('http://localhost:1919')
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-
- describe('fail handler assertion failure', function () {
- fail(this, () => {
- cy.on('fail', () => {
- expect('actual').to.equal('expected')
- })
-
- cy.get('#does-not-exist')
- })
-
- verify(this, {
- column: 29,
- message: `expected 'actual' to equal 'expected'`,
- })
- })
-
- describe('fail handler exception', function () {
- fail(this, () => {
- cy.on('fail', () => {
- ({}).bar()
- })
-
- cy.get('#does-not-exist')
- })
-
- verify(this, {
- column: 14,
- message: 'bar is not a function',
- })
- })
-})
-
-context('uncaught errors', () => {
- describe('sync app exception', function () {
- fail(this, () => {
- cy.visit('/js_errors.html')
- cy.get('.sync-error').click()
- })
-
- verify(this, {
- message: [
- 'The following error originated from your application code',
- 'qux is not defined',
- ],
- regex: /localhost\:\d+\/js_errors.html:\d+:\d+/,
- hasCodeFrame: false,
- verifyOpenInIde: false,
- })
- })
-
- describe('async app exception', function () {
- fail(this, () => {
- cy.visit('/js_errors.html')
- cy.get('.async-error').click()
- cy.wait(10000)
- })
-
- verify(this, {
- message: [
- 'The following error originated from your application code',
- 'qax is not defined',
- ],
- regex: /localhost\:\d+\/js_errors.html:\d+:\d+/,
- hasCodeFrame: false,
- verifyOpenInIde: false,
- })
- })
-
- describe('async exception', function () {
- fail(this, () => {
- setTimeout(() => {
- ({}).bar()
- })
-
- cy.wait(10000)
- })
-
- verify(this, {
- column: 14,
- message: [
- 'bar is not a function',
- 'The following error originated from your test code',
- ],
- })
- })
-
- describe('async exception with done', function () {
- fail(this, (done) => {
- setTimeout(() => {
- ({}).bar()
- }, 20)
- })
-
- verify(this, {
- column: 14,
- message: [
- 'bar is not a function',
- 'The following error originated from your test code',
- ],
- codeFrameText: 'fail(this,(done)=>',
- })
- })
-})
-
-// covering cases where there is a bug in Cypress and we shouldn't show
-// the invocation stack. it should show the original stack even if it is
-// thrown within a command
-context('unexpected errors', () => {
- describe('Cypress method error', function () {
- const isJquery = Cypress.dom.isJquery
-
- beforeEach(() => {
- Cypress.dom.isJquery = isJquery
- })
-
- fail(this, () => {
- top.window.eval(`Cypress.dom.isJquery = () => { throw new Error('thrown in CypressdomisJquery') }`)
-
- cy.get('body')
- })
-
- verifyInternalError(this, {
- method: 'Cypress.dom.isJquery',
- })
- })
-
- describe('internal cy error', function () {
- const cyExpect = cy.expect
-
- beforeEach(() => {
- cy.expect = cyExpect
- })
-
- fail(this, () => {
- top.window.eval(`cy.expect = () => { throw new Error('thrown in cyexpect') }`)
-
- cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
- })
-
- verifyInternalError(this, {
- method: 'cy.expect',
- })
- })
-})
diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_spec.ts b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_spec.ts
deleted file mode 100644
index 812b07f10215..000000000000
--- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/various_failures_spec.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * This tests various failure scenarios where an error and code frame is displayed
- * It does this by having a test fail and then a subsequent test run that
- * tests the appearance of the command log
- * Because of this, the test order is important
- * There should be the same number of failing tests as there are passing
- * tests, because each failure has a verification test (e.g. 11 fail, 11 pass)
- */
-
-// simple example of typescript types
-type Foo = {
- something: string
-}
-
-import { fail, setup, verify } from '../support/util'
-
-setup({ verifyStackLineIsSpecFile: true })
-
-context('validation errors', function () {
- describe('from cypress with docsUrl', function () {
- beforeEach(() => {
- Cypress.config('isInteractive', true)
- })
-
- fail(this, () => {
- cy.viewport()
- })
-
- verify(this, {
- line: 26, // this only has 1 test, so we can be specific
- column: 10,
- verifyDocsLearnMore: 'https://on.cypress.io/viewport',
- message: 'can only accept a string preset or',
- stack: ['throwErrBadArgs', 'From Your Spec Code:'],
- })
- })
-
- describe('from cypress without docsUrl', function () {
- beforeEach(() => {
- Cypress.config('isInteractive', false)
- })
-
- fail(this, () => {
- cy.viewport()
- })
-
- verify(this, {
- line: 44, // this only has 1 test, so we can be specific
- column: 10,
- verifyDocsContent: 'https://on.cypress.io/viewport',
- message: 'can only accept a string preset or',
- stack: ['throwErrBadArgs', 'From Your Spec Code:'],
- })
- })
-})
diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/support/commands.js b/packages/server/test/support/fixtures/projects/e2e/cypress/support/commands.js
index 69e0babb6f5b..e69de29bb2d1 100644
--- a/packages/server/test/support/fixtures/projects/e2e/cypress/support/commands.js
+++ b/packages/server/test/support/fixtures/projects/e2e/cypress/support/commands.js
@@ -1,425 +0,0 @@
-import { sendXhr, abortXhr } from './util'
-
-Cypress.Commands.add('failExpect', () => {
- expect('actual').to.equal('expected')
-})
-
-Cypress.Commands.add('failAssert', () => {
- assert(false, 'should be true')
-})
-
-Cypress.Commands.add('failAssertMethod', () => {
- assert.equal('actual', 'expected')
-})
-
-Cypress.Commands.add('failException', () => {
- ({}).bar()
-})
-
-Cypress.Commands.add('failCommand', () => {
- cy.get('#does-not-exist')
-})
-
-Cypress.Commands.add('failChainedCommand', () => {
- cy.get('body').find('#does-not-exist')
-})
-
-Cypress.Commands.add('failThenAssertion', () => {
- cy.wrap({}).then(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failShouldCallbackAssertion', () => {
- cy.wrap({}).should(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failThenException', () => {
- cy.wrap({}).then(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failThenCommandFailure', () => {
- cy.wrap({}).then(() => {
- cy.get('#does-not-exist')
- })
-})
-
-Cypress.Commands.add('failShouldCallbackException', () => {
- cy.wrap({}).should(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failShouldAssertion', () => {
- cy.wrap({})
- .should('have.property', 'foo')
-})
-
-Cypress.Commands.add('failAfterMultipleShoulds', () => {
- cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
- .should('equal', 'bar')
-})
-
-Cypress.Commands.add('failAfterMultipleShouldCallbacksException', () => {
- cy.wrap({})
- .should(() => {
- expect(true).to.be.true
- })
- .should(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failAfterMultipleShouldCallbacksAssertion', () => {
- cy.wrap({})
- .should(() => {
- expect(true).to.be.true
- })
- .should(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failAfterCallbackSuccessAssertion', () => {
- cy.wrap({})
- .should(() => {
- expect(true).to.be.true
- })
- .should('have.property', 'foo')
-})
-
-Cypress.Commands.add('failCommandAfterShouldSuccess', () => {
- cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
- cy.get('#does-not-exist')
-})
-
-Cypress.Commands.add('failEachAssertion', () => {
- cy.wrap([1]).each(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failEachException', () => {
- cy.wrap([1]).each(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failEachCommandFailure', () => {
- cy.wrap([1]).each(() => {
- cy.get('#does-not-exist')
- })
-})
-
-Cypress.Commands.add('failSpreadAssertion', () => {
- cy.wrap([1, 2, 3]).spread(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failSpreadException', () => {
- cy.wrap([1, 2, 3]).spread(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failSpreadCommandFailure', () => {
- cy.wrap([1, 2, 3]).spread(() => {
- cy.get('#does-not-exist')
- })
-})
-
-Cypress.Commands.add('failWithinAssertion', () => {
- cy.get('body').within(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failWithinException', () => {
- cy.get('body').within(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failWithinCommandFailure', () => {
- cy.get('body').within(() => {
- cy.get('#does-not-exist')
- })
-})
-
-Cypress.Commands.add('failWrapAssertion', () => {
- cy.wrap(() => {
- expect('actual').to.equal('expected')
- }).then((fn) => fn())
-})
-
-Cypress.Commands.add('failWrapException', () => {
- cy.wrap(() => {
- ({}).bar()
- }).then((fn) => fn())
-})
-
-Cypress.Commands.add('failWrapCommandFailure', () => {
- cy.wrap(() => {
- cy.get('#does-not-exist')
- }).then((fn) => fn())
-})
-
-Cypress.Commands.add('failVisitBeforeLoadAssertion', () => {
- cy.visit('/index.html', {
- onBeforeLoad () {
- expect('actual').to.equal('expected')
- },
- })
-})
-
-Cypress.Commands.add('failVisitBeforeLoadException', () => {
- cy.visit('/index.html', {
- onBeforeLoad () {
- ({}).bar()
- },
- })
-})
-
-Cypress.Commands.add('failVisitLoadAssertion', () => {
- cy.visit('/index.html', {
- onLoad () {
- expect('actual').to.equal('expected')
- },
- })
-})
-
-Cypress.Commands.add('failVisitLoadException', () => {
- cy.visit('/index.html', {
- onLoad () {
- ({}).bar()
- },
- })
-})
-
-Cypress.Commands.add('failRouteCallbackAssertion', () => {
- cy.server().route(() => {
- expect('actual').to.equal('expected')
- })
-})
-
-Cypress.Commands.add('failRouteCallbackException', () => {
- cy.server().route(() => {
- ({}).bar()
- })
-})
-
-Cypress.Commands.add('failRouteCallbackCommandFailure', () => {
- cy.server().route(() => {
- cy.get('#does-not-exist')
-
- return '/foo'
- })
-})
-
-Cypress.Commands.add('failRouteOnAbortAssertion', () => {
- cy.server().route({
- url: '/foo',
- onAbort () {
- expect('actual').to.equal('expected')
- },
- })
- .window().then(abortXhr)
-})
-
-Cypress.Commands.add('failRouteOnAbortException', () => {
- cy.server().route({
- url: '/foo',
- onAbort () {
- ({}).bar()
- },
- })
- .window().then(abortXhr)
-})
-
-Cypress.Commands.add('failRouteOnRequestAssertion', () => {
- cy.server().route({
- url: '/foo',
- onRequest () {
- expect('actual').to.equal('expected')
- },
- })
- .window().then(sendXhr)
-})
-
-Cypress.Commands.add('failRouteOnRequestException', () => {
- cy.server().route({
- url: '/foo',
- onRequest () {
- ({}).bar()
- },
- })
- .window().then(sendXhr)
-})
-
-Cypress.Commands.add('failRouteOnResponseAssertion', () => {
- cy.server().route({
- url: '/users',
- onResponse () {
- expect('actual').to.equal('expected')
- },
- })
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
-})
-
-Cypress.Commands.add('failRouteOnResponseException', () => {
- cy.server().route({
- url: '/users',
- onResponse () {
- ({}).bar()
- },
- })
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
-})
-
-Cypress.Commands.add('failServerOnAbortAssertion', () => {
- cy.server({
- onAbort () {
- expect('actual').to.equal('expected')
- },
- })
- .route('/foo')
- .window().then(abortXhr)
-})
-
-Cypress.Commands.add('failServerOnAbortException', () => {
- cy.server({
- onAbort () {
- ({}).bar()
- },
- })
- .route('/foo')
- .window().then(abortXhr)
-})
-
-Cypress.Commands.add('failServerOnRequestAssertion', () => {
- cy.server({
- onRequest () {
- expect('actual').to.equal('expected')
- },
- })
- .route('/foo')
- .window().then(sendXhr)
-})
-
-Cypress.Commands.add('failServerOnRequestException', () => {
- cy.server({
- onRequest () {
- ({}).bar()
- },
- })
- .route('/foo')
- .window().then(sendXhr)
-})
-
-Cypress.Commands.add('failServerOnResponseAssertion', () => {
- cy.server({
- onResponse () {
- expect('actual').to.equal('expected')
- },
- })
- .route('/users')
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
-})
-
-Cypress.Commands.add('failServerOnResponseException', () => {
- cy.server({
- onResponse () {
- ({}).bar()
- },
- })
- .route('/users')
- .visit('/xhr.html').get('#fetch').click()
- .wait(10000)
-})
-
-Cypress.Commands.add('failReadFileExistence', () => {
- cy.readFile('does-not-exist', { timeout: 0 })
-})
-
-Cypress.Commands.add('cypressValidationError', () => {
- cy.viewport()
-})
-
-Cypress.Commands.add('chaiExpectValidationError', () => {
- expect(true).to.be.nope
-})
-
-Cypress.Commands.add('chaiAssertValidationError', () => {
- assert.deepInclude()
-})
-
-Cypress.Commands.add('failEventHandlerAssertion', () => {
- cy.on('window:load', () => {
- expect('actual').to.equal('expected')
- })
-
- cy.visit('http://localhost:1919')
-})
-
-Cypress.Commands.add('failEventHandlerException', () => {
- cy.on('window:load', () => {
- ({}).bar()
- })
-
- cy.visit('http://localhost:1919')
-})
-
-Cypress.Commands.add('failFailHandlerAssertion', () => {
- cy.on('fail', () => {
- expect('actual').to.equal('expected')
- })
-
- cy.get('#does-not-exist')
-})
-
-Cypress.Commands.add('failFailHandlerException', () => {
- cy.on('fail', () => {
- ({}).bar()
- })
-
- cy.get('#does-not-exist')
-})
-
-Cypress.Commands.add('failSyncAppException', () => {
- cy.visit('/js_errors.html')
- cy.get('.sync-error').click()
-})
-
-Cypress.Commands.add('failAsyncAppException', () => {
- cy.visit('/js_errors.html')
- cy.get('.async-error').click()
- cy.wait(10000)
-})
-
-Cypress.Commands.add('failAsyncException', () => {
- setTimeout(() => {
- ({}).bar()
- })
-
- cy.wait(10000)
-})
-
-Cypress.Commands.add('failInternalCypressMethod', () => {
- top.window.eval(`Cypress.dom.isJquery = () => { throw new Error('thrown in CypressdomisJquery') }`)
-
- cy.get('body')
-})
-
-Cypress.Commands.add('failInternalCyMethod', () => {
- top.window.eval(`cy.expect = () => { throw new Error('thrown in cyexpect') }`)
-
- cy.wrap({ foo: 'foo' }).should('have.property', 'foo')
-})
diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js b/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js
index 7416345e6d45..27e017398261 100644
--- a/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js
+++ b/packages/server/test/support/fixtures/projects/e2e/cypress/support/index.js
@@ -1,5 +1,3 @@
-import './commands'
-
before(function () {
if (Cypress.browser.family === 'chromium' && Cypress.browser.name !== 'electron') {
return Cypress.automation('remote:debugger:protocol', {
diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js b/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js
index e6da7bfb499a..c067a10e0b42 100644
--- a/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js
+++ b/packages/server/test/support/fixtures/projects/e2e/cypress/support/util.js
@@ -1,7 +1,6 @@
const { _ } = Cypress
let count = 1
-let shouldVerifyStackLineIsSpecFile = true
let openInIdePath = Cypress.spec
// ensure title is unique since it's necessary for querying the UI
@@ -12,76 +11,23 @@ const getTitle = (ctx) => {
return `${parentTitle} ${ctx.title}`.trim()
}
-export const setup = ({ verifyStackLineIsSpecFile, idePath }) => {
- shouldVerifyStackLineIsSpecFile = verifyStackLineIsSpecFile
- if (idePath) openInIdePath = idePath
-}
-
-// NOTE: use { defaultCommandTimeout: 0 } once per-test configuration is
-// implemented (https://github.com/cypress-io/cypress/pull/5346)
export const fail = (ctx, test) => {
const title = `${count++}) ✗ FAIL - ${getTitle(ctx)}`
- const withDone = test.length > 0
-
- if (withDone) {
- it(title, (done) => {
- cy.timeout(0) // speed up failures to not retry since we know they should fail
-
- return test(done)
- })
- return
- }
-
- it(title, () => {
- cy.timeout(0) // speed up failures to not retry since we know they should fail
-
- return test()
- })
+ it(title, { defaultCommandTimeout: 0 }, test)
}
export const verify = (ctx, options) => {
const {
- hasCodeFrame = true,
- verifyOpenInIde = true,
- verifyDocsContent,
- verifyDocsLearnMore,
+ line,
column,
- codeFrameText,
message,
stack,
} = options
- let { regex, line } = options
-
- // if no specific line, just accept any number
- line = line || '\\d+'
-
- // test only the column number because the line number is brittle
- // since any changes to this file can affect it
- if (!regex) {
- regex = shouldVerifyStackLineIsSpecFile ?
- new RegExp(`${Cypress.spec.relative}:${line}:${column}`) :
- new RegExp(`cypress\/support\/commands\.js:${line}:${column}`)
- }
-
- const testOpenInIde = (runnerWs) => {
- if (_.isRegExp(openInIdePath.absolute)) {
- expect(runnerWs.emit.withArgs('open:file').lastCall.args[1].file).to.match(openInIdePath.absolute)
- } else {
- expect(runnerWs.emit).to.be.calledWithMatch('open:file', {
- file: openInIdePath.absolute,
- })
- }
- }
- it(`✓ VERIFY`, function () {
- const currTest = this.test
- const currTestIndex = Cypress._.findIndex(ctx.tests, (test) => {
- return test === currTest
- })
- // find the previous test in the suite
- const prevTest = ctx.tests[currTestIndex - 1]
+ const fileRegex = new RegExp(`${Cypress.spec.relative}:${line}:${column}`)
+ it(`✓ VERIFY`, function () {
const runnerWs = window.top.runnerWs
cy.stub(window.top.runnerWs, 'emit').callThrough().withArgs('get:user:editor')
@@ -101,123 +47,52 @@ export const verify = (ctx, options) => {
.contains(`FAIL - ${getTitle(ctx)}`)
.closest('.runnable-wrapper')
.within(() => {
+ cy.contains('View stack trace').click()
+
_.each([].concat(message), (msg) => {
cy.get('.runnable-err-message')
.should('include.text', msg)
- // TODO: get this working. it currently fails in a bizarre way
- // displayed stack trace should not include message
- // cy.get('.runnable-err-stack-trace')
- // .invoke('text')
- // .should('not.include.text', msg)
+ cy.get('.runnable-err-stack-trace')
+ .should('not.include.text', msg)
})
- cy.contains('View stack trace').click()
-
cy.get('.runnable-err-stack-trace')
.invoke('text')
- .should('match', regex)
+ .should('match', fileRegex)
- if (stack) {
- _.each([].concat(stack), (stackLine) => {
- cy.get('.runnable-err-stack-trace')
- .should('include.text', stackLine)
- })
- }
+ _.each([].concat(stack), (stackLine) => {
+ cy.get('.runnable-err-stack-trace')
+ .should('include.text', stackLine)
+ })
cy.get('.runnable-err-stack-trace')
.should('not.include.text', '__stackReplacementMarker')
- const docsUrl = _.get(prevTest, 'err.docsUrl')
-
- if (verifyDocsLearnMore) {
- expect(docsUrl).to.eq(verifyDocsLearnMore)
-
- // make sure Learn More is there
- // and the docs url is not embedded
- // in the error message
- cy
- .get('.runnable-err-message')
- .should('not.contain', docsUrl)
- .contains('Learn more')
- .should('have.attr', 'href', docsUrl)
- }
-
- if (verifyDocsContent) {
- expect(docsUrl).to.be.undefined
-
- // verify that the docsUrl is
- // embedded in the content, but
- // that there's no Learn More link
- cy
- .get('.runnable-err-message')
- .should('contain', verifyDocsContent)
- .contains('Learn more')
- .should('not.exist')
- }
-
- if (verifyOpenInIde) {
- cy.contains('.runnable-err-stack-trace .runnable-err-file-path', openInIdePath.relative)
- .click()
- .should(() => {
- testOpenInIde(runnerWs)
+ cy.contains('.runnable-err-stack-trace .runnable-err-file-path', openInIdePath.relative)
+ .click()
+ .should(() => {
+ expect(runnerWs.emit).to.be.calledWithMatch('open:file', {
+ file: openInIdePath.absolute,
})
- }
-
- if (!hasCodeFrame) return
+ })
cy
.get('.test-err-code-frame .runnable-err-file-path')
.invoke('text')
- .should('match', regex)
-
- // most code frames will show `fail(this,()=>` as the 1st line but
- // for some it's cut off due to the test code being more lines,
- // so we prefer the `codeFrameText`
- cy.get('.test-err-code-frame pre span').should('include.text', codeFrameText || 'fail(this,()=>')
-
- if (verifyOpenInIde) {
- cy.contains('.test-err-code-frame .runnable-err-file-path', openInIdePath.relative)
- .click()
- .should(() => {
- expect(runnerWs.emit.withArgs('open:file')).to.be.calledTwice
- testOpenInIde(runnerWs)
- })
- }
- })
- })
-}
-
-export const verifyInternalError = (ctx, { method }) => {
- it(`✓ VERIFY`, () => {
- cy.wrap(Cypress.$(window.top.document.body))
- .find('.reporter')
- .contains(`FAIL - ${getTitle(ctx)}`)
- .closest('.runnable-wrapper')
- .within(() => {
- cy.get('.runnable-err-message')
- .should('include.text', `thrown in ${method.replace(/\./g, '')}`)
+ .should('match', fileRegex)
- cy.get('.runnable-err-stack-trace')
- .should('include.text', method)
+ // code frames will show `fail(this,()=>` as the 1st line
+ cy.get('.test-err-code-frame pre span').should('include.text', 'fail(this,()=>')
- cy.get('.test-err-code-frame')
- .should('not.exist')
+ cy.contains('.test-err-code-frame .runnable-err-file-path', openInIdePath.relative)
+ .click()
+ .should(() => {
+ expect(runnerWs.emit.withArgs('open:file')).to.be.calledTwice
+ expect(runnerWs.emit).to.be.calledWithMatch('open:file', {
+ file: openInIdePath.absolute,
+ })
+ })
})
})
}
-
-export const sendXhr = (win) => {
- const xhr = new win.XMLHttpRequest()
-
- xhr.open('GET', '/foo')
- xhr.send()
-
- return xhr
-}
-
-export const abortXhr = (win) => {
- const xhr = sendXhr(win)
-
- xhr.abort()
-}
diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress/integration/failing_spec.ts b/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress/integration/failing_spec.ts
index 364ccfed4c66..9f13d3578b48 100644
--- a/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress/integration/failing_spec.ts
+++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor-awesome-typescript-loader/cypress/integration/failing_spec.ts
@@ -1,10 +1,7 @@
/**
- * This tests various failure scenarios where an error and code frame is displayed
+ * This tests the error UI for a certain webpack preprocessor setup.
* It does this by having a test fail and then a subsequent test run that
- * tests the appearance of the command log
- * Because of this, the test order is important
- * There should be the same number of failing tests as there are passing
- * tests, because each failure has a verification test (e.g. 11 fail, 11 pass)
+ * verifies the appearance of the command log.
*/
// simple example of typescript types
@@ -12,9 +9,7 @@ type Foo = {
something: string
}
-import { fail, setup, verify } from '../../../e2e/cypress/support/util'
-
-setup({ verifyStackLineIsSpecFile: true })
+import { fail, verify } from '../../../e2e/cypress/support/util'
context('validation errors', function () {
beforeEach(() => {
@@ -28,7 +23,7 @@ context('validation errors', function () {
})
verify(this, {
- line: 27, // this only has 1 test, so we can be specific
+ line: 22,
column: 8,
message: 'can only accept a string preset or',
stack: ['throwErrBadArgs', 'From Your Spec Code:'],
diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress/integration/failing_spec.ts b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress/integration/failing_spec.ts
index 0ad966876553..f62e9b0a2a4e 100644
--- a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress/integration/failing_spec.ts
+++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader-compiler-options/cypress/integration/failing_spec.ts
@@ -1,12 +1,9 @@
///
/**
- * This tests various failure scenarios where an error and code frame is displayed
+ * This tests the error UI for a certain webpack preprocessor setup.
* It does this by having a test fail and then a subsequent test run that
- * tests the appearance of the command log
- * Because of this, the test order is important
- * There should be the same number of failing tests as there are passing
- * tests, because each failure has a verification test (e.g. 11 fail, 11 pass)
+ * verifies the appearance of the command log.
*/
// simple example of typescript types
@@ -14,9 +11,7 @@ type Foo = {
something: string
}
-import { fail, setup, verify } from '../../../e2e/cypress/support/util'
-
-setup({ verifyStackLineIsSpecFile: true })
+import { fail, verify } from '../../../e2e/cypress/support/util'
context('validation errors', function () {
beforeEach(() => {
@@ -30,7 +25,7 @@ context('validation errors', function () {
})
verify(this, {
- line: 29, // this only has 1 test, so we can be specific
+ line: 24,
column: 8,
message: 'can only accept a string preset or',
stack: ['throwErrBadArgs', 'From Your Spec Code:'],
diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress/integration/failing_spec.ts b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress/integration/failing_spec.ts
index 0ad966876553..f62e9b0a2a4e 100644
--- a/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress/integration/failing_spec.ts
+++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor-ts-loader/cypress/integration/failing_spec.ts
@@ -1,12 +1,9 @@
///
/**
- * This tests various failure scenarios where an error and code frame is displayed
+ * This tests the error UI for a certain webpack preprocessor setup.
* It does this by having a test fail and then a subsequent test run that
- * tests the appearance of the command log
- * Because of this, the test order is important
- * There should be the same number of failing tests as there are passing
- * tests, because each failure has a verification test (e.g. 11 fail, 11 pass)
+ * verifies the appearance of the command log.
*/
// simple example of typescript types
@@ -14,9 +11,7 @@ type Foo = {
something: string
}
-import { fail, setup, verify } from '../../../e2e/cypress/support/util'
-
-setup({ verifyStackLineIsSpecFile: true })
+import { fail, verify } from '../../../e2e/cypress/support/util'
context('validation errors', function () {
beforeEach(() => {
@@ -30,7 +25,7 @@ context('validation errors', function () {
})
verify(this, {
- line: 29, // this only has 1 test, so we can be specific
+ line: 24,
column: 8,
message: 'can only accept a string preset or',
stack: ['throwErrBadArgs', 'From Your Spec Code:'],
diff --git a/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress/integration/failing_spec.js b/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress/integration/failing_spec.js
index e060e602851b..03efddb77617 100644
--- a/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress/integration/failing_spec.js
+++ b/packages/server/test/support/fixtures/projects/webpack-preprocessor/cypress/integration/failing_spec.js
@@ -1,15 +1,10 @@
/**
- * This tests various failure scenarios where an error and code frame is displayed
+ * This tests the error UI for a certain webpack preprocessor setup.
* It does this by having a test fail and then a subsequent test run that
- * tests the appearance of the command log
- * Because of this, the test order is important
- * There should be the same number of failing tests as there are passing
- * tests, because each failure has a verification test (e.g. 11 fail, 11 pass)
+ * verifies the appearance of the command log.
*/
-import { fail, setup, verify } from '../../../e2e/cypress/support/util'
-
-setup({ verifyStackLineIsSpecFile: true })
+import { fail, verify } from '../../../e2e/cypress/support/util'
context('validation errors', function () {
beforeEach(() => {
@@ -21,7 +16,7 @@ context('validation errors', function () {
})
verify(this, {
- line: 20, // this only has 1 test, so we can be specific
+ line: 15,
column: 8,
message: 'can only accept a string preset or',
stack: ['throwErrBadArgs', 'From Your Spec Code:'],