Skip to content

Commit

Permalink
from review: add additional tests and fix some edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
gabbersepp committed Nov 8, 2019
1 parent 05b49db commit 1503393
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 14 deletions.
23 changes: 18 additions & 5 deletions packages/driver/src/cy/commands/connectors.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,18 @@ module.exports = (Commands, Cypress, cy, state, config) ->
return invokeBaseFn(options or { log: true }, subject, str, args...)

invokeFn = (subject, optionsOrStr, args...) ->
optionsPassed = not _.isString(optionsOrStr)
optionsPassed = _.isObject(optionsOrStr)
options = null
str = null

if not optionsPassed
str = optionsOrStr
options = { log: true }
else if args.length > 0
else
options = optionsOrStr
str = args[0]
args = args.slice(1)
if args.length > 0
str = args[0]
args = args.slice(1)

return invokeBaseFn(options, subject, str, args...)

Expand Down Expand Up @@ -178,8 +179,20 @@ module.exports = (Commands, Cypress, cy, state, config) ->
consoleProps: ->
Subject: subject

if not str
$utils.throwErrByPath("invoke_its.null_or_undefined_property_name", {
onFail: options._log
args: { cmd: name, identifier: if isCmdIts then "property" else "function" }
})

if not _.isString(str)
$utils.throwErrByPath("invoke_its.invalid_1st_arg", {
$utils.throwErrByPath("invoke_its.invalid_prop_name_arg", {
onFail: options._log
args: { cmd: name, identifier: if isCmdIts then "property" else "function" }
})

if not _.isObject(options) or _.isFunction(options)
$utils.throwErrByPath("invoke_its.invalid_options_arg", {
onFail: options._log
args: { cmd: name }
})
Expand Down
4 changes: 3 additions & 1 deletion packages/driver/src/cypress/error_messages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,9 @@ module.exports = {
cy.wrap({ foo: {{value}} }).its('foo.baz').should('not.exist')
"""
invalid_1st_arg: "#{cmd('{{cmd}}')} only accepts a string as the first argument."
invalid_prop_name_arg: "#{cmd('{{cmd}}')} only accepts a string as the {{identifier}}Name argument."
null_or_undefined_property_name: "#{cmd('{{cmd}}')} expects the {{identifier}} name to have a value."
invalid_options_arg: "#{cmd('{{cmd}}')} only accepts an object as the options argument."
invalid_num_of_args:
"""
#{cmd('{{cmd}}')} does not accept additional arguments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,103 @@ describe "src/cy/commands/connectors", ->

cy.wrap(obj).invoke("foo.bar")

describe "accepts a options argument", ->

it "changes subject to function invocation", ->
cy.noop({ foo: -> "foo" }).invoke({ log: false }, "foo").then (str) ->
expect(str).to.eq "foo"

it "forwards any additional arguments", ->
cy.noop({ bar: (num1, num2) -> num1 + num2 }).invoke({ log: false }, "bar", 1, 2).then (num) ->
expect(num).to.eq 3

cy.noop({ bar: -> undefined }).invoke({ log: false }, "bar").then (val) ->
expect(val).to.be.undefined

describe "errors", ->
beforeEach ->
Cypress.config("defaultCommandTimeout", 50)

cy.on "log:added", (attrs, log) =>
@lastLog = log

return null

it "throws when function name is missing", (done) ->
cy.on "fail", (err) =>
lastLog = @lastLog
expect(err.message).to.include "cy.invoke() expects the function name to have a value"
expect(lastLog.get("error").message).to.include(err.message)
done()

cy.wrap({ foo: -> "foo"}).invoke({})

it "throws when function name is not of type string", (done) ->
cy.on "fail", (err) =>
lastLog = @lastLog
expect(err.message).to.include "cy.invoke() only accepts a string as the functionName argument."
expect(lastLog.get("error").message).to.include(err.message)
done()

cy.wrap({ foo: -> "foo"}).invoke({}, 123)

it "throws when function name is not of type string", (done) ->
cy.on "fail", (err) =>
lastLog = @lastLog
expect(err.message).to.include "cy.invoke() only accepts a string as the functionName argument."
expect(lastLog.get("error").message).to.include(err.message)
done()

cy.wrap({ foo: -> "foo"}).invoke(123)

describe ".log", ->
beforeEach ->
@obj = {
foo: "foo bar baz"
num: 123
bar: -> "bar"
attr: (key, value) ->
obj = {}
obj[key] = value
obj
sum: (a, b) -> a + b
}

cy.on "log:added", (attrs, log) =>
@lastLog = log

return null

it "logs obj as a function", ->
cy.noop(@obj).invoke({ log: true }, "bar").then ->
obj = {
name: "invoke"
message: ".bar()"
}

lastLog = @lastLog

_.each obj, (value, key) =>
expect(lastLog.get(key)).to.deep.eq value

it "logs obj with arguments", ->
cy.noop(@obj).invoke({ log: true }, "attr", "numbers", [1,2,3]).then ->
expect(@lastLog.invoke("consoleProps")).to.deep.eq {
Command: "invoke"
Function: ".attr(numbers, [1, 2, 3])"
"With Arguments": ["numbers", [1,2,3]]
Subject: @obj
Yielded: {numbers: [1,2,3]}
}

it "can be disabled", ->
cy.noop(@obj).invoke({ log: true }, "sum", 1, 2).then ->
expect(@lastLog.invoke("consoleProps")).to.have.property("Function", ".sum(1, 2)")
@lastLog = undefined

cy.noop(@obj).invoke({ log: false }, "sum", 1, 2).then ->
expect(@lastLog).to.be.undefined

describe ".log", ->
beforeEach ->
@obj = {
Expand Down Expand Up @@ -566,14 +663,6 @@ describe "src/cy/commands/connectors", ->
Yielded: $btn.get(0)
}

it "can be disabled", ->
cy.noop(@obj).invoke({ log: true }, "sum", 1, 2).then ->
expect(@lastLog.invoke("consoleProps")).to.have.property("Function", ".sum(1, 2)")
@lastLog = undefined

cy.noop(@obj).invoke({ log: false }, "sum", 1, 2).then ->
expect(@lastLog).to.be.undefined

describe "errors", ->
beforeEach ->
Cypress.config("defaultCommandTimeout", 50)
Expand Down Expand Up @@ -857,6 +946,51 @@ describe "src/cy/commands/connectors", ->
cy.wrap(obj).its("foo").should("be.undefined")
cy.wrap(obj).its("foo").should("eq", undefined)

describe "accepts a options argument and works as without options argument", ->

it "proxies to #invokeFn", ->
fn = -> "bar"
cy.wrap({foo: fn}).its("foo", { log: false }).should("eq", fn)

it "does not invoke a function and uses as a property", ->
fn = -> "fn"
fn.bar = "bar"

cy.wrap(fn).its("bar", { log: false }).should("eq", "bar")

describe ".log", ->
beforeEach ->
@obj = {
foo: "foo bar baz"
num: 123
}

cy.on "log:added", (attrs, log) =>
@lastLog = log

return null

it "logs obj as a property", ->
cy.noop(@obj).its("foo", { log: true }).then ->
obj = {
name: "its"
message: ".foo"
}

lastLog = @lastLog

_.each obj, (value, key) =>
expect(lastLog.get(key)).to.deep.eq value

it "#consoleProps as a regular property", ->
cy.noop(@obj).its("num", { log: true }).then ->
expect(@lastLog.invoke("consoleProps")).to.deep.eq {
Command: "its"
Property: ".num"
Subject: @obj
Yielded: 123
}

describe ".log", ->
beforeEach ->
@obj = {
Expand Down Expand Up @@ -1141,6 +1275,33 @@ describe "src/cy/commands/connectors", ->

cy.wrap(fn).its("bar", { log: false }, "baz").should("eq", "baz")

it "throws when options argument is not an object", (done) ->
cy.on "fail", (err) =>
lastLog = @lastLog
expect(err.message).to.include "cy.its() only accepts an object as the options argument."
expect(lastLog.get("error").message).to.include(err.message)
done()

cy.wrap({ foo: "string" }).its("foo", "bar")

it "throws when property name is missing", (done) ->
cy.on "fail", (err) =>
lastLog = @lastLog
expect(err.message).to.include "cy.its() expects the property name to have a value"
expect(lastLog.get("error").message).to.include(err.message)
done()

cy.wrap({ foo: "foo"}).its()

it "throws when property name is not of type string", (done) ->
cy.on "fail", (err) =>
lastLog = @lastLog
expect(err.message).to.include "cy.its() only accepts a string as the propertyName argument."
expect(lastLog.get("error").message).to.include(err.message)
done()

cy.wrap({ foo: "foo"}).its(123)

it "resets traversalErr and throws the right assertion", (done) ->
cy.timeout(200)

Expand Down

0 comments on commit 1503393

Please sign in to comment.