Skip to content

Commit

Permalink
feat: add support for callback functions (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
bahmutov committed Sep 7, 2022
1 parent 12a1c18 commit 96bbdf2
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 1 deletion.
61 changes: 61 additions & 0 deletions cypress/e2e/callback.cy.js
@@ -0,0 +1,61 @@
// @ts-check

import '../../src'

describe('assertion callback function', () => {
context('predicate', () => {
const isEven = (n) => n % 2 === 0

it('if branch', () => {
cy.wrap(42)
.if(isEven)
.log('even')
.then(cy.spy().as('if'))
.else()
.log('odd')
.then(cy.spy().as('else'))
cy.get('@if').should('have.been.called')
cy.get('@else').should('not.be.called')
})

it('else branch', () => {
cy.wrap(1)
.if(isEven)
.log('even')
.then(cy.spy().as('if'))
.else()
.log('odd')
.then(cy.spy().as('else'))
cy.get('@else').should('have.been.called')
cy.get('@if').should('not.be.called')
})
})

context('Chai assertion', () => {
const is42 = (n) => expect(n).to.equal(42)

it('if branch', () => {
cy.wrap(42)
.if(is42)
.log('even')
.then(cy.spy().as('if'))
.else()
.log('odd')
.then(cy.spy().as('else'))
cy.get('@if').should('have.been.called')
cy.get('@else').should('not.be.called')
})

it('else branch', () => {
cy.wrap(1)
.if(is42)
.log('even')
.then(cy.spy().as('if'))
.else()
.log('odd')
.then(cy.spy().as('else'))
cy.get('@else').should('have.been.called')
cy.get('@if').should('not.be.called')
})
})
})
32 changes: 32 additions & 0 deletions src/index.d.ts
@@ -1,3 +1,15 @@
/**
* A function that returns true if the value is good for "if" branch
* No Cypress commands allowed.
*/
type PredicateFn = (x: any) => boolean

/**
* A function that uses Chai assertions inside.
* No Cypress commands allowed.
*/
type AssertionFn = (x: any) => void

declare namespace Cypress {
interface Chainable {
/**
Expand All @@ -10,6 +22,25 @@ declare namespace Cypress {
* cy.wrap(1).if('equal', 1).should('equal', 1)
*/
if(assertion?: string, value?: any): Chainable<any>

/**
* Child `.if()` command to start an optional chain
* depending on the subject
* @param callback Predicate function (returning a Boolean value)
* @example
* cy.wrap(1).if(n => n % 2 === 0)...
*/
if(callback: PredicateFn): Chainable<any>

/**
* Child `.if()` command to start an optional chain
* depending on the subject
* @param callback Function with Chai assertions
* @example
* cy.wrap(1).if(n => expect(n).to.equal(1))...
*/
if(callback: AssertionFn): Chainable<any>

/**
* Creates new chain of commands that only
* execute if the previous `.if()` command skipped
Expand All @@ -21,6 +52,7 @@ declare namespace Cypress {
* .else().check()
*/
else(): Chainable<any>

/**
* Finishes if/else commands and continues
* with the subject yielded by the original command
Expand Down
13 changes: 12 additions & 1 deletion src/index.js
Expand Up @@ -55,7 +55,18 @@ Cypress.Commands.add(
let assertionsPassed = true
if (hasSubject && assertion) {
try {
if (assertion.startsWith('not') || assertion.startsWith('have')) {
if (Cypress._.isFunction(assertion)) {
const result = assertion(subject)
if (Cypress._.isBoolean(result)) {
// function was a predicate
if (!result) {
throw new Error('Predicate function failed')
}
}
} else if (
assertion.startsWith('not') ||
assertion.startsWith('have')
) {
const parts = assertion.split('.')
let assertionReduced = expect(subject).to
parts.forEach((assertionPart, k) => {
Expand Down

0 comments on commit 96bbdf2

Please sign in to comment.