Skip to content

Commit

Permalink
add Loggable options to its() / invoke() command (#5519)
Browse files Browse the repository at this point in the history
* add Loggable options to its() command

* add test for new Loggable option for its()

* add loggable options to invoke()

* add type definition
fix: only set logger config once. afterwards other commands can overwrite the logger config as done in line 322
remove unused error message (usage was removed in a former commit)
remove test that is unnecessary now

* add check if its() was passed additional arguments next to options

* try to fix test

* do not log 'this' context

* from review: add additional tests and fix some edge cases

* add tests for combination of loggable options and numeric index

* fix wrong indentation

* write as 'functionName' and 'propertyName' to match other error message

* Update tests to reflect newly worded errors


Co-authored-by: Jennifer Shehane <shehane.jennifer@gmail.com>
  • Loading branch information
gabbersepp and jennifer-shehane committed Dec 4, 2019
1 parent bbd519a commit 259bfbe
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 36 deletions.
7 changes: 5 additions & 2 deletions cli/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ declare namespace Cypress {
* @see https://on.cypress.io/invoke
*/
invoke<T extends (...args: any[]) => any, Subject extends T[]>(index: number): Chainable<ReturnType<T>>
invoke<T extends (...args: any[]) => any, Subject extends T[]>(options: Loggable, index: number): Chainable<ReturnType<T>>

/**
* Invoke a function on the previously yielded subject.
Expand All @@ -882,6 +883,7 @@ declare namespace Cypress {
* @see https://on.cypress.io/invoke
*/
invoke(functionName: keyof Subject, ...args: any[]): Chainable<Subject> // don't have a way to express return types yet
invoke(options: Loggable, functionName: keyof Subject, ...args: any[]): Chainable<Subject>

/**
* Get a property’s value on the previously yielded subject.
Expand All @@ -893,14 +895,15 @@ declare namespace Cypress {
* // Drill into nested properties by using dot notation
* cy.wrap({foo: {bar: {baz: 1}}}).its('foo.bar.baz')
*/
its<K extends keyof Subject>(propertyName: K): Chainable<Subject[K]>
its<K extends keyof Subject>(propertyName: K, options?: Loggable): Chainable<Subject[K]>

/**
* Get a value by index from an array yielded from the previous command.
* @see https://on.cypress.io/its
* @example
* cy.wrap(['a', 'b']).its(1).should('equal', 'b')
*/
its<T, Subject extends T[]>(index: number): Chainable<T>
its<T, Subject extends T[]>(index: number, options?: Loggable): Chainable<T>

/**
* Get the last DOM element within a set of DOM elements.
Expand Down
61 changes: 46 additions & 15 deletions packages/driver/src/cy/commands/connectors.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,26 @@ module.exports = (Commands, Cypress, cy, state, config) ->
}
.finally(cleanup)

invokeFn = (subject, str, args...) ->
options = {}
invokeItsFn = (subject, str, options, args...) ->
return invokeBaseFn(options or { log: true }, subject, str, args...)

invokeFn = (subject, optionsOrStr, args...) ->
optionsPassed = _.isObject(optionsOrStr) and !_.isFunction(optionsOrStr)
options = null
str = null

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

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

invokeBaseFn = (options, subject, str, args...) ->

## name could be invoke or its!
name = state("current").get("name")
Expand All @@ -154,24 +172,37 @@ module.exports = (Commands, Cypress, cy, state, config) ->

traversalErr = null

options._log = Cypress.log
message: message
$el: if $dom.isElement(subject) then subject else null
consoleProps: ->
Subject: subject
if options.log
options._log = Cypress.log
message: message
$el: if $dom.isElement(subject) then subject else null
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) and not _.isNumber(str)
$utils.throwErrByPath("invoke_its.invalid_1st_arg", {
$utils.throwErrByPath("invoke_its.invalid_prop_name_arg", {
onFail: options._log
args: { cmd: name }
args: { cmd: name, identifier: if isCmdIts then "property" else "function" }
})

if isCmdIts and args.length > 0
$utils.throwErrByPath("invoke_its.invalid_num_of_args", {
if not _.isObject(options) or _.isFunction(options)
$utils.throwErrByPath("invoke_its.invalid_options_arg", {
onFail: options._log
args: { cmd: name }
})

if isCmdIts and args and args.length > 0
$utils.throwErrByPath("invoke_its.invalid_num_of_args", {
onFail: options._log
args: { cmd: name }
})

## TODO: use the new error utils that are part of
## the error message enhancements PR
propertyNotOnSubjectErr = (prop) ->
Expand Down Expand Up @@ -449,9 +480,9 @@ module.exports = (Commands, Cypress, cy, state, config) ->
## return values are undefined. prob should rethink
## this and investigate why that is the default behavior
## of child commands
invoke: ->
invokeFn.apply(@, arguments)
invoke: (subject, optionsOrStr, args...) ->
invokeFn.apply(@, [subject, optionsOrStr, args...])

its: ->
invokeFn.apply(@, arguments)
its: (subject, str, options, args...) ->
invokeItsFn.apply(@, [subject, str, options, args...])
})
13 changes: 7 additions & 6 deletions packages/driver/src/cypress/error_messages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -409,12 +409,13 @@ module.exports = {
cy.wrap({ foo: {{value}} }).its('foo.baz').should('not.exist')
"""
invalid_1st_arg: "#{cmd('{{cmd}}')} only accepts a string or a number as the first argument."
invalid_num_of_args:
"""
#{cmd('{{cmd}}')} only accepts a single argument.
If you want to invoke a function with arguments, use cy.invoke().
invalid_prop_name_arg: "#{cmd('{{cmd}}')} only accepts a string or a number as the {{identifier}}Name argument."
null_or_undefined_property_name: "#{cmd('{{cmd}}')} expects the {{identifier}}Name argument 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.
If you want to invoke a function with arguments, use cy.invoke().
"""
timed_out:
"""
Expand Down
Loading

4 comments on commit 259bfbe

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 259bfbe Dec 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/3.7.1/linux-x64/circle-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-206284/cypress.zip
npm install https://cdn.cypress.io/beta/npm/3.7.1/circle-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-206272/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 259bfbe Dec 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 ia32 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

set CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/3.7.1/win32-ia32/appveyor-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-29297873/cypress.zip
npm install https://cdn.cypress.io/beta/binary/3.7.1/win32-ia32/appveyor-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-29297873/cypress.zip

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 259bfbe Dec 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

set CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/3.7.1/win32-x64/appveyor-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-29297873/cypress.zip
npm install https://cdn.cypress.io/beta/binary/3.7.1/win32-x64/appveyor-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-29297873/cypress.zip

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 259bfbe Dec 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/3.7.1/darwin-x64/circle-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-206288/cypress.zip
npm install https://cdn.cypress.io/beta/npm/3.7.1/circle-develop-259bfbecbe40cfecdeb2f5b73ee8e65bd5c41f92-206286/cypress.tgz

Please sign in to comment.