diff --git a/packages/driver/src/cy/commands/actions/check.coffee b/packages/driver/src/cy/commands/actions/check.coffee index f20177a68756..407ba1683956 100644 --- a/packages/driver/src/cy/commands/actions/check.coffee +++ b/packages/driver/src/cy/commands/actions/check.coffee @@ -18,14 +18,12 @@ checkOrUncheck = (type, subject, values = [], options = {}) -> ## make sure we're an array of values values = [].concat(values) - userOptions = Object.assign({}, options) - ## keep an array of subjects which ## are potentially reduced down ## to new filtered subjects matchingElements = [] - _.defaults options, + opts = _.defaults {}, options, $el: subject log: true force: false @@ -58,10 +56,10 @@ checkOrUncheck = (type, subject, values = [], options = {}) -> if not isAcceptableElement($el) node = $dom.stringify($el) - word = $utils.plural(options.$el, "contains", "is") + word = $utils.plural(opts.$el, "contains", "is") phrase = if type is "check" then " and :radio" else "" $utils.throwErrByPath "check_uncheck.invalid_element", { - onFail: options._log + onFail: opts._log args: { node, word, phrase, cmd: type } } @@ -75,33 +73,33 @@ checkOrUncheck = (type, subject, values = [], options = {}) -> "Elements": $el.length } - if options.log and isElActionable + if opts.log and isElActionable ## figure out the options which actually change the behavior of clicks - deltaOptions = $utils.filterOutOptions(options) + deltaOptions = $utils.filterOutOptions(opts) - options._log = Cypress.log - options: userOptions + opts._log = Cypress.log + options: options $el: $el consoleProps: -> _.extend consoleProps, { Options: deltaOptions } - options._log.snapshot("before", {next: "after"}) + opts._log.snapshot("before", {next: "after"}) ## if the checkbox was already checked ## then notify the user of this note ## and bail if isNoop($el) - if !options.force + if !opts.force ## still ensure visibility even if the command is noop - cy.ensureVisibility($el, options._log) - if options._log + cy.ensureVisibility($el, opts._log) + if opts._log inputType = if $el.is(":radio") then "radio" else "checkbox" consoleProps.Note = "This #{inputType} was already #{type}ed. No operation took place." - options._log.snapshot().end() + opts._log.snapshot().end() return null @@ -112,26 +110,26 @@ checkOrUncheck = (type, subject, values = [], options = {}) -> $el: $el log: false verify: false - _log: options._log - force: options.force - timeout: options.timeout - interval: options.interval + _log: opts._log + force: opts.force + timeout: opts.timeout + interval: opts.interval }).then -> - options._log.snapshot().end() if options._log + opts._log.snapshot().end() if opts._log return null ## return our original subject when our promise resolves Promise - .resolve(options.$el.toArray()) + .resolve(opts.$el.toArray()) .each(checkOrUncheckEl) .then -> ## filter down our $el to the ## matching elements - options.$el = options.$el.filter(matchingElements) + opts.$el = opts.$el.filter(matchingElements) do verifyAssertions = => - cy.verifyUpcomingAssertions(options.$el, options, { + cy.verifyUpcomingAssertions(opts.$el, opts, { onRetry: verifyAssertions }) diff --git a/packages/driver/src/cy/commands/actions/click.js b/packages/driver/src/cy/commands/actions/click.js index df409eb05915..eac1a0dd2f89 100644 --- a/packages/driver/src/cy/commands/actions/click.js +++ b/packages/driver/src/cy/commands/actions/click.js @@ -41,14 +41,13 @@ module.exports = (Commands, Cypress, cy, state, config) => { ({ options, position, x, y } = $actionability.getPositionFromArguments(positionOrX, y, options)) - const userOptions = Object.assign({}, options) const message = $utils.stringify([ position ? `position: ${position}` : undefined, x ? `x: ${x}` : undefined, y ? `y: ${y}` : undefined, ]) - _.defaults(options, { + const opts = _.defaults({}, options, { $el: subject, log: true, verify: true, @@ -65,9 +64,9 @@ module.exports = (Commands, Cypress, cy, state, config) => { // throw if we're trying to click multiple elements // and we did not pass the multiple flag - if ((options.multiple === false) && (options.$el.length > 1)) { + if ((opts.multiple === false) && (opts.$el.length > 1)) { $utils.throwErrByPath('click.multiple_elements', { - args: { cmd: eventName, num: options.$el.length }, + args: { cmd: eventName, num: opts.$el.length }, }) } @@ -75,23 +74,23 @@ module.exports = (Commands, Cypress, cy, state, config) => { let deltaOptions const $el = $dom.wrap(el) - if (options.log) { + if (opts.log) { // figure out the options which actually change the behavior of clicks - deltaOptions = $utils.filterOutOptions(options, defaultOptions) + deltaOptions = $utils.filterOutOptions(opts, defaultOptions) - options._log = Cypress.log({ + opts._log = Cypress.log({ message, - options: userOptions, + options, $el, }) - options._log.snapshot('before', { next: 'after' }) + opts._log.snapshot('before', { next: 'after' }) } - if (options.errorOnSelect && $el.is('select')) { + if (opts.errorOnSelect && $el.is('select')) { $utils.throwErrByPath('click.on_select_element', { args: { cmd: eventName }, - onFail: options._log, + onFail: opts._log, }) } @@ -105,19 +104,19 @@ module.exports = (Commands, Cypress, cy, state, config) => { const elClicked = domEvents.moveEvents.el - if (options._log) { - consoleObj = options._log.invoke('consoleProps') + if (opts._log) { + consoleObj = opts._log.invoke('consoleProps') } const consoleProps = function () { consoleObj = _.defaults(consoleObj != null ? consoleObj : {}, { - 'Applied To': $dom.getElements(options.$el), - 'Elements': options.$el.length, + 'Applied To': $dom.getElements(opts.$el), + 'Elements': opts.$el.length, 'Coords': _.pick(fromElWindow, 'x', 'y'), // always absolute 'Options': deltaOptions, }) - if (options.$el.get(0) !== elClicked) { + if (opts.$el.get(0) !== elClicked) { // only do this if $elToClick isnt $el consoleObj['Actual Element Clicked'] = $dom.getElements($(elClicked)) } @@ -131,18 +130,18 @@ module.exports = (Commands, Cypress, cy, state, config) => { .delay($actionability.delay, 'click') .then(() => { // display the red dot at these coords - if (options._log) { + if (opts._log) { // because we snapshot and output a command per click // we need to manually snapshot + end them - options._log.set({ coords: fromAutWindow, consoleProps }) + opts._log.set({ coords: fromAutWindow, consoleProps }) } // we need to split this up because we want the coordinates - // to mutate our passed in options._log but we dont necessary + // to mutate our passed in opts._log but we dont necessary // want to snapshot and end our command if we're a different // action like (cy.type) and we're borrowing the click action - if (options._log && options.log) { - return options._log.snapshot().end() + if (opts._log && opts.log) { + return opts._log.snapshot().end() } }) .return(null) @@ -152,7 +151,7 @@ module.exports = (Commands, Cypress, cy, state, config) => { // because we're issuing the clicks synchonrously // once we establish the coordinates and the element // passes all of the internal checks - return $actionability.verify(cy, $el, options, { + return $actionability.verify(cy, $el, opts, { onScroll ($el, type) { return Cypress.action('cy:scrolled', $el, type) }, @@ -160,7 +159,7 @@ module.exports = (Commands, Cypress, cy, state, config) => { onReady ($elToClick, coords) { const { fromElViewport, fromElWindow, fromAutWindow } = coords - const forceEl = options.force && $elToClick.get(0) + const forceEl = opts.force && $elToClick.get(0) const moveEvents = mouse.move(fromElViewport, forceEl) @@ -177,26 +176,26 @@ module.exports = (Commands, Cypress, cy, state, config) => { .catch((err) => { // snapshot only on click failure err.onFail = function () { - if (options._log) { - return options._log.snapshot() + if (opts._log) { + return opts._log.snapshot() } } // if we give up on waiting for actionability then // lets throw this error and log the command - return $utils.throwErr(err, { onFail: options._log }) + return $utils.throwErr(err, { onFail: opts._log }) }) } return Promise - .each(options.$el.toArray(), perform) + .each(opts.$el.toArray(), perform) .then(() => { - if (options.verify === false) { - return options.$el + if (opts.verify === false) { + return opts.$el } const verifyAssertions = () => { - return cy.verifyUpcomingAssertions(options.$el, options, { + return cy.verifyUpcomingAssertions(opts.$el, opts, { onRetry: verifyAssertions, }) } diff --git a/packages/driver/src/cy/commands/actions/focus.coffee b/packages/driver/src/cy/commands/actions/focus.coffee index fedc2fc1d82b..61dea2da1ae3 100644 --- a/packages/driver/src/cy/commands/actions/focus.coffee +++ b/packages/driver/src/cy/commands/actions/focus.coffee @@ -9,74 +9,68 @@ $actionability = require("../../actionability") module.exports = (Commands, Cypress, cy, state, config) -> Commands.addAll({ prevSubject: ["element", "window"] }, { focus: (subject, options = {}) -> - userOptions = Object.assign({}, options) - ## we should throw errors by default! ## but allow them to be silenced - _.defaults(options, { + opts = _.defaults({}, options, { $el: subject error: true log: true verify: true }) - if isWin = $dom.isWindow(options.$el) + if isWin = $dom.isWindow(opts.$el) ## get this into a jquery object - options.$el = $dom.wrap(options.$el) + opts.$el = $dom.wrap(opts.$el) - if options.log - options._log = Cypress.log - $el: options.$el - options: userOptions + if opts.log + opts._log = Cypress.log + $el: opts.$el + options: options consoleProps: -> - "Applied To": $dom.getElements(options.$el) + "Applied To": $dom.getElements(opts.$el) - el = options.$el.get(0) + el = opts.$el.get(0) ## the body is not really focusable, but it ## can have focus on initial page load. ## this is instead a noop. ## TODO: throw on body instead (breaking change) - isBody = $dom.isJquery(options.$el) && - $elements.isElement(options.$el.get(0)) && - $elements.isBody(options.$el.get(0)) + isBody = $dom.isJquery(opts.$el) && + $elements.isElement(opts.$el.get(0)) && + $elements.isBody(opts.$el.get(0)) ## http://www.w3.org/$R/html5/editing.html#specially-focusable ## ensure there is only 1 dom element in the subject ## make sure its allowed to be focusable - if not (isWin or isBody or $dom.isFocusable(options.$el)) - return if options.error is false + if not (isWin or isBody or $dom.isFocusable(opts.$el)) + return if opts.error is false - node = $dom.stringify(options.$el) + node = $dom.stringify(opts.$el) $utils.throwErrByPath("focus.invalid_element", { - onFail: options._log + onFail: opts._log args: { node } }) - if (num = options.$el.length) and num > 1 - return if options.error is false + if (num = opts.$el.length) and num > 1 + return if opts.error is false $utils.throwErrByPath("focus.multiple_elements", { - onFail: options._log + onFail: opts._log args: { num } }) cy.fireFocus(el) - # return options.$el if options.verify is false - do verifyAssertions = -> - cy.verifyUpcomingAssertions(options.$el, options, { + cy.verifyUpcomingAssertions(opts.$el, opts, { onRetry: verifyAssertions }) blur: (subject, options = {}) -> - userOptions = Object.assign({}, options) - ## we should throw errors by default! ## but allow them to be silenced - _.defaults(options, { + opts = _.defaults({}, options, { $el: subject $focused: cy.getFocused() error: true @@ -85,56 +79,56 @@ module.exports = (Commands, Cypress, cy, state, config) -> force: false }) - { $el, $focused } = options + { $el, $focused } = opts - if isWin = $dom.isWindow(options.$el) + if isWin = $dom.isWindow(opts.$el) ## get this into a jquery object - options.$el = $dom.wrap(options.$el) + opts.$el = $dom.wrap(opts.$el) - isBody = options.$el.is("body") + isBody = opts.$el.is("body") - if options.log - options._log = Cypress.log - $el: options.$el - options: userOptions + if opts.log + opts._log = Cypress.log + $el: opts.$el + options: options consoleProps: -> - "Applied To": $dom.getElements(options.$el) + "Applied To": $dom.getElements(opts.$el) - if (num = options.$el.length) and num > 1 - return if options.error is false + if (num = opts.$el.length) and num > 1 + return if opts.error is false $utils.throwErrByPath("blur.multiple_elements", { - onFail: options._log + onFail: opts._log args: { num } }) ## if we haven't forced the blur, and we don't currently ## have a focused element OR we aren't the window or body then error - if (options.force isnt true) and (not $focused) and (not isWin) and (not isBody) - return if options.error is false + if (opts.force isnt true) and (not $focused) and (not isWin) and (not isBody) + return if opts.error is false - $utils.throwErrByPath("blur.no_focused_element", { onFail: options._log }) + $utils.throwErrByPath("blur.no_focused_element", { onFail: opts._log }) ## if we're currently window dont check for the wrong ## focused element because window will not show up ## as $focused - if (options.force isnt true) and (not isWin) and (not isBody) and ( - options.$el.get(0) isnt $focused.get(0) + if (opts.force isnt true) and (not isWin) and (not isBody) and ( + opts.$el.get(0) isnt $focused.get(0) ) - return if options.error is false + return if opts.error is false node = $dom.stringify($focused) $utils.throwErrByPath("blur.wrong_focused_element", { - onFail: options._log + onFail: opts._log args: { node } }) - el = options.$el.get(0) + el = opts.$el.get(0) cy.fireBlur(el) do verifyAssertions = -> - cy.verifyUpcomingAssertions(options.$el, options, { + cy.verifyUpcomingAssertions(opts.$el, opts, { onRetry: verifyAssertions }) }) diff --git a/packages/driver/src/cy/commands/actions/scroll.coffee b/packages/driver/src/cy/commands/actions/scroll.coffee index eefd6e507bab..0da4078a81c0 100644 --- a/packages/driver/src/cy/commands/actions/scroll.coffee +++ b/packages/driver/src/cy/commands/actions/scroll.coffee @@ -37,8 +37,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> if subject.length > 1 $utils.throwErrByPath("scrollIntoView.multiple_elements", {args: { num: subject.length }}) - userOptions = Object.assign({}, options) - _.defaults(options, { + opts = _.defaults({}, options, { $el: subject $parent: state("window") log: true @@ -48,58 +47,58 @@ module.exports = (Commands, Cypress, cy, state, config) -> }) ## figure out the options which actually change the behavior of clicks - deltaOptions = $utils.filterOutOptions(options) + deltaOptions = $utils.filterOutOptions(opts) ## here we want to figure out what has to actually ## be scrolled to get to this element, cause we need ## to scrollTo passing in that element. - options.$parent = findScrollableParent(options.$el, state("window")) + opts.$parent = findScrollableParent(opts.$el, state("window")) - if options.$parent is state("window") + if opts.$parent is state("window") parentIsWin = true ## jQuery scrollTo looks for the prop contentWindow ## otherwise it'll use the wrong window to scroll :( - options.$parent.contentWindow = options.$parent + opts.$parent.contentWindow = opts.$parent ## if we cannot parse an integer out of duration ## which could be 500 or "500", then it's NaN...throw - if isNaNOrInfinity(options.duration) - $utils.throwErrByPath("scrollIntoView.invalid_duration", {args: { duration: options.duration }}) + if isNaNOrInfinity(opts.duration) + $utils.throwErrByPath("scrollIntoView.invalid_duration", {args: { duration: opts.duration }}) - if !(options.easing is "swing" or options.easing is "linear") - $utils.throwErrByPath("scrollIntoView.invalid_easing", {args: { easing: options.easing }}) + if !(opts.easing is "swing" or opts.easing is "linear") + $utils.throwErrByPath("scrollIntoView.invalid_easing", {args: { easing: opts.easing }}) - if options.log + if opts.log log = { - $el: options.$el - options: userOptions + $el: opts.$el + options: options consoleProps: -> obj = { ## merge into consoleProps without mutating it - "Applied To": $dom.getElements(options.$el) - "Scrolled Element": $dom.getElements(options.$el) + "Applied To": $dom.getElements(opts.$el) + "Scrolled Element": $dom.getElements(opts.$el) } return obj } - options._log = Cypress.log(log) + opts._log = Cypress.log(log) if not parentIsWin ## scroll the parent into view first ## before attemp - options.$parent[0].scrollIntoView() + opts.$parent[0].scrollIntoView() scrollIntoView = -> new Promise (resolve, reject) => ## scroll our axes - $(options.$parent).scrollTo(options.$el, { - axis: options.axis - easing: options.easing - duration: options.duration - offset: options.offset + $(opts.$parent).scrollTo(opts.$el, { + axis: opts.axis + easing: opts.easing + duration: opts.duration + offset: opts.offset done: (animation, jumpedToEnd) -> - resolve(options.$el) + resolve(opts.$el) fail: (animation, jumpedToEnd) -> ## its Promise object is rejected try @@ -108,13 +107,13 @@ module.exports = (Commands, Cypress, cy, state, config) -> reject(err) always: -> if parentIsWin - delete options.$parent.contentWindow + delete opts.$parent.contentWindow }) scrollIntoView() .then ($el) -> do verifyAssertions = -> - cy.verifyUpcomingAssertions($el, options, { + cy.verifyUpcomingAssertions($el, opts, { onRetry: verifyAssertions }) }) @@ -195,8 +194,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> if (!isWin && $container.length > 1) $utils.throwErrByPath("scrollTo.multiple_containers", {args: { num: $container.length }}) - userOptions = Object.assign({}, options) - _.defaults(options, { + opts = _.defaults({}, options, { $el: $container log: true duration: 0 @@ -208,21 +206,21 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## if we cannot parse an integer out of duration ## which could be 500 or "500", then it's NaN...throw - if isNaNOrInfinity(options.duration) - $utils.throwErrByPath("scrollTo.invalid_duration", {args: { duration: options.duration }}) + if isNaNOrInfinity(opts.duration) + $utils.throwErrByPath("scrollTo.invalid_duration", {args: { duration: opts.duration }}) - if !(options.easing is "swing" or options.easing is "linear") - $utils.throwErrByPath("scrollTo.invalid_easing", {args: { easing: options.easing }}) + if !(opts.easing is "swing" or opts.easing is "linear") + $utils.throwErrByPath("scrollTo.invalid_easing", {args: { easing: opts.easing }}) ## if we cannot parse an integer out of y or x ## which could be 50 or "50px" or "50%" then ## it's NaN/Infinity...throw - if isNaNOrInfinity(options.y) or isNaNOrInfinity(options.x) + if isNaNOrInfinity(opts.y) or isNaNOrInfinity(opts.x) $utils.throwErrByPath("scrollTo.invalid_target", {args: { x, y }}) - if options.log + if opts.log deltaOptions = $utils.stringify( - $utils.filterOutOptions(options, {duration: 0, easing: 'swing'}) + $utils.filterOutOptions(opts, {duration: 0, easing: 'swing'}) ) messageArgs = [] @@ -234,7 +232,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> log = { message: messageArgs.join(", "), - options: userOptions + options: options consoleProps: -> ## merge into consoleProps without mutating it obj = {} @@ -247,32 +245,32 @@ module.exports = (Commands, Cypress, cy, state, config) -> if deltaOptions obj.Options = deltaOptions - obj["Scrolled Element"] = $dom.getElements(options.$el) + obj["Scrolled Element"] = $dom.getElements(opts.$el) return obj } - if !isWin then log.$el = options.$el + if !isWin then log.$el = opts.$el - options._log = Cypress.log(log) + opts._log = Cypress.log(log) ensureScrollability = -> try ## make sure our container can even be scrolled cy.ensureScrollability($container, "scrollTo") catch err - options.error = err - cy.retry(ensureScrollability, options) + opts.error = err + cy.retry(ensureScrollability, opts) scrollTo = -> new Promise (resolve, reject) -> ## scroll our axis' - $(options.$el).scrollTo({left: x, top: y}, { - axis: options.axis - easing: options.easing - duration: options.duration + $(opts.$el).scrollTo({left: x, top: y}, { + axis: opts.axis + easing: opts.easing + duration: opts.duration done: (animation, jumpedToEnd) -> - resolve(options.$el) + resolve(opts.$el) fail: (animation, jumpedToEnd) -> ## its Promise object is rejected try @@ -282,14 +280,14 @@ module.exports = (Commands, Cypress, cy, state, config) -> }) if isWin - delete options.$el.contentWindow + delete opts.$el.contentWindow Promise .try(ensureScrollability) .then(scrollTo) .then ($el) -> do verifyAssertions = -> - cy.verifyUpcomingAssertions($el, options, { + cy.verifyUpcomingAssertions($el, opts, { onRetry: verifyAssertions }) }) diff --git a/packages/driver/src/cy/commands/actions/select.coffee b/packages/driver/src/cy/commands/actions/select.coffee index dd8786136127..52cfbb9419d7 100644 --- a/packages/driver/src/cy/commands/actions/select.coffee +++ b/packages/driver/src/cy/commands/actions/select.coffee @@ -10,28 +10,27 @@ newLineRe = /\n/g module.exports = (Commands, Cypress, cy, state, config) -> Commands.addAll({ prevSubject: "element" }, { select: (subject, valueOrText, options = {}) -> - userOptions = Object.assign({}, options) - _.defaults options, + opts = _.defaults {}, options, $el: subject log: true force: false consoleProps = {} - if options.log + if opts.log ## figure out the options which actually change the behavior of clicks - deltaOptions = $utils.filterOutOptions(options) + deltaOptions = $utils.filterOutOptions(opts) - options._log = Cypress.log - options: userOptions - $el: options.$el + opts._log = Cypress.log + options: options + $el: opts.$el consoleProps: -> ## merge into consoleProps without mutating it _.extend {}, consoleProps, - "Applied To": $dom.getElements(options.$el) + "Applied To": $dom.getElements(opts.$el) "Options": deltaOptions - options._log.snapshot("before", {next: "after"}) + opts._log.snapshot("before", {next: "after"}) ## if subject is a is disabled - if options.$el.prop("disabled") - node = $dom.stringify(options.$el) + if opts.$el.prop("disabled") + node = $dom.stringify(opts.$el) $utils.throwErrByPath "select.disabled", { args: { node } } values = [] optionEls = [] - optionsObjects = options.$el.find("option").map((index, el) -> + optionsObjects = opts.$el.find("option").map((index, el) -> ## push the value in values array if its ## found within the valueOrText value = $elements.getNativeProp(el, "value") @@ -130,9 +129,9 @@ module.exports = (Commands, Cypress, cy, state, config) -> Promise .try(getOptions) .catch (err) -> - options.error = err + opts.error = err - cy.retry(retryOptions, options) + cy.retry(retryOptions, opts) Promise .try(retryOptions) @@ -142,15 +141,15 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## preserve the selected values consoleProps.Selected = values - cy.now("click", options.$el, { - $el: options.$el + cy.now("click", opts.$el, { + $el: opts.$el log: false verify: false errorOnSelect: false ## prevent click errors since we want the select to be clicked - _log: options._log - force: options.force - timeout: options.timeout - interval: options.interval + _log: opts._log + force: opts.force + timeout: opts.timeout + interval: opts.interval }).then( -> ## TODO: @@ -170,8 +169,8 @@ module.exports = (Commands, Cypress, cy, state, config) -> log: false verify: false force: true ## always force the click to happen on the