From b5fc7a0362bf9be863754e1fd64fa6f39fbe4a40 Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Tue, 26 May 2020 14:57:14 -0400 Subject: [PATCH 1/7] remove Cypress object proxying related code for certain utils --- packages/driver/src/cy/commands/navigation.js | 12 +++++------ packages/driver/src/cypress.js | 20 +------------------ .../commands/navigation_spec.coffee | 10 +++++----- packages/runner/src/iframe/aut-iframe.js | 4 ++-- packages/runner/src/lib/event-manager.js | 20 +++++++++---------- 5 files changed, 24 insertions(+), 42 deletions(-) diff --git a/packages/driver/src/cy/commands/navigation.js b/packages/driver/src/cy/commands/navigation.js index efdca3d0a809..a0ee4fcc936d 100644 --- a/packages/driver/src/cy/commands/navigation.js +++ b/packages/driver/src/cy/commands/navigation.js @@ -917,14 +917,14 @@ module.exports = (Commands, Cypress, cy, state, config) => { // state for like scrollTop let s = { currentId: id, - tests: Cypress.getTestsState(), - startTime: Cypress.getStartTime(), - emissions: Cypress.getEmissions(), + tests: Cypress.runner.getTestsState(), + startTime: Cypress.runner.getStartTime(), + emissions: Cypress.runner.getEmissions(), } - s.passed = Cypress.countByTestState(s.tests, 'passed') - s.failed = Cypress.countByTestState(s.tests, 'failed') - s.pending = Cypress.countByTestState(s.tests, 'pending') + s.passed = Cypress.runner.countByTestState(s.tests, 'passed') + s.failed = Cypress.runner.countByTestState(s.tests, 'failed') + s.pending = Cypress.runner.countByTestState(s.tests, 'pending') s.numLogs = $Log.countLogsByTests(s.tests) return Cypress.action('cy:collect:run:state') diff --git a/packages/driver/src/cypress.js b/packages/driver/src/cypress.js index 06f90df13357..63e30aa559c0 100644 --- a/packages/driver/src/cypress.js +++ b/packages/driver/src/cypress.js @@ -35,11 +35,6 @@ const browserInfo = require('./cypress/browser') const resolvers = require('./cypress/resolvers') const debug = require('debug')('cypress:driver:cypress') -const proxies = { - runner: 'getStartTime getTestsState getEmissions setNumLogs countByTestState getDisplayPropsForLog getConsolePropsForLogById getSnapshotPropsForLogById getErrorByTestId setStartTime resumeAtTest normalizeAll'.split(' '), - cy: 'detachDom getStyles'.split(' '), -} - const jqueryProxyFn = function (...args) { if (!this.cy) { $errUtils.throwErrByPath('miscellaneous.no_cy') @@ -91,7 +86,6 @@ class $Cypress { this.mocha = null this.runner = null this.Commands = null - this._RESUMED_AT_TEST = null this.$autIframe = null this.onSpecReady = null @@ -243,7 +237,7 @@ class $Cypress { // mocha runner has begun running the tests this.emit('run:start') - if (this._RESUMED_AT_TEST) { + if (this.runner.getResumedAtTest() !== null) { return } @@ -624,18 +618,6 @@ $Cypress.prototype.minimatch = minimatch $Cypress.prototype.sinon = sinon $Cypress.prototype.lolex = lolex -// proxy all of the methods in proxies -// to their corresponding objects -_.each(proxies, (methods, key) => { - return _.each(methods, (method) => { - return $Cypress.prototype[method] = function (...args) { - const prop = this[key] - - return prop && prop[method].apply(prop, args) - } - }) -}) - // attaching these so they are accessible // via the runner + integration spec helper $Cypress.$ = $ diff --git a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee index 5364db693292..b772d1e42be2 100644 --- a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee @@ -660,11 +660,11 @@ describe "src/cy/commands/navigation", -> beforeEach -> Cypress.emit("test:before:run", { id: 888 }) - cy.stub(Cypress, "getEmissions").returns([]) - cy.stub(Cypress, "getTestsState").returns([]) - cy.stub(Cypress, "getStartTime").returns("12345") + cy.stub(Cypress.runner, "getEmissions").returns([]) + cy.stub(Cypress.runner, "getTestsState").returns([]) + cy.stub(Cypress.runner, "getStartTime").returns("12345") cy.stub(Cypress.Log, "countLogsByTests").withArgs([]).returns(1) - cy.stub(Cypress, "countByTestState") + cy.stub(Cypress.runner, "countByTestState") .withArgs([], "passed").returns(2) .withArgs([], "failed").returns(3) .withArgs([], "pending").returns(4) @@ -767,7 +767,7 @@ describe "src/cy/commands/navigation", -> describe ".log", -> beforeEach -> - cy.stub(Cypress, "getEmissions").returns([]) + cy.stub(Cypress.runner, "getEmissions").returns([]) @logs = [] diff --git a/packages/runner/src/iframe/aut-iframe.js b/packages/runner/src/iframe/aut-iframe.js index 978e378aec8b..219e4b4f9f9d 100644 --- a/packages/runner/src/iframe/aut-iframe.js +++ b/packages/runner/src/iframe/aut-iframe.js @@ -56,12 +56,12 @@ export default class AutIframe { if (!Cypress) return - return Cypress.detachDom(this._contents()) + return Cypress.cy.detachDom(this._contents()) } restoreDom = (snapshot) => { const Cypress = eventManager.getCypress() - const { headStyles, bodyStyles } = Cypress ? Cypress.getStyles(snapshot) : {} + const { headStyles, bodyStyles } = Cypress ? Cypress.cy.getStyles(snapshot) : {} const { body, htmlAttrs } = snapshot const contents = this._contents() const $html = contents.find('html') diff --git a/packages/runner/src/lib/event-manager.js b/packages/runner/src/lib/event-manager.js index 69509bae1b0d..d817ec4e4afd 100644 --- a/packages/runner/src/lib/event-manager.js +++ b/packages/runner/src/lib/event-manager.js @@ -74,7 +74,7 @@ const eventManager = { }) const logCommand = (logId) => { - const consoleProps = Cypress.getConsolePropsForLogById(logId) + const consoleProps = Cypress.runner.getConsolePropsForLogById(logId) logger.logFormatted(consoleProps) } @@ -111,7 +111,7 @@ const eventManager = { function sendEventIfSnapshotProps (logId, event) { if (!Cypress) return - const snapshotProps = Cypress.getSnapshotPropsForLogById(logId) + const snapshotProps = Cypress.runner.getSnapshotPropsForLogById(logId) if (snapshotProps) { localBus.emit(event, snapshotProps) @@ -217,7 +217,7 @@ const eventManager = { // get the current runnable in case we reran mid-test due to a visit // to a new domain ws.emit('get:existing:run:state', (state = {}) => { - const runnables = Cypress.normalizeAll(state.tests) + const runnables = Cypress.runner.normalizeAll(state.tests) const run = () => { performance.mark('initialize-end') performance.measure('initialize', 'initialize-start', 'initialize-end') @@ -228,18 +228,18 @@ const eventManager = { reporterBus.emit('runnables:ready', runnables) if (state.numLogs) { - Cypress.setNumLogs(state.numLogs) + Cypress.runner.setNumLogs(state.numLogs) } if (state.startTime) { - Cypress.setStartTime(state.startTime) + Cypress.runner.setStartTime(state.startTime) } if (state.currentId) { // if we have a currentId it means // we need to tell the Cypress to skip // ahead to that test - Cypress.resumeAtTest(state.currentId, state.emissions) + Cypress.runner.resumeAtTest(state.currentId, state.emissions) } if (config.isTextTerminal && !state.currentId) { @@ -270,13 +270,13 @@ const eventManager = { }) Cypress.on('log:added', (log) => { - const displayProps = Cypress.getDisplayPropsForLog(log) + const displayProps = Cypress.runner.getDisplayPropsForLog(log) reporterBus.emit('reporter:log:add', displayProps) }) Cypress.on('log:changed', (log) => { - const displayProps = Cypress.getDisplayPropsForLog(log) + const displayProps = Cypress.runner.getDisplayPropsForLog(log) reporterBus.emit('reporter:log:state:changed', displayProps) }) @@ -339,8 +339,8 @@ const eventManager = { }) reporterBus.emit('reporter:start', { - firefoxGcInterval: Cypress.getFirefoxGcInterval(), - startTime: Cypress.getStartTime(), + firefoxGcInterval: Cypress.runner.getFirefoxGcInterval(), + startTime: Cypress.runner.getStartTime(), numPassed: state.passed, numFailed: state.failed, numPending: state.pending, From 512ccd099180ef74079a4cc46f71814730475ce2 Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Tue, 26 May 2020 15:46:18 -0400 Subject: [PATCH 2/7] fix Cypress._RESUMED_AT_TEST access --- packages/driver/src/cypress.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/driver/src/cypress.js b/packages/driver/src/cypress.js index 63e30aa559c0..bb6228ac0b2a 100644 --- a/packages/driver/src/cypress.js +++ b/packages/driver/src/cypress.js @@ -237,7 +237,7 @@ class $Cypress { // mocha runner has begun running the tests this.emit('run:start') - if (this.runner.getResumedAtTest() !== null) { + if (this._RESUMED_AT_TEST) { return } From 2802664667cb546eda832927cd06695275bf31be Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Tue, 26 May 2020 15:52:42 -0400 Subject: [PATCH 3/7] fix Cypress._RESUMED_AT_TEST access 2 --- packages/driver/src/cypress.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/driver/src/cypress.js b/packages/driver/src/cypress.js index bb6228ac0b2a..2d2bd3d76e39 100644 --- a/packages/driver/src/cypress.js +++ b/packages/driver/src/cypress.js @@ -86,6 +86,7 @@ class $Cypress { this.mocha = null this.runner = null this.Commands = null + this._RESUMED_AT_TEST = null this.$autIframe = null this.onSpecReady = null From e5a1040ddb45bad56d37f2f8114a1213086588d7 Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Tue, 26 May 2020 16:34:24 -0400 Subject: [PATCH 4/7] fix firefoxgcinterval access --- packages/runner/src/lib/event-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runner/src/lib/event-manager.js b/packages/runner/src/lib/event-manager.js index d817ec4e4afd..888549e5a182 100644 --- a/packages/runner/src/lib/event-manager.js +++ b/packages/runner/src/lib/event-manager.js @@ -339,7 +339,7 @@ const eventManager = { }) reporterBus.emit('reporter:start', { - firefoxGcInterval: Cypress.runner.getFirefoxGcInterval(), + firefoxGcInterval: Cypress.getFirefoxGcInterval(), startTime: Cypress.runner.getStartTime(), numPassed: state.passed, numFailed: state.failed, From e3ad51a518be13b5a5c86dbe7998bf198083360c Mon Sep 17 00:00:00 2001 From: Ben Kucera <14625260+Bkucera@users.noreply.github.com> Date: Wed, 27 May 2020 11:35:53 -0400 Subject: [PATCH 5/7] fix decaf after merge --- .../commands/navigation_spec.coffee | 2204 ----------------- .../integration/commands/navigation_spec.js | 10 +- 2 files changed, 5 insertions(+), 2209 deletions(-) delete mode 100644 packages/driver/test/cypress/integration/commands/navigation_spec.coffee diff --git a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee deleted file mode 100644 index b772d1e42be2..000000000000 --- a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee +++ /dev/null @@ -1,2204 +0,0 @@ -$ = Cypress.$.bind(Cypress) -{ _, Promise } = Cypress - -Cookie = require("js-cookie") - -describe "src/cy/commands/navigation", -> - context "#reload", -> - before -> - cy - .visit("/fixtures/generic.html") - .then (win) -> - @body = win.document.body.outerHTML - - beforeEach -> - doc = cy.state("document") - @win = cy.state("window") - - $(doc.body).empty().html(@body) - - afterEach -> - cy.state("window", @win) - - it "calls into window.location.reload", -> - locReload = cy.spy(Cypress.utils, "locReload") - - cy.reload().then -> - expect(locReload).to.be.calledWith(false) - - it "can pass forceReload", -> - locReload = cy.spy(Cypress.utils, "locReload") - - cy.reload(true).then -> - expect(locReload).to.be.calledWith(true) - - it "can pass forceReload + options", -> - locReload = cy.spy(Cypress.utils, "locReload") - - cy.reload(true, {}).then -> - expect(locReload).to.be.calledWith(true) - - it "can pass just options", -> - locReload = cy.spy(Cypress.utils, "locReload") - - cy.reload({}).then -> - expect(locReload).to.be.calledWith(false) - - it "returns the window object", -> - cy - .window().then (oldWin) -> - oldWin.foo = "bar" - expect(oldWin.foo).to.eq("bar") - - cy.reload().then (win) -> - expect(win).not.to.be.undefined - expect(win.foo).to.be.undefined - - expect(win).to.eq(cy.state("window")) - - it "removes window:load listeners", -> - listeners = cy.listeners("window:load") - - winLoad = cy.spy(cy, "once").withArgs("window:load") - - cy.reload().then -> - expect(winLoad).to.be.calledOnce - - expect(cy.listeners("window:load")).to.deep.eq(listeners) - - ## TODO: fix this - it.skip "(FLAKY) sets timeout to Cypress.config(pageLoadTimeout)", -> - timeout = cy.spy(Promise.prototype, "timeout") - - Cypress.config("pageLoadTimeout", 4567) - - cy.reload().then -> - expect(timeout).to.be.calledWith(4567, "reload") - - it "fires stability:changed and window events events", -> - stub1 = cy.stub() - stub2 = cy.stub() - stub3 = cy.stub() - - cy.on("stability:changed", stub1) - cy.on("window:before:unload", stub2) - cy.on("window:unload", stub3) - - cy.reload().then -> - expect(stub1.firstCall).to.be.calledWith(false, "beforeunload") - expect(stub1.secondCall).to.be.calledWith(true, "load") - expect(stub2).to.be.calledOnce - expect(stub3).to.be.calledOnce - - it "removes listeners", -> - win = cy.state("window") - - rel = cy.stub(win, "removeEventListener") - - cy.reload().then -> - expect(rel).to.be.calledWith("beforeunload") - expect(rel).to.be.calledWith("unload") - - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 100) - - @logs = [] - - cy.on "log:added", (attrs, log) => - @lastLog = log - @logs.push(log) - - return null - - it "logs once on failure", (done) -> - cy.on "fail", (err) => - expect(@logs.length).to.eq(1) - done() - - cy.reload(Infinity) - - it "throws passing more than 2 args", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq("`cy.reload()` can only accept a boolean or `options` as its arguments.") - expect(err.docsUrl).to.eq("https://on.cypress.io/reload") - done() - - cy.reload(1, 2, 3) - - it "throws passing 2 invalid arguments", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq("`cy.reload()` can only accept a boolean or `options` as its arguments.") - expect(err.docsUrl).to.eq("https://on.cypress.io/reload") - done() - - cy.reload(true, 1) - - it "throws passing 1 invalid argument", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq("`cy.reload()` can only accept a boolean or `options` as its arguments.") - expect(err.docsUrl).to.eq("https://on.cypress.io/reload") - done() - - cy.reload(1) - - it "fully refreshes page", -> - cy - .window().then (win) -> - win.foo = "foo" - .reload() - .window().then (win) -> - expect(win.foo).to.be.undefined - - it "throws when reload times out", (done) -> - cy.timeout(1000) - locReload = cy.spy(Cypress.utils, "locReload") - - cy - .visit("/timeout?ms=100").then -> - expected = false - - ## wait until the window finishes loading first - ## else we can potentially move onto the next test - ## while we're still unstable, which will result in - ## properties on the window being inaccessible - ## since we only visit once at the beginning of these tests - cy.on "window:load", -> - expect(expected).to.be.true - done() - - cy.on "fail", (err) -> - expected = true - - expect(err.message).to.include "Your page did not fire its `load` event within `1ms`." - - .reload({timeout: 1}) - - describe ".log", -> - beforeEach -> - @logs = [] - - cy.on "log:added", (attrs, log) => - if attrs.name is "reload" - @lastLog = log - - @logs.push(log) - - return null - - it "logs reload", -> - cy.reload().then -> - expect(@lastLog.get("name")).to.eq("reload") - - it "can turn off logging", -> - cy.reload({log: false}).then -> - expect(@lastLog).to.be.undefined - - it "does not log 'Page Load' events", -> - cy.reload().then -> - @logs.slice(0).forEach (log) -> - expect(log.get("name")).not.eq('page load') - - it "logs before + after", -> - beforeunload = false - - cy - .window().then (win) -> - cy.on "window:before:unload", => - lastLog = @lastLog - - beforeunload = true - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0].name).to.eq("before") - expect(lastLog.get("snapshots")[0].body).to.be.an("object") - - return undefined - - .reload().then -> - lastLog = @lastLog - - expect(beforeunload).to.be.true - expect(lastLog.get("snapshots").length).to.eq(2) - expect(lastLog.get("snapshots")[1].name).to.eq("after") - expect(lastLog.get("snapshots")[1].body).to.be.an("object") - - context "#go", -> - before -> - cy - .visit("/fixtures/generic.html") - .then (win) -> - @body = win.document.body.outerHTML - - beforeEach -> - doc = cy.state("document") - - $(doc.body).empty().html(@body) - - ## TODO: fix this - it.skip "(FLAKY) sets timeout to Cypress.config(pageLoadTimeout)", -> - timeout = cy.spy Promise.prototype, "timeout" - Cypress.config("pageLoadTimeout", 4567) - - cy - .visit("/fixtures/jquery.html") - .go("back").then -> - expect(timeout).to.be.calledWith(4567, "go") - - it "removes listeners", -> - cy - .visit("/fixtures/generic.html") - .visit("/fixtures/jquery.html") - .then -> - winLoadListeners = cy.listeners("window:load") - beforeWinUnloadListeners = cy.listeners("window:before:unload") - - cyOn = cy.spy(cy, "once") - - winLoad = cyOn.withArgs("window:load") - beforeWinUnload = cyOn.withArgs("window:before:unload") - - cy.go("back").then -> - expect(winLoad).to.be.calledOnce - expect(beforeWinUnload).to.be.calledOnce - - expect(cy.listeners("window:load")).to.deep.eq(winLoadListeners) - expect(cy.listeners("window:before:unload")).to.deep.eq(beforeWinUnloadListeners) - - it "fires stability:changed and window events events", -> - stub1= cy.stub() - stub2 = cy.stub() - stub3 = cy.stub() - - cy - .visit("/fixtures/generic.html") - .visit("/fixtures/jquery.html") - .then -> - cy.on("stability:changed", stub1) - cy.on("window:before:unload", stub2) - cy.on("window:unload", stub3) - .go("back").then -> - expect(stub1.firstCall).to.be.calledWith(false, "beforeunload") - expect(stub1.secondCall).to.be.calledWith(true, "load") - expect(stub2).to.be.calledOnce - expect(stub3).to.be.calledOnce - - it "removes listeners from window", -> - cy - .visit("/fixtures/generic.html") - .visit("/fixtures/jquery.html") - .then (win) -> - rel = cy.stub(win, "removeEventListener") - - cy.go("back").then -> - expect(rel).to.be.calledWith("beforeunload") - expect(rel).to.be.calledWith("unload") - - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 50) - - @logs = [] - - cy.on "log:added", (attrs, log) => - if attrs.name is "go" - @lastLog = log - @logs.push(log) - - return null - - _.each [null, undefined, NaN, Infinity, {}, [], ->{}], (val) => - it "throws on: '#{val}'", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq("`cy.go()` accepts only a string or number argument") - expect(err.docsUrl).to.eq("https://on.cypress.io/go") - done() - - cy.go(val) - - it "throws on invalid string", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq("`cy.go()` accepts either `forward` or `back`. You passed: `foo`") - expect(err.docsUrl).to.eq("https://on.cypress.io/go") - - done() - - cy.go("foo") - - it "throws on zero", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq("`cy.go()` cannot accept `0`. The number must be greater or less than `0`.") - expect(err.docsUrl).to.eq("https://on.cypress.io/go") - - done() - - cy.go(0) - - it "throws when go times out", (done) -> - cy.timeout(1000) - cy - .visit("/timeout?ms=100") - .visit("/fixtures/jquery.html") - .then -> - expected = false - - ## wait until the window finishes loading first - ## else we can potentially move onto the next test - ## while we're still unstable, which will result in - ## properties on the window being inaccessible - ## since we only visit once at the beginning of these tests - cy.on "window:load", -> - expect(expected).to.be.true - done() - - cy.on "fail", (err) -> - expected = true - - expect(err.message).to.include "Your page did not fire its `load` event within `1ms`." - - cy.go("back", {timeout: 1}) - - it "only logs once on error", (done) -> - cy.on "fail", (err) => - expect(@logs.length).to.eq(1) - expect(@logs[0].get("error")).to.eq(err) - done() - - cy - .visit("/fixtures/jquery.html") - .go("back", {timeout: 1}) - - describe ".log", -> - beforeEach -> - cy.visit("/fixtures/generic.html").then -> - @logs = [] - - cy.on "log:added", (attrs, log) => - if attrs.name is "go" - @lastLog = log - - @logs.push(log) - - return null - - it "logs go", -> - cy - .visit("/fixtures/jquery.html") - .go("back").then -> - lastLog = @lastLog - - expect(lastLog.get("name")).to.eq("go") - expect(lastLog.get("message")).to.eq("back") - - it "can turn off logging", -> - cy - .visit("/fixtures/jquery.html") - .go("back", {log: false}).then -> - expect(@lastLog).to.be.undefined - - it "does not log 'Page Load' events", -> - cy - .visit("/fixtures/jquery.html") - .go("back").then -> - @logs.slice(0).forEach (log) -> - expect(log.get("name")).not.eq('page load') - - it "logs before + after", -> - beforeunload = false - - cy - .visit("/fixtures/jquery.html") - .window().then (win) -> - cy.on "window:before:unload", => - lastLog = @lastLog - - beforeunload = true - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0].name).to.eq("before") - expect(lastLog.get("snapshots")[0].body).to.be.an("object") - - return undefined - - cy.go("back").then -> - lastLog = @lastLog - - expect(beforeunload).to.be.true - expect(lastLog.get("snapshots").length).to.eq(2) - expect(lastLog.get("snapshots")[1].name).to.eq("after") - expect(lastLog.get("snapshots")[1].body).to.be.an("object") - - context "#visit", -> - ## TODO: fix this - it.skip "(FLAKY) sets timeout to Cypress.config(pageLoadTimeout)", -> - timeout = cy.spy Promise.prototype, "timeout" - - Cypress.config("pageLoadTimeout", 4567) - - cy.visit("/fixtures/jquery.html").then -> - expect(timeout).to.be.calledWith(4567) - - it "removes window:load listeners", -> - listeners = cy.listeners("window:load") - - winLoad = cy.spy(cy, "once").withArgs("window:load") - - cy.visit("/fixtures/generic.html").then -> - ## once for about:blank, once for $iframe src - expect(winLoad).to.be.calledTwice - - expect(cy.listeners("window:load")).to.deep.eq(listeners) - - it "can visit pages on the same originPolicy", -> - cy - .visit("http://localhost:3500/fixtures/jquery.html") - .visit("http://localhost:3500/fixtures/generic.html") - .visit("http://localhost:3500/fixtures/dimensions.html") - - it "resolves the subject to the remote iframe window", -> - cy.visit("/fixtures/jquery.html").then (win) -> - expect(win).to.eq cy.state("$autIframe").prop("contentWindow") - - it "changes the src of the iframe to the initial src", -> - cy.visit("/fixtures/jquery.html").then -> - src = cy.state("$autIframe").attr("src") - expect(src).to.eq "http://localhost:3500/fixtures/jquery.html" - - it "invokes onLoad callback", (done) -> - ctx = @ - - cy.visit("/fixtures/jquery.html", { - onLoad: (contentWindow) -> - thisValue = @ is ctx - - expect(thisValue).be.true - expect(!!contentWindow.Cypress).to.be.true - done() - }) - - it "invokes onBeforeLoad callback with cy context", (done) -> - ctx = @ - - cy.visit("/fixtures/jquery.html", { - onBeforeLoad: (contentWindow) -> - thisValue = @ is ctx - - expect(thisValue).be.true - - expect(!!contentWindow.Cypress).to.be.true - done() - }) - - it "does not error without an onBeforeLoad callback", -> - cy.visit("/fixtures/jquery.html").then -> - prev = cy.state("current").get("prev") - expect(prev.get("args")).to.have.length(1) - - it "calls resolve:url with http:// when localhost", -> - backend = cy.spy(Cypress, "backend") - - cy - .visit("localhost:3500/timeout") - .then -> - expect(backend).to.be.calledWith("resolve:url", "http://localhost:3500/timeout") - - it "prepends hostname when visiting locally", -> - prop = cy.spy(cy.state("$autIframe"), "prop") - - cy - .visit("fixtures/jquery.html") - .then -> - expect(prop).to.be.calledWith("src", "http://localhost:3500/fixtures/jquery.html") - - it "can visit relative pages on the same originPolicy", -> - ## as long as we are already on the localhost:3500 - ## domain this will work - - cy - .visit("http://localhost:3500/fixtures/dimensions.html") - .visit("/fixtures/jquery.html") - - it "can visit relative pages with domain like query params", -> - cy - .visit("http://localhost:3500/fixtures/generic.html") - .visit("http://localhost:3500/fixtures/dimensions.html?email=briancypress.io") - - it "can visit pages with non-2xx status codes when option failOnStatusCode is false", -> - cy - .visit("localhost:3500/status-404", { failOnStatusCode: false }) - .visit("localhost:3500/status-500", { failOnStatusCode: false }) - - it "strips username + password out of the url when provided", -> - backend = cy.spy(Cypress, "backend") - - cy - .visit("http://cypress:password123@localhost:3500/timeout") - .then -> - expect(backend).to.be.calledWith("resolve:url", "http://localhost:3500/timeout") - - it "passes auth options", -> - backend = cy.spy(Cypress, "backend") - - auth = { - username: "cypress" - password: "password123" - } - - cy - .visit("http://localhost:3500/timeout", { auth }) - .then -> - expect(backend).to.be.calledWithMatch("resolve:url", "http://localhost:3500/timeout", { auth }) - - it "does not support file:// protocol", (done) -> - Cypress.config("baseUrl", "") - - cy.on "fail", (err) -> - expect(err.message).to.contain("`cy.visit()` failed because the 'file://...' protocol is not supported by Cypress.") - done() - - cy.visit("file:///cypress/fixtures/generic.html") - - ## https://github.com/cypress-io/cypress/issues/1727 - it "can visit a page with undefined content type and html-shaped body", -> - cy - .visit("http://localhost:3500/undefined-content-type") - - describe "when only hashes are changing", -> - it "short circuits the visit if the page will not refresh", -> - count = 0 - urls = [] - - cy.on "window:load", -> - urls.push cy.state("window").location.href - - count += 1 - - cy - ## about:blank yes (1) - .visit("/fixtures/generic.html?foo#bar") ## yes (2) - .visit("/fixtures/generic.html?foo#foo") ## no (2) - .visit("/fixtures/generic.html?bar#bar") ## yes (3) - .visit("/fixtures/dimensions.html?bar#bar") ## yes (4) - .visit("/fixtures/dimensions.html?baz#bar") ## yes (5) - .visit("/fixtures/dimensions.html#bar") ## yes (6) - .visit("/fixtures/dimensions.html") ## yes (7) - .visit("/fixtures/dimensions.html#baz") ## no (7) - .visit("/fixtures/dimensions.html#") ## no (7) - .then -> - expect(count).to.eq(7) - expect(urls).to.deep.eq([ - "about:blank" - "http://localhost:3500/fixtures/generic.html?foo#bar" - "http://localhost:3500/fixtures/generic.html?bar#bar" - "http://localhost:3500/fixtures/dimensions.html?bar#bar" - "http://localhost:3500/fixtures/dimensions.html?baz#bar" - "http://localhost:3500/fixtures/dimensions.html#bar" - "http://localhost:3500/fixtures/dimensions.html" - ]) - - ## https://github.com/cypress-io/cypress/issues/1311 - it "window immediately resolves and doesn't reload when visiting the same URL with hashes", -> - onLoad = cy.stub() - - cy - .visit("http://localhost:3500/fixtures/generic.html#foo").then (win) -> - win.foo = 'bar' - .visit("http://localhost:3500/fixtures/generic.html#foo", { - onLoad: onLoad - }).then (win) -> - expect(win.bar).to.not.exist - expect(onLoad).not.to.have.been.called - - it "can send headers", -> - cy.visit({ - url: "http://localhost:3500/dump-headers", - headers: { - "x-foo-baz": "bar-quux" - } - }) - cy.contains('"x-foo-baz":"bar-quux"') - - it "can send user-agent header", -> - cy.visit({ - url: "http://localhost:3500/dump-headers", - headers: { - "user-agent": "something special" - } - }) - cy.contains('"user-agent":"something special"') - - it "can send querystring params", -> - qs = { "foo bar": "baz quux" } - - cy - .visit("http://localhost:3500/dump-qs", { qs }) - .then -> - cy.contains(JSON.stringify(qs)) - cy.url().should('eq', 'http://localhost:3500/dump-qs?foo%20bar=baz%20quux') - - describe "can send a POST request", -> - it "automatically urlencoded using an object body", -> - cy.visit("http://localhost:3500/post-only", { - method: "POST", - body: { - bar: "baz" - } - }) - cy.contains("it worked!").contains("{\"bar\":\"baz\"}") - - it "with any string body and headers", -> - cy.visit("http://localhost:3500/post-only", { - method: "POST", - headers: { - "content-type": "application/json" - } - body: JSON.stringify({ - bar: "baz" - }) - }) - cy.contains("it worked!").contains("{\"bar\":\"baz\"}") - - describe "when origins don't match", -> - beforeEach -> - Cypress.emit("test:before:run", { id: 888 }) - - cy.stub(Cypress.runner, "getEmissions").returns([]) - cy.stub(Cypress.runner, "getTestsState").returns([]) - cy.stub(Cypress.runner, "getStartTime").returns("12345") - cy.stub(Cypress.Log, "countLogsByTests").withArgs([]).returns(1) - cy.stub(Cypress.runner, "countByTestState") - .withArgs([], "passed").returns(2) - .withArgs([], "failed").returns(3) - .withArgs([], "pending").returns(4) - - it "emits preserve:run:state with title + fn", (done) -> - obj = { - currentId: 888 - tests: [] - emissions: [] - startTime: "12345" - numLogs: 1 - passed: 2 - failed: 3 - pending: 4 - } - - fn = (eventName, state) -> - _.each obj, (value, key) -> - expect(state[key]).to.deep.eq(value) - - done() - - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - url: "http://localhost:4200" - }) - .withArgs("preserve:run:state") - .callsFake(fn) - - cy.visit("http://localhost:4200") - - it "replaces window.location when origins don't match", (done) -> - fn = (str, win) -> - isEqual = win is top.window - - expect(isEqual).to.be.true - expect(str).to.eq("http://localhost:4200/foo?bar=baz#/tests/integration/foo_spec.js") - - done() - - fakeUrl = Cypress.Location.create("http://localhost:3500/foo?bar=baz#/tests/integration/foo_spec.js") - - cy.stub(Cypress.utils, "locExisting").returns(fakeUrl) - cy.stub(Cypress.utils, "locHref") - .callThrough() - .withArgs("http://localhost:4200/foo?bar=baz#/tests/integration/foo_spec.js") - .callsFake(fn) - - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - url: "http://localhost:4200" - }) - .withArgs("preserve:run:state") - .resolves() - - cy.visit("http://localhost:4200") - - describe "location getter overrides", -> - before -> - cy - .visit("/fixtures/jquery.html?foo=bar#dashboard?baz=quux") - .window().as("win").then (win) -> - ## ensure href always returns the full path - ## so our tests guarantee that in fact we are - ## overriding the location getters - expect(win.location.href).to.include "/fixtures/jquery.html?foo=bar#dashboard?baz=quux" - - beforeEach -> - @win = cy.state("window") - - @eq = (attr, str) => - expect(@win.location[attr]).to.eq str - - it "hash", -> - @eq "hash", "#dashboard?baz=quux" - - it "hostname", -> - @eq "hostname", "localhost" - - it "origin", -> - @eq "origin", "http://localhost:3500" - - it "pathname", -> - @eq "pathname", "/fixtures/jquery.html" - - it "port", -> - @eq "port", "3500" - - it "protocol", -> - @eq "protocol", "http:" - - it "search", -> - @eq "search", "?foo=bar" - - describe ".log", -> - beforeEach -> - cy.stub(Cypress.runner, "getEmissions").returns([]) - - @logs = [] - - cy.on "log:added", (attrs, log) => - if attrs.name is "visit" - @lastLog = log - - @logs.push(log) - - return null - - it "preserves url on subsequent visits", -> - cy.visit("/fixtures/jquery.html").get("button").then -> - expect(@lastLog.get("url")).to.eq "http://localhost:3500/fixtures/jquery.html" - - it "does not log 'Page Load' events", -> - cy - .visit("/fixtures/generic.html") - .visit("/fixtures/jquery.html") - .then -> - @logs.slice(0).forEach (log) -> - expect(log.get("name")).not.eq('page load') - - it "logs immediately before resolving", -> - expected = false - - cy.on "log:added", (attrs, log) -> - cy.removeAllListeners("log:added") - - expect(log.pick("name", "message")).to.deep.eq { - name: "visit" - message: "localhost:3500/fixtures/jquery.html#/hash" - } - - expected = true - - cy.visit("localhost:3500/fixtures/jquery.html#/hash").then -> - expect(expected).to.be.true - - it "logs obj once complete", -> - cy.visit("http://localhost:3500/fixtures/generic.html").then -> - obj = { - state: "passed" - name: "visit" - message: "http://localhost:3500/fixtures/generic.html" - url: "http://localhost:3500/fixtures/generic.html" - } - - lastLog = @lastLog - - _.each obj, (value, key) => - expect(lastLog.get(key)).deep.eq(value, "expected key: #{key} to eq value: #{value}") - - it "logs obj once complete when onLoad is not called", -> - cy.visit("http://localhost:3500/fixtures/generic.html#foo") - cy.visit("http://localhost:3500/fixtures/generic.html#foo").then -> - obj = { - state: "passed" - name: "visit" - message: "http://localhost:3500/fixtures/generic.html#foo" - url: "http://localhost:3500/fixtures/generic.html#foo" - } - - lastLog = @lastLog - - _.each obj, (value, key) => - expect(lastLog.get(key)).deep.eq(value, "expected key: #{key} to eq value: #{value}") - - it "snapshots once", -> - cy.visit("/fixtures/generic.html").then -> - lastLog = @lastLog - - expect(lastLog.get("snapshots").length).to.eq(1) - expect(lastLog.get("snapshots")[0]).to.be.an("object") - - it "can turn off logging", -> - cy.visit("/timeout?ms=0", {log: false}).then -> - expect(@lastLog).not.to.exist - - it "displays file attributes as consoleProps", -> - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - contentType: "text/html" - url: "http://localhost:3500/foo/bar" - filePath: "/path/to/foo/bar" - redirects: [1, 2] - cookies: [{}, {}] - }) - - cy.visit("/fixtures/jquery.html").then -> - expect(@lastLog.invoke("consoleProps")).to.deep.eq({ - "Command": "visit" - "File Served": "/path/to/foo/bar" - "Resolved Url": "http://localhost:3500/foo/bar" - "Redirects": [1, 2] - "Cookies Set": [{}, {}] - }) - - it "displays http attributes as consoleProps", -> - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - contentType: "text/html" - url: "http://localhost:3500/foo" - originalUrl: "http://localhost:3500/foo" - redirects: [1, 2] - cookies: [{}, {}] - }) - - cy.visit("http://localhost:3500/foo").then -> - expect(@lastLog.invoke("consoleProps")).to.deep.eq({ - "Command": "visit" - "Resolved Url": "http://localhost:3500/foo" - "Redirects": [1, 2] - "Cookies Set": [{}, {}] - }) - - it "displays originalUrl http attributes as consoleProps", -> - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - contentType: "text/html" - url: "http://localhost:3500/foo/bar" - originalUrl: "http://localhost:3500/foo" - redirects: [1, 2] - cookies: [{}, {}] - }) - - cy.visit("http://localhost:3500/foo").then -> - expect(@lastLog.invoke("consoleProps")).to.deep.eq({ - "Command": "visit" - "Original Url": "http://localhost:3500/foo" - "Resolved Url": "http://localhost:3500/foo/bar" - "Redirects": [1, 2] - "Cookies Set": [{}, {}] - }) - - it "indicates redirects in the message", -> - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - contentType: "text/html" - url: "http://localhost:3500/foo/bar" - originalUrl: "http://localhost:3500/foo" - redirects: [1, 2] - cookies: [{}, {}] - }) - - cy.visit("http://localhost:3500/foo").then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq( - "http://localhost:3500/foo -> 1 -> 2" - ) - - it "indicates POST in the message", -> - cy.visit("http://localhost:3500/post-only", { - method: "POST" - }).then -> - lastLog = @lastLog - - expect(lastLog.get("message")).to.eq( - "POST http://localhost:3500/post-only" - ) - - it "displays note in consoleProps when visiting the same page with a hash", -> - cy.visit("http://localhost:3500/fixtures/generic.html#foo") - .visit("http://localhost:3500/fixtures/generic.html#foo") - .then -> - expect(@lastLog.invoke("consoleProps")).to.deep.eq({ - "Command": "visit" - "Note": "Because this visit was to the same hash, the page did not reload and the onBeforeLoad and onLoad callbacks did not fire." - }) - - it "logs options if they are supplied", -> - cy.visit({ - url: "http://localhost:3500/fixtures/generic.html" - headers: { - "foo": "bar" - }, - notReal: "baz" - }) - .then -> - expect(@lastLog.invoke("consoleProps")["Options"]).to.deep.eq({ - url: "http://localhost:3500/fixtures/generic.html" - headers: { - "foo": "bar" - } - }) - - it "does not log options if they are not supplied", -> - cy.visit("http://localhost:3500/fixtures/generic.html") - .then -> - expect(@lastLog.invoke("consoleProps")["Options"]).to.be.undefined - - describe "errors", -> - beforeEach -> - Cypress.config("defaultCommandTimeout", 50) - - @logs = [] - - cy.on "log:added", (attrs, log) => - if attrs.name is "visit" - @lastLog = log - @logs.push(log) - - return null - - it "sets error command state", (done) -> - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .rejects(new Error) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(lastLog.get("state")).to.eq "failed" - expect(lastLog.get("error")).to.eq err - done() - - cy.visit("/fixtures/generic.html") - - it "logs once on error", (done) -> - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .rejects(new Error) - - cy.on "fail", (err) => - expect(@logs.length).to.eq(1) - done() - - cy.visit("/fixtures/generic.html") - - it "logs once on timeout error", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(@logs.length).to.eq(1) - expect(err.message).to.include "Your page did not fire its `load` event within `20ms`." - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("/timeout?ms=5000", {timeout: 20}) - - it "cancels resolve url promise on timeout", (done) -> - cy.on "collect:run:state", -> - done(new Error("should not have tried to swap domains")) - - fn = -> - ## resolve after 100ms - Promise.delay(100) - .then -> - done(new Error("should not have invoked this callback")) - - p = cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .callsFake(fn) - - cy.on "fail", -> done() - - cy.visit("/", {timeout: 20}) - - it "throws when url isnt a string", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.eq "`cy.visit()` must be called with a `url` or an `options` object containing a `url` as its 1st argument" - expect(err.docsUrl).to.eq("https://on.cypress.io/visit") - done() - - cy.visit() - - it "throws when url is specified twice", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.contain "`cy.visit()` must be called with only one `url`. You specified two urls" - expect(err.docsUrl).to.eq("https://on.cypress.io/visit") - done() - - cy.visit("http://foobarbaz", { - url: "http://foobarbaz" - }) - - it "throws when method is unsupported", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.contain "`cy.visit()` was called with an invalid method: `FOO`" - expect(err.docsUrl).to.eq("https://on.cypress.io/visit") - done() - - cy.visit({ - url: "http://foobarbaz", - method: "FOO" - }) - - it "throws when headers is not an object", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.contain "`cy.visit()` requires the `headers` option to be an object" - expect(err.docsUrl).to.eq("https://on.cypress.io/visit") - done() - - cy.visit({ - url: "http://foobarbaz", - headers: "quux" - }) - - [ - "foo", - null, - false, - ].forEach (qs) => - str = String(qs) - - it "throws when qs is #{str}", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.contain "`cy.visit()` requires the `qs` option to be an object, but received: `#{str}`" - done() - - cy.visit({ - url: "http://foobarbaz", - qs - }) - - it "throws when failOnStatusCode is false and retryOnStatusCodeFailure is true", (done) -> - cy.on "fail", (err) -> - expect(err.message).to.contain "These options are incompatible with each other." - done() - - cy.visit({ - url: "http://foobarbaz", - failOnStatusCode: false - retryOnStatusCodeFailure: true - }) - - it "throws when attempting to visit a 2nd domain on different port", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include("`cy.visit()` failed because you are attempting to visit a URL that is of a different origin.") - expect(err.message).to.include("The new URL is considered a different origin because the following parts of the URL are different:") - expect(err.message).to.include("> port") - expect(err.docsUrl).to.eq("https://on.cypress.io/cannot-visit-different-origin-domain") - expect(@logs.length).to.eq(2) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("http://localhost:3500/fixtures/generic.html") - cy.visit("http://localhost:3501/fixtures/generic.html") - - it "throws when attempting to visit a 2nd domain on different protocol", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include("`cy.visit()` failed because you are attempting to visit a URL that is of a different origin.") - expect(err.message).to.include("The new URL is considered a different origin because the following parts of the URL are different:") - expect(err.message).to.include("> protocol") - expect(err.docsUrl).to.eq("https://on.cypress.io/cannot-visit-different-origin-domain") - expect(@logs.length).to.eq(2) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("http://localhost:3500/fixtures/generic.html") - cy.visit("https://localhost:3500/fixtures/generic.html") - - it "throws when attempting to visit a 2nd domain on different superdomain", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include("`cy.visit()` failed because you are attempting to visit a URL that is of a different origin.") - expect(err.message).to.include("The new URL is considered a different origin because the following parts of the URL are different:") - expect(err.message).to.include("> superdomain") - expect(err.docsUrl).to.eq("https://on.cypress.io/cannot-visit-different-origin-domain") - expect(@logs.length).to.eq(2) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("http://localhost:3500/fixtures/generic.html") - cy.visit("http://google.com:3500/fixtures/generic.html") - - it "throws attemping to visit 2 unique ip addresses", (done) -> - $autIframe = cy.state("$autIframe") - - load = -> - $autIframe.trigger("load") - - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves({ - isOkStatusCode: true - isHtml: true - url: "http://127.0.0.1:3500" - }) - - ## whenever we're told to change the src - ## just fire the load event directly on the $autIframe - cy.stub(Cypress.utils, "iframeSrc").callsFake(load) - - ## make it seem like we're already on http://127.0.0.1:3500 - one = Cypress.Location.create("http://127.0.0.1:3500/fixtures/generic.html") - cy.stub(Cypress.utils, "locExisting") - .returns(one) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include("`cy.visit()` failed because you are attempting to visit a URL that is of a different origin.") - expect(err.docsUrl).to.eq("https://on.cypress.io/cannot-visit-different-origin-domain") - expect(@logs.length).to.eq(2) - expect(lastLog.get("error")).to.eq(err) - done() - - cy - .visit("http://127.0.0.1:3500/fixtures/generic.html") - .visit("http://126.0.0.1:3500/fixtures/generic.html") - - it "does not call resolve:url when throws attemping to visit a 2nd domain", (done) -> - backend = cy.spy(Cypress, "backend") - - cy.on "fail", (err) => - expect(backend).to.be.calledWithMatch("resolve:url", "http://localhost:3500/fixtures/generic.html") - expect(backend).not.to.be.calledWithMatch("resolve:url", "http://google.com:3500/fixtures/generic.html") - done() - - cy - .visit("http://localhost:3500/fixtures/generic.html") - .visit("http://google.com:3500/fixtures/generic.html") - - it "displays loading_network_failed when _resolveUrl throws", (done) -> - err1 = new Error("connect ECONNREFUSED 127.0.0.1:64646") - - ## dont log else we create an endless loop! - emit = cy.spy(Cypress, "emit").log(false) - - backend = cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .rejects(err1) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - http://localhost:3500/foo.html - - We attempted to make an http request to this URL but the request failed without a response. - - We received this error at the network level: - - > Error: connect ECONNREFUSED 127.0.0.1:64646 - - Common situations why this would fail: - - you don't have internet access - - you forgot to run / boot your web server - - your web server isn't accessible - - you have weird network configuration settings on your computer - """) - expect(err1.url).to.include("/foo.html") - expect(emit).to.be.calledWith("visit:failed", err1) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("/foo.html") - - it "displays loading_file_failed when _resolveUrl resp is not ok", (done) -> - obj = { - isOkStatusCode: false - isHtml: true - contentType: "text/html" - originalUrl: "/foo.html" - filePath: "/path/to/foo.html" - status: 404 - statusText: "Not Found" - redirects: [] - } - - visitErrObj = _.clone(obj) - obj.url = obj.originalUrl - - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves(obj) - - ## dont log else we create an endless loop! - emit = cy.spy(Cypress, "emit").log(false) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - /foo.html - - We failed looking for this file at the path: - - /path/to/foo.html - - The internal Cypress web server responded with: - - > 404: Not Found - """) - expect(emit).to.be.calledWithMatch("visit:failed", obj) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("/foo.html") - - it "displays loading_file_failed redirects when _resolveUrl resp is not ok", (done) -> - obj = { - isOkStatusCode: false - isHtml: true - contentType: "text/html" - originalUrl: "/bar" - filePath: "/path/to/bar/" - status: 404 - statusText: "Not Found" - redirects: [ - "301: http://localhost:3500/bar/" - ] - } - - visitErrObj = _.clone(obj) - obj.url = obj.originalUrl - - cy.stub(Cypress, "backend") - .withArgs("resolve:url") - .resolves(obj) - - ## dont log else we create an endless loop! - emit = cy.spy(Cypress, "emit").log(false) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - /bar - - We failed looking for this file at the path: - - /path/to/bar/ - - The internal Cypress web server responded with: - - > 404: Not Found - - We were redirected '1' time to: - - - 301: http://localhost:3500/bar/ - """) - expect(emit).to.be.calledWithMatch("visit:failed", obj) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("/bar") - - it "displays loading_http_failed when _resolveUrl resp is not ok", (done) -> - obj = { - isOkStatusCode: false - isHtml: true - contentType: "text/html" - originalUrl: "https://google.com/foo" - status: 500 - statusText: "Server Error" - redirects: [] - } - - visitErrObj = _.clone(obj) - obj.url = obj.originalUrl - - cy.stub(Cypress, "backend") - .withArgs("resolve:url", "https://google.com/foo") - .resolves(obj) - - ## dont log else we create an endless loop! - emit = cy.spy(Cypress, "emit").log(false) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - https://google.com/foo - - The response we received from your web server was: - - > 500: Server Error - - This was considered a failure because the status code was not `2xx`. - - If you do not want status codes to cause failures pass the option: `failOnStatusCode: false` - """) - expect(emit).to.be.calledWithMatch("visit:failed", obj) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("https://google.com/foo") - - it "displays loading_http_failed redirects when _resolveUrl resp is not ok", (done) -> - obj = { - isOkStatusCode: false - isHtml: true - contentType: "text/html" - originalUrl: "https://google.com/foo" - status: 401 - statusText: "Unauthorized" - redirects: [ - "302: https://google.com/bar/" - "301: https://gmail.com/" - ] - } - - visitErrObj = _.clone(obj) - obj.url = obj.originalUrl - - cy.stub(Cypress, "backend") - .withArgs("resolve:url", "https://google.com/foo") - .resolves(obj) - - ## dont log else we create an endless loop! - emit = cy.spy(Cypress, "emit").log(false) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - https://google.com/foo - - The response we received from your web server was: - - > 401: Unauthorized - - This was considered a failure because the status code was not `2xx`. - - This http request was redirected '2' times to: - - - 302: https://google.com/bar/ - - 301: https://gmail.com/ - - If you do not want status codes to cause failures pass the option: `failOnStatusCode: false` - """) - expect(emit).to.be.calledWithMatch("visit:failed", obj) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("https://google.com/foo") - - ## https://github.com/cypress-io/cypress/issues/3101 - [{ - contentType: 'application/json', - pathName: 'json-content-type' - }, { - contentType: 'text/html; charset=utf-8,text/html', - pathName: 'invalid-content-type' - }] - .forEach ({contentType, pathName}) -> - it "displays loading_invalid_content_type when content type is #{contentType} on http requests", (done) -> - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - http://localhost:3500/#{pathName} - - The `content-type` of the response we received from your web server was: - - > `#{contentType}` - - This was considered a failure because responses must have `content-type: 'text/html'` - - However, you can likely use `cy.request()` instead of `cy.visit()`. - - `cy.request()` will automatically get and set cookies and enable you to parse responses. - """) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("http://localhost:3500/#{pathName}") - - it "displays loading_invalid_content_type when isHtml is false on file requests", (done) -> - obj = { - isOkStatusCode: true - isHtml: false - filePath: "/path/to/bar/" - contentType: "application/json" - originalUrl: "https://google.com/foo" - status: 200 - statusText: "OK" - } - - visitErrObj = _.clone(obj) - obj.url = obj.originalUrl - - cy.stub(Cypress, "backend") - .withArgs("resolve:url", "https://google.com/foo") - .resolves(obj) - - ## dont log else we create an endless loop! - emit = cy.spy(Cypress, "emit").log(false) - - cy.on "fail", (err) => - lastLog = @lastLog - - expect(err.message).to.include(""" - `cy.visit()` failed trying to load: - - https://google.com/foo - - The `content-type` of the response we received from this local file was: - - > `application/json` - - This was considered a failure because responses must have `content-type: 'text/html'` - - However, you can likely use `cy.request()` instead of `cy.visit()`. - - `cy.request()` will automatically get and set cookies and enable you to parse responses. - """) - expect(emit).to.be.calledWithMatch("visit:failed", obj) - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - done() - - cy.visit("https://google.com/foo") - - it "displays body_circular when body is circular", (done) -> - foo = { - bar: { - baz: {} - } - } - - foo.bar.baz.quux = foo - - cy.visit({ - method: "POST" - url: "http://foo.invalid/" - body: foo - }) - - cy.on "fail", (err) => - lastLog = @lastLog - expect(@logs.length).to.eq(1) - expect(lastLog.get("error")).to.eq(err) - expect(lastLog.get("state")).to.eq("failed") - expect(err.message).to.eq """ - The `body` parameter supplied to `cy.visit()` contained a circular reference at the path "bar.baz.quux". - - `body` can only be a string or an object with no circular references. - """ - expect(err.docsUrl).to.eq("https://on.cypress.io/visit") - - done() - - context "#page load", -> - it "sets initial=true and then removes", -> - Cookie.remove("__cypress.initial") - - expect(Cookie.get("__cypress.initial")).to.be.undefined - - expected = false - - cy.on "window:before:unload", -> - expected = true - expect(Cookie.get("__cypress.initial")).to.eq("true") - - ## this navigates us to a new page so - ## we should be setting the initial cookie - cy - .visit("/fixtures/form.html") - .then -> - cy.once "window:unload", -> - expect(cy.state("onPageLoadErr")).to.be.a("function") - - null - .get("a:first").click().then -> - listeners = cy.listeners("window:load") - - ## everything should have unbound properly - expect(listeners.length).to.eq(0) - - expect(expected).to.be.true - - expect(cy.state("onPageLoadErr")).to.be.null - - expect(Cookie.get("__cypress.initial")).to.be.undefined - - ## TODO: broken - https://github.com/cypress-io/cypress/issues/4973 (chrome76+ and firefox) - it.skip "does not reset the timeout", (done) -> - cy.timeout(1000) - - ## previously loading would reset the timeout - ## which could cause failures on the next test - ## if there was logic after a test finished running - cy.window().then (win) => - timeout = cy.spy(cy, "timeout") - - ## we are unstable at this point - cy.on "window:before:unload", -> - cy.whenStable -> - expect(timeout).not.to.be.called - done() - - win.location.href = "about:blank" - - it "does not time out current commands until stability is reached", -> - ## on the first retry cause a page load event synchronously - cy.on "command:retry", (options) -> - switch options._retries - when 1 - win = cy.state("window") - - ## load a page which times out after 500ms - ## to guarantee that url does not time out - $a = win.$("jquery") - .appendTo(win.document.body) - - causeSynchronousBeforeUnload($a) - - when 2 - ## on 2nd retry add the DOM element - win = cy.state("window") - $("