Skip to content

feat: add no-add rule to disallow .and() in favor of .should()#310

Open
todd-m-kemp wants to merge 2 commits intocypress-io:masterfrom
todd-m-kemp:tk/new-rule-no-and
Open

feat: add no-add rule to disallow .and() in favor of .should()#310
todd-m-kemp wants to merge 2 commits intocypress-io:masterfrom
todd-m-kemp:tk/new-rule-no-and

Conversation

@todd-m-kemp
Copy link
Copy Markdown

@todd-m-kemp todd-m-kemp commented Mar 27, 2026

Description

Add no-add rule to disallow .and() in favour of .should().

Cypress's .and() is an alias for .should(). This rule enforces consistent use of .should() across Cypress test chains, and includes an auto-fixer that replaces .and() with .should() automatically.

Changes:

  • lib/rules/no-add.js — new rule implementation with rootIsCy traversal to correctly identify Cypress chains
  • tests/lib/rules/no-add.js — 20 tests covering valid and invalid cases including nested .within(), .then(), long chains, multiple .and() calls, and non-cy roots
  • docs/rules/no-add.md — rule documentation
  • lib/index.js — rule registered in plugin index

Motivation

We often see folks write code that looks something like this:

cy.get('elem')
  .should('be.visible')
  .and('have.text', 'blah')
  .click();

and after a PR review tells them that they don't need to explicitly check for visibility since they are clicking the element, they delete the visibility assertion and we end up with code that looks like this:

cy.get('elem')
  .and('have.text', 'blah')
  .click();

which is functional, but doesn't read well. To avoid code that looks like this, we would just like to disallow the use of .and() suite-wide so that the use of .should() is required.


Note

Low Risk
Adds an opt-in lint rule with a straightforward string replacement auto-fix, with scope limited to Cypress-rooted call chains and covered by unit tests.

Overview
Adds a new cypress/no-and rule that reports .and() calls specifically within Cypress command chains and provides an auto-fix that rewrites .and(...) to .should(...).

Registers the rule in the plugin index, adds rule docs, and introduces a dedicated test suite covering both Cypress and non-Cypress call chains (including nested/long chains and multiple .and() occurrences).

Written by Cursor Bugbot for commit b722323. This will update automatically on new commits. Configure here.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 27, 2026

CLA assistant check
All committers have signed the CLA.

@cypress-app-bot
Copy link
Copy Markdown

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment on lines +34 to +51
function rootIsCy(node) {
let current = node.callee.object
while (current) {
if (current.type === 'Identifier' && current.name === 'cy') {
return true
}
if (current.type === 'CallExpression') {
current = current.callee.object
}
else if (current.type === 'MemberExpression') {
current = current.object
}
else {
break
}
}
return false
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I was looking at other PRs and came across this comment.

The approach I took here works and is suitable for this use case but for code cleanliness reasons I expect that I should just use that approach instead. It's likely worth waiting for that to work to be completed and merged in and updating accordingly here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants