From 4802ab92825dd7b6cabae9fb777db8f162ca4dd9 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Wed, 1 Feb 2023 12:11:39 -0800 Subject: [PATCH 1/8] feat: add Cypress.Commands.overwriteQuery --- packages/driver/cypress/e2e/cypress/cy.cy.js | 49 +++++++++++++++++++ packages/driver/src/cypress/commands.ts | 36 ++++++++++---- packages/driver/src/cypress/error_messages.ts | 8 ++- 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/packages/driver/cypress/e2e/cypress/cy.cy.js b/packages/driver/cypress/e2e/cypress/cy.cy.js index fd7f5291d006..52aa44df2b6d 100644 --- a/packages/driver/cypress/e2e/cypress/cy.cy.js +++ b/packages/driver/cypress/e2e/cypress/cy.cy.js @@ -565,5 +565,54 @@ describe('driver/src/cypress/cy', () => { cy.get('body').find('#specific-contains').children().should('have.class', 'active') }) + + context('overwriting queries', () => { + it('does not allow commands to overwrite queries', () => { + const fn = () => Cypress.Commands.overwrite('get', () => {}) + + expect(fn).to.throw().with.property('message') + .and.include('Cannot overwite the `get` query. Queries can only be overwritten with `Cypress.Commands.overwriteQuery()`.') + + expect(fn).to.throw().with.property('docsUrl') + .and.include('https://on.cypress.io/api') + }) + + it('does not allow queries to overwrite commands', () => { + const fn = () => Cypress.Commands.overwriteQuery('click', () => {}) + + expect(fn).to.throw().with.property('message') + .and.include('Cannot overwite the `click` command. Commands can only be overwritten with `Cypress.Commands.overwrite()`.') + + expect(fn).to.throw().with.property('docsUrl') + .and.include('https://on.cypress.io/api') + }) + + it('can call the originalFn', () => { + // Ensure nothing gets confused when we overwrite the same query multiple times. + // Both overwrites should succeed, layered on top of each other. + + let overwriteCalled = 0 + + Cypress.Commands.overwriteQuery('get', function (originalFn, ...args) { + overwriteCalled++ + + return originalFn.call(this, ...args) + }) + + let secondOverwriteCalled = 0 + + Cypress.Commands.overwriteQuery('get', function (originalFn, ...args) { + secondOverwriteCalled++ + + return originalFn.call(this, ...args) + }) + + cy.get('button').should('have.length', 24) + cy.then(() => { + expect(overwriteCalled).to.eq(1) + expect(secondOverwriteCalled).to.eq(1) + }) + }) + }) }) }) diff --git a/packages/driver/src/cypress/commands.ts b/packages/driver/src/cypress/commands.ts index c4e51904bafa..44e4532d09ca 100644 --- a/packages/driver/src/cypress/commands.ts +++ b/packages/driver/src/cypress/commands.ts @@ -27,11 +27,9 @@ const getTypeByPrevSubject = (prevSubject) => { return 'parent' } -const internalError = (path, name) => { +const internalError = (path, args) => { $errUtils.throwErrByPath(path, { - args: { - name, - }, + args, stack: (new cy.state('specWindow').Error('add command stack')).stack, errProps: { appendToStack: { @@ -88,11 +86,11 @@ export default { add (name, options, fn) { if (builtInCommandNames[name]) { - internalError('miscellaneous.invalid_new_command', name) + internalError('miscellaneous.invalid_new_command', { name }) } if (reservedCommandNames.has(name)) { - internalError('miscellaneous.reserved_command', name) + internalError('miscellaneous.reserved_command', { name }) } // .hover & .mount are special case commands. allow as builtins so users @@ -126,11 +124,11 @@ export default { const original = commands[name] if (queries[name]) { - internalError('miscellaneous.invalid_overwrite_query_with_command', name) + internalError('miscellaneous.invalid_overwrite_query_with_command', { name }) } if (!original) { - internalError('miscellaneous.invalid_overwrite', name) + internalError('miscellaneous.invalid_overwrite', { name, type: 'command' }) } function originalFn (...args) { @@ -159,11 +157,11 @@ export default { addQuery (name: string, fn: () => QueryFunction) { if (reservedCommandNames.has(name)) { - internalError('miscellaneous.reserved_command_query', name) + internalError('miscellaneous.reserved_command_query', { name }) } if (cy[name]) { - internalError('miscellaneous.invalid_new_query', name) + internalError('miscellaneous.invalid_new_query', { name }) } if (addingBuiltIns) { @@ -173,6 +171,24 @@ export default { queries[name] = fn cy.addQuery({ name, fn }) }, + + overwriteQuery (name: string, fn: () => QueryFunction) { + if (commands[name]) { + internalError('miscellaneous.invalid_overwrite_command_with_query', { name }) + } + + const original = queries[name] + + if (!original) { + internalError('miscellaneous.invalid_overwrite', { name, type: 'command' }) + } + + queries[name] = function overridden (...args) { + return fn.call(this, original, ...args) + } + + cy.addQuery({ name, fn: queries[name] }) + }, } addingBuiltIns = true diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index f89958dd2d8a..b65c3d58e6a5 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -862,11 +862,15 @@ export default { docsUrl: 'https://on.cypress.io/api/custom-queries', }, invalid_overwrite: { - message: 'Cannot overwite command for: `{{name}}`. An existing command does not exist by that name.', + message: 'Cannot overwite command for: `{{name}}`. An existing {{type}} does not exist by that name.', + docsUrl: 'https://on.cypress.io/api', + }, + invalid_overwrite_command_with_query: { + message: 'Cannot overwite the `{{name}}` command. Commands can only be overwritten with `Cypress.Commands.overwrite()`.', docsUrl: 'https://on.cypress.io/api', }, invalid_overwrite_query_with_command: { - message: 'Cannot overwite the `{{name}}` query. Queries cannot be overwritten.', + message: 'Cannot overwite the `{{name}}` query. Queries can only be overwritten with `Cypress.Commands.overwriteQuery()`.', docsUrl: 'https://on.cypress.io/api', }, invoking_child_without_parent (obj) { From 27c666ab8fa7c015f3c981b0583866f637d93d43 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Wed, 1 Feb 2023 12:29:59 -0800 Subject: [PATCH 2/8] Add changelog entry --- cli/CHANGELOG.md | 8 ++++++-- packages/driver/src/cypress/error_messages.ts | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 15c3204b027f..19dac860b1f6 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,8 +1,12 @@ - -## 12.5.1 + +## 12.6.0 _Released 02/10/2023 (PENDING)_ +**Features:** + +- It is now possible to overwrite query commands using the newly added `Cypress.Commands.overwriteQuery`. See [the docs](https://on.cypress.io/api/custom-queries) for details. + **Dependency Updates:** - Upgraded [`simple-git`](https://github.com/steveukx/git-js) from `3.15.0` to `3.16.0` to address this [security vulnerability](https://github.com/advisories/GHSA-9p95-fxvg-qgq2) where Remote Code Execution (RCE) via the clone(), pull(), push() and listRemote() methods due to improper input sanitization was possible. Addressed in [#25603](https://github.com/cypress-io/cypress/pull/25603). diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index b65c3d58e6a5..32d4e0d40ad2 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -863,15 +863,15 @@ export default { }, invalid_overwrite: { message: 'Cannot overwite command for: `{{name}}`. An existing {{type}} does not exist by that name.', - docsUrl: 'https://on.cypress.io/api', + docsUrl: 'https://on.cypress.io/api/custom-commands', }, invalid_overwrite_command_with_query: { message: 'Cannot overwite the `{{name}}` command. Commands can only be overwritten with `Cypress.Commands.overwrite()`.', - docsUrl: 'https://on.cypress.io/api', + docsUrl: 'https://on.cypress.io/api/custom-commands', }, invalid_overwrite_query_with_command: { message: 'Cannot overwite the `{{name}}` query. Queries can only be overwritten with `Cypress.Commands.overwriteQuery()`.', - docsUrl: 'https://on.cypress.io/api', + docsUrl: 'https://on.cypress.io/api/custom-queries', }, invoking_child_without_parent (obj) { return stripIndent`\ From 9eaa13214df6fc45fbe82f40728b7764bdbd1f97 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Wed, 1 Feb 2023 12:44:53 -0800 Subject: [PATCH 3/8] Add types for overwriteQuery --- cli/types/cypress.d.ts | 9 +++++++++ packages/driver/src/cypress/commands.ts | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 6aa84eb495a8..b03dc9a0466b 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -53,6 +53,9 @@ declare namespace Cypress { interface QueryFn { (this: Command, ...args: Parameters): (subject: any) => any } + interface QueryFnWithOriginalFn { + (this: Command, originalFn: QueryFn, ...args: Parameters): (subject: any) => any + } interface ObjectLike { [key: string]: any } @@ -648,6 +651,12 @@ declare namespace Cypress { * @see https://on.cypress.io/api/custom-queries */ addQuery(name: T, fn: QueryFn): void + + /** + * Overwrite an existing Cypress query with a new implementation + * @see https://on.cypress.io/api/custom-queries + */ + overwriteQuery(name: T, fn: QueryFnWithOriginalFn): void } /** diff --git a/packages/driver/src/cypress/commands.ts b/packages/driver/src/cypress/commands.ts index 44e4532d09ca..75e4f2566a83 100644 --- a/packages/driver/src/cypress/commands.ts +++ b/packages/driver/src/cypress/commands.ts @@ -184,7 +184,9 @@ export default { } queries[name] = function overridden (...args) { - return fn.call(this, original, ...args) + args.unshift(original) + + return fn.apply(this, args) } cy.addQuery({ name, fn: queries[name] }) From 151a71f0bb7e1177c346a6842f60906e8a085dd4 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Wed, 1 Feb 2023 13:13:49 -0800 Subject: [PATCH 4/8] Fix changelog entry --- cli/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 19dac860b1f6..721dd5faa6bc 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,7 +5,7 @@ _Released 02/10/2023 (PENDING)_ **Features:** -- It is now possible to overwrite query commands using the newly added `Cypress.Commands.overwriteQuery`. See [the docs](https://on.cypress.io/api/custom-queries) for details. +- It is now possible to overwrite query commands using the newly added `Cypress.Commands.overwriteQuery`. See [the docs](https://on.cypress.io/api/custom-queries) for details. Addressed in [#25674](https://github.com/cypress-io/cypress/pull/25674). **Dependency Updates:** From bc6b29c6b9c71c1b625bcead4cbd164ff1cb5349 Mon Sep 17 00:00:00 2001 From: Blue F Date: Wed, 1 Feb 2023 13:55:30 -0800 Subject: [PATCH 5/8] Update cli/CHANGELOG.md Co-authored-by: Emily Rohrbough --- cli/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 721dd5faa6bc..676ac080a4d1 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,7 +5,7 @@ _Released 02/10/2023 (PENDING)_ **Features:** -- It is now possible to overwrite query commands using the newly added `Cypress.Commands.overwriteQuery`. See [the docs](https://on.cypress.io/api/custom-queries) for details. Addressed in [#25674](https://github.com/cypress-io/cypress/pull/25674). +- It is now possible to overwrite query commands using [`Cypress.Commands.overwriteQuery`](https://on.cypress.io/api/custom-queries). Addresses [#25078](https://github.com/cypress-io/cypress/issues/25078). **Dependency Updates:** From 2890d7051b7b067fcef1b9d2ec118dafdf22e0f5 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 6 Feb 2023 10:06:00 -0800 Subject: [PATCH 6/8] TS fix --- packages/driver/src/cypress/commands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/driver/src/cypress/commands.ts b/packages/driver/src/cypress/commands.ts index 75e4f2566a83..36bf924f3085 100644 --- a/packages/driver/src/cypress/commands.ts +++ b/packages/driver/src/cypress/commands.ts @@ -155,7 +155,7 @@ export default { return cy.addCommand(overridden) }, - addQuery (name: string, fn: () => QueryFunction) { + addQuery (name: string, fn: (...args: any[]) => QueryFunction) { if (reservedCommandNames.has(name)) { internalError('miscellaneous.reserved_command_query', { name }) } @@ -172,7 +172,7 @@ export default { cy.addQuery({ name, fn }) }, - overwriteQuery (name: string, fn: () => QueryFunction) { + overwriteQuery (name: string, fn: (...args: any[]) => QueryFunction) { if (commands[name]) { internalError('miscellaneous.invalid_overwrite_command_with_query', { name }) } From 58e19c7b4c8cdf03a32a9e6825d8eea76ce9b49c Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 6 Feb 2023 11:04:05 -0800 Subject: [PATCH 7/8] Changelog fix --- cli/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 589e819896c0..0eea25b913e3 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,7 +5,7 @@ _Released 02/14/2023 (PENDING)_ **Features:** -- It is now possible to overwrite query commands using [`Cypress.Commands.overwriteQuery`](https://on.cypress.io/api/custom-queries). Addresses [#25078](https://github.com/cypress-io/cypress/issues/25078). +- It is now possible to overwrite query commands using [`Cypress.Commands.overwriteQuery`](https://on.cypress.io/api/custom-queries). Addressed in [#25674](https://github.com/cypress-io/cypress/pull/25674). - Added the "Open in IDE" feature for failed tests reported from the Debug page. Addressed in [#25691](https://github.com/cypress-io/cypress/pull/25691). **Misc:** From 132745249c5e7b502765ef8f5cc565ecffbbb73c Mon Sep 17 00:00:00 2001 From: Blue F Date: Wed, 8 Feb 2023 09:24:52 -0800 Subject: [PATCH 8/8] Update cli/CHANGELOG.md Co-authored-by: Zach Bloomquist --- cli/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 66521a23f7b6..374887234d8b 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -25,7 +25,6 @@ _Released 02/10/2023_ - Fixed a regression introduced in Cypress [12.5.0](https://docs.cypress.io/guides/references/changelog#12-5-0) where the `runnable` was not included in the [`test:after:run`](https://docs.cypress.io/api/events/catalog-of-events) event. Fixes [#25663](https://github.com/cypress-io/cypress/issues/25663). - **Dependency Updates:** - Upgraded [`simple-git`](https://github.com/steveukx/git-js) from `3.15.0` to `3.16.0` to address this [security vulnerability](https://github.com/advisories/GHSA-9p95-fxvg-qgq2) where Remote Code Execution (RCE) via the clone(), pull(), push() and listRemote() methods due to improper input sanitization was possible. Addressed in [#25603](https://github.com/cypress-io/cypress/pull/25603).