Skip to content

Commit

Permalink
feat: add Cypress.Commands.overwriteQuery (#25674)
Browse files Browse the repository at this point in the history
* feat: add Cypress.Commands.overwriteQuery

Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
Co-authored-by: Zach Bloomquist <git@chary.us>
  • Loading branch information
3 people committed Feb 13, 2023
1 parent 0acdd2c commit a11e266
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 16 deletions.
3 changes: 2 additions & 1 deletion cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
## 12.6.0

_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). 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).
- Added a new CLI flag, called [`--auto-cancel-after-failures`](https://docs.cypress.io/guides/guides/command-line#Options), that overrides the project-level CI ["Auto Cancellation"](https://docs.cypress.io/guides/cloud/smart-orchestration#Auto-Cancellation) value when recording to the Cloud. This gives Cloud users on Business and Enterprise plans the flexibility to alter the auto-cancellation value per run. Addressed in [#25237](https://github.com/cypress-io/cypress/pull/25237).
- Added `Cypress.require()` for including dependencies within the `cy.origin()` callback. Removed support for `require()` and `import()` within the callback. Addresses [#24976](https://github.com/cypress-io/cypress/issues/24976).
Expand Down
9 changes: 9 additions & 0 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ declare namespace Cypress {
interface QueryFn<T extends keyof ChainableMethods> {
(this: Command, ...args: Parameters<ChainableMethods[T]>): (subject: any) => any
}
interface QueryFnWithOriginalFn<T extends keyof Chainable> {
(this: Command, originalFn: QueryFn<T>, ...args: Parameters<ChainableMethods[T]>): (subject: any) => any
}
interface ObjectLike {
[key: string]: any
}
Expand Down Expand Up @@ -648,6 +651,12 @@ declare namespace Cypress {
* @see https://on.cypress.io/api/custom-queries
*/
addQuery<T extends keyof Chainable>(name: T, fn: QueryFn<T>): void

/**
* Overwrite an existing Cypress query with a new implementation
* @see https://on.cypress.io/api/custom-queries
*/
overwriteQuery<T extends keyof Chainable>(name: T, fn: QueryFnWithOriginalFn<T>): void
}

/**
Expand Down
49 changes: 49 additions & 0 deletions packages/driver/cypress/e2e/cypress/cy.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
})
})
})
40 changes: 29 additions & 11 deletions packages/driver/src/cypress/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -157,13 +155,13 @@ 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)
internalError('miscellaneous.reserved_command_query', { name })
}

if (cy[name]) {
internalError('miscellaneous.invalid_new_query', name)
internalError('miscellaneous.invalid_new_query', { name })
}

if (addingBuiltIns) {
Expand All @@ -173,6 +171,26 @@ export default {
queries[name] = fn
cy.addQuery({ name, fn })
},

overwriteQuery (name: string, fn: (...args: any[]) => 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) {
args.unshift(original)

return fn.apply(this, args)
}

cy.addQuery({ name, fn: queries[name] })
},
}

addingBuiltIns = true
Expand Down
12 changes: 8 additions & 4 deletions packages/driver/src/cypress/error_messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -862,12 +862,16 @@ 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.',
docsUrl: 'https://on.cypress.io/api',
message: 'Cannot overwite command for: `{{name}}`. An existing {{type}} does not exist by that name.',
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/custom-commands',
},
invalid_overwrite_query_with_command: {
message: 'Cannot overwite the `{{name}}` query. Queries cannot be overwritten.',
docsUrl: 'https://on.cypress.io/api',
message: 'Cannot overwite the `{{name}}` query. Queries can only be overwritten with `Cypress.Commands.overwriteQuery()`.',
docsUrl: 'https://on.cypress.io/api/custom-queries',
},
invoking_child_without_parent (obj) {
return stripIndent`\
Expand Down

5 comments on commit a11e266

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a11e266 Feb 13, 2023

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 arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/linux-arm64/develop-a11e266b8b4c7d22c58d429e3e047311f4990308/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a11e266 Feb 13, 2023

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 build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/linux-x64/develop-a11e266b8b4c7d22c58d429e3e047311f4990308/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a11e266 Feb 13, 2023

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 build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/darwin-x64/develop-a11e266b8b4c7d22c58d429e3e047311f4990308/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a11e266 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/win32-x64/develop-a11e266b8b4c7d22c58d429e3e047311f4990308/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on a11e266 Feb 13, 2023

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 arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/darwin-arm64/develop-a11e266b8b4c7d22c58d429e3e047311f4990308/cypress.tgz

Please sign in to comment.