Easy conditional if-else logic for your Cypress testsDo not use

Overview

cypress-if cypress version ci

Easy conditional if-else logic for your Cypress tests

Tested with cy.get, cy.contains, cy.find, .then, .within commands in Cypress v9 and v10+.

Install

Add this package as a dev dependency

$ npm i -D cypress-if
# or using Yarn
$ yarn add -D cypress-if

Include this package in your spec or support file

import 'cypress-if'

Types for the .if() and .else() commands are described in the src/index.d.ts file.

Use

Let's say, there is a dialog that might sometimes be visible when you visit the page. You can close it by finding it using the cy.get command follows by the .if() command. If the dialog really exists, then all commands chained after .if() run. If the dialog is not found, then the rest of the chain is skipped.

cy.get('dialog#survey').if().contains('button', 'Close').click()

Dialog was open

Assertions

By default, the .if() command just checks the existence of the element returned by the cy.get command. You might use instead a different assertion, like close a dialog if it is visible:

cy.get('dialog#survey').if('visible').contains('button', 'Close').click()

If the dialog was invisible, the visibility assertion fails, and the rest of the commands was skipped

Dialog was closed

You can use assertions with arguments

cy.wrap(42).if('equal', 42)...

You can use assertions with not

cy.get('#enrolled').if('not.checked').check()

Callback function

You can check the value yourself by writing a callback function, similar to the should(callback) and its many examples. You can use predicate and Chai assertions, but you cannot use any Cypress commands inside the callback, since it only synchronously checks the given value.

// predicate function returning a boolean
const isEven = (n) => n % 2 === 0
cy.wrap(42).if(isEven).log('even').else().log('odd')
// a function using Chai assertions
const is42 = (n) => expect(n).to.equal(42)
cy.wrap(42).if(is42).log('42!').else().log('some other number')

For more examples, see the cypress/e2e/callback.cy.js spec

Combining assertions

If you want to right complex assertions that combine other checks using AND, OR connectors, please use a callback function.

// AND predicate using &&
cy.wrap(42).if((n) => n > 20 && n < 50)
// AND connector using Chai "and" connector
cy.wrap(42).if((n) => expect(n).to.be.greaterThan(20).and.to.be.lessThan(50))
// OR predicate using ||
cy.wrap(42).if((n) => n > 20 || n < 10)

Unfortunately, there is no Chai OR connector.

For more examples, see the cypress/e2e/and-or.cy.js spec file

else command

You can chain .else() command that is only executed if the .if() is skipped.

cy.contains('Accept cookies')
  .if('visible')
  .click()
  .else()
  .log('no cookie banner')

The subject from the .if() command will be passed to the .else() chain, this allows you to work with the original element:

cy.get('#enrolled')
  .if('checked')
  .log('**already enrolled**')
  // the checkbox should be passed into .else()
  .else()
  .check()

Multiple commands

Sometimes it makes sense to place the "if" or "else" commands into .then() block

cy.get('#survey')
  .if('visible')
  .then(() => {
    cy.log('closing the survey')
    cy.contains('button', 'Close').click()
  })
  .else()
  .then(() => {
    cy.log('Already closed')
  })

Within

You can attach .within() command to the .if()

cy.get('#survey')
  .if('visible')
  .within(() => {
    // fill the survey
    // click the submit button
  })

finally

You might want to finish if/else command chains and continue afterwards. This is the purpose for the .finally() child command:

cy.get('#agreed')
  .if('not.checked')
  .check()
  .else()
  .log('already checked')
  .finally()
  .should('be.checked')

More examples

Check out the spec files in cypress/e2e folder. If you still have a question, open a GitHub issue.

Debugging

This module uses debug module to output verbose browser console messages when needed. To turn the logging on, open the browser's DevTools console and set the local storage entry:

localStorage.debug = 'cypress-if'

If you re-run the tests, you should see the messages appear in the console

Debug messages in the console

See also

Small print

Author: Gleb Bahmutov <[email protected]> © 2022

License: MIT - do anything with the code, but don't blame me if it does not work.

Support: if you find any problems with this module, email / tweet / open issue on Github

MIT License

