From 95ee9b9005e9ad013039b99bb7177dba203c9fcd Mon Sep 17 00:00:00 2001 From: Blue F Date: Mon, 5 Dec 2022 13:50:56 -0800 Subject: [PATCH 1/2] fix: .within() now throws an error if given more than one subject. (#24975) * fix: .within() now throws an error if given more than one subject. * Fix own tests for new .within() behavior Co-authored-by: Emily Rohrbough --- .../app/cypress/e2e/runner/sessions.ui.cy.ts | 2 + packages/app/cypress/e2e/runs.cy.ts | 5 +- .../cypress/e2e/commands/querying/root.cy.js | 4 +- .../e2e/commands/querying/within.cy.js | 13 +++- .../driver/src/cy/commands/querying/within.ts | 4 ++ packages/driver/src/cypress/error_messages.ts | 14 +++++ .../launchpad/cypress/e2e/project-setup.cy.ts | 60 ++++++++----------- 7 files changed, 61 insertions(+), 41 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..c17eb3aa5b01 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') @@ -301,6 +302,7 @@ describe('runner/cypress sessions.ui.spec', { validateSessionsInstrumentPanel(['user1']) cy.get('.command-name-session') + .first() .within(() => { cy.contains('failed') diff --git a/packages/app/cypress/e2e/runs.cy.ts b/packages/app/cypress/e2e/runs.cy.ts index 9ce00b553bae..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').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/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..bf25609772bb 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 (using \`.first()\`, for example) 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: { 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 166bf8ebd2fa45b818b3b4b48aafca5c62bd93e2 Mon Sep 17 00:00:00 2001 From: Emily Rohrbough Date: Mon, 5 Dec 2022 16:47:29 -0600 Subject: [PATCH 2/2] chore: tweak splash screen verbiage (#24981) --- packages/launchpad/src/migration/MajorVersionWelcome.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/launchpad/src/migration/MajorVersionWelcome.vue b/packages/launchpad/src/migration/MajorVersionWelcome.vue index 45251846da81..959e67e2c19c 100644 --- a/packages/launchpad/src/migration/MajorVersionWelcome.vue +++ b/packages/launchpad/src/migration/MajorVersionWelcome.vue @@ -54,7 +54,7 @@

- Cypress now has full support for testing multiple domains of different origins in a single test with the + Cypress now has full support for testing multiple origins in a single test with the cy.origin() command! To take a deep-dive into how this works, read our