Skip to content

Commit

Permalink
fix: Fix "coordsHistory must be at least 2 sets of coords" error (#15643
Browse files Browse the repository at this point in the history
)
  • Loading branch information
chrisbreiding authored Mar 24, 2021
1 parent 56234e5 commit d9c3ae2
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 12 deletions.
14 changes: 14 additions & 0 deletions packages/driver/cypress/integration/commands/actions/click_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,20 @@ describe('src/cy/commands/actions/click', () => {
})
})

it('each click gets a full command timeout', () => {
cy.spy(cy, 'retry')

cy.get('#three-buttons button').click({ multiple: true }).then(() => {
const [firstCall, secondCall] = cy.retry.getCalls()
const firstCallOptions = firstCall.args[1]
const secondCallOptions = secondCall.args[1]

// ensure we clone the options object passed to `retry()` so that
// each click in `{ multiple: true }` gets its own full timeout
expect(firstCallOptions !== secondCallOptions, 'Expected click retry options to be different object references between clicks').to.be.true
})
})

// this test needs to increase the height + width of the div
// when we implement scrollBy the delta of the left/top
it('can click elements which are huge and the center is naturally below the fold', () => {
Expand Down
28 changes: 21 additions & 7 deletions packages/driver/src/cy/actionability.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,16 +261,29 @@ const getCoordinatesForEl = function (cy, $el, options) {
}

const ensureNotAnimating = function (cy, $el, coordsHistory, animationDistanceThreshold) {
// if we dont have at least 2 points
// then automatically retry
// if we dont have at least 2 points, we throw this error to force a
// retry, which will get us another point.
// this error is purposefully generic because if the actionability
//check times out, this error is the one displayed to the user and
// saying something like "coordsHistory must be at least 2 sets
// of coords" is not very useful.
// that would only happen if the actionability check times out, which
// shouldn't happen with default timeouts, but could theoretically
// on a very, very slow system
// https://github.com/cypress-io/cypress/issues/3738
if (coordsHistory.length < 2) {
$errUtils.throwErrByPath('dom.animation_coords_history_invalid')
$errUtils.throwErrByPath('dom.actionability_failed', {
args: {
node: $dom.stringify($el),
cmd: cy.state('current').get('name'),
},
})
}

// verify that our element is not currently animating
// by verifying it is still at the same coordinates within
// 5 pixels of x/y
return cy.ensureElementIsNotAnimating($el, coordsHistory, animationDistanceThreshold)
cy.ensureElementIsNotAnimating($el, coordsHistory, animationDistanceThreshold)
}

const verify = function (cy, $el, options, callbacks) {
Expand Down Expand Up @@ -336,7 +349,6 @@ const verify = function (cy, $el, options, callbacks) {
}

return Promise.try(() => {
let retryActionability
const coordsHistory = []

const runAllChecks = function () {
Expand Down Expand Up @@ -426,15 +438,17 @@ const verify = function (cy, $el, options, callbacks) {
// element passes every single check, we MUST fire the event
// synchronously else we risk the state changing between
// the checks and firing the event!
return (retryActionability = function () {
const retryActionability = () => {
try {
return runAllChecks()
} catch (err) {
options.error = err

return cy.retry(retryActionability, options)
}
})()
}

return retryActionability()
})
}

Expand Down
13 changes: 9 additions & 4 deletions packages/driver/src/cy/commands/actions/click.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ module.exports = (Commands, Cypress, cy, state, config) => {
})
}

// we want to add this delay delta to our
// runnables timeout so we prevent it from
// timing out from multiple clicks
// add this delay delta to the runnables timeout because we delay
// by it below before performing each click
cy.timeout($actionability.delay, true, eventName)

const createLog = (domEvents, fromElWindow, fromAutWindow) => {
Expand Down Expand Up @@ -169,11 +168,17 @@ module.exports = (Commands, Cypress, cy, state, config) => {
.return(null)
}

// if { multiple: true }, make a shallow copy of options, since
// properties like `total` and `_retries` are mutated by
// $actionability.verify and retrying, but each click should
// have its own full timeout
const individualOptions = { ... options }

// must use callbacks here instead of .then()
// because we're issuing the clicks synchronously
// 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, individualOptions, {
onScroll ($el, type) {
return Cypress.action('cy:scrolled', $el, type)
},
Expand Down
8 changes: 7 additions & 1 deletion packages/driver/src/cypress/error_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ module.exports = {
},

dom: {
actionability_failed: stripIndent`
${cmd('{{cmd}}')} could not be issued because we could not determine the actionability of this element:
\`{{node}}\`
You can prevent this by passing \`{force: true}\` to disable all error checking.
`,
animating: {
message: stripIndent`\
${cmd('{{cmd}}')} could not be issued because this element is currently animating:
Expand All @@ -305,7 +312,6 @@ module.exports = {
- Passing \`{animationDistanceThreshold: 20}\` which decreases the sensitivity`,
docsUrl: 'https://on.cypress.io/element-is-animating',
},
animation_coords_history_invalid: 'coordsHistory must be at least 2 sets of coords',
animation_check_failed: 'Not enough coord points provided to calculate distance.',
center_hidden: {
message: stripIndent`\
Expand Down

4 comments on commit d9c3ae2

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on d9c3ae2 Mar 24, 2021

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.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.7.2/appveyor-develop-d9c3ae24c3f96c8c385f974d8d6a7a38d84ed763/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on d9c3ae2 Mar 24, 2021

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.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.7.2/appveyor-develop-d9c3ae24c3f96c8c385f974d8d6a7a38d84ed763/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on d9c3ae2 Mar 24, 2021

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.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.9.0/circle-develop-d9c3ae24c3f96c8c385f974d8d6a7a38d84ed763/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on d9c3ae2 Mar 24, 2021

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.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/6.9.0/circle-develop-d9c3ae24c3f96c8c385f974d8d6a7a38d84ed763/cypress.tgz

Please sign in to comment.