Copyright (c) 2022 Gleb Bahmutov <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • Getting error cy.currentSubject is not a function

    Getting error cy.currentSubject is not a function

    Getting error cy.currentSubject is not a function on using the cypress if plugin Cypress Version: 9.6.0

    Below is the sample code:

    	cy.get('div[role="dialog"]')
    			.if('visible')
    			.then(() => {
    				cy.log('closing the dialog');
    				cy.contains('button', 'Close').click();
    			})
    			.else()
    			.then(() => {
    				cy.log('Already closed');
    			});
    

    cypress if

    enhancement released 
    opened by shash-hegde 4
  • Why does it say

    Why does it say "Do not use" in About?

    Why does it say "Do not use" in the About section of this GitHub repository?

    About

    Easy conditional if-else logic for your Cypress testsDo not use

    opened by papb 3
  • Possible issue with overriding

    Possible issue with overriding

    If someone has already overwritten the .get() command, and cypress-if is added afterwards, the user will lose his overwritten changes because this plugin does the same?

    question 
    opened by ktxxt 3
  • Add

    Add "finally"?

    Should we have the .finally() command?

    cy.get('#checkbox')
      .if('not.checked')
      .check()
      .else()
      .log('already checked')
      .finally()
      .should('be.checked')
    
    enhancement question released 
    opened by bahmutov 3
  • Get still fails if element doesnt exist

    Get still fails if element doesnt exist

    I have 3 elements that appear depending on the test that use the locators

    "app-target-taxonomies-toolbar span:nth-child(1) span" "app-target-taxonomies-toolbar span:nth-child(2) span" "app-target-taxonomies-toolbar span:nth-child(3) span"

    i used the below code with your library so that if visible it grabs the text in these elements and wraps them in a variable

            cy.get(app-target-taxonomies-toolbar span:nth-child(1) span").if('visible').invoke('text').then(tagTextDisplayed => {
                cy.wrap(tagTextDisplayed.trim()).as('tagTextDisplayed1').else().log("No tag present")
            })
            cy.get(app-target-taxonomies-toolbar span:nth-child(2) span").if('visible').invoke('text').then(tagTextDisplayed => {
                cy.wrap(tagTextDisplayed.trim()).as('tagTextDisplayed2').else().log("No tag present")
            })
            cy.get(app-target-taxonomies-toolbar span:nth-child(3) span").if('visible').invoke('text').then(tagTextDisplayed => {
                cy.wrap(tagTextDisplayed.trim()).as('tagTextDisplayed3').else().log("No tag present")
            })
    

    In my test only 2 of the 3 tags are displayed

    Expected Results : Find the 2 present tags and wrap the variable , the 1 missing tag is logged as as "No tag present" Actual Result: Finds the 2 present tags but chokes on the missing tag.

    image

    question 
    opened by MassimoLobrutto 2
  • Seems not.exist assertion does not work correctly

    Seems not.exist assertion does not work correctly

    In the example below, it should take the IF path

    it('checks an element that does not exists using not.exist', () => {
      cy.get('#not-found').should('not.exist')
      cy.get('#not-found')
        .if('not.exist')
        .then(cy.spy().as('if'))
        .else()
        .then(cy.spy().as('else'))
      cy.get('@if').should('have.been.calledOnce')
      cy.get('@else').should('not.have.been.called')
    })
    
    bug released 
    opened by bahmutov 2
  • Module parse failed: Unexpected token

    Module parse failed: Unexpected token

    Error: Webpack Compilation Error ./node_modules/cypress-if/src/index.js 3:33 Module parse failed: Unexpected token (3:33) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders | const debug = require('debug')('cypress-if') |

    const isIfCommand = (cmd) => cmd?.attributes?.name === 'if'

    I tried installed debug and require module and that wouldn't fix it. Is there a solution to this problem?

    released 
    opened by hiyunfengzhao 2
  • Added support for xpath

    Added support for xpath

    @bahmutov Thanks for the plugin. I believe adding xpath support will also help users a lot, hence added the required changes for that. Please let me know your thoughts. Thanks, Gurudatt

    opened by gurudattgd04 2
  • Determine the end of the chain correctly

    Determine the end of the chain correctly

    Currently stops at the command with type: parent but that is not too accurate, since some commands are dual

    cy.get('[htmlfor="toggle-all"]')
      .if('visible')
      .click()
      .get('.clear-completed')
      .click()
      .else()
      .log('**nothing to complete**');
    

    Here I expect the "if" branch to stop at "else()" but it stops at "get" and thus executes the .get('.clear-completed') command

    Screen Shot 2022-08-31 at 09 22 35 released 
    opened by bahmutov 2
  • chore(deps): update dependency cypress to v11

    chore(deps): update dependency cypress to v11

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | cypress | 10.11.0 -> 11.0.1 | age | adoption | passing | confidence |


    Release Notes

    cypress-io/cypress

    v11.0.1

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​11-0-1

    v11.0.0

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​11-0-0


    Configuration

    📅 Schedule: Branch creation - "after 10pm every weekday,every weekend,before 5am every weekday" (UTC), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    released type: dependencies renovate 
    opened by renovate[bot] 1
  • Unable to use if('exist') in cy.xpath()

    Unable to use if('exist') in cy.xpath()

    I am trying to use cypress-if for validating whether the element is present or not using XPath. In some cases, it is hard to write CSS selectors as compared to XPath. Upon trying the same with XPath, we are getting 'element not found error' when it is not present, but it is working fine when it is present. Since the test case trying to achieve when the element is not found I need to update something else. Below is my sample code.

     cy.xpath(objects[page][locator]).if('exist').then(()=>{
                    cy.log('locator Exists')
            }).else().then(()=>{
                    cy.log('Locator Not Exists')
            })
    
    released 
    opened by naveensivakumar013 1
  • chore(deps): update dependency cypress to v12

    chore(deps): update dependency cypress to v12

    Mend Renovate

    This PR contains the following updates:

    | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | cypress | 11.2.0 -> 12.2.0 | age | adoption | passing | confidence |


    Release Notes

    cypress-io/cypress

    v12.2.0

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​12-2-0

    v12.1.0

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​12-1-0

    v12.0.2

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​12-0-2

    v12.0.1

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​12-0-1

    v12.0.0

    Compare Source

    Changelog: https://docs.cypress.io/guides/references/changelog#​12-0-0


    Configuration

    📅 Schedule: Branch creation - "after 10pm every weekday,every weekend,before 5am every weekday" (UTC), Automerge - At any time (no schedule defined).

    🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

    Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

    🔕 Ignore: Close this PR and you won't be reminded about this update again.


    • [ ] If you want to rebase/retry this PR, check this box

    This PR has been generated by Mend Renovate. View repository job log here.

    type: dependencies renovate 
    opened by renovate[bot] 0
  • will this work in before hooks and in custom commands?

    will this work in before hooks and in custom commands?

    I'm trying to detect if I'm logged in and if so, log out in a before hook. I put it in my custom login command. It's failing when it can't find an element (which I would think would just continue to the then())

    question 
    opened by bgk17 4
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    Open

    These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

    Detected dependencies

    github-actions
    .github/workflows/badges.yml
    .github/workflows/ci.yml
    • cypress-io/github-action v4
    • cypress-io/github-action v4
    • cypress-io/github-action v4
    • cypress-io/github-action v4
    npm
    package.json
    • debug ^4.3.4
    • cypress 11.2.0

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
Releases(v1.10.2)
Owner
Gleb Bahmutov
JavaScript ninja, image processing expert, software quality fanatic. Sr Director of Engineering at Mercari US. MS MVP for OSS work, GitHub Star.
Gleb Bahmutov
Cypress commands are asynchronous. It's a common pattern to use a then callback to get the value of a cypress command

cypress-thenify Rationale Cypress commands are asynchronous. It's a common pattern to use a then callback to get the value of a cypress command. Howev

Mikhail Bolotov 15 Oct 2, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Annotation tools for the web. Select text, images, or (nearly) anything else, and add your notes.

Annotator Annotator is a JavaScript library for building annotation applications in browsers. It provides a set of interoperable tools for annotating

Open Annotation 2.6k Dec 23, 2022
Kirby Conditional Blocks plugin

Kirby 3 plugin: disables blocks in layout fields when the column width does not match the block requirements

Roman Steiner 13 Dec 21, 2022
Sachit Yadav 6 Nov 3, 2022
Context-carrying logger with conditional methods.

logger Provides a simple logging interface as well as a LogContext class which carries a context around. Installation npm install @rocicorp/logger Us

Rocicorp 9 May 20, 2022
The docs for PizzaPlace. What else?

Website This website is built using Docusaurus 2, a modern static website generator. Installation $ yarn Local Development $ yarn start This command

PizzaPlace Developers 3 Oct 10, 2022
Keep your Business Logic appart from your actions/loaders plumbing

Remix Domains Remix Domains helps you to keep your Business Logic appart from your actions/loaders plumbing. It does this by enforcing the parameters'

Seasoned 290 Jan 2, 2023
A "Basic-to-Lisp" compiler. But Basic is not real Basic, and Lisp is not real Lisp.

Basic2Lisp A "Basic-to-Lisp" compiler. But Basic is not real Basic, and Lisp is not real Lisp. Syntax Print-Sth Put some-value to standard output. PRI

Hana Yabuki 5 Jul 10, 2022
🧩 TypeScript utility type in order to ensure to return only properties (not methods) containing values in primitive types such as number or boolean (not Value Objects)

?? TypeScript Primitives type TypeScript utility type in order to ensure to return only properties (not methods) containing values in primitive types

CodelyTV 82 Dec 7, 2022
A template for your Next.js projects including Typescript, Eslint, Prettier, Jest, Cypress and Docker.

Next.js Template Quickly start a new Next.js project A template for your Next.js projects including Typescript, Eslint, Prettier, Jest, Cypress and Do

Lorenzo Carneli 2 Oct 7, 2022
Build redux logic, without getting nervous 😬

Redux Cool Build redux logic, without getting nervous ?? Description Redux Cool is an awesome tiny package that allows you to easily and intuitively w

Redux Cool 24 Nov 3, 2022
An inheritable and strong logic template front-end mvvm framework.

Intact 文档 Documents 简介 Intact作为一个可继承,并且拥有强逻辑模板的前端MVVM框架,有着如下特色: 充分利用组合与继承的思想,来最高限度地复用代码 同时支持数据驱动和组件实例化调用,来最便捷地实现功能 强逻辑模板,赋予模板更多功能和职责,来完成业务逻辑和表现逻辑分离 安装

Javey 55 Oct 21, 2022
Kasada's p.js partially deobfuscated, still has VM logic

Kasada's p.js Deobfuscated The script was obfuscated by replacing most strings with a function to grab the string from an array and decode it. Ex: _0x

null 11 Nov 9, 2022
Play logic games and claim exclusive NFTs!

Bit Gaming Samruk Hackathon Winner ?? Play-to-earn DAO with exclusive NFT collection Idea We are bringing together curious minds and reward them with

Temirzhan Yussupov 3 Jun 21, 2022