From 66bd158e309c13a5fc6e739c04c8b637c7fc82d4 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Mon, 17 Oct 2022 22:25:50 -0400 Subject: [PATCH] feat: add cy.raise (#44) ## raise This plugin includes a utility custom command `cy.raise` that lets you conveniently throw an error. ```js cy.get('li').if('not.have.length', 3).raise('Wrong number of todos') ``` **Tip:** the above syntax works, but you better pass an Error instance rather than a string to get the exact stack trace location ```js cy.get('li').if('not.have.length', 3).raise(new Error('Wrong number of todos')) ``` --- README.md | 14 +++++++ cypress/e2e/raise-error.cy.js | 72 +++++++++++++++++++++++++++++++++++ src/index.d.ts | 9 +++++ src/index.js | 12 ++++++ 4 files changed, 107 insertions(+) create mode 100644 cypress/e2e/raise-error.cy.js diff --git a/README.md b/README.md index 6d8e591..e563245 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,20 @@ cy.wrap(42).if('not.null') // takes IF path See spec [null.cy.js](./cypress/e2e/null.cy.js) +## raise + +This plugin includes a utility custom command `cy.raise` that lets you conveniently throw an error. + +```js +cy.get('li').if('not.have.length', 3).raise('Wrong number of todos') +``` + +**Tip:** the above syntax works, but you better pass an Error instance rather than a string to get the exact stack trace location + +```js +cy.get('li').if('not.have.length', 3).raise(new Error('Wrong number of todos')) +``` + ## More examples Check out the spec files in [cypress/e2e](./cypress/e2e/) folder. If you still have a question, [open a GitHub issue](https://github.com/bahmutov/cypress-if/issues). diff --git a/cypress/e2e/raise-error.cy.js b/cypress/e2e/raise-error.cy.js new file mode 100644 index 0000000..7a9a784 --- /dev/null +++ b/cypress/e2e/raise-error.cy.js @@ -0,0 +1,72 @@ +/// +// @ts-check + +import '../../src' + +it('raises an error if wrong number of elements', () => { + // prevent ".raise" from failing the test + Cypress.Commands.overwrite('raise', cy.stub().as('raise')) + + cy.visit('cypress/index.html') + // we have 3 items + cy.get('#fruits li').should('have.length', 3) + // force an error + cy.get('#fruits li') + .if('have.length', 1) + .then(cy.spy().as('if')) + .log('right number of elements') + .else() + .log('too many elements') + .then(cy.spy().as('else')) + .raise('Too many elements') + cy.get('@else').should('have.been.calledOnce') + cy.get('@if').should('not.have.been.called') +}) + +it('raises an error if not the right number of elements', () => { + // prevent ".raise" from failing the test + Cypress.Commands.overwrite('raise', cy.stub().as('raise')) + + cy.visit('cypress/index.html') + // we have 3 items + cy.get('#fruits li').should('have.length', 3) + // force an error + cy.get('#fruits li') + .if('not.have.length', 1) + .log('wrong number of items') + .then(cy.spy().as('else')) + .raise('Too many elements') + cy.get('@else').should('have.been.calledOnce') +}) + +it('raises an error instance', () => { + // prevent ".raise" from failing the test + Cypress.Commands.overwrite('raise', cy.stub().as('raise')) + + cy.visit('cypress/index.html') + // we have 3 items + cy.get('#fruits li').should('have.length', 3) + // force an error + cy.get('#fruits li') + .if('not.have.length', 1) + .log('wrong number of items') + .then(cy.spy().as('else')) + // when using an Error instance (and not a string) + // the error stack will point at this spec location + .raise(new Error('Too many elements')) + cy.get('@else').should('have.been.calledOnce') +}) + +it.skip('raises an error if element does not exist', () => { + // prevent ".raise" from failing the test + Cypress.Commands.overwrite('raise', cy.stub().as('raise')) + + cy.visit('cypress/index.html') + // force an error + cy.get('#does-not-exist') + .if('not.exist') + .log('no such element') + .then(cy.spy().as('else')) + .raise('Cannot find it') + cy.get('@else').should('have.been.calledOnce') +}) diff --git a/src/index.d.ts b/src/index.d.ts index 7577fd1..55b572f 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -64,5 +64,14 @@ declare namespace Cypress { * .finally().should('be.checked') */ finally(): Chainable + + /** + * A simple way to throw an error + * @example + * cy.get('li') + * .if('not.have.length', 3) + * .raise('wrong number of todo items') + */ + raise(x: string | Error): Chainable } } diff --git a/src/index.js b/src/index.js index 4ec6243..2b636f6 100644 --- a/src/index.js +++ b/src/index.js @@ -321,3 +321,15 @@ Cypress.Commands.overwrite('task', function (task, args, options) { return task(args, options) }) + +Cypress.Commands.add('raise', (x) => { + if (Cypress._.isError(x)) { + throw x + } + const e = new Error( + String(x) + + '\n' + + 'cypress-if tip: pass an error instance to have correct stack', + ) + throw e +})