From e4b033c5399b57e928c60ba7bf2843aef18b175c Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 5 Dec 2022 09:27:59 -0800 Subject: [PATCH 1/5] fix: .within() now throws an error if given more than one subject. --- .../cypress/e2e/commands/querying/within.cy.js | 13 +++++++++++-- packages/driver/src/cy/commands/querying/within.ts | 4 ++++ packages/driver/src/cypress/error_messages.ts | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/driver/cypress/e2e/commands/querying/within.cy.js b/packages/driver/cypress/e2e/commands/querying/within.cy.js index d24aa8ecae98..ceb739b3d9a0 100644 --- a/packages/driver/cypress/e2e/commands/querying/within.cy.js +++ b/packages/driver/cypress/e2e/commands/querying/within.cy.js @@ -228,7 +228,7 @@ describe('src/cy/commands/querying/within', () => { }) it('provides additional information in console prop', () => { - cy.get('div').within(() => {}) + cy.get('div').first().within(() => {}) cy.then(function () { const { lastLog } = this @@ -237,7 +237,6 @@ describe('src/cy/commands/querying/within', () => { expect(consoleProps).to.be.an('object') expect(consoleProps.Command).to.eq('within') expect(consoleProps.Yielded).to.not.be.null - expect(consoleProps.Yielded).to.have.length(55) }) }) }) @@ -304,6 +303,16 @@ describe('src/cy/commands/querying/within', () => { cy.get('#list').within(() => {}) }) + + it('throws when given multiple subjects', (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include('`cy.within()` can only be called on a single element. Your subject contained 9 elements.') + + done() + }) + + cy.get('ul').within(() => {}) + }) }) }) diff --git a/packages/driver/src/cy/commands/querying/within.ts b/packages/driver/src/cy/commands/querying/within.ts index 03c5b79b861f..b24f0c0218aa 100644 --- a/packages/driver/src/cy/commands/querying/within.ts +++ b/packages/driver/src/cy/commands/querying/within.ts @@ -107,6 +107,10 @@ export default (Commands, Cypress, cy, state) => { $errUtils.throwErrByPath('within.invalid_argument', { onFail: log }) } + if (subject.length > 1) { + $errUtils.throwErrByPath('within.multiple_elements', { args: { num: subject.length }, onFail: log }) + } + return withinFn(subject, fn) }) }, diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index 78d34e344eb3..dea93934a2da 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -2404,6 +2404,20 @@ export default { message: `${cmd('within')} must be called with a function.`, docsUrl: 'https://on.cypress.io/within', }, + multiple_elements (args) { + return { + message: stripIndent` + ${cmd('within')} can only be called on a single element. Your subject contained {{num}} elements. Narrow down your subject to a single element before calling \`.within()\`. + + To run \`.within()\` over multiple subjects, use \`.each()\`. + + \`cy.get('div').each($div => {\` + \` cy.wrap($div).within(() => { ... })\` + \`})\` + `, + docsUrl: 'https://on.cypress.io/within', + } + }, }, wrap: { From fa14e9d06f06233435e843f1e205ab90b76f84a6 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 5 Dec 2022 10:18:20 -0800 Subject: [PATCH 2/5] Fix own tests for new .within() behavior --- packages/app/cypress/e2e/runner/sessions.ui.cy.ts | 1 + packages/app/cypress/e2e/runs.cy.ts | 2 +- packages/driver/cypress/e2e/commands/querying/root.cy.js | 4 ++-- packages/driver/src/cypress/error_messages.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/app/cypress/e2e/runner/sessions.ui.cy.ts b/packages/app/cypress/e2e/runner/sessions.ui.cy.ts index d0377188ab24..67594574b2d6 100644 --- a/packages/app/cypress/e2e/runner/sessions.ui.cy.ts +++ b/packages/app/cypress/e2e/runner/sessions.ui.cy.ts @@ -106,6 +106,7 @@ describe('runner/cypress sessions.ui.spec', { validateSessionsInstrumentPanel(['blank_session']) cy.get('.command-name-session') + .first() .within(() => { cy.contains('blank_session') cy.contains('failed') diff --git a/packages/app/cypress/e2e/runs.cy.ts b/packages/app/cypress/e2e/runs.cy.ts index 9ce00b553bae..7d1038181001 100644 --- a/packages/app/cypress/e2e/runs.cy.ts +++ b/packages/app/cypress/e2e/runs.cy.ts @@ -941,7 +941,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 3).should('be.visible') cy.wrap(obj).invoke('toCall') - cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible').within(() => { + cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible').first().within(() => { cy.get('[data-cy="runResults-passed-count"]').should('contain', 100) }) diff --git a/packages/driver/cypress/e2e/commands/querying/root.cy.js b/packages/driver/cypress/e2e/commands/querying/root.cy.js index 194afca72a8b..e2823a76510e 100644 --- a/packages/driver/cypress/e2e/commands/querying/root.cy.js +++ b/packages/driver/cypress/e2e/commands/querying/root.cy.js @@ -17,7 +17,7 @@ describe('src/cy/commands/querying', () => { it('returns withinSubject if exists', () => { const form = cy.$$('form') - cy.get('form').within(() => { + cy.get('form').first().within(() => { cy .get('input') .root().then(($root) => { @@ -100,7 +100,7 @@ describe('src/cy/commands/querying', () => { it('sets $el to withinSubject', () => { const form = cy.$$('form') - cy.get('form').within(() => { + cy.get('form').first().within(() => { cy .get('input') .root().then(function ($root) { diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index dea93934a2da..bf25609772bb 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -2407,7 +2407,7 @@ export default { multiple_elements (args) { return { message: stripIndent` - ${cmd('within')} can only be called on a single element. Your subject contained {{num}} elements. Narrow down your subject to a single element before calling \`.within()\`. + ${cmd('within')} can only be called on a single element. Your subject contained {{num}} elements. Narrow down your subject to a single element (using \`.first()\`, for example) before calling \`.within()\`. To run \`.within()\` over multiple subjects, use \`.each()\`. From 450c2b048fd947a0636362f5b6643e5eebb6124f Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 5 Dec 2022 11:16:29 -0800 Subject: [PATCH 3/5] Another test fix --- packages/app/cypress/e2e/runner/sessions.ui.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/app/cypress/e2e/runner/sessions.ui.cy.ts b/packages/app/cypress/e2e/runner/sessions.ui.cy.ts index 67594574b2d6..c17eb3aa5b01 100644 --- a/packages/app/cypress/e2e/runner/sessions.ui.cy.ts +++ b/packages/app/cypress/e2e/runner/sessions.ui.cy.ts @@ -302,6 +302,7 @@ describe('runner/cypress sessions.ui.spec', { validateSessionsInstrumentPanel(['user1']) cy.get('.command-name-session') + .first() .within(() => { cy.contains('failed') From 7e70b3385a13244d3b34e355b3cc5548a4984ce3 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 5 Dec 2022 11:26:54 -0800 Subject: [PATCH 4/5] More fixes from launchpad --- .../launchpad/cypress/e2e/project-setup.cy.ts | 60 ++++++++----------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/packages/launchpad/cypress/e2e/project-setup.cy.ts b/packages/launchpad/cypress/e2e/project-setup.cy.ts index c38f896eccd6..26d16e99f4ee 100644 --- a/packages/launchpad/cypress/e2e/project-setup.cy.ts +++ b/packages/launchpad/cypress/e2e/project-setup.cy.ts @@ -87,12 +87,10 @@ describe('Launchpad: Setup Project', () => { cy.contains('h1', 'Configuration files') cy.findByText('We added the following files to your project:') - cy.get('[data-cy=valid]').within(() => { - cy.contains('cypress.config.js') - cy.containsPath('cypress/support/e2e.js') - cy.containsPath('cypress/support/commands.js') - cy.containsPath('cypress/fixtures/example.json') - }) + cy.get('[data-cy=valid]').as('valid').contains('cypress.config.js') + cy.get('@valid').containsPath('cypress/support/e2e.js') + cy.get('@valid').containsPath('cypress/support/commands.js') + cy.get('@valid').containsPath('cypress/fixtures/example.json') cy.get('[data-cy=valid] [data-cy=collapsible-header]').each((element) => { cy.wrap(element).should('have.attr', 'aria-expanded', 'false') @@ -247,12 +245,10 @@ describe('Launchpad: Setup Project', () => { cy.contains('h1', 'Configuration files') cy.findByText('We added the following files to your project:') - cy.get('[data-cy=valid]').within(() => { - cy.contains('cypress.config.js') - cy.containsPath('cypress/support/e2e.js') - cy.containsPath('cypress/support/commands.js') - cy.containsPath('cypress/fixtures/example.json') - }) + cy.get('[data-cy=valid]').as('valid').contains('cypress.config.js') + cy.get('@valid').containsPath('cypress/support/e2e.js') + cy.get('@valid').containsPath('cypress/support/commands.js') + cy.get('@valid').containsPath('cypress/fixtures/example.json') cy.get('[data-cy=valid] [data-cy=collapsible-header]').each((element) => { cy.wrap(element).should('have.attr', 'aria-expanded', 'false') @@ -278,12 +274,10 @@ describe('Launchpad: Setup Project', () => { cy.contains('h1', 'Configuration files') cy.findByText('We added the following files to your project:') - cy.get('[data-cy=valid]').within(() => { - cy.contains('cypress.config.js') - cy.containsPath('cypress/support/e2e.js') - cy.containsPath('cypress/support/commands.js') - cy.containsPath('cypress/fixtures/example.json') - }) + cy.get('[data-cy=valid]').as('valid').contains('cypress.config.js') + cy.get('@valid').containsPath('cypress/support/e2e.js') + cy.get('@valid').containsPath('cypress/support/commands.js') + cy.get('@valid').containsPath('cypress/fixtures/example.json') verifyScaffoldedFiles('e2e') @@ -317,12 +311,10 @@ describe('Launchpad: Setup Project', () => { cy.contains('h1', 'Configuration files') cy.findByText('We added the following files to your project:') - cy.get('[data-cy=valid]').within(() => { - cy.contains('cypress.config.js') - cy.containsPath('cypress/support/e2e.js') - cy.containsPath('cypress/support/commands.js') - cy.containsPath('cypress/fixtures/example.json') - }) + cy.get('[data-cy=valid]').as('valid').contains('cypress.config.js') + cy.get('@valid').containsPath('cypress/support/e2e.js') + cy.get('@valid').containsPath('cypress/support/commands.js') + cy.get('@valid').containsPath('cypress/fixtures/example.json') cy.get('[data-cy=valid] [data-cy=collapsible-header]').each((element) => { cy.wrap(element).should('have.attr', 'aria-expanded', 'false') @@ -353,12 +345,10 @@ describe('Launchpad: Setup Project', () => { cy.contains('h1', 'Configuration files') cy.findByText('We added the following files to your project:') - cy.get('[data-cy=valid]').within(() => { - cy.contains('cypress.config.ts') - cy.containsPath('cypress/support/e2e.ts') - cy.containsPath('cypress/support/commands.ts') - cy.containsPath('cypress/fixtures/example.json') - }) + cy.get('[data-cy=valid]').as('valid').contains('cypress.config.ts') + cy.get('@valid').containsPath('cypress/support/e2e.ts') + cy.get('@valid').containsPath('cypress/support/commands.ts') + cy.get('@valid').containsPath('cypress/fixtures/example.json') cy.get('[data-cy=valid] [data-cy=collapsible-header]').each((element) => { cy.wrap(element).should('have.attr', 'aria-expanded', 'false') @@ -410,12 +400,10 @@ describe('Launchpad: Setup Project', () => { cy.findByRole('button', { name: 'Skip' }).click() - cy.get('[data-cy=valid]').within(() => { - cy.contains('cypress.config.js') - cy.containsPath('cypress/support/component-index.html') - cy.containsPath('cypress/support/component.js') - cy.containsPath('cypress/support/commands.js') - }) + cy.get('[data-cy=valid]').as('valid').contains('cypress.config.js') + cy.get('@valid').containsPath('cypress/support/component-index.html') + cy.get('@valid').containsPath('cypress/support/component.js') + cy.get('@valid').containsPath('cypress/support/commands.js') verifyScaffoldedFiles('component') }) From 11b268476e2c6d13869451a956f58cf9ab2db9e9 Mon Sep 17 00:00:00 2001 From: Blue F Date: Mon, 5 Dec 2022 12:42:57 -0800 Subject: [PATCH 5/5] Update packages/app/cypress/e2e/runs.cy.ts Co-authored-by: Emily Rohrbough --- packages/app/cypress/e2e/runs.cy.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/app/cypress/e2e/runs.cy.ts b/packages/app/cypress/e2e/runs.cy.ts index 7d1038181001..9c9958eca317 100644 --- a/packages/app/cypress/e2e/runs.cy.ts +++ b/packages/app/cypress/e2e/runs.cy.ts @@ -941,7 +941,10 @@ describe('App: Runs', { viewportWidth: 1200 }, () => { cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 3).should('be.visible') cy.wrap(obj).invoke('toCall') - cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible').first().within(() => { + cy.get('[data-cy="run-card-icon-PASSED"]') + .should('have.length', 3) + .should('be.visible') + .first().within(() => { cy.get('[data-cy="runResults-passed-count"]').should('contain', 100) })