diff --git a/content/_changelogs/12.0.0.md b/content/_changelogs/12.0.0.md index 58151442cb..fac9213443 100644 --- a/content/_changelogs/12.0.0.md +++ b/content/_changelogs/12.0.0.md @@ -11,6 +11,11 @@ _Released MM/DD/YYYY_ - Cypress now throws an error if commands are invoked from inside a `.should()` callback. This previously resulted in unusual and undefined behavior; it is now explicitly an error. +- The [`.within()`](/api/commands/within) command now throws an error if given + more than one DOM element as a subject. This is done for consistency - in + older versions, some commands inside a `.within()` block would respect all + passed in elements, while others silently discarded subjects beyond the first + and `.screenshot()` would throw an error. - `Cookies.defaults` and `Cookies.preserveOnce` have been removed. Please update to use [`cy.session()`](/api/commands/session) to preserve session details between tests. Addresses diff --git a/content/api/commands/within.md b/content/api/commands/within.md index c73be241e1..649593ac31 100644 --- a/content/api/commands/within.md +++ b/content/api/commands/within.md @@ -20,7 +20,9 @@ chain further commands that rely on the subject after `.within()`. ** Correct Usage** ```javascript -cy.get('.list').within(($list) => {}) // Yield the `.list` and scope all commands within it +cy.get('.list') + .first() + .within(($list) => {}) // Yield the first `.list` and scope all commands within it ``` ** Incorrect Usage** @@ -28,6 +30,7 @@ cy.get('.list').within(($list) => {}) // Yield the `.list` and scope all command ```javascript cy.within(() => {}) // Errors, cannot be chained off 'cy' cy.getCookies().within(() => {}) // Errors, 'getCookies' does not yield DOM element +cy.get('div').within(($divs) => {}) // Probably errors, because get('div') yields multiple elements ``` ### Arguments @@ -179,7 +182,8 @@ cy.get('form').within(($form) => { ### Requirements [](/guides/core-concepts/introduction-to-cypress#Chains-of-Commands) -
  • `.within()` requires being chained off a previous command.
  • +- `.within()` requires being chained off a previous command that yields exactly + one DOM element. ### Assertions [](/guides/core-concepts/introduction-to-cypress#Assertions) @@ -211,10 +215,11 @@ outputs the following: ## History -| Version | Changes | -| --------------------------------------------- | ------------------------------------------------------- | -| [< 0.3.3](/guides/references/changelog#0-3-3) | `.within()` command added | -| [5.4.0](/guides/references/changelog#5-4-0) | fixed the yielded value to always be the parent element | +| Version | Changes | +| --------------------------------------------- | -------------------------------------------------------------------------------- | +| [12.0.0](/guides/references/changelog#12-0-0) | `.within()` now throws an error when given more than one element as the subject. | +| [5.4.0](/guides/references/changelog#5-4-0) | fixed the yielded value to always be the parent element | +| [< 0.3.3](/guides/references/changelog#0-3-3) | `.within()` command added | ## See also diff --git a/content/guides/references/migration-guide.md b/content/guides/references/migration-guide.md index 32c89d05e2..206ad74472 100644 --- a/content/guides/references/migration-guide.md +++ b/content/guides/references/migration-guide.md @@ -269,9 +269,10 @@ command instead. #### `.invoke()` -[`.invoke()`](/api/commands/invoke) now throws an error if the function returns -a promise. If you wish to call a method that returns a promise and wait for it -to resolve, use [`.then()`](/api/commands/then) instead of `.invoke()`. +The [`.invoke()`](/api/commands/invoke) command now throws an error if the +function returns a promise. If you wish to call a method that returns a promise +and wait for it to resolve, use [`.then()`](/api/commands/then) instead of +`.invoke()`. ```diff cy.wrap(myAPI) @@ -296,7 +297,72 @@ assertions to their own chain. For example, rewrite #### `.should()` -[`.should()`](/api/commands/should) now throws an error if Cypress commands are +The [`.should()`](/api/commands/should) assertion now throws an error if Cypress +commands are invoked from inside a `.should()` callback. This previously +resulted in unusual and undefined behavior. If you wish to execute a series of +commands on the yielded value, use`.then()` instead. + +```diff +cy.get('button') +- .should(($button) => { + + }) ++ .then(api => api.makeARequest('http://example.com')) + .then(res => { ...handle response... }) +``` + +#### `.within()` + +The [`.within()`](/api/commands/within) command now throws an error if it is +passed multiple elements as the subject. This previously resulted in +inconsistent behavior, where some commands would use all passed in elements, +some would use only the first and ignore the rest, and +[`.screenshot()`](/api/commands/screenshot) would throw an error if used inside +a `.within()` block with multiple elements. + +If you were relying on the old behavior, you have several options depending on +the desired result. + +The simplest option is to reduce the subject to a single element. + +```diff +cy.get('tr') ++ .first() // Limit the subject to a single element before calling .within() + .within(() => { + cy.contains('Edit').click() + }) +``` + +If you have multiple subjects and wish to run commands over the collection as a +whole, you can alias the subject rather than use `.within()`. + +```diff +cy.get('tr') +- .within(() => { +- cy.get('td').should('have.class', 'foo') +- cy.get('td').should('have.class', 'bar') +- }) ++ .as('rows') // Store multiple elements as an alias + ++cy.get('@rows').find('td').should('have.class', 'foo') ++cy.get('@rows').find('td').should('have.class', 'bar') +``` + +Or if you have a collection and want to run commands over every element, use +`.each()` in conjunction with `.within()`. + +```diff +cy.get('tr') +- .within(() => { +- cy.contains('Edit').should('have.attr', 'disabled') +- }) ++ .each($tr => { ++ cy.wrap($tr).within(() => { ++ cy.contains('Edit').should('have.attr', 'disabled') ++ }) ++ }) +``` + invoked from inside a `.should()` callback. This previously resulted in unusual and undefined behavior. If you wish to execute a series of commands on the yielded value, use`.then()` instead.