mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-30 03:51:21 -05:00
feat: add Cypress.Commands.overwriteQuery (#25674)
* feat: add Cypress.Commands.overwriteQuery Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com> Co-authored-by: Zach Bloomquist <git@chary.us>
This commit is contained in:
+2
-1
@@ -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).
|
||||
|
||||
Vendored
+9
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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
|
||||
|
||||
@@ -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`\
|
||||
|
||||
Reference in New Issue
Block a user