mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-31 03:29:43 -06:00
Merge pull request #7345 from sainthkh/decaff-driver-7
This commit is contained in:
@@ -53,7 +53,7 @@ describe('src/cy/commands/actions/check', () => {
|
||||
})
|
||||
|
||||
it('changes the subject when matching values even if noop', () => {
|
||||
const checked = $('<input type=\'checkbox\' name=\'colors\' value=\'blue\' checked>')
|
||||
const checked = $(`<input type='checkbox' name='colors' value='blue' checked>`)
|
||||
|
||||
$('[name=colors]').parent().append(checked)
|
||||
|
||||
|
||||
@@ -553,16 +553,12 @@ describe('src/cy/commands/agents', () => {
|
||||
|
||||
it('does not include stack with calls when assertion fails', function (done) {
|
||||
cy.on('fail', () => {
|
||||
const messages = [
|
||||
expect(this.lastLog.get('message')).to.include([
|
||||
' foo("str", 5, true) => "return value"',
|
||||
' foo(null, undefined, [1, 2, 3]) => "return value"',
|
||||
' foo({g: 1}, Array[5], Object{6}) => "return value"',
|
||||
' foo(1, 2, 3, 4, 5) => "return value"',
|
||||
]
|
||||
|
||||
messages.forEach((msg) => {
|
||||
expect(this.lastLog.get('message')).to.include(msg)
|
||||
})
|
||||
].join('\n'))
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
describe "src/cy/commands/clock", ->
|
||||
beforeEach ->
|
||||
@window = cy.state("window")
|
||||
|
||||
@setTimeoutSpy = cy.spy(@window, "setTimeout")
|
||||
@setIntervalSpy = cy.spy(@window, "setInterval")
|
||||
|
||||
describe "#clock", ->
|
||||
it "sets clock as subject", ->
|
||||
cy.clock().then (clock) ->
|
||||
expect(clock).to.exist
|
||||
expect(clock.tick).to.be.a("function")
|
||||
|
||||
it "assigns clock to test context", ->
|
||||
cy.clock().then (clock) ->
|
||||
expect(clock).to.eq(@clock)
|
||||
|
||||
it "proxies lolex clock, replacing window time methods", (done) ->
|
||||
expect(@setTimeoutSpy).not.to.be.called
|
||||
cy.clock().then (clock) ->
|
||||
## lolex calls setTimeout once as part of its setup
|
||||
## but it shouldn't be called again by the @window.setTimeout()
|
||||
expect(@setTimeoutSpy).to.be.calledOnce
|
||||
@window.setTimeout =>
|
||||
expect(@setTimeoutSpy).to.be.calledOnce
|
||||
done()
|
||||
clock.tick()
|
||||
|
||||
it "takes now arg", ->
|
||||
now = 1111111111111
|
||||
cy.clock(now).then (clock) ->
|
||||
expect(new @window.Date().getTime()).to.equal(now)
|
||||
clock.tick(4321)
|
||||
expect(new @window.Date().getTime()).to.equal(now + 4321)
|
||||
|
||||
it "restores window time methods when calling restore", (done) ->
|
||||
cy.clock().then (clock) ->
|
||||
@window.setTimeout =>
|
||||
expect(@setTimeoutSpy).to.be.calledOnce
|
||||
clock.restore()
|
||||
expect(@window.setTimeout).to.equal(@setTimeoutSpy)
|
||||
@window.setTimeout =>
|
||||
expect(@setTimeoutSpy).to.be.calledTwice
|
||||
done()
|
||||
clock.tick()
|
||||
|
||||
it "unsets clock after restore", ->
|
||||
cy.clock().then (clock) ->
|
||||
expect(cy.state("clock")).to.exist
|
||||
clock.restore()
|
||||
expect(cy.state("clock")).to.be.null
|
||||
expect(@clock).to.be.null
|
||||
|
||||
it "automatically restores clock on 'restore' event", ->
|
||||
cy.clock().then (clock) ->
|
||||
r = cy.spy(clock, "restore")
|
||||
|
||||
Cypress.emit("test:before:run", {})
|
||||
|
||||
expect(r).to.be.called
|
||||
|
||||
it "returns clock on subsequent calls, ignoring arguments", ->
|
||||
cy
|
||||
.clock()
|
||||
.clock(400)
|
||||
.then (clock) ->
|
||||
expect(clock.details().now).to.equal(0)
|
||||
|
||||
it "new Date() is an instance of Date", ->
|
||||
cy.clock()
|
||||
cy.window().then (win) ->
|
||||
expect(new win.Date()).to.be.an.instanceof(win.Date)
|
||||
expect(new win.Date() instanceof win.Date).to.be.true
|
||||
|
||||
## this test was written to catch a bug in lolex (dep) 3 and is fixed by lolex 4 upgrade,
|
||||
it "doesn't override window.performance members", ->
|
||||
cy.clock()
|
||||
.then (clock) ->
|
||||
cy.window().then (win) ->
|
||||
expect(win.performance.getEntries()).to.deep.eq([])
|
||||
clock.restore()
|
||||
expect(win.performance.getEntries().length).to.be.at.least(1)
|
||||
|
||||
context "errors", ->
|
||||
it "throws if now is not a number (or options object)", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.equal("`cy.clock()` only accepts a number or an `options` object for its first argument. You passed: `\"250\"`")
|
||||
expect(err.docsUrl).to.equal("https://on.cypress.io/clock")
|
||||
done()
|
||||
|
||||
cy.clock("250")
|
||||
|
||||
it "throws if methods is not an array (or options object)", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.equal("`cy.clock()` only accepts an array of function names or an `options` object for its second argument. You passed: `\"setTimeout\"`")
|
||||
expect(err.docsUrl).to.equal("https://on.cypress.io/clock")
|
||||
done()
|
||||
|
||||
cy.clock(0, "setTimeout")
|
||||
|
||||
it "throws if methods is not an array of strings (or options object)", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.equal("`cy.clock()` only accepts an array of function names or an `options` object for its second argument. You passed: `[42]`")
|
||||
expect(err.docsUrl).to.equal("https://on.cypress.io/clock")
|
||||
done()
|
||||
|
||||
cy.clock(0, [42])
|
||||
|
||||
context "arg for which functions to replace", ->
|
||||
it "replaces specified functions", (done) ->
|
||||
cy.clock(null, ["setTimeout"]).then (clock) ->
|
||||
@window.setTimeout =>
|
||||
expect(@setTimeoutSpy).to.be.calledOnce
|
||||
done()
|
||||
clock.tick()
|
||||
|
||||
it "does not replace other functions", (done) ->
|
||||
cy.clock(null, ["setTimeout"]).then (clock) =>
|
||||
interval = @window.setInterval =>
|
||||
@window.clearInterval(interval)
|
||||
expect(@setIntervalSpy).to.be.called
|
||||
@window.setTimeout =>
|
||||
expect(@setTimeoutSpy).to.be.calledOnce
|
||||
done()
|
||||
clock.tick()
|
||||
, 5
|
||||
|
||||
context "options", ->
|
||||
beforeEach ->
|
||||
@logged = false
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if log.get("name") is "clock"
|
||||
@logged = true
|
||||
|
||||
return null
|
||||
|
||||
it "can be first arg", ->
|
||||
cy.clock({log: false}).then =>
|
||||
expect(@logged).to.be.false
|
||||
|
||||
it "can be second arg", ->
|
||||
cy.clock(new Date().getTime(), {log: false}).then =>
|
||||
expect(@logged).to.be.false
|
||||
|
||||
it "can be third arg", ->
|
||||
cy.clock(new Date().getTime(), ["setTimeout"], {log: false}).then =>
|
||||
expect(@logged).to.be.false
|
||||
|
||||
context "window changes", ->
|
||||
it "binds to default window before visit", ->
|
||||
cy.clock(null, ["setTimeout"]).then (clock) =>
|
||||
onSetTimeout = cy.spy()
|
||||
cy.state("window").setTimeout(onSetTimeout)
|
||||
clock.tick()
|
||||
expect(onSetTimeout).to.be.called
|
||||
|
||||
it "re-binds to new window when window changes", ->
|
||||
newWindow = {
|
||||
setTimeout: ->
|
||||
clearTimeout: ->
|
||||
Date: ->
|
||||
XMLHttpRequest: {
|
||||
prototype: {}
|
||||
}
|
||||
}
|
||||
cy.clock(null, ["setTimeout"]).then (clock) =>
|
||||
Cypress.emit("window:before:load", newWindow)
|
||||
onSetTimeout = cy.spy()
|
||||
newWindow.setTimeout(onSetTimeout)
|
||||
clock.tick()
|
||||
expect(onSetTimeout).to.be.called
|
||||
|
||||
it "binds to window if called before visit", ->
|
||||
cy.clock()
|
||||
cy.visit('/fixtures/dom.html') ## should not throw
|
||||
|
||||
context "logging", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
name = log.get("name")
|
||||
if name in ["clock", "tick", "restore"]
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "logs when created", ->
|
||||
cy.clock().then =>
|
||||
log = @logs[0]
|
||||
expect(@logs.length).to.equal(1)
|
||||
expect(log.get("name")).to.eq("clock")
|
||||
expect(log.get("message")).to.eq("")
|
||||
expect(log.get("type")).to.eq("parent")
|
||||
expect(log.get("state")).to.eq("passed")
|
||||
expect(log.get("snapshots").length).to.eq(1)
|
||||
expect(log.get("snapshots")[0]).to.be.an("object")
|
||||
|
||||
it "logs when restored", ->
|
||||
cy.clock().then (clock) =>
|
||||
clock.restore()
|
||||
|
||||
log = @logs[1]
|
||||
expect(@logs.length).to.equal(2)
|
||||
expect(log.get("name")).to.eq("restore")
|
||||
expect(log.get("message")).to.eq("")
|
||||
|
||||
it "does not log when auto-restored", (done) ->
|
||||
cy.clock().then =>
|
||||
Cypress.emit("test:before:run", {})
|
||||
expect(@logs.length).to.equal(1)
|
||||
done()
|
||||
|
||||
it "does not log when log: false", ->
|
||||
cy.clock({log: false}).then (clock) =>
|
||||
clock.tick()
|
||||
clock.restore()
|
||||
expect(@logs.length).to.equal(0)
|
||||
|
||||
it "only logs the first call", ->
|
||||
cy
|
||||
.clock()
|
||||
.clock()
|
||||
.clock()
|
||||
.then =>
|
||||
expect(@logs.length).to.equal(1)
|
||||
|
||||
context "#consoleProps", ->
|
||||
beforeEach ->
|
||||
cy.clock(100, ["setTimeout"]).then (@clock) ->
|
||||
@clock.tick(100)
|
||||
|
||||
it "includes clock's now value", ->
|
||||
consoleProps = @logs[0].invoke("consoleProps")
|
||||
expect(consoleProps["Now"]).to.equal(100)
|
||||
|
||||
it "includes methods replaced by clock", ->
|
||||
consoleProps = @logs[0].invoke("consoleProps")
|
||||
expect(consoleProps["Methods replaced"]).to.eql(["setTimeout"])
|
||||
|
||||
it "logs ticked amount on tick", ->
|
||||
createdConsoleProps = @logs[0].invoke("consoleProps")
|
||||
expect(createdConsoleProps["Ticked"]).to.be.undefined
|
||||
tickedConsoleProps = @logs[1].invoke("consoleProps")
|
||||
expect(tickedConsoleProps["Ticked"]).to.equal("100 milliseconds")
|
||||
|
||||
it "properties are unaffected by future actions", ->
|
||||
@clock.tick(100)
|
||||
@clock.restore()
|
||||
consoleProps = @logs[1].invoke("consoleProps")
|
||||
expect(consoleProps["Now"]).to.equal(200)
|
||||
expect(consoleProps["Methods replaced"]).to.eql(["setTimeout"])
|
||||
|
||||
describe "#tick", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if log.get("name") is "tick"
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "moves time ahead and triggers callbacks", (done) ->
|
||||
cy
|
||||
.clock()
|
||||
.then =>
|
||||
@window.setTimeout ->
|
||||
done()
|
||||
, 1000
|
||||
.tick(1000)
|
||||
|
||||
it "returns the clock object", ->
|
||||
cy
|
||||
.clock()
|
||||
.tick(1000).then (clock) ->
|
||||
expect(clock).to.equal(@clock)
|
||||
|
||||
it "defaults to 0ms", ->
|
||||
cy.clock()
|
||||
.tick().then (clock) ->
|
||||
consoleProps = @logs[0].invoke("consoleProps")
|
||||
expect(consoleProps["Ticked"]).to.equal("0 milliseconds")
|
||||
|
||||
context "errors", ->
|
||||
it "throws if there is not a clock", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.equal("`cy.tick()` cannot be called without first calling `cy.clock()`")
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/tick')
|
||||
done()
|
||||
|
||||
cy.tick()
|
||||
|
||||
it "throws if ms is not undefined or a number", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.equal("`clock.tick()`/`cy.tick()` only accepts a number as their argument. You passed: `\"100\"`")
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/tick')
|
||||
done()
|
||||
|
||||
cy.clock().tick("100")
|
||||
|
||||
context "logging", ->
|
||||
it "logs number of milliseconds", ->
|
||||
cy
|
||||
.clock()
|
||||
.tick(250)
|
||||
.then ->
|
||||
log = @logs[0]
|
||||
expect(@logs.length).to.equal(1)
|
||||
expect(log.get("name")).to.eq("tick")
|
||||
expect(log.get("message")).to.eq("250ms")
|
||||
|
||||
it "logs before and after snapshots", ->
|
||||
cy
|
||||
.clock()
|
||||
.tick(250)
|
||||
.then ->
|
||||
log = @logs[0]
|
||||
expect(log.get("snapshots").length).to.eq(2)
|
||||
expect(log.get("snapshots")[0].name).to.equal("before")
|
||||
expect(log.get("snapshots")[1].name).to.equal("after")
|
||||
454
packages/driver/test/cypress/integration/commands/clock_spec.js
Normal file
454
packages/driver/test/cypress/integration/commands/clock_spec.js
Normal file
@@ -0,0 +1,454 @@
|
||||
describe('src/cy/commands/clock', () => {
|
||||
beforeEach(function () {
|
||||
this.window = cy.state('window')
|
||||
|
||||
this.setTimeoutSpy = cy.spy(this.window, 'setTimeout')
|
||||
this.setIntervalSpy = cy.spy(this.window, 'setInterval')
|
||||
})
|
||||
|
||||
describe('#clock', () => {
|
||||
it('sets clock as subject', () => {
|
||||
cy.clock().then((clock) => {
|
||||
expect(clock).to.exist
|
||||
expect(clock.tick).to.be.a('function')
|
||||
})
|
||||
})
|
||||
|
||||
it('assigns clock to test context', () => {
|
||||
cy.clock().then(function (clock) {
|
||||
expect(clock).to.eq(this.clock)
|
||||
})
|
||||
})
|
||||
|
||||
it('proxies lolex clock, replacing window time methods', function (done) {
|
||||
expect(this.setTimeoutSpy).not.to.be.called
|
||||
|
||||
cy.clock().then(function (clock) {
|
||||
// lolex calls setTimeout once as part of its setup
|
||||
// but it shouldn't be called again by the @window.setTimeout()
|
||||
expect(this.setTimeoutSpy).to.be.calledOnce
|
||||
this.window.setTimeout(() => {
|
||||
expect(this.setTimeoutSpy).to.be.calledOnce
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
clock.tick()
|
||||
})
|
||||
})
|
||||
|
||||
it('takes now arg', () => {
|
||||
const now = 1111111111111
|
||||
|
||||
cy.clock(now).then(function (clock) {
|
||||
expect(new this.window.Date().getTime()).to.equal(now)
|
||||
clock.tick(4321)
|
||||
expect(new this.window.Date().getTime()).to.equal(now + 4321)
|
||||
})
|
||||
})
|
||||
|
||||
it('restores window time methods when calling restore', (done) => {
|
||||
cy.clock().then(function (clock) {
|
||||
this.window.setTimeout(() => {
|
||||
expect(this.setTimeoutSpy).to.be.calledOnce
|
||||
clock.restore()
|
||||
expect(this.window.setTimeout).to.equal(this.setTimeoutSpy)
|
||||
this.window.setTimeout(() => {
|
||||
expect(this.setTimeoutSpy).to.be.calledTwice
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
clock.tick()
|
||||
})
|
||||
})
|
||||
|
||||
it('unsets clock after restore', () => {
|
||||
cy.clock().then(function (clock) {
|
||||
expect(cy.state('clock')).to.exist
|
||||
clock.restore()
|
||||
expect(cy.state('clock')).to.be.null
|
||||
expect(this.clock).to.be.null
|
||||
})
|
||||
})
|
||||
|
||||
it('automatically restores clock on \'restore\' event', () => {
|
||||
cy.clock().then((clock) => {
|
||||
const r = cy.spy(clock, 'restore')
|
||||
|
||||
Cypress.emit('test:before:run', {})
|
||||
|
||||
expect(r).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('returns clock on subsequent calls, ignoring arguments', () => {
|
||||
cy
|
||||
.clock()
|
||||
.clock(400)
|
||||
.then((clock) => {
|
||||
expect(clock.details().now).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('new Date() is an instance of Date', () => {
|
||||
cy.clock()
|
||||
|
||||
cy.window().then((win) => {
|
||||
expect(new win.Date()).to.be.an.instanceof(win.Date)
|
||||
expect(new win.Date() instanceof win.Date).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
// this test was written to catch a bug in lolex (dep) 3 and is fixed by lolex 4 upgrade,
|
||||
it('doesn\'t override window.performance members', () => {
|
||||
cy.clock()
|
||||
.then((clock) => {
|
||||
cy.window().then((win) => {
|
||||
expect(win.performance.getEntries()).to.deep.eq([])
|
||||
clock.restore()
|
||||
expect(win.performance.getEntries().length).to.be.at.least(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('errors', () => {
|
||||
it('throws if now is not a number (or options object)', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.equal('`cy.clock()` only accepts a number or an `options` object for its first argument. You passed: `"250"`')
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/clock')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.clock('250')
|
||||
})
|
||||
|
||||
it('throws if methods is not an array (or options object)', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.equal('`cy.clock()` only accepts an array of function names or an `options` object for its second argument. You passed: `"setTimeout"`')
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/clock')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.clock(0, 'setTimeout')
|
||||
})
|
||||
|
||||
it('throws if methods is not an array of strings (or options object)', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.equal('`cy.clock()` only accepts an array of function names or an `options` object for its second argument. You passed: `[42]`')
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/clock')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.clock(0, [42])
|
||||
})
|
||||
})
|
||||
|
||||
context('arg for which functions to replace', () => {
|
||||
it('replaces specified functions', (done) => {
|
||||
cy.clock(null, ['setTimeout']).then(function (clock) {
|
||||
this.window.setTimeout(() => {
|
||||
expect(this.setTimeoutSpy).to.be.calledOnce
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
clock.tick()
|
||||
})
|
||||
})
|
||||
|
||||
it('does not replace other functions', function (done) {
|
||||
cy.clock(null, ['setTimeout']).then((clock) => {
|
||||
const interval = this.window.setInterval(() => {
|
||||
this.window.clearInterval(interval)
|
||||
expect(this.setIntervalSpy).to.be.called
|
||||
this.window.setTimeout(() => {
|
||||
expect(this.setTimeoutSpy).to.be.calledOnce
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
clock.tick()
|
||||
}, 5)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('options', () => {
|
||||
beforeEach(function () {
|
||||
this.logged = false
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (log.get('name') === 'clock') {
|
||||
this.logged = true
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('can be first arg', function () {
|
||||
cy.clock({ log: false }).then(() => {
|
||||
expect(this.logged).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
it('can be second arg', function () {
|
||||
cy.clock(new Date().getTime(), { log: false }).then(() => {
|
||||
expect(this.logged).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
it('can be third arg', function () {
|
||||
cy.clock(new Date().getTime(), ['setTimeout'], { log: false }).then(() => {
|
||||
expect(this.logged).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('window changes', () => {
|
||||
it('binds to default window before visit', () => {
|
||||
cy.clock(null, ['setTimeout']).then((clock) => {
|
||||
const onSetTimeout = cy.spy()
|
||||
|
||||
cy.state('window').setTimeout(onSetTimeout)
|
||||
clock.tick()
|
||||
|
||||
expect(onSetTimeout).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('re-binds to new window when window changes', () => {
|
||||
const newWindow = {
|
||||
setTimeout () {},
|
||||
clearTimeout () {},
|
||||
Date () {},
|
||||
XMLHttpRequest: {
|
||||
prototype: {},
|
||||
},
|
||||
}
|
||||
|
||||
cy.clock(null, ['setTimeout']).then((clock) => {
|
||||
Cypress.emit('window:before:load', newWindow)
|
||||
const onSetTimeout = cy.spy()
|
||||
|
||||
newWindow.setTimeout(onSetTimeout)
|
||||
clock.tick()
|
||||
|
||||
expect(onSetTimeout).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('binds to window if called before visit', () => {
|
||||
cy.clock()
|
||||
cy.visit('/fixtures/dom.html')// should not throw
|
||||
})
|
||||
})
|
||||
|
||||
context('logging', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
const name = log.get('name')
|
||||
|
||||
if (['clock', 'tick', 'restore'].includes(name)) {
|
||||
return this.logs.push(log)
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('logs when created', function () {
|
||||
cy.clock().then(() => {
|
||||
const log = this.logs[0]
|
||||
|
||||
expect(this.logs.length).to.equal(1)
|
||||
expect(log.get('name')).to.eq('clock')
|
||||
expect(log.get('message')).to.eq('')
|
||||
expect(log.get('type')).to.eq('parent')
|
||||
expect(log.get('state')).to.eq('passed')
|
||||
expect(log.get('snapshots').length).to.eq(1)
|
||||
expect(log.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
|
||||
it('logs when restored', function () {
|
||||
cy.clock().then((clock) => {
|
||||
clock.restore()
|
||||
|
||||
const log = this.logs[1]
|
||||
|
||||
expect(this.logs.length).to.equal(2)
|
||||
expect(log.get('name')).to.eq('restore')
|
||||
expect(log.get('message')).to.eq('')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not log when auto-restored', function (done) {
|
||||
cy.clock().then(() => {
|
||||
Cypress.emit('test:before:run', {})
|
||||
expect(this.logs.length).to.equal(1)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('does not log when log: false', function () {
|
||||
cy.clock({ log: false }).then((clock) => {
|
||||
clock.tick()
|
||||
clock.restore()
|
||||
|
||||
expect(this.logs.length).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('only logs the first call', function () {
|
||||
cy
|
||||
.clock()
|
||||
.clock()
|
||||
.clock()
|
||||
.then(() => {
|
||||
expect(this.logs.length).to.equal(1)
|
||||
})
|
||||
})
|
||||
|
||||
context('#consoleProps', () => {
|
||||
beforeEach(() => {
|
||||
cy.clock(100, ['setTimeout']).then(function (clock) {
|
||||
this.clock = clock
|
||||
this.clock.tick(100)
|
||||
})
|
||||
})
|
||||
|
||||
it('includes clock\'s now value', function () {
|
||||
const consoleProps = this.logs[0].invoke('consoleProps')
|
||||
|
||||
expect(consoleProps['Now']).to.equal(100)
|
||||
})
|
||||
|
||||
it('includes methods replaced by clock', function () {
|
||||
const consoleProps = this.logs[0].invoke('consoleProps')
|
||||
|
||||
expect(consoleProps['Methods replaced']).to.eql(['setTimeout'])
|
||||
})
|
||||
|
||||
it('logs ticked amount on tick', function () {
|
||||
const createdConsoleProps = this.logs[0].invoke('consoleProps')
|
||||
|
||||
expect(createdConsoleProps['Ticked']).to.be.undefined
|
||||
|
||||
const tickedConsoleProps = this.logs[1].invoke('consoleProps')
|
||||
|
||||
expect(tickedConsoleProps['Ticked']).to.equal('100 milliseconds')
|
||||
})
|
||||
|
||||
it('properties are unaffected by future actions', function () {
|
||||
this.clock.tick(100)
|
||||
this.clock.restore()
|
||||
const consoleProps = this.logs[1].invoke('consoleProps')
|
||||
|
||||
expect(consoleProps['Now']).to.equal(200)
|
||||
expect(consoleProps['Methods replaced']).to.eql(['setTimeout'])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#tick', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (log.get('name') === 'tick') {
|
||||
this.logs.push(log)
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('moves time ahead and triggers callbacks', function (done) {
|
||||
cy
|
||||
.clock()
|
||||
.then(() => {
|
||||
return this.window.setTimeout(() => {
|
||||
done()
|
||||
}, 1000)
|
||||
}).tick(1000)
|
||||
})
|
||||
|
||||
it('returns the clock object', () => {
|
||||
cy
|
||||
.clock()
|
||||
.tick(1000).then(function (clock) {
|
||||
expect(clock).to.equal(this.clock)
|
||||
})
|
||||
})
|
||||
|
||||
it('defaults to 0ms', () => {
|
||||
cy.clock()
|
||||
.tick().then(function (clock) {
|
||||
const consoleProps = this.logs[0].invoke('consoleProps')
|
||||
|
||||
expect(consoleProps['Ticked']).to.equal('0 milliseconds')
|
||||
})
|
||||
})
|
||||
|
||||
context('errors', () => {
|
||||
it('throws if there is not a clock', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.equal('`cy.tick()` cannot be called without first calling `cy.clock()`')
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/tick')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.tick()
|
||||
})
|
||||
|
||||
it('throws if ms is not undefined or a number', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.equal('`clock.tick()`/`cy.tick()` only accepts a number as their argument. You passed: `"100"`')
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/tick')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.clock().tick('100')
|
||||
})
|
||||
})
|
||||
|
||||
context('logging', () => {
|
||||
it('logs number of milliseconds', () => {
|
||||
cy
|
||||
.clock()
|
||||
.tick(250)
|
||||
.then(function () {
|
||||
const log = this.logs[0]
|
||||
|
||||
expect(this.logs.length).to.equal(1)
|
||||
expect(log.get('name')).to.eq('tick')
|
||||
expect(log.get('message')).to.eq('250ms')
|
||||
})
|
||||
})
|
||||
|
||||
it('logs before and after snapshots', () => {
|
||||
cy
|
||||
.clock()
|
||||
.tick(250)
|
||||
.then(function () {
|
||||
const log = this.logs[0]
|
||||
|
||||
expect(log.get('snapshots').length).to.eq(2)
|
||||
expect(log.get('snapshots')[0].name).to.equal('before')
|
||||
expect(log.get('snapshots')[1].name).to.equal('after')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,76 +0,0 @@
|
||||
_ = Cypress._
|
||||
$ = Cypress.$
|
||||
|
||||
describe "src/cy/commands/commands", ->
|
||||
before ->
|
||||
cy
|
||||
.visit("/fixtures/dom.html")
|
||||
.then (win) ->
|
||||
@body = win.document.body.outerHTML
|
||||
|
||||
beforeEach ->
|
||||
doc = cy.state("document")
|
||||
|
||||
$(doc.body).empty().html(@body)
|
||||
|
||||
it "can invoke commands by name", ->
|
||||
body = cy.$$("body")
|
||||
|
||||
cy
|
||||
.get("body").then ($body) ->
|
||||
expect($body.get(0)).to.eq(body.get(0))
|
||||
.command("get", "body").then ($body) ->
|
||||
expect($body.get(0)).to.eq(body.get(0))
|
||||
|
||||
it "can invoke child commands by name", ->
|
||||
div = cy.$$("body>div:first")
|
||||
|
||||
cy
|
||||
.get("body").find("div:first").then ($div) ->
|
||||
expect($div.get(0)).to.eq(div.get(0))
|
||||
.get("body").command("find", "div:first").then ($div) ->
|
||||
expect($div.get(0)).to.eq(div.get(0))
|
||||
|
||||
it "does not add cmds to cy.commands queue", ->
|
||||
cy.command("get", "body").then ->
|
||||
names = cy.queue.names()
|
||||
expect(names).to.deep.eq(["get", "then"])
|
||||
|
||||
context "custom commands", ->
|
||||
beforeEach ->
|
||||
Cypress.Commands.add "dashboard.selectWindows", =>
|
||||
cy
|
||||
.get("[contenteditable]")
|
||||
.first()
|
||||
|
||||
Cypress.Commands.add "login", { prevSubject: true }, (subject, email) =>
|
||||
cy
|
||||
.wrap(subject.find("input:first"))
|
||||
.type(email)
|
||||
|
||||
it "works with custom commands", ->
|
||||
input = cy.$$("input:first")
|
||||
|
||||
cy
|
||||
.get("input:first")
|
||||
.parent()
|
||||
.command("login", "brian@foo.com").then ($input) ->
|
||||
expect($input.get(0)).to.eq(input.get(0))
|
||||
|
||||
it "works with namespaced commands", ->
|
||||
ce = cy.$$("[contenteditable]").first()
|
||||
|
||||
cy
|
||||
.command("dashboard.selectWindows").then ($ce) ->
|
||||
expect($ce.get(0)).to.eq(ce.get(0))
|
||||
|
||||
context "errors", ->
|
||||
it "throws when cannot find command by name", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
cmds = _.keys(Cypress.Chainer.prototype)
|
||||
expect(cmds.length).to.be.gt(1)
|
||||
expect(err.message).to.eq("Could not find a command for: `fooDoesNotExist`.\n\nAvailable commands are: \`#{cmds.join("`, `")}\`.\n")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/api")
|
||||
done()
|
||||
|
||||
cy.get("body").command("fooDoesNotExist", "bar", "baz")
|
||||
@@ -0,0 +1,101 @@
|
||||
const { _, $ } = Cypress
|
||||
|
||||
describe('src/cy/commands/commands', () => {
|
||||
before(() => {
|
||||
cy
|
||||
.visit('/fixtures/dom.html')
|
||||
.then(function (win) {
|
||||
this.body = win.document.body.outerHTML
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
const doc = cy.state('document')
|
||||
|
||||
$(doc.body).empty().html(this.body)
|
||||
})
|
||||
|
||||
it('can invoke commands by name', () => {
|
||||
const body = cy.$$('body')
|
||||
|
||||
cy
|
||||
.get('body').then(($body) => {
|
||||
expect($body.get(0)).to.eq(body.get(0))
|
||||
})
|
||||
.command('get', 'body').then(($body) => {
|
||||
expect($body.get(0)).to.eq(body.get(0))
|
||||
})
|
||||
})
|
||||
|
||||
it('can invoke child commands by name', () => {
|
||||
const div = cy.$$('body>div:first')
|
||||
|
||||
cy
|
||||
.get('body').find('div:first').then(($div) => {
|
||||
expect($div.get(0)).to.eq(div.get(0))
|
||||
})
|
||||
.get('body').command('find', 'div:first').then(($div) => {
|
||||
expect($div.get(0)).to.eq(div.get(0))
|
||||
})
|
||||
})
|
||||
|
||||
it('does not add cmds to cy.commands queue', () => {
|
||||
cy.command('get', 'body').then(() => {
|
||||
const names = cy.queue.names()
|
||||
|
||||
expect(names).to.deep.eq(['get', 'then'])
|
||||
})
|
||||
})
|
||||
|
||||
context('custom commands', () => {
|
||||
beforeEach(() => {
|
||||
Cypress.Commands.add('dashboard.selectWindows', () => {
|
||||
cy
|
||||
.get('[contenteditable]')
|
||||
.first()
|
||||
})
|
||||
|
||||
Cypress.Commands.add('login', { prevSubject: true }, (subject, email) => {
|
||||
cy
|
||||
.wrap(subject.find('input:first'))
|
||||
.type(email)
|
||||
})
|
||||
})
|
||||
|
||||
it('works with custom commands', () => {
|
||||
const input = cy.$$('input:first')
|
||||
|
||||
cy
|
||||
.get('input:first')
|
||||
.parent()
|
||||
.command('login', 'brian@foo.com').then(($input) => {
|
||||
expect($input.get(0)).to.eq(input.get(0))
|
||||
})
|
||||
})
|
||||
|
||||
it('works with namespaced commands', () => {
|
||||
const ce = cy.$$('[contenteditable]').first()
|
||||
|
||||
cy
|
||||
.command('dashboard.selectWindows').then(($ce) => {
|
||||
expect($ce.get(0)).to.eq(ce.get(0))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('errors', () => {
|
||||
it('throws when cannot find command by name', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
const cmds = _.keys(Cypress.Chainer.prototype)
|
||||
|
||||
expect(cmds.length).to.be.gt(1)
|
||||
expect(err.message).to.eq(`Could not find a command for: \`fooDoesNotExist\`.\n\nAvailable commands are: \`${cmds.join('`, `')}\`.\n`)
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/api')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.get('body').command('fooDoesNotExist', 'bar', 'baz')
|
||||
})
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
2016
packages/driver/test/cypress/integration/commands/connectors_spec.js
Normal file
2016
packages/driver/test/cypress/integration/commands/connectors_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1252
packages/driver/test/cypress/integration/commands/cookies_spec.js
Normal file
1252
packages/driver/test/cypress/integration/commands/cookies_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
||||
Promise = Cypress.Promise
|
||||
|
||||
describe "src/cy/commands/debugging", ->
|
||||
context "#debug", ->
|
||||
beforeEach ->
|
||||
@utilsLog = cy.stub(Cypress.utils, "log")
|
||||
|
||||
it "does not change the subject", ->
|
||||
cy.wrap({}).debug().then (subject) ->
|
||||
expect(subject).to.deep.eq({})
|
||||
|
||||
it "logs current subject", ->
|
||||
obj = {foo: "bar"}
|
||||
|
||||
cy.wrap(obj).its("foo").debug().then ->
|
||||
expect(@utilsLog).to.be.calledWithMatch("Current Subject: ", "bar")
|
||||
|
||||
it "logs previous command", ->
|
||||
cy.wrap({}).debug().then ->
|
||||
expect(@utilsLog).to.be.calledWithMatch("Command Name: ", "wrap")
|
||||
expect(@utilsLog).to.be.calledWithMatch("Command Args: ", [{}])
|
||||
expect(@utilsLog).to.be.calledWithMatch("Current Subject: ", {})
|
||||
|
||||
it "logs undefined on being parent", ->
|
||||
cy.debug().then ->
|
||||
expect(@utilsLog).to.be.calledWithMatch("Current Subject: ", undefined)
|
||||
expect(@utilsLog).to.be.calledWithMatch("Command Name: ", undefined)
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "debug"
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "can turn off logging", ->
|
||||
cy
|
||||
.wrap([], {log: false})
|
||||
.debug({log: false}).then ->
|
||||
expect(@lastLog).to.be.undefined
|
||||
|
||||
context "#pause", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "pause"
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "can pause between each command and skips assertions", ->
|
||||
expected = false
|
||||
|
||||
cy.once "paused", (name) =>
|
||||
## should be pending
|
||||
expect(@lastLog.get("state")).to.eq("pending")
|
||||
|
||||
expect(name).to.eq("wrap")
|
||||
|
||||
cy.once "paused", (name) ->
|
||||
expected = true
|
||||
|
||||
expect(name).to.eq("then")
|
||||
|
||||
## resume the rest of the commands so this
|
||||
## test ends
|
||||
Cypress.emit("resume:all")
|
||||
|
||||
Cypress.emit("resume:next")
|
||||
|
||||
cy.pause().wrap({}).should("deep.eq", {}).then ->
|
||||
expect(expected).to.be.true
|
||||
|
||||
## should be pending
|
||||
expect(@lastLog.get("state")).to.eq("passed")
|
||||
|
||||
## should no longer have onPaused
|
||||
expect(cy.state("onPaused")).to.be.null
|
||||
@@ -0,0 +1,102 @@
|
||||
describe('src/cy/commands/debugging', () => {
|
||||
context('#debug', () => {
|
||||
beforeEach(function () {
|
||||
this.utilsLog = cy.stub(Cypress.utils, 'log')
|
||||
})
|
||||
|
||||
it('does not change the subject', () => {
|
||||
cy.wrap({}).debug().then((subject) => {
|
||||
expect(subject).to.deep.eq({})
|
||||
})
|
||||
})
|
||||
|
||||
it('logs current subject', () => {
|
||||
const obj = { foo: 'bar' }
|
||||
|
||||
cy.wrap(obj).its('foo').debug().then(function () {
|
||||
expect(this.utilsLog).to.be.calledWithMatch('Current Subject: ', 'bar')
|
||||
})
|
||||
})
|
||||
|
||||
it('logs previous command', () => {
|
||||
cy.wrap({}).debug().then(function () {
|
||||
expect(this.utilsLog).to.be.calledWithMatch('Command Name: ', 'wrap')
|
||||
expect(this.utilsLog).to.be.calledWithMatch('Command Args: ', [{}])
|
||||
expect(this.utilsLog).to.be.calledWithMatch('Current Subject: ', {})
|
||||
})
|
||||
})
|
||||
|
||||
it('logs undefined on being parent', () => {
|
||||
cy.debug().then(function () {
|
||||
expect(this.utilsLog).to.be.calledWithMatch('Current Subject: ', undefined)
|
||||
|
||||
expect(this.utilsLog).to.be.calledWithMatch('Command Name: ', undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'debug') {
|
||||
this.lastLog = log
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('can turn off logging', () => {
|
||||
cy
|
||||
.wrap([], { log: false })
|
||||
.debug({ log: false }).then(function () {
|
||||
expect(this.lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#pause', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'pause') {
|
||||
this.lastLog = log
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('can pause between each command and skips assertions', function () {
|
||||
let expected = false
|
||||
|
||||
cy.once('paused', (name) => {
|
||||
// should be pending
|
||||
expect(this.lastLog.get('state')).to.eq('pending')
|
||||
|
||||
expect(name).to.eq('wrap')
|
||||
|
||||
cy.once('paused', (name) => {
|
||||
expected = true
|
||||
|
||||
expect(name).to.eq('then')
|
||||
|
||||
// resume the rest of the commands so this
|
||||
// test ends
|
||||
Cypress.emit('resume:all')
|
||||
})
|
||||
|
||||
Cypress.emit('resume:next')
|
||||
})
|
||||
|
||||
cy.pause().wrap({}).should('deep.eq', {}).then(function () {
|
||||
expect(expected).to.be.true
|
||||
|
||||
// should be pending
|
||||
expect(this.lastLog.get('state')).to.eq('passed')
|
||||
|
||||
// should no longer have onPaused
|
||||
expect(cy.state('onPaused')).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,306 +0,0 @@
|
||||
_ = Cypress._
|
||||
Promise = Cypress.Promise
|
||||
|
||||
describe "src/cy/commands/exec", ->
|
||||
okResponse = { code: 0 }
|
||||
|
||||
context "#exec", ->
|
||||
beforeEach ->
|
||||
Cypress.config("execTimeout", 2500)
|
||||
|
||||
## call through normally on everything
|
||||
cy.stub(Cypress, "backend").callThrough()
|
||||
|
||||
it "triggers 'exec' with the right options", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.exec("ls").then ->
|
||||
expect(Cypress.backend).to.be.calledWith("exec", {
|
||||
cmd: "ls"
|
||||
timeout: 2500
|
||||
env: {}
|
||||
})
|
||||
|
||||
it "passes through environment variables", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.exec("ls", { env: { FOO: "foo" } }).then ->
|
||||
expect(Cypress.backend).to.be.calledWith("exec", {
|
||||
cmd: "ls"
|
||||
timeout: 2500
|
||||
env: {
|
||||
FOO: "foo"
|
||||
}
|
||||
})
|
||||
|
||||
it "really works", ->
|
||||
# output is trimmed
|
||||
cy.exec("echo foo", { timeout: 20000 }).its("stdout").should("eq", "foo")
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "can turn off logging", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.exec('ls', { log: false }).then ->
|
||||
logs = _.filter @logs, (log) ->
|
||||
log.get("name") is "exec"
|
||||
|
||||
expect(logs.length).to.eq(0)
|
||||
|
||||
it "logs immediately before resolving", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "exec"
|
||||
expect(log.get("state")).to.eq("pending")
|
||||
expect(log.get("message")).to.eq("ls")
|
||||
|
||||
cy.exec("ls").then =>
|
||||
throw new Error("failed to log before resolving") unless @lastLog
|
||||
|
||||
describe "timeout", ->
|
||||
it "defaults timeout to Cypress.config(execTimeout)", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
timeout = cy.spy(Promise.prototype, "timeout")
|
||||
|
||||
cy.exec("ls").then ->
|
||||
expect(timeout).to.be.calledWith(2500)
|
||||
|
||||
it "can override timeout", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
timeout = cy.spy(Promise.prototype, "timeout")
|
||||
|
||||
cy.exec("li", { timeout: 1000 }).then ->
|
||||
expect(timeout).to.be.calledWith(1000)
|
||||
|
||||
it "clears the current timeout and restores after success", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.timeout(100)
|
||||
|
||||
clearTimeout = cy.spy(cy, "clearTimeout")
|
||||
|
||||
cy.on "exec", =>
|
||||
expect(clearTimeout).to.be.calledOnce
|
||||
|
||||
cy.exec("ls").then ->
|
||||
expect(cy.timeout()).to.eq(100)
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 50)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "exec"
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "throws when cmd is absent", (done) ->
|
||||
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("`cy.exec()` must be passed a non-empty string as its 1st argument. You passed: ''.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
`cy.exec()`
|
||||
|
||||
it "throws when cmd isn't a string", (done) ->
|
||||
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("`cy.exec()` must be passed a non-empty string as its 1st argument. You passed: '3'.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec(3)
|
||||
|
||||
it "throws when cmd is an empty string", (done) ->
|
||||
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("`cy.exec()` must be passed a non-empty string as its 1st argument. You passed: ''.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec('')
|
||||
|
||||
it "throws when the execution errors", (done) ->
|
||||
Cypress.backend.rejects(new Error("exec failed"))
|
||||
|
||||
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("`cy.exec('ls')` failed with the following error:\n\n> \"Error: exec failed\"")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "throws after timing out", (done) ->
|
||||
Cypress.backend.resolves(Promise.delay(250))
|
||||
|
||||
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("`cy.exec('ls')` timed out after waiting `50ms`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec("ls", { timeout: 50 })
|
||||
|
||||
it "logs once on error", (done) ->
|
||||
Cypress.backend.rejects(new Error("exec failed"))
|
||||
|
||||
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")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "can timeout from the backend's response", (done) ->
|
||||
err = new Error("timeout")
|
||||
err.timedOut = true
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.include("`cy.exec('sleep 2')` timed out after waiting `100ms`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec("sleep 2", {
|
||||
timeout: 100
|
||||
})
|
||||
|
||||
it "can really time out", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.include("`cy.exec('sleep 2')` timed out after waiting `100ms`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec("sleep 2", {
|
||||
timeout: 100
|
||||
})
|
||||
|
||||
describe "when error code is non-zero", ->
|
||||
it "throws error that includes useful information and exit code", (done) ->
|
||||
Cypress.backend.resolves({ code: 1 })
|
||||
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.contain("`cy.exec('ls')` failed because the command exited with a non-zero code.\n\nPass `{failOnNonZeroExit: false}` to ignore exit code failures.")
|
||||
expect(err.message).to.contain("Code: 1")
|
||||
expect(err.docsUrl).to.contain("https://on.cypress.io/exec")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "throws error that includes stderr if it exists and is non-empty", (done) ->
|
||||
Cypress.backend.resolves({ code: 1, stderr: "error output", stdout: "" })
|
||||
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.contain("Stderr:\nerror output")
|
||||
expect(err.message).not.to.contain("Stdout")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "throws error that includes stdout if it exists and is non-empty", (done) ->
|
||||
Cypress.backend.resolves({ code: 1, stderr: "", stdout: "regular output" })
|
||||
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.contain("\nStdout:\nregular output")
|
||||
expect(err.message).not.to.contain("Stderr")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "throws error that includes stdout and stderr if they exists and are non-empty", (done) ->
|
||||
Cypress.backend.resolves({ code: 1, stderr: "error output", stdout: "regular output" })
|
||||
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.contain("\nStdout:\nregular output\nStderr:\nerror output")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "truncates the stdout and stderr in the error message", (done) ->
|
||||
Cypress.backend.resolves({
|
||||
code: 1
|
||||
stderr: "#{_.range(200).join()}stderr should be truncated"
|
||||
stdout: "#{_.range(200).join()}stdout should be truncated"
|
||||
})
|
||||
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).not.to.contain("stderr should be truncated")
|
||||
expect(err.message).not.to.contain("stdout should be truncated")
|
||||
expect(err.message).to.contain("...")
|
||||
done()
|
||||
|
||||
cy.exec("ls")
|
||||
|
||||
it "can really fail", (done) ->
|
||||
cy.on "fail", (err) =>
|
||||
lastLog = @lastLog
|
||||
|
||||
{ Yielded } = lastLog.invoke("consoleProps")
|
||||
|
||||
# output is trimmed
|
||||
expect(Yielded).to.deep.eq({
|
||||
stdout: "foo"
|
||||
stderr: ""
|
||||
code: 1
|
||||
})
|
||||
|
||||
done()
|
||||
|
||||
cy.exec("echo foo && exit 1")
|
||||
|
||||
describe "and failOnNonZeroExit is false", ->
|
||||
it "does not error", ->
|
||||
response = { code: 1, stderr: "error output", stdout: "regular output" }
|
||||
Cypress.backend.resolves(response)
|
||||
|
||||
cy
|
||||
.exec("ls", { failOnNonZeroExit: false })
|
||||
.should("deep.eq", response)
|
||||
|
||||
it "does not really fail", ->
|
||||
cy.exec("echo foo && exit 1", {
|
||||
failOnNonZeroExit: false
|
||||
})
|
||||
384
packages/driver/test/cypress/integration/commands/exec_spec.js
Normal file
384
packages/driver/test/cypress/integration/commands/exec_spec.js
Normal file
@@ -0,0 +1,384 @@
|
||||
const { _, Promise } = Cypress
|
||||
|
||||
describe('src/cy/commands/exec', () => {
|
||||
const okResponse = { code: 0 }
|
||||
|
||||
context('#exec', () => {
|
||||
beforeEach(() => {
|
||||
Cypress.config('execTimeout', 2500)
|
||||
|
||||
// call through normally on everything
|
||||
cy.stub(Cypress, 'backend').callThrough()
|
||||
})
|
||||
|
||||
it('triggers \'exec\' with the right options', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.exec('ls').then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith('exec', {
|
||||
cmd: 'ls',
|
||||
timeout: 2500,
|
||||
env: {},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('passes through environment variables', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.exec('ls', { env: { FOO: 'foo' } }).then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith('exec', {
|
||||
cmd: 'ls',
|
||||
timeout: 2500,
|
||||
env: {
|
||||
FOO: 'foo',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('really works', () => {
|
||||
// output is trimmed
|
||||
cy.exec('echo foo', { timeout: 20000 }).its('stdout').should('eq', 'foo')
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('can turn off logging', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.exec('ls', { log: false }).then(function () {
|
||||
const logs = _.filter(this.logs, (log) => {
|
||||
return log.get('name') === 'exec'
|
||||
})
|
||||
|
||||
expect(logs.length).to.eq(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('logs immediately before resolving', function () {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'exec') {
|
||||
expect(log.get('state')).to.eq('pending')
|
||||
expect(log.get('message')).to.eq('ls')
|
||||
}
|
||||
})
|
||||
|
||||
cy.exec('ls').then(() => {
|
||||
if (!this.lastLog) {
|
||||
throw new Error('failed to log before resolving')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('timeout', () => {
|
||||
it('defaults timeout to Cypress.config(execTimeout)', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
const timeout = cy.spy(Promise.prototype, 'timeout')
|
||||
|
||||
cy.exec('ls').then(() => {
|
||||
expect(timeout).to.be.calledWith(2500)
|
||||
})
|
||||
})
|
||||
|
||||
it('can override timeout', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
const timeout = cy.spy(Promise.prototype, 'timeout')
|
||||
|
||||
cy.exec('li', { timeout: 1000 }).then(() => {
|
||||
expect(timeout).to.be.calledWith(1000)
|
||||
})
|
||||
})
|
||||
|
||||
it('clears the current timeout and restores after success', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.timeout(100)
|
||||
|
||||
const clearTimeout = cy.spy(cy, 'clearTimeout')
|
||||
|
||||
cy.on('exec', () => {
|
||||
expect(clearTimeout).to.be.calledOnce
|
||||
})
|
||||
|
||||
cy.exec('ls').then(() => {
|
||||
expect(cy.timeout()).to.eq(100)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 50)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'exec') {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('throws when cmd is absent', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.exec()` must be passed a non-empty string as its 1st argument. You passed: \'\'.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec()
|
||||
})
|
||||
|
||||
it('throws when cmd isn\'t a string', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.exec()` must be passed a non-empty string as its 1st argument. You passed: \'3\'.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec(3)
|
||||
})
|
||||
|
||||
it('throws when cmd is an empty string', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.exec()` must be passed a non-empty string as its 1st argument. You passed: \'\'.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('')
|
||||
})
|
||||
|
||||
it('throws when the execution errors', function (done) {
|
||||
Cypress.backend.rejects(new Error('exec failed'))
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
|
||||
expect(err.message).to.eq('`cy.exec(\'ls\')` failed with the following error:\n\n> "Error: exec failed"')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('throws after timing out', function (done) {
|
||||
Cypress.backend.resolves(Promise.delay(250))
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.exec(\'ls\')` timed out after waiting `50ms`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls', { timeout: 50 })
|
||||
})
|
||||
|
||||
it('logs once on error', function (done) {
|
||||
Cypress.backend.rejects(new Error('exec failed'))
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('can timeout from the backend\'s response', (done) => {
|
||||
const err = new Error('timeout')
|
||||
|
||||
err.timedOut = true
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`cy.exec(\'sleep 2\')` timed out after waiting `100ms`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('sleep 2', {
|
||||
timeout: 100,
|
||||
})
|
||||
})
|
||||
|
||||
it('can really time out', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`cy.exec(\'sleep 2\')` timed out after waiting `100ms`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('sleep 2', {
|
||||
timeout: 100,
|
||||
})
|
||||
})
|
||||
|
||||
describe('when error code is non-zero', () => {
|
||||
it('throws error that includes useful information and exit code', (done) => {
|
||||
Cypress.backend.resolves({ code: 1 })
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.contain('`cy.exec(\'ls\')` failed because the command exited with a non-zero code.\n\nPass `{failOnNonZeroExit: false}` to ignore exit code failures.')
|
||||
expect(err.message).to.contain('Code: 1')
|
||||
expect(err.docsUrl).to.contain('https://on.cypress.io/exec')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('throws error that includes stderr if it exists and is non-empty', (done) => {
|
||||
Cypress.backend.resolves({ code: 1, stderr: 'error output', stdout: '' })
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.contain('Stderr:\nerror output')
|
||||
expect(err.message).not.to.contain('Stdout')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('throws error that includes stdout if it exists and is non-empty', (done) => {
|
||||
Cypress.backend.resolves({ code: 1, stderr: '', stdout: 'regular output' })
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.contain('\nStdout:\nregular output')
|
||||
expect(err.message).not.to.contain('Stderr')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('throws error that includes stdout and stderr if they exists and are non-empty', (done) => {
|
||||
Cypress.backend.resolves({ code: 1, stderr: 'error output', stdout: 'regular output' })
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.contain('\nStdout:\nregular output\nStderr:\nerror output')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('truncates the stdout and stderr in the error message', (done) => {
|
||||
Cypress.backend.resolves({
|
||||
code: 1,
|
||||
stderr: `${_.range(200).join()}stderr should be truncated`,
|
||||
stdout: `${_.range(200).join()}stdout should be truncated`,
|
||||
})
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).not.to.contain('stderr should be truncated')
|
||||
expect(err.message).not.to.contain('stdout should be truncated')
|
||||
expect(err.message).to.contain('...')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('ls')
|
||||
})
|
||||
|
||||
it('can really fail', function (done) {
|
||||
cy.on('fail', () => {
|
||||
const { lastLog } = this
|
||||
|
||||
const { Yielded } = lastLog.invoke('consoleProps')
|
||||
|
||||
// output is trimmed
|
||||
expect(Yielded).to.deep.eq({
|
||||
stdout: 'foo',
|
||||
stderr: '',
|
||||
code: 1,
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.exec('echo foo && exit 1')
|
||||
})
|
||||
|
||||
describe('and failOnNonZeroExit is false', () => {
|
||||
it('does not error', () => {
|
||||
const response = { code: 1, stderr: 'error output', stdout: 'regular output' }
|
||||
|
||||
Cypress.backend.resolves(response)
|
||||
|
||||
cy
|
||||
.exec('ls', { failOnNonZeroExit: false })
|
||||
.should('deep.eq', response)
|
||||
})
|
||||
|
||||
it('does not really fail', () => {
|
||||
cy.exec('echo foo && exit 1', {
|
||||
failOnNonZeroExit: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,464 +0,0 @@
|
||||
_ = Cypress._
|
||||
|
||||
okResponse = {
|
||||
contents: "contents"
|
||||
filePath: "/path/to/foo.json"
|
||||
}
|
||||
|
||||
describe "src/cy/commands/files", ->
|
||||
beforeEach ->
|
||||
## call through normally on everything
|
||||
cy.stub(Cypress, "backend").callThrough()
|
||||
|
||||
describe "#readFile", ->
|
||||
it "triggers 'read:file' with the right options", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile("foo.json").then ->
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
"read:file",
|
||||
"foo.json",
|
||||
{ encoding: "utf8" }
|
||||
)
|
||||
|
||||
it "can take encoding as second argument", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile("foo.json", "ascii").then ->
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
"read:file",
|
||||
"foo.json",
|
||||
{ encoding: "ascii" }
|
||||
)
|
||||
|
||||
it "sets the contents as the subject", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json').then (subject) ->
|
||||
expect(subject).to.equal("contents")
|
||||
|
||||
it "retries to read when ENOENT", ->
|
||||
err = new Error("foo")
|
||||
err.code = "ENOENT"
|
||||
|
||||
retries = 0
|
||||
|
||||
cy.on "command:retry", ->
|
||||
retries += 1
|
||||
|
||||
Cypress.backend
|
||||
.onFirstCall()
|
||||
.rejects(err)
|
||||
.onSecondCall()
|
||||
.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json').then ->
|
||||
expect(retries).to.eq(1)
|
||||
|
||||
it "retries assertions until they pass", ->
|
||||
retries = 0
|
||||
|
||||
cy.on "command:retry", ->
|
||||
retries += 1
|
||||
|
||||
Cypress.backend
|
||||
.onFirstCall()
|
||||
.resolves({
|
||||
contents: "foobarbaz"
|
||||
})
|
||||
.onSecondCall()
|
||||
.resolves({
|
||||
contents: "quux"
|
||||
})
|
||||
|
||||
cy.readFile("foo.json").should("eq", "quux").then ->
|
||||
expect(retries).to.eq(1)
|
||||
|
||||
it "really works", ->
|
||||
cy.readFile("cypress.json").its("baseUrl").should("eq", "http://localhost:3500")
|
||||
|
||||
it "works when contents are supposed to be null", ->
|
||||
cy.readFile("does-not-exist").should("be.null")
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "can turn off logging", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json', { log: false }).then ->
|
||||
logs = _.filter @logs, (log) ->
|
||||
log.get("name") is "readFile"
|
||||
|
||||
expect(logs.length).to.eq(0)
|
||||
|
||||
it "logs immediately before resolving", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "readFile"
|
||||
expect(log.get("state")).to.eq("pending")
|
||||
expect(log.get("message")).to.eq("foo.json")
|
||||
|
||||
cy.readFile("foo.json").then =>
|
||||
throw new Error("failed to log before resolving") unless @lastLog
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 50)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "readFile"
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "throws when file argument is absent", (done) ->
|
||||
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("`cy.readFile()` must be passed a non-empty string as its 1st argument. You passed: `undefined`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/readfile")
|
||||
done()
|
||||
|
||||
`cy.readFile()`
|
||||
|
||||
it "throws when file argument is not a string", (done) ->
|
||||
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("`cy.readFile()` must be passed a non-empty string as its 1st argument. You passed: `2`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/readfile")
|
||||
done()
|
||||
|
||||
cy.readFile(2)
|
||||
|
||||
it "throws when file argument is an empty string", (done) ->
|
||||
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("`cy.readFile()` must be passed a non-empty string as its 1st argument. You passed: ``.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/readfile")
|
||||
done()
|
||||
|
||||
cy.readFile("")
|
||||
|
||||
it "throws when there is an error reading the file", (done) ->
|
||||
err = new Error("EISDIR: illegal operation on a directory, read")
|
||||
err.name = "EISDIR"
|
||||
err.code = "EISDIR"
|
||||
err.filePath = "/path/to/foo"
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
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 """
|
||||
`cy.readFile(\"foo\")` failed while trying to read the file at the following path:
|
||||
|
||||
`/path/to/foo`
|
||||
|
||||
The following error occurred:
|
||||
|
||||
> "EISDIR: illegal operation on a directory, read"
|
||||
"""
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/readfile")
|
||||
|
||||
done()
|
||||
|
||||
cy.readFile("foo")
|
||||
|
||||
it "has implicit existence assertion and throws a specific error when file does not exist", (done) ->
|
||||
err = new Error("ENOENT: no such file or directory, open 'foo.json'")
|
||||
err.name = "ENOENT"
|
||||
err.code = "ENOENT"
|
||||
err.filePath = "/path/to/foo.json"
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
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("""Timed out retrying: `cy.readFile(\"foo.json\")` failed because the file does not exist at the following path:
|
||||
|
||||
`/path/to/foo.json`
|
||||
""")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/readfile")
|
||||
done()
|
||||
|
||||
cy.readFile("foo.json")
|
||||
|
||||
it "throws a specific error when file exists when it shouldn't", (done) ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
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("""
|
||||
Timed out retrying: `cy.readFile(\"foo.json\")` failed because the file exists when expected not to exist at the following path:
|
||||
|
||||
`/path/to/foo.json`
|
||||
""")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/readfile")
|
||||
done()
|
||||
|
||||
cy.readFile("foo.json").should("not.exist")
|
||||
|
||||
it "passes through assertion error when not about existence", (done) ->
|
||||
Cypress.backend.resolves({
|
||||
contents: "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("Timed out retrying: expected 'foo' to equal 'contents'")
|
||||
done()
|
||||
|
||||
cy.readFile("foo.json").should("equal", "contents")
|
||||
|
||||
describe "#writeFile", ->
|
||||
it "triggers 'write:file' with the right options", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents").then ->
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
"write:file",
|
||||
"foo.txt",
|
||||
"contents",
|
||||
{
|
||||
encoding: "utf8"
|
||||
flag: "w"
|
||||
}
|
||||
)
|
||||
|
||||
it "can take encoding as third argument", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents", "ascii").then ->
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
"write:file",
|
||||
"foo.txt",
|
||||
"contents",
|
||||
{
|
||||
encoding: "ascii"
|
||||
flag: "w"
|
||||
}
|
||||
)
|
||||
|
||||
it "can take encoding as part of options", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents", {encoding: "ascii"}).then ->
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
"write:file",
|
||||
"foo.txt",
|
||||
"contents",
|
||||
{
|
||||
encoding: "ascii"
|
||||
flag: "w"
|
||||
}
|
||||
)
|
||||
|
||||
it "yields null", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents").then (subject) ->
|
||||
expect(subject).to.not.exist
|
||||
|
||||
it "can write a string", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents")
|
||||
|
||||
it "can write an array as json", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.json", [])
|
||||
|
||||
it "can write an object as json", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.json", {})
|
||||
|
||||
it "writes the file to the filesystem, overwriting existing file", ->
|
||||
cy
|
||||
.writeFile("cypress/fixtures/foo.txt", "")
|
||||
.writeFile("cypress/fixtures/foo.txt", "bar")
|
||||
.readFile("cypress/fixtures/foo.txt").should("equal", "bar")
|
||||
.exec("rm cypress/fixtures/foo.txt")
|
||||
|
||||
describe ".flag", ->
|
||||
it "sends a flag if specified", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents", { flag: "a+" }).then ->
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
"write:file",
|
||||
"foo.txt",
|
||||
"contents",
|
||||
{
|
||||
encoding: "utf8",
|
||||
flag: "a+"
|
||||
})
|
||||
|
||||
it "appends content to existing file if specified", ->
|
||||
cy
|
||||
.writeFile("cypress/fixtures/foo.txt", "foo")
|
||||
.writeFile("cypress/fixtures/foo.txt", "bar", { flag: "a+"})
|
||||
.readFile("cypress/fixtures/foo.txt").should("equal", "foobar")
|
||||
.exec("rm cypress/fixtures/foo.txt")
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "can turn off logging", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile("foo.txt", "contents", { log: false }).then ->
|
||||
logs = _.filter @logs, (log) ->
|
||||
log.get("name") is "writeFile"
|
||||
|
||||
expect(logs.length).to.eq(0)
|
||||
|
||||
it "logs immediately before resolving", ->
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "writeFile"
|
||||
expect(log.get("state")).to.eq("pending")
|
||||
expect(log.get("message")).to.eq("foo.txt", "contents")
|
||||
|
||||
cy.writeFile("foo.txt", "contents").then =>
|
||||
throw new Error("failed to log before resolving") unless @lastLog
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 50)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "writeFile"
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "throws when file name argument is absent", (done) ->
|
||||
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("`cy.writeFile()` must be passed a non-empty string as its 1st argument. You passed: `undefined`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/writefile")
|
||||
done()
|
||||
|
||||
`cy.writeFile()`
|
||||
|
||||
it "throws when file name argument is not a string", (done) ->
|
||||
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("`cy.writeFile()` must be passed a non-empty string as its 1st argument. You passed: `2`.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/writefile")
|
||||
done()
|
||||
|
||||
cy.writeFile(2)
|
||||
|
||||
it "throws when contents argument is absent", (done) ->
|
||||
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("`cy.writeFile()` must be passed a non-empty string, an object, or an array as its 2nd argument. You passed: `undefined`.")
|
||||
done()
|
||||
|
||||
cy.writeFile("foo.txt")
|
||||
|
||||
it "throws when contents argument is not a string, object, or array", (done) ->
|
||||
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("`cy.writeFile()` must be passed a non-empty string, an object, or an array as its 2nd argument. You passed: `2`.")
|
||||
done()
|
||||
|
||||
cy.writeFile("foo.txt", 2)
|
||||
|
||||
it "throws when there is an error writing the file", (done) ->
|
||||
err = new Error("WHOKNOWS: unable to write file")
|
||||
err.name = "WHOKNOWS"
|
||||
err.code = "WHOKNOWS"
|
||||
err.filePath = "/path/to/foo.txt"
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
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 """`cy.writeFile(\"foo.txt\")` failed while trying to write the file at the following path:
|
||||
|
||||
`/path/to/foo.txt`
|
||||
|
||||
The following error occurred:
|
||||
|
||||
> "WHOKNOWS: unable to write file"
|
||||
"""
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/writefile")
|
||||
|
||||
done()
|
||||
|
||||
cy.writeFile("foo.txt", "contents")
|
||||
572
packages/driver/test/cypress/integration/commands/files_spec.js
Normal file
572
packages/driver/test/cypress/integration/commands/files_spec.js
Normal file
@@ -0,0 +1,572 @@
|
||||
const { stripIndent } = require('common-tags')
|
||||
const { _ } = Cypress
|
||||
|
||||
const okResponse = {
|
||||
contents: 'contents',
|
||||
filePath: '/path/to/foo.json',
|
||||
}
|
||||
|
||||
describe('src/cy/commands/files', () => {
|
||||
beforeEach(() => {
|
||||
// call through normally on everything
|
||||
cy.stub(Cypress, 'backend').callThrough()
|
||||
})
|
||||
|
||||
describe('#readFile', () => {
|
||||
it('triggers \'read:file\' with the right options', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json').then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
'read:file',
|
||||
'foo.json',
|
||||
{ encoding: 'utf8' },
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('can take encoding as second argument', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json', 'ascii').then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
'read:file',
|
||||
'foo.json',
|
||||
{ encoding: 'ascii' },
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('sets the contents as the subject', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json').then((subject) => {
|
||||
expect(subject).to.equal('contents')
|
||||
})
|
||||
})
|
||||
|
||||
it('retries to read when ENOENT', () => {
|
||||
const err = new Error('foo')
|
||||
|
||||
err.code = 'ENOENT'
|
||||
|
||||
let retries = 0
|
||||
|
||||
cy.on('command:retry', () => {
|
||||
retries += 1
|
||||
})
|
||||
|
||||
Cypress.backend
|
||||
.onFirstCall()
|
||||
.rejects(err)
|
||||
.onSecondCall()
|
||||
.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json').then(() => {
|
||||
expect(retries).to.eq(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('retries assertions until they pass', () => {
|
||||
let retries = 0
|
||||
|
||||
cy.on('command:retry', () => {
|
||||
retries += 1
|
||||
})
|
||||
|
||||
Cypress.backend
|
||||
.onFirstCall()
|
||||
.resolves({
|
||||
contents: 'foobarbaz',
|
||||
})
|
||||
.onSecondCall()
|
||||
.resolves({
|
||||
contents: 'quux',
|
||||
})
|
||||
|
||||
cy.readFile('foo.json').should('eq', 'quux').then(() => {
|
||||
expect(retries).to.eq(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('really works', () => {
|
||||
cy.readFile('cypress.json').its('baseUrl').should('eq', 'http://localhost:3500')
|
||||
})
|
||||
|
||||
it('works when contents are supposed to be null', () => {
|
||||
cy.readFile('does-not-exist').should('be.null')
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('can turn off logging', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.readFile('foo.json', { log: false }).then(function () {
|
||||
const logs = _.filter(this.logs, (log) => {
|
||||
return log.get('name') === 'readFile'
|
||||
})
|
||||
|
||||
expect(logs.length).to.eq(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('logs immediately before resolving', function () {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'readFile') {
|
||||
expect(log.get('state')).to.eq('pending')
|
||||
expect(log.get('message')).to.eq('foo.json')
|
||||
}
|
||||
})
|
||||
|
||||
cy.readFile('foo.json').then(() => {
|
||||
if (!this.lastLog) {
|
||||
throw new Error('failed to log before resolving')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 50)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'readFile') {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('throws when file argument is absent', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.readFile()` must be passed a non-empty string as its 1st argument. You passed: `undefined`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/readfile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile()
|
||||
})
|
||||
|
||||
it('throws when file argument is not a string', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.readFile()` must be passed a non-empty string as its 1st argument. You passed: `2`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/readfile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile(2)
|
||||
})
|
||||
|
||||
it('throws when file argument is an empty string', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.readFile()` must be passed a non-empty string as its 1st argument. You passed: ``.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/readfile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile('')
|
||||
})
|
||||
|
||||
it('throws when there is an error reading the file', function (done) {
|
||||
const err = new Error('EISDIR: illegal operation on a directory, read')
|
||||
|
||||
err.name = 'EISDIR'
|
||||
err.code = 'EISDIR'
|
||||
err.filePath = '/path/to/foo'
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq(stripIndent`\
|
||||
\`cy.readFile(\"foo\")\` failed while trying to read the file at the following path:
|
||||
|
||||
\`/path/to/foo\`
|
||||
|
||||
The following error occurred:
|
||||
|
||||
> "EISDIR: illegal operation on a directory, read"`)
|
||||
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/readfile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile('foo')
|
||||
})
|
||||
|
||||
it('has implicit existence assertion and throws a specific error when file does not exist', function (done) {
|
||||
const err = new Error('ENOENT: no such file or directory, open \'foo.json\'')
|
||||
|
||||
err.name = 'ENOENT'
|
||||
err.code = 'ENOENT'
|
||||
err.filePath = '/path/to/foo.json'
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
|
||||
expect(err.message).to.eq(stripIndent`
|
||||
Timed out retrying: \`cy.readFile(\"foo.json\")\` failed because the file does not exist at the following path:
|
||||
|
||||
\`/path/to/foo.json\``)
|
||||
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/readfile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile('foo.json')
|
||||
})
|
||||
|
||||
it('throws a specific error when file exists when it shouldn\'t', function (done) {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq(stripIndent`\
|
||||
Timed out retrying: \`cy.readFile(\"foo.json\")\` failed because the file exists when expected not to exist at the following path:
|
||||
|
||||
\`/path/to/foo.json\``)
|
||||
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/readfile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile('foo.json').should('not.exist')
|
||||
})
|
||||
|
||||
it('passes through assertion error when not about existence', function (done) {
|
||||
Cypress.backend.resolves({
|
||||
contents: 'foo',
|
||||
})
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('Timed out retrying: expected \'foo\' to equal \'contents\'')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.readFile('foo.json').should('equal', 'contents')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#writeFile', () => {
|
||||
it('triggers \'write:file\' with the right options', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents').then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
'write:file',
|
||||
'foo.txt',
|
||||
'contents',
|
||||
{
|
||||
encoding: 'utf8',
|
||||
flag: 'w',
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('can take encoding as third argument', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents', 'ascii').then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
'write:file',
|
||||
'foo.txt',
|
||||
'contents',
|
||||
{
|
||||
encoding: 'ascii',
|
||||
flag: 'w',
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('can take encoding as part of options', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents', { encoding: 'ascii' }).then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
'write:file',
|
||||
'foo.txt',
|
||||
'contents',
|
||||
{
|
||||
encoding: 'ascii',
|
||||
flag: 'w',
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('yields null', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents').then((subject) => {
|
||||
expect(subject).to.not.exist
|
||||
})
|
||||
})
|
||||
|
||||
it('can write a string', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents')
|
||||
})
|
||||
|
||||
it('can write an array as json', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.json', [])
|
||||
})
|
||||
|
||||
it('can write an object as json', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.json', {})
|
||||
})
|
||||
|
||||
it('writes the file to the filesystem, overwriting existing file', () => {
|
||||
cy
|
||||
.writeFile('cypress/fixtures/foo.txt', '')
|
||||
.writeFile('cypress/fixtures/foo.txt', 'bar')
|
||||
.readFile('cypress/fixtures/foo.txt').should('equal', 'bar')
|
||||
.exec('rm cypress/fixtures/foo.txt')
|
||||
})
|
||||
|
||||
describe('.flag', () => {
|
||||
it('sends a flag if specified', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents', { flag: 'a+' }).then(() => {
|
||||
expect(Cypress.backend).to.be.calledWith(
|
||||
'write:file',
|
||||
'foo.txt',
|
||||
'contents',
|
||||
{
|
||||
encoding: 'utf8',
|
||||
flag: 'a+',
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('appends content to existing file if specified', () => {
|
||||
cy
|
||||
.writeFile('cypress/fixtures/foo.txt', 'foo')
|
||||
.writeFile('cypress/fixtures/foo.txt', 'bar', { flag: 'a+' })
|
||||
.readFile('cypress/fixtures/foo.txt').should('equal', 'foobar')
|
||||
.exec('rm cypress/fixtures/foo.txt')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('can turn off logging', () => {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.writeFile('foo.txt', 'contents', { log: false }).then(function () {
|
||||
const logs = _.filter(this.logs, (log) => {
|
||||
return log.get('name') === 'writeFile'
|
||||
})
|
||||
|
||||
expect(logs.length).to.eq(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('logs immediately before resolving', function () {
|
||||
Cypress.backend.resolves(okResponse)
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'writeFile') {
|
||||
expect(log.get('state')).to.eq('pending')
|
||||
expect(log.get('message')).to.eq('foo.txt', 'contents')
|
||||
}
|
||||
})
|
||||
|
||||
cy.writeFile('foo.txt', 'contents').then(() => {
|
||||
if (!this.lastLog) {
|
||||
throw new Error('failed to log before resolving')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 50)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'writeFile') {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('throws when file name argument is absent', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.writeFile()` must be passed a non-empty string as its 1st argument. You passed: `undefined`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/writefile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.writeFile()
|
||||
})
|
||||
|
||||
it('throws when file name argument is not a string', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.writeFile()` must be passed a non-empty string as its 1st argument. You passed: `2`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/writefile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.writeFile(2)
|
||||
})
|
||||
|
||||
it('throws when contents argument is absent', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.writeFile()` must be passed a non-empty string, an object, or an array as its 2nd argument. You passed: `undefined`.')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.writeFile('foo.txt')
|
||||
})
|
||||
|
||||
it('throws when contents argument is not a string, object, or array', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq('`cy.writeFile()` must be passed a non-empty string, an object, or an array as its 2nd argument. You passed: `2`.')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.writeFile('foo.txt', 2)
|
||||
})
|
||||
|
||||
it('throws when there is an error writing the file', function (done) {
|
||||
const err = new Error('WHOKNOWS: unable to write file')
|
||||
|
||||
err.name = 'WHOKNOWS'
|
||||
err.code = 'WHOKNOWS'
|
||||
err.filePath = '/path/to/foo.txt'
|
||||
|
||||
Cypress.backend.rejects(err)
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(err.message).to.eq(stripIndent`
|
||||
\`cy.writeFile(\"foo.txt\")\` failed while trying to write the file at the following path:
|
||||
|
||||
\`/path/to/foo.txt\`
|
||||
|
||||
The following error occurred:
|
||||
|
||||
> "WHOKNOWS: unable to write file"`)
|
||||
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/writefile')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.writeFile('foo.txt', 'contents')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,208 +0,0 @@
|
||||
_ = Cypress._
|
||||
Promise = Cypress.Promise
|
||||
|
||||
describe "src/cy/commands/fixtures", ->
|
||||
beforeEach ->
|
||||
Cypress.emit("clear:fixtures:cache")
|
||||
|
||||
## call all of the fixture triggers async to simulate
|
||||
## the real browser environment
|
||||
context "#fixture", ->
|
||||
beforeEach ->
|
||||
## call through normally on everything
|
||||
cy.stub(Cypress, "backend").callThrough()
|
||||
|
||||
it "triggers 'fixture' on Cypress", ->
|
||||
Cypress.backend.withArgs("get:fixture").resolves({foo: "bar"})
|
||||
|
||||
cy.fixture("foo").as("f").then (obj) ->
|
||||
expect(obj).to.deep.eq {foo: "bar"}
|
||||
|
||||
expect(Cypress.backend).to.be.calledWith("get:fixture", "foo", {})
|
||||
|
||||
it "can support an array of fixtures"
|
||||
|
||||
it "can have encoding as second argument", ->
|
||||
Cypress.backend.withArgs("get:fixture").resolves({foo: "bar"})
|
||||
|
||||
cy.fixture("foo", "ascii").then (obj) ->
|
||||
expect(obj).to.deep.eq {foo: "bar"}
|
||||
|
||||
expect(Cypress.backend).to.be.calledWith("get:fixture", "foo", {
|
||||
encoding: "ascii"
|
||||
})
|
||||
|
||||
it "can have encoding as second argument and options as third argument", ->
|
||||
Cypress.backend.withArgs("get:fixture").resolves({foo: "bar"})
|
||||
|
||||
cy.fixture("foo", "ascii", {timeout: 1000}).then (obj) ->
|
||||
expect(obj).to.deep.eq {foo: "bar"}
|
||||
|
||||
expect(Cypress.backend).to.be.calledWith("get:fixture", "foo", {
|
||||
encoding: "ascii"
|
||||
})
|
||||
|
||||
it "really works", ->
|
||||
cy.fixture("example").should("deep.eq", { example: true })
|
||||
|
||||
it "can read a fixture without extension with multiple dots in the name", ->
|
||||
cy.fixture("foo.bar.baz").should("deep.eq", { quux: "quuz" })
|
||||
|
||||
it "looks for csv without extension", ->
|
||||
cy.fixture("comma-separated").should "equal", """
|
||||
One,Two,Three
|
||||
1,2,3
|
||||
|
||||
"""
|
||||
|
||||
it "handles files with unknown extensions, reading them as utf-8", ->
|
||||
cy.fixture("yaml.yaml").should "equal", """
|
||||
- foo
|
||||
- bar
|
||||
-
|
||||
|
||||
"""
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 50)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if attrs.name is "fixture"
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "throws if fixturesFolder is set to false", (done) ->
|
||||
Cypress.config("fixturesFolder", false)
|
||||
|
||||
cy.on "fail", =>
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(@logs.length).to.eq(1)
|
||||
expect(lastLog.get("error").message).to.eq("`cy.fixture()` is not valid because you have configured `fixturesFolder` to `false`.")
|
||||
expect(lastLog.get("error").docsUrl).to.eq("https://on.cypress.io/fixture")
|
||||
expect(lastLog.get("state")).to.eq("failed")
|
||||
expect(lastLog.get("name")).to.eq "fixture"
|
||||
done()
|
||||
|
||||
cy.fixture("foo")
|
||||
|
||||
it "throws when fixture cannot be found without extension", (done) ->
|
||||
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(lastLog.get("name")).to.eq "fixture"
|
||||
expect(lastLog.get("message")).to.eq "err"
|
||||
|
||||
expect(err.message).to.include "A fixture file could not be found"
|
||||
expect(err.message).to.include "cypress/fixtures/err"
|
||||
done()
|
||||
|
||||
cy.fixture("err")
|
||||
|
||||
it "throws when fixture cannot be found with extension", (done) ->
|
||||
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(lastLog.get("name")).to.eq "fixture"
|
||||
expect(lastLog.get("message")).to.eq "err.txt"
|
||||
|
||||
expect(err.message).to.include "A fixture file could not be found"
|
||||
expect(err.message).to.include "cypress/fixtures/err.txt"
|
||||
done()
|
||||
|
||||
cy.fixture("err.txt")
|
||||
|
||||
it "throws after timing out", (done) ->
|
||||
Cypress.backend.withArgs("get:fixture").resolves(Promise.delay(1000))
|
||||
|
||||
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(lastLog.get("name")).to.eq "fixture"
|
||||
expect(lastLog.get("message")).to.eq "foo, {timeout: 50}"
|
||||
expect(err.message).to.eq("`cy.fixture()` timed out waiting `50ms` to receive a fixture. No fixture was ever sent by the server.")
|
||||
expect(err.docsUrl).to.eq("https://on.cypress.io/fixture")
|
||||
done()
|
||||
|
||||
cy.fixture("foo", {timeout: 50})
|
||||
|
||||
describe "timeout", ->
|
||||
it "sets timeout to Cypress.config(responseTimeout)", ->
|
||||
Cypress.config("responseTimeout", 2500)
|
||||
|
||||
Cypress.backend.withArgs("get:fixture").resolves({foo: "bar"})
|
||||
|
||||
timeout = cy.spy(Promise.prototype, "timeout")
|
||||
|
||||
cy.fixture("foo").then ->
|
||||
expect(timeout).to.be.calledWith(2500)
|
||||
|
||||
it "can override timeout", ->
|
||||
Cypress.backend.withArgs("get:fixture").resolves({foo: "bar"})
|
||||
|
||||
timeout = cy.spy(Promise.prototype, "timeout")
|
||||
|
||||
cy.fixture("foobar", {timeout: 1000}).then ->
|
||||
expect(timeout).to.be.calledWith(1000)
|
||||
|
||||
it "clears the current timeout and restores after success", ->
|
||||
Cypress.backend.withArgs("get:fixture").resolves({foo: "bar"})
|
||||
|
||||
cy.timeout(100)
|
||||
|
||||
cy.spy(cy, "clearTimeout")
|
||||
|
||||
cy.fixture("foo").then ->
|
||||
expect(cy.clearTimeout).to.be.calledWith("get:fixture")
|
||||
|
||||
## restores the timeout afterwards
|
||||
expect(cy.timeout()).to.eq(100)
|
||||
|
||||
describe "caching", ->
|
||||
beforeEach ->
|
||||
Cypress.backend
|
||||
.withArgs("get:fixture", "foo")
|
||||
.resolves({foo: "bar"})
|
||||
.withArgs("get:fixture", "bar")
|
||||
.resolves({bar: "baz"})
|
||||
|
||||
it "caches fixtures by name", ->
|
||||
cy.fixture("foo").then (obj) =>
|
||||
expect(obj).to.deep.eq({foo: "bar"})
|
||||
|
||||
cy.fixture("bar").then (obj) =>
|
||||
expect(obj).to.deep.eq {bar: "baz"}
|
||||
|
||||
cy.fixture("foo").then (obj) =>
|
||||
expect(obj).to.deep.eq {foo: "bar"}
|
||||
|
||||
.then ->
|
||||
expect(Cypress.backend).to.be.calledTwice
|
||||
|
||||
it "clones fixtures to prevent accidental mutation", ->
|
||||
cy.fixture("foo").then (obj) ->
|
||||
## mutate the object
|
||||
obj.baz = "quux"
|
||||
|
||||
cy.fixture("foo").then (obj2) ->
|
||||
obj2.lorem = "ipsum"
|
||||
expect(obj2).not.to.have.property("baz")
|
||||
|
||||
cy.fixture("foo").then (obj3) ->
|
||||
expect(obj3).not.to.have.property("lorem")
|
||||
.then ->
|
||||
expect(Cypress.backend).to.be.calledOnce
|
||||
@@ -0,0 +1,250 @@
|
||||
const { Promise } = Cypress
|
||||
|
||||
describe('src/cy/commands/fixtures', () => {
|
||||
beforeEach(() => {
|
||||
return Cypress.emit('clear:fixtures:cache')
|
||||
})
|
||||
|
||||
// call all of the fixture triggers async to simulate
|
||||
// the real browser environment
|
||||
context('#fixture', () => {
|
||||
beforeEach(() => {
|
||||
// call through normally on everything
|
||||
cy.stub(Cypress, 'backend').callThrough()
|
||||
})
|
||||
|
||||
it('triggers \'fixture\' on Cypress', () => {
|
||||
Cypress.backend.withArgs('get:fixture').resolves({ foo: 'bar' })
|
||||
|
||||
cy.fixture('foo').as('f').then((obj) => {
|
||||
expect(obj).to.deep.eq({ foo: 'bar' })
|
||||
expect(Cypress.backend).to.be.calledWith('get:fixture', 'foo', {})
|
||||
})
|
||||
})
|
||||
|
||||
it('can support an array of fixtures')
|
||||
|
||||
it('can have encoding as second argument', () => {
|
||||
Cypress.backend.withArgs('get:fixture').resolves({ foo: 'bar' })
|
||||
|
||||
cy.fixture('foo', 'ascii').then((obj) => {
|
||||
expect(obj).to.deep.eq({ foo: 'bar' })
|
||||
expect(Cypress.backend).to.be.calledWith('get:fixture', 'foo', {
|
||||
encoding: 'ascii',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('can have encoding as second argument and options as third argument', () => {
|
||||
Cypress.backend.withArgs('get:fixture').resolves({ foo: 'bar' })
|
||||
|
||||
cy.fixture('foo', 'ascii', { timeout: 1000 }).then((obj) => {
|
||||
expect(obj).to.deep.eq({ foo: 'bar' })
|
||||
expect(Cypress.backend).to.be.calledWith('get:fixture', 'foo', {
|
||||
encoding: 'ascii',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('really works', () => {
|
||||
cy.fixture('example').should('deep.eq', { example: true })
|
||||
})
|
||||
|
||||
it('can read a fixture without extension with multiple dots in the name', () => {
|
||||
cy.fixture('foo.bar.baz').should('deep.eq', { quux: 'quuz' })
|
||||
})
|
||||
|
||||
it('looks for csv without extension', () => {
|
||||
cy.fixture('comma-separated').should('equal', [
|
||||
'One,Two,Three\n',
|
||||
'1,2,3\n',
|
||||
].join(''))
|
||||
})
|
||||
|
||||
it('handles files with unknown extensions, reading them as utf-8', () => {
|
||||
cy.fixture('yaml.yaml').should('equal', [
|
||||
'- foo\n',
|
||||
'- bar\n',
|
||||
'- \n',
|
||||
].join(''))
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 50)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (attrs.name === 'fixture') {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('throws if fixturesFolder is set to false', function (done) {
|
||||
Cypress.config('fixturesFolder', false)
|
||||
|
||||
cy.on('fail', () => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error').message).to.eq('`cy.fixture()` is not valid because you have configured `fixturesFolder` to `false`.')
|
||||
expect(lastLog.get('error').docsUrl).to.eq('https://on.cypress.io/fixture')
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('name')).to.eq('fixture')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.fixture('foo')
|
||||
})
|
||||
|
||||
it('throws when fixture cannot be found without extension', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('name')).to.eq('fixture')
|
||||
expect(lastLog.get('message')).to.eq('err')
|
||||
|
||||
expect(err.message).to.include('A fixture file could not be found')
|
||||
expect(err.message).to.include('cypress/fixtures/err')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.fixture('err')
|
||||
})
|
||||
|
||||
it('throws when fixture cannot be found with extension', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('name')).to.eq('fixture')
|
||||
expect(lastLog.get('message')).to.eq('err.txt')
|
||||
|
||||
expect(err.message).to.include('A fixture file could not be found')
|
||||
expect(err.message).to.include('cypress/fixtures/err.txt')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.fixture('err.txt')
|
||||
})
|
||||
|
||||
it('throws after timing out', function (done) {
|
||||
Cypress.backend.withArgs('get:fixture').resolves(Promise.delay(1000))
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('name')).to.eq('fixture')
|
||||
expect(lastLog.get('message')).to.eq('foo, {timeout: 50}')
|
||||
expect(err.message).to.eq('`cy.fixture()` timed out waiting `50ms` to receive a fixture. No fixture was ever sent by the server.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/fixture')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.fixture('foo', { timeout: 50 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('timeout', () => {
|
||||
it('sets timeout to Cypress.config(responseTimeout)', () => {
|
||||
Cypress.config('responseTimeout', 2500)
|
||||
|
||||
Cypress.backend.withArgs('get:fixture').resolves({ foo: 'bar' })
|
||||
|
||||
const timeout = cy.spy(Promise.prototype, 'timeout')
|
||||
|
||||
cy.fixture('foo').then(() => {
|
||||
expect(timeout).to.be.calledWith(2500)
|
||||
})
|
||||
})
|
||||
|
||||
it('can override timeout', () => {
|
||||
Cypress.backend.withArgs('get:fixture').resolves({ foo: 'bar' })
|
||||
|
||||
const timeout = cy.spy(Promise.prototype, 'timeout')
|
||||
|
||||
cy.fixture('foobar', { timeout: 1000 }).then(() => {
|
||||
expect(timeout).to.be.calledWith(1000)
|
||||
})
|
||||
})
|
||||
|
||||
it('clears the current timeout and restores after success', () => {
|
||||
Cypress.backend.withArgs('get:fixture').resolves({ foo: 'bar' })
|
||||
|
||||
cy.timeout(100)
|
||||
|
||||
cy.spy(cy, 'clearTimeout')
|
||||
|
||||
cy.fixture('foo').then(() => {
|
||||
expect(cy.clearTimeout).to.be.calledWith('get:fixture')
|
||||
|
||||
// restores the timeout afterwards
|
||||
expect(cy.timeout()).to.eq(100)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('caching', () => {
|
||||
beforeEach(() => {
|
||||
Cypress.backend
|
||||
.withArgs('get:fixture', 'foo')
|
||||
.resolves({ foo: 'bar' })
|
||||
.withArgs('get:fixture', 'bar')
|
||||
.resolves({ bar: 'baz' })
|
||||
})
|
||||
|
||||
it('caches fixtures by name', () => {
|
||||
cy.fixture('foo').then((obj) => {
|
||||
expect(obj).to.deep.eq({ foo: 'bar' })
|
||||
|
||||
cy.fixture('bar').then((obj) => {
|
||||
expect(obj).to.deep.eq({ bar: 'baz' })
|
||||
|
||||
cy.fixture('foo').then((obj) => {
|
||||
expect(obj).to.deep.eq({ foo: 'bar' })
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
expect(Cypress.backend).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
|
||||
it('clones fixtures to prevent accidental mutation', () => {
|
||||
cy.fixture('foo').then((obj) => {
|
||||
// mutate the object
|
||||
obj.baz = 'quux'
|
||||
|
||||
cy.fixture('foo').then((obj2) => {
|
||||
obj2.lorem = 'ipsum'
|
||||
expect(obj2).not.to.have.property('baz')
|
||||
|
||||
cy.fixture('foo').then((obj3) => {
|
||||
expect(obj3).not.to.have.property('lorem')
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
expect(Cypress.backend).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,86 +0,0 @@
|
||||
describe "src/cy/commands/local_storage", ->
|
||||
context "#clearLocalStorage", ->
|
||||
it "passes keys onto Cypress.LocalStorage.clear", ->
|
||||
clear = cy.spy Cypress.LocalStorage, "clear"
|
||||
|
||||
cy.clearLocalStorage("foo").then ->
|
||||
expect(clear).to.be.calledWith "foo"
|
||||
|
||||
it "sets the storages", ->
|
||||
localStorage = window.localStorage
|
||||
remoteStorage = cy.state("window").localStorage
|
||||
|
||||
setStorages = cy.spy Cypress.LocalStorage, "setStorages"
|
||||
|
||||
cy.clearLocalStorage().then ->
|
||||
expect(setStorages).to.be.calledWith localStorage, remoteStorage
|
||||
|
||||
it "unsets the storages", ->
|
||||
unsetStorages = cy.spy Cypress.LocalStorage, "unsetStorages"
|
||||
|
||||
cy.clearLocalStorage().then ->
|
||||
expect(unsetStorages).to.be.called
|
||||
|
||||
it "sets subject to remote localStorage", ->
|
||||
ls = cy.state("window").localStorage
|
||||
|
||||
cy.clearLocalStorage().then (remote) ->
|
||||
expect(remote).to.eq ls
|
||||
|
||||
describe "test:before:run", ->
|
||||
it "clears localStorage before each test run", ->
|
||||
clear = cy.spy Cypress.LocalStorage, "clear"
|
||||
|
||||
Cypress.emit("test:before:run", {})
|
||||
|
||||
expect(clear).to.be.calledWith []
|
||||
|
||||
describe "errors", ->
|
||||
it "throws when being passed a non string or regexp", (done) ->
|
||||
cy.on "fail", (err) ->
|
||||
expect(err.message).to.include "`cy.clearLocalStorage()` must be called with either a string or regular expression."
|
||||
expect(err.docsUrl).to.include("https://on.cypress.io/clearlocalstorage")
|
||||
done()
|
||||
# A number is used as an object will be considered as `options`
|
||||
cy.clearLocalStorage(1)
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "ends immediately", ->
|
||||
cy.clearLocalStorage().then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
|
||||
it "snapshots immediately", ->
|
||||
cy.clearLocalStorage().then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("snapshots").length).to.eq(1)
|
||||
expect(lastLog.get("snapshots")[0]).to.be.an("object")
|
||||
|
||||
describe "without log", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "log is disabled", ->
|
||||
cy.clearLocalStorage('foo', {log: false}).then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
|
||||
it "log is disabled without key", ->
|
||||
cy.clearLocalStorage({log: false}).then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
describe('src/cy/commands/local_storage', () => {
|
||||
context('#clearLocalStorage', () => {
|
||||
it('passes keys onto Cypress.LocalStorage.clear', () => {
|
||||
const clear = cy.spy(Cypress.LocalStorage, 'clear')
|
||||
|
||||
cy.clearLocalStorage('foo').then(() => {
|
||||
expect(clear).to.be.calledWith('foo')
|
||||
})
|
||||
})
|
||||
|
||||
it('sets the storages', () => {
|
||||
const {
|
||||
localStorage,
|
||||
} = window
|
||||
const remoteStorage = cy.state('window').localStorage
|
||||
|
||||
const setStorages = cy.spy(Cypress.LocalStorage, 'setStorages')
|
||||
|
||||
cy.clearLocalStorage().then(() => {
|
||||
expect(setStorages).to.be.calledWith(localStorage, remoteStorage)
|
||||
})
|
||||
})
|
||||
|
||||
it('unsets the storages', () => {
|
||||
const unsetStorages = cy.spy(Cypress.LocalStorage, 'unsetStorages')
|
||||
|
||||
cy.clearLocalStorage().then(() => {
|
||||
expect(unsetStorages).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('sets subject to remote localStorage', () => {
|
||||
const ls = cy.state('window').localStorage
|
||||
|
||||
cy.clearLocalStorage().then((remote) => {
|
||||
expect(remote).to.eq(ls)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test:before:run', () => {
|
||||
it('clears localStorage before each test run', () => {
|
||||
const clear = cy.spy(Cypress.LocalStorage, 'clear')
|
||||
|
||||
Cypress.emit('test:before:run', {})
|
||||
|
||||
expect(clear).to.be.calledWith([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
it('throws when being passed a non string or regexp', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`cy.clearLocalStorage()` must be called with either a string or regular expression.')
|
||||
expect(err.docsUrl).to.include('https://on.cypress.io/clearlocalstorage')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
// A number is used as an object will be considered as `options`
|
||||
cy.clearLocalStorage(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('ends immediately', () => {
|
||||
cy.clearLocalStorage().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
})
|
||||
})
|
||||
|
||||
it('snapshots immediately', () => {
|
||||
cy.clearLocalStorage().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('snapshots').length).to.eq(1)
|
||||
expect(lastLog.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('log is disabled', () => {
|
||||
cy.clearLocalStorage('foo', { log: false }).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('log is disabled without key', () => {
|
||||
cy.clearLocalStorage({ log: false }).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,396 +0,0 @@
|
||||
_ = Cypress._
|
||||
$ = Cypress.$
|
||||
|
||||
describe "src/cy/commands/location", ->
|
||||
beforeEach ->
|
||||
cy.visit("/fixtures/generic.html")
|
||||
|
||||
context "#url", ->
|
||||
it "returns the location href", ->
|
||||
cy.url().then (url) ->
|
||||
expect(url).to.eq "http://localhost:3500/fixtures/generic.html"
|
||||
|
||||
it "eventually resolves", ->
|
||||
_.delay =>
|
||||
win = cy.state("window")
|
||||
win.location.href = "/foo/bar/baz.html"
|
||||
, 100
|
||||
|
||||
cy.url().should("match", /baz/).and("eq", "http://localhost:3500/foo/bar/baz.html")
|
||||
|
||||
it "catches thrown errors", ->
|
||||
cy.stub(Cypress.utils, "locToString")
|
||||
.onFirstCall().throws(new Error)
|
||||
.onSecondCall().returns("http://localhost:3500/baz.html")
|
||||
|
||||
cy.url().should("include", "/baz.html")
|
||||
|
||||
describe "assertion verification", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if log.get("name") is "assert"
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "eventually passes the assertion", ->
|
||||
cy.on "command:retry", _.after 2, _.once =>
|
||||
win = cy.state("window")
|
||||
win.location.href = "/foo/bar/baz.html"
|
||||
|
||||
cy.url().should("match", /baz/).then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("name")).to.eq("assert")
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 100)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "eventually fails the assertion", (done) ->
|
||||
cy.on "fail", (err) =>
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(err.message).to.include(lastLog.get("error").message)
|
||||
expect(err.message).not.to.include("undefined")
|
||||
expect(lastLog.get("name")).to.eq("assert")
|
||||
expect(lastLog.get("state")).to.eq("failed")
|
||||
expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError)
|
||||
|
||||
done()
|
||||
|
||||
cy.url().should("eq", "not-this")
|
||||
|
||||
it "does not log an additional log on failure", (done) ->
|
||||
cy.on "fail", =>
|
||||
expect(@logs.length).to.eq(2)
|
||||
done()
|
||||
|
||||
cy.url().should("eq", "not-this")
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "ends immediately", ->
|
||||
cy.url().then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
|
||||
it "snapshots immediately", ->
|
||||
cy.url().then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("snapshots").length).to.eq(1)
|
||||
expect(lastLog.get("snapshots")[0]).to.be.an("object")
|
||||
|
||||
it "logs obj", ->
|
||||
cy.url().then ->
|
||||
obj = {
|
||||
name: "url"
|
||||
message: ""
|
||||
}
|
||||
|
||||
lastLog = @lastLog
|
||||
|
||||
_.each obj, (value, key) =>
|
||||
expect(lastLog.get(key)).to.deep.eq value
|
||||
|
||||
it "does not emit when {log: false}", ->
|
||||
cy.url({log: false}).then ->
|
||||
expect(@log).to.be.undefined
|
||||
|
||||
it "#consoleProps", ->
|
||||
cy.url().then ->
|
||||
consoleProps = @lastLog.invoke("consoleProps")
|
||||
|
||||
expect(consoleProps).to.deep.eq {
|
||||
Command: "url"
|
||||
Yielded: "http://localhost:3500/fixtures/generic.html"
|
||||
}
|
||||
|
||||
context "#hash", ->
|
||||
it "returns the location hash", ->
|
||||
cy.hash().then (hash) ->
|
||||
expect(hash).to.eq ""
|
||||
|
||||
it "eventually resolves", ->
|
||||
_.delay ->
|
||||
win = cy.state("window")
|
||||
win.location.hash = "users/1"
|
||||
, 100
|
||||
|
||||
cy.hash().should("match", /users/).and("eq", "#users/1")
|
||||
|
||||
describe "assertion verification", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if log.get("name") is "assert"
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "eventually passes the assertion", ->
|
||||
cy.on "command:retry", _.after 2, =>
|
||||
win = cy.state("window")
|
||||
win.location.hash = "users/1"
|
||||
|
||||
cy.hash().should("match", /users/).then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("name")).to.eq("assert")
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 100)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "eventually fails the assertion", (done) ->
|
||||
cy.on "fail", (err) =>
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(err.message).to.include(lastLog.get("error").message)
|
||||
expect(err.message).not.to.include("undefined")
|
||||
expect(lastLog.get("name")).to.eq("assert")
|
||||
expect(lastLog.get("state")).to.eq("failed")
|
||||
expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError)
|
||||
|
||||
done()
|
||||
|
||||
cy.hash().should("eq", "not-this")
|
||||
|
||||
it "does not log an additional log on failure", (done) ->
|
||||
cy.on "fail", =>
|
||||
expect(@logs.length).to.eq(2)
|
||||
done()
|
||||
|
||||
cy.hash().should("eq", "not-this")
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "ends immediately", ->
|
||||
cy.hash().then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
|
||||
it "snapshots immediately", ->
|
||||
cy.hash().then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("snapshots").length).to.eq(1)
|
||||
expect(lastLog.get("snapshots")[0]).to.be.an("object")
|
||||
|
||||
it "logs obj", ->
|
||||
cy.hash().then ->
|
||||
obj = {
|
||||
name: "hash"
|
||||
message: ""
|
||||
}
|
||||
|
||||
lastLog = @lastLog
|
||||
|
||||
_.each obj, (value, key) =>
|
||||
expect(lastLog.get(key)).to.deep.eq value
|
||||
|
||||
it "does not emit when {log: false}", ->
|
||||
cy.hash({log: false}).then ->
|
||||
expect(@log).to.be.undefined
|
||||
|
||||
it "#consoleProps", ->
|
||||
cy.hash().then ->
|
||||
consoleProps = @lastLog.invoke("consoleProps")
|
||||
|
||||
expect(consoleProps).to.deep.eq {
|
||||
Command: "hash"
|
||||
Yielded: ""
|
||||
}
|
||||
|
||||
context "#location", ->
|
||||
it "returns the location object", ->
|
||||
cy.location().then (loc) ->
|
||||
expect(loc).to.have.keys ["auth", "authObj", "hash", "href", "host", "hostname", "origin", "pathname", "port", "protocol", "search", "originPolicy", "superDomain", "toString"]
|
||||
|
||||
it "returns a specific key from location object", ->
|
||||
cy.location("href").then (href) ->
|
||||
expect(href).to.eq "http://localhost:3500/fixtures/generic.html"
|
||||
|
||||
it "eventually resolves", ->
|
||||
_.delay ->
|
||||
win = cy.state("window")
|
||||
win.location.pathname = "users/1"
|
||||
, 100
|
||||
|
||||
cy.location().should("have.property", "pathname").and("match", /users/)
|
||||
|
||||
describe "assertion verification", ->
|
||||
beforeEach ->
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
if log.get("name") is "assert"
|
||||
@lastLog = log
|
||||
|
||||
return null
|
||||
|
||||
it "eventually passes the assertion", ->
|
||||
cy.on "command:retry", _.after 2, _.once =>
|
||||
win = cy.state("window")
|
||||
win.location.pathname = "users/1"
|
||||
|
||||
cy.location("pathname").should("match", /users/).then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("name")).to.eq("assert")
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
|
||||
describe "errors", ->
|
||||
beforeEach ->
|
||||
Cypress.config("defaultCommandTimeout", 100)
|
||||
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "throws when passed a non-existent key", (done) ->
|
||||
cy.on "fail", (err) =>
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(err.message).to.include(lastLog.get("error").message)
|
||||
expect(err.message).to.include("Location object does not have key: `ladida`")
|
||||
expect(err.docsUrl).to.include("https://on.cypress.io/location")
|
||||
expect(lastLog.get("name")).to.eq("location")
|
||||
expect(lastLog.get("state")).to.eq("failed")
|
||||
|
||||
done()
|
||||
|
||||
cy.location('ladida')
|
||||
|
||||
it "eventually fails the assertion", (done) ->
|
||||
cy.on "fail", (err) =>
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(err.message).to.include(lastLog.get("error").message)
|
||||
expect(err.message).not.to.include("undefined")
|
||||
expect(lastLog.get("name")).to.eq("assert")
|
||||
expect(lastLog.get("state")).to.eq("failed")
|
||||
expect(lastLog.get("error")).to.be.an.instanceof(chai.AssertionError)
|
||||
|
||||
done()
|
||||
|
||||
cy.location("pathname").should("eq", "not-this")
|
||||
|
||||
it "does not log an additional log on failure", (done) ->
|
||||
logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) ->
|
||||
logs.push(log)
|
||||
|
||||
cy.on "fail", =>
|
||||
expect(@logs.length).to.eq(2)
|
||||
done()
|
||||
|
||||
cy.location("pathname").should("eq", "not-this")
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@logs = []
|
||||
|
||||
cy.on "log:added", (attrs, log) =>
|
||||
@lastLog = log
|
||||
@logs.push(log)
|
||||
|
||||
return null
|
||||
|
||||
it "ends immediately", ->
|
||||
cy.location("href").then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("ended")).to.be.true
|
||||
expect(lastLog.get("state")).to.eq("passed")
|
||||
|
||||
it "snapshots immediately", ->
|
||||
cy.location("href").then ->
|
||||
lastLog = @lastLog
|
||||
|
||||
expect(lastLog.get("snapshots").length).to.eq(1)
|
||||
expect(lastLog.get("snapshots")[0]).to.be.an("object")
|
||||
|
||||
it "does not emit when {log: false} as options", ->
|
||||
cy.location("href", {log: false}).then ->
|
||||
expect(@log).to.be.undefined
|
||||
|
||||
it "does not emit when {log: false} as key", ->
|
||||
cy.location({log: false}).then ->
|
||||
expect(@log).to.be.undefined
|
||||
|
||||
it "logs obj without a message", ->
|
||||
cy.location().then ->
|
||||
obj = {
|
||||
name: "location"
|
||||
message: ""
|
||||
}
|
||||
|
||||
lastLog = @lastLog
|
||||
|
||||
_.each obj, (value, key) =>
|
||||
expect(lastLog.get(key)).to.deep.eq value
|
||||
|
||||
it "logs obj with a message", ->
|
||||
cy.location("origin").then ->
|
||||
obj = {
|
||||
name: "location"
|
||||
message: "origin"
|
||||
}
|
||||
|
||||
lastLog = @lastLog
|
||||
|
||||
_.each obj, (value, key) =>
|
||||
expect(lastLog.get(key)).to.deep.eq value
|
||||
|
||||
it "#consoleProps", ->
|
||||
cy.location().then ->
|
||||
consoleProps = @lastLog.invoke("consoleProps")
|
||||
|
||||
expect(_.keys(consoleProps)).to.deep.eq ["Command", "Yielded"]
|
||||
expect(consoleProps.Command).to.eq "location"
|
||||
expect(_.keys(consoleProps.Yielded)).to.deep.eq ["auth", "authObj", "hash", "href", "host", "hostname", "origin", "pathname", "port", "protocol", "search", "originPolicy", "superDomain", "toString"]
|
||||
@@ -0,0 +1,513 @@
|
||||
const { _ } = Cypress
|
||||
|
||||
describe('src/cy/commands/location', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/generic.html')
|
||||
})
|
||||
|
||||
context('#url', () => {
|
||||
it('returns the location href', () => {
|
||||
cy.url().then((url) => {
|
||||
expect(url).to.eq('http://localhost:3500/fixtures/generic.html')
|
||||
})
|
||||
})
|
||||
|
||||
it('eventually resolves', () => {
|
||||
_.delay(() => {
|
||||
const win = cy.state('window')
|
||||
|
||||
win.location.href = '/foo/bar/baz.html'
|
||||
}, 100)
|
||||
|
||||
cy.url().should('match', /baz/).and('eq', 'http://localhost:3500/foo/bar/baz.html')
|
||||
})
|
||||
|
||||
it('catches thrown errors', () => {
|
||||
cy.stub(Cypress.utils, 'locToString')
|
||||
.onFirstCall().throws(new Error)
|
||||
.onSecondCall().returns('http://localhost:3500/baz.html')
|
||||
|
||||
cy.url().should('include', '/baz.html')
|
||||
})
|
||||
|
||||
describe('assertion verification', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (log.get('name') === 'assert') {
|
||||
this.lastLog = log
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('eventually passes the assertion', () => {
|
||||
cy.on('command:retry', _.after(2, _.once(() => {
|
||||
const win = cy.state('window')
|
||||
|
||||
win.location.href = '/foo/bar/baz.html'
|
||||
})))
|
||||
|
||||
cy.url().should('match', /baz/).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('name')).to.eq('assert')
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 100)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('eventually fails the assertion', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(err.message).to.include(lastLog.get('error').message)
|
||||
expect(err.message).not.to.include('undefined')
|
||||
expect(lastLog.get('name')).to.eq('assert')
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.url().should('eq', 'not-this')
|
||||
})
|
||||
|
||||
it('does not log an additional log on failure', function (done) {
|
||||
cy.on('fail', () => {
|
||||
expect(this.logs.length).to.eq(2)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.url().should('eq', 'not-this')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('ends immediately', () => {
|
||||
cy.url().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
})
|
||||
})
|
||||
|
||||
it('snapshots immediately', () => {
|
||||
cy.url().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('snapshots').length).to.eq(1)
|
||||
expect(lastLog.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
|
||||
it('logs obj', () => {
|
||||
cy.url().then(function () {
|
||||
const obj = {
|
||||
name: 'url',
|
||||
message: '',
|
||||
}
|
||||
|
||||
const { lastLog } = this
|
||||
|
||||
_.each(obj, (value, key) => {
|
||||
expect(lastLog.get(key)).to.deep.eq(value)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit when {log: false}', () => {
|
||||
cy.url({ log: false }).then(function () {
|
||||
expect(this.log).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('#consoleProps', () => {
|
||||
cy.url().then(function () {
|
||||
const consoleProps = this.lastLog.invoke('consoleProps')
|
||||
|
||||
expect(consoleProps).to.deep.eq({
|
||||
Command: 'url',
|
||||
Yielded: 'http://localhost:3500/fixtures/generic.html',
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#hash', () => {
|
||||
it('returns the location hash', () => {
|
||||
cy.hash().then((hash) => {
|
||||
expect(hash).to.eq('')
|
||||
})
|
||||
})
|
||||
|
||||
it('eventually resolves', () => {
|
||||
_.delay(() => {
|
||||
const win = cy.state('window')
|
||||
|
||||
win.location.hash = 'users/1'
|
||||
}, 100)
|
||||
|
||||
cy.hash().should('match', /users/).and('eq', '#users/1')
|
||||
})
|
||||
|
||||
describe('assertion verification', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (log.get('name') === 'assert') {
|
||||
this.lastLog = log
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('eventually passes the assertion', () => {
|
||||
cy.on('command:retry', _.after(2, () => {
|
||||
const win = cy.state('window')
|
||||
|
||||
win.location.hash = 'users/1'
|
||||
}))
|
||||
|
||||
cy.hash().should('match', /users/).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('name')).to.eq('assert')
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 100)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('eventually fails the assertion', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(err.message).to.include(lastLog.get('error').message)
|
||||
expect(err.message).not.to.include('undefined')
|
||||
expect(lastLog.get('name')).to.eq('assert')
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.hash().should('eq', 'not-this')
|
||||
})
|
||||
|
||||
it('does not log an additional log on failure', function (done) {
|
||||
cy.on('fail', () => {
|
||||
expect(this.logs.length).to.eq(2)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.hash().should('eq', 'not-this')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('ends immediately', () => {
|
||||
cy.hash().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
})
|
||||
})
|
||||
|
||||
it('snapshots immediately', () => {
|
||||
cy.hash().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('snapshots').length).to.eq(1)
|
||||
expect(lastLog.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
|
||||
it('logs obj', () => {
|
||||
cy.hash().then(function () {
|
||||
const obj = {
|
||||
name: 'hash',
|
||||
message: '',
|
||||
}
|
||||
|
||||
const { lastLog } = this
|
||||
|
||||
_.each(obj, (value, key) => {
|
||||
expect(lastLog.get(key)).to.deep.eq(value)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit when {log: false}', () => {
|
||||
cy.hash({ log: false }).then(function () {
|
||||
expect(this.log).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('#consoleProps', () => {
|
||||
cy.hash().then(function () {
|
||||
const consoleProps = this.lastLog.invoke('consoleProps')
|
||||
|
||||
expect(consoleProps).to.deep.eq({
|
||||
Command: 'hash',
|
||||
Yielded: '',
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#location', () => {
|
||||
it('returns the location object', () => {
|
||||
cy.location().then((loc) => {
|
||||
expect(loc).to.have.keys(['auth', 'authObj', 'hash', 'href', 'host', 'hostname', 'origin', 'pathname', 'port', 'protocol', 'search', 'originPolicy', 'superDomain', 'toString'])
|
||||
})
|
||||
})
|
||||
|
||||
it('returns a specific key from location object', () => {
|
||||
cy.location('href').then((href) => {
|
||||
expect(href).to.eq('http://localhost:3500/fixtures/generic.html')
|
||||
})
|
||||
})
|
||||
|
||||
it('eventually resolves', () => {
|
||||
_.delay(() => {
|
||||
const win = cy.state('window')
|
||||
|
||||
win.location.pathname = 'users/1'
|
||||
}, 100)
|
||||
|
||||
cy.location().should('have.property', 'pathname').and('match', /users/)
|
||||
})
|
||||
|
||||
describe('assertion verification', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
if (log.get('name') === 'assert') {
|
||||
this.lastLog = log
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('eventually passes the assertion', () => {
|
||||
cy.on('command:retry', _.after(2, _.once(() => {
|
||||
const win = cy.state('window')
|
||||
|
||||
win.location.pathname = 'users/1'
|
||||
})))
|
||||
|
||||
cy.location('pathname').should('match', /users/).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('name')).to.eq('assert')
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
beforeEach(function () {
|
||||
Cypress.config('defaultCommandTimeout', 100)
|
||||
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('throws when passed a non-existent key', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(err.message).to.include(lastLog.get('error').message)
|
||||
expect(err.message).to.include('Location object does not have key: `ladida`')
|
||||
expect(err.docsUrl).to.include('https://on.cypress.io/location')
|
||||
expect(lastLog.get('name')).to.eq('location')
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.location('ladida')
|
||||
})
|
||||
|
||||
it('eventually fails the assertion', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(err.message).to.include(lastLog.get('error').message)
|
||||
expect(err.message).not.to.include('undefined')
|
||||
expect(lastLog.get('name')).to.eq('assert')
|
||||
expect(lastLog.get('state')).to.eq('failed')
|
||||
expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.location('pathname').should('eq', 'not-this')
|
||||
})
|
||||
|
||||
it('does not log an additional log on failure', function (done) {
|
||||
const logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
logs.push(log)
|
||||
})
|
||||
|
||||
cy.on('fail', () => {
|
||||
expect(this.logs.length).to.eq(2)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.location('pathname').should('eq', 'not-this')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
this.logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
this.logs.push(log)
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('ends immediately', () => {
|
||||
cy.location('href').then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
})
|
||||
})
|
||||
|
||||
it('snapshots immediately', () => {
|
||||
cy.location('href').then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('snapshots').length).to.eq(1)
|
||||
expect(lastLog.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit when {log: false} as options', () => {
|
||||
cy.location('href', { log: false }).then(function () {
|
||||
expect(this.log).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit when {log: false} as key', () => {
|
||||
cy.location({ log: false }).then(function () {
|
||||
expect(this.log).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('logs obj without a message', () => {
|
||||
cy.location().then(function () {
|
||||
const obj = {
|
||||
name: 'location',
|
||||
message: '',
|
||||
}
|
||||
|
||||
const { lastLog } = this
|
||||
|
||||
_.each(obj, (value, key) => {
|
||||
expect(lastLog.get(key)).to.deep.eq(value)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('logs obj with a message', () => {
|
||||
cy.location('origin').then(function () {
|
||||
const obj = {
|
||||
name: 'location',
|
||||
message: 'origin',
|
||||
}
|
||||
|
||||
const { lastLog } = this
|
||||
|
||||
_.each(obj, (value, key) => {
|
||||
expect(lastLog.get(key)).to.deep.eq(value)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('#consoleProps', () => {
|
||||
cy.location().then(function () {
|
||||
const consoleProps = this.lastLog.invoke('consoleProps')
|
||||
|
||||
expect(_.keys(consoleProps)).to.deep.eq(['Command', 'Yielded'])
|
||||
expect(consoleProps.Command).to.eq('location')
|
||||
expect(_.keys(consoleProps.Yielded)).to.deep.eq(['auth', 'authObj', 'hash', 'href', 'host', 'hostname', 'origin', 'pathname', 'port', 'protocol', 'search', 'originPolicy', 'superDomain', 'toString'])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user