Socket
Socket
Sign inDemoInstall

eslint-plugin-cypress

Package Overview
Dependencies
2
Maintainers
3
Versions
42
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.2.0 to 3.3.0

jest.config-legacy.js

54

CONTRIBUTING.md

@@ -5,13 +5,47 @@ # Contributing to cypress-io/eslint-plugin-cypress

## Preparation
* Fork and clone this repository
* Branch from the default `master` branch using a descriptive new branch name
* Install dependencies with `npm ci`
## Rule references
* Refer to the [ESLint documentation](https://eslint.org/docs/latest/) and the [Custom Rules](https://eslint.org/docs/latest/extend/custom-rules) page
## New rule
To add a new rule:
* Fork and clone this repository
* Generate a new rule (a [yeoman generator](https://github.com/eslint/generator-eslint) is available)
* Write test scenarios then implement logic
* Describe the rule in the generated `docs` file
* Run `npm test` to run [Jest](https://jestjs.io/) or
* Run `npm start` to run [Jest](https://jestjs.io/) in [watchAll](https://jestjs.io/docs/cli#--watchall) mode where it remains active and reruns when source changes are made
* Make sure all tests are passing
* Add the rule to the [README](README.md) file
* Create a PR
Use the following commit message conventions: https://github.com/semantic-release/semantic-release#commit-message-format
* Follow the instructions in the ESLint [generator-eslint](https://www.npmjs.com/package/generator-eslint) documentation to install [Yeoman](https://www.npmjs.com/package/yo) and the generator
* Run the new rule generator `yo eslint:rule` and answer the questions
- select "ESLint Plugin"
- for "Type a short description of this rule" provide text which starts with one of "enforce", "require" or "disallow" (all lower case)
* Yeoman creates three boilerplate files:
- `docs/rules/<rule-id>.md`
- `lib/rules/<rule-id>.js`
- `test/rules/<rule-id>.js`
* Run `npm run lint-fix`
* Address the linting errors by editing `lib/rules/<rule-id>.js`
- Add a `meta.messages` property (see [MessageIds](https://eslint.org/docs/latest/extend/custom-rules#messageids))
- Select the appropriate `meta.type` property using `problem`, `suggestion`, or `layout`
* Complete the new rule by adding content to the three files previously created
* Run `eslint-doc-generator` to generate automated documentation sections (see [Document generation](#document-generation) below)
* Review documentation changes
* Run `npm run lint`
* Run `npm test` to run [Jest](https://jestjs.io/) (or run `npm start` to run [Jest](https://jestjs.io/) in [watchAll](https://jestjs.io/docs/cli#--watchall) mode where it remains active and reruns when source changes are made)
* Make sure all tests are passing
* Add the rule to [legacy.js](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/legacy.js) and to [flat.js](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/lib/flat.js)
* Create a git commit with a commit message similar to: `feat: add rule <description>` (see [commit message conventions](https://github.com/semantic-release/semantic-release#commit-message-format))
* Create a PR from your branch
## Document generation
This plugin uses the ESLint [eslint-doc-generator](https://www.npmjs.com/package/eslint-doc-generator) to generate consistent documentation.
* Install with `npm install eslint-doc-generator -g`
* Run `eslint-doc-generator` in the root directory of the plugin
## Legacy tests
* The directory [tests-legacy](https://github.com/cypress-io/eslint-plugin-cypress/tree/master/tests-legacy) contains tests which are compatible with the legacy [ESLint v8 RuleTester](https://eslint.org/docs/v8.x/integrate/nodejs-api#ruletester) utility. It is not expected to add new rules to this set of tests.
* The directory [tests](https://github.com/cypress-io/eslint-plugin-cypress/tree/master/tests) is for tests compatible with the current [ESLint RuleTester](https://eslint.org/docs/latest/integrate/nodejs-api#ruletester).

126

FLAT-CONFIG.md

@@ -13,3 +13,3 @@ # Cypress ESLint Plugin - Flat Config

The Cypress ESLint Plugin (`eslint-plugin-cypress`) is currently based on ESLint `8.x` and has not yet been migrated to support Flat Config natively. [ESLint's new config system, Part 2: Introduction to flat config](https://eslint.org/blog/2022/08/new-config-system-part-2/) from August 2022 introduced the [Backwards compatibility utility](https://eslint.org/blog/2022/08/new-config-system-part-2/#backwards-compatibility-utility). This gives the capability to use `eslint-plugin-cypress` in an ESLint flat config environment.
Cypress ESLint Plugin (`eslint-plugin-cypress`) in release [3.2.0](https://github.com/cypress-io/eslint-plugin-cypress/releases/tag/v3.2.0) offered the first support of ESLint `9.x` flat config files using the [Backwards compatibility utility](https://eslint.org/blog/2022/08/new-config-system-part-2/#backwards-compatibility-utility). Current releases have removed the dependency on this utility and the examples in this document have been updated correspondingly.

@@ -23,3 +23,3 @@ The following information details installation and usage examples for `eslint-plugin-cypress` together with related plugins in an ESLint flat config environment.

```shell
npm install eslint @eslint/eslintrc eslint-plugin-cypress@^3.1.1 --save-dev
npm install eslint eslint-plugin-cypress --save-dev
```

@@ -30,3 +30,3 @@

```shell
yarn add eslint @eslint/eslintrc eslint-plugin-cypress@^3.1.1 --dev
yarn add eslint eslint-plugin-cypress --dev
```

@@ -36,20 +36,33 @@

Add a flat configuration file `eslint.config.mjs` file to the root directory of your Cypress project. In the following sections, different examples of possible configuration file contents are given, together with some brief explanations. Adapt these examples according to your needs.
Add a flat configuration file `eslint.config.mjs` to the root directory of your Cypress project and include the following instructions to import the available flat configurations using:
```shell
import pluginCypress from 'eslint-plugin-cypress/flat'
```
There are two specific flat configurations available:
| Configuration | Content |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `configs.globals` | defines globals `cy`, `Cypress`, `expect`, `assert` and `chai` used in Cypress test specs as well as `globals.browser` and `globals.mocha` from [globals](https://www.npmjs.com/package/globals). Additionally, `languageOptions` of `ecmaVersion: 2019` and `sourceType: 'module'` for backwards compatibility with earlier versions of this plugin are defined. There are no default rules enabled in this configuration. |
| `configs.recommended` | enables [recommended Rules](README.md#rules). It includes also `configs.global` (see above) |
In the following sections, different examples of possible configuration file contents are given, together with some brief explanations. Adapt these examples according to your needs.
### Cypress
All rules from `eslint-plugin-cypress` are available through the `FlatCompat` class of [@eslint/eslintrc](https://www.npmjs.com/package/@eslint/eslintrc).
All rules from `eslint-plugin-cypress` are available through `eslint-plugin-cypress/flat`.
- [cypress/unsafe-to-chain-command](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/unsafe-to-chain-command.md) is active and set to `error`
```js
import { FlatCompat } from '@eslint/eslintrc'
const compat = new FlatCompat()
import pluginCypress from 'eslint-plugin-cypress/flat'
export default [
...compat.config(
{
plugins: ['cypress'],
rules: {
'cypress/unsafe-to-chain-command': 'error'
}
})
{
plugins: {
cypress: pluginCypress
},
rules: {
'cypress/unsafe-to-chain-command': 'error'
}
}
]

@@ -60,22 +73,31 @@ ```

The `eslint-plugin-cypress` [recommended rules](README.md#rules) `plugin:cypress/recommended` are activated, except for
The `eslint-plugin-cypress` [recommended rules](README.md#rules) `configs.recommended` are activated, except for
- [cypress/no-unnecessary-waiting](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-unnecessary-waiting.md) set to `off`
```js
import { FlatCompat } from '@eslint/eslintrc'
const compat = new FlatCompat()
import pluginCypress from 'eslint-plugin-cypress/flat'
export default [
...compat.config(
{
extends: ['plugin:cypress/recommended'],
rules: {
'cypress/no-unnecessary-waiting': 'off'
}
})
pluginCypress.configs.recommended,
{
rules: {
'cypress/no-unnecessary-waiting': 'off'
}
}
]
```
### Cypress globals
The `configs.globals` are activated.
```js
import pluginCypress from 'eslint-plugin-cypress/flat'
export default [
pluginCypress.configs.globals
]
```
### Cypress and Mocha recommended
[eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) is added to the previous example. This plugin offers a flat file recommended option `configs.flat.recommended`.
[eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) is added to the example [Cypress recommended](#cypress-recommended). This plugin offers a flat file recommended option `configs.flat.recommended`.

@@ -91,20 +113,15 @@ The settings for individual `mocha` rules from the `configs.flat.recommended` option are changed.

```js
import { FlatCompat } from '@eslint/eslintrc'
import mochaPlugin from 'eslint-plugin-mocha'
const compat = new FlatCompat()
import pluginMocha from 'eslint-plugin-mocha'
import pluginCypress from 'eslint-plugin-cypress/flat'
export default [
mochaPlugin.configs.flat.recommended, {
pluginMocha.configs.flat.recommended,
pluginCypress.configs.recommended,
{
rules: {
'mocha/no-exclusive-tests': 'error',
'mocha/no-skipped-tests': 'error',
'mocha/no-mocha-arrows': 'off'
'mocha/no-exclusive-tests': 'warn',
'mocha/no-skipped-tests': 'warn',
'mocha/no-mocha-arrows': 'off',
'cypress/no-unnecessary-waiting': 'off'
}
},
...compat.config(
{
extends: ['plugin:cypress/recommended'],
rules: {
'cypress/no-unnecessary-waiting': 'off'
}
})
}
]

@@ -115,27 +132,22 @@ ```

[eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) is combined with the Cypress plugin `eslint-plugin-cypress`.
[eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) (minimum version [eslint-plugin-chai-friendly@0.8.0](https://github.com/ihordiachenko/eslint-plugin-chai-friendly/releases/tag/v0.8.0) required for ESLint v9 support and flat config support) is combined with the Cypress plugin `eslint-plugin-cypress`.
The [eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) plugin does not currently offer flat config options and so the `FlatCompat` class of [@eslint/eslintrc](https://www.npmjs.com/package/@eslint/eslintrc) enables this plugin to be used too. The recommended rules for both plugins are used: `plugin:cypress/recommended` and `plugin:chai-friendly/recommended`.
The recommended rules for both plugins are used: `pluginCypress.configs.recommended` and `pluginChaiFriendly.configs.recommended`:
```shell
npm install eslint-plugin-chai-friendly --save-dev
npm install eslint-plugin-chai-friendly@^0.8.0 --save-dev
```
```js
import { FlatCompat } from '@eslint/eslintrc'
const compat = new FlatCompat()
import pluginCypress from 'eslint-plugin-cypress/flat'
import pluginChaiFriendly from 'eslint-plugin-chai-friendly'
export default [
...compat.config(
{
extends: [
'plugin:cypress/recommended',
'plugin:chai-friendly/recommended'
],
rules: {
'cypress/no-unnecessary-waiting': 'off',
}
})
pluginCypress.configs.recommended,
pluginChaiFriendly.configs.recommended,
{
rules: {
'cypress/no-unnecessary-waiting': 'off',
},
}
]
```
**Pending the resolution of issue https://github.com/ihordiachenko/eslint-plugin-chai-friendly/issues/32 [eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) cannot be used with ESLint `v9`.**
{
"name": "eslint-plugin-cypress",
"version": "3.2.0",
"version": "3.3.0",
"description": "An ESLint plugin for projects using Cypress",
"main": "index.js",
"main": "legacy.js",
"exports": {
".": "./legacy.js",
"./flat": "./lib/flat.js"
},
"author": "Cypress-io",

@@ -28,8 +32,8 @@ "license": "MIT",

"devDependencies": {
"@eslint/eslintrc": "^3.0.2",
"@eslint/js": "^9.2.0",
"eslint": "^8.57.0",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.3.0",
"eslint": "^9.3.0",
"eslint-plugin-eslint-plugin": "^6.1.0",
"eslint-plugin-mocha": "^10.4.3",
"eslint-plugin-n": "^17.4.0",
"eslint-plugin-n": "^17.7.0",
"husky": "^9.0.11",

@@ -45,2 +49,3 @@ "jest": "^29.7.0",

"test": "jest",
"test:legacy": "jest --config jest.config-legacy.js",
"test-watch": "jest --watchAll",

@@ -47,0 +52,0 @@ "prepare": "husky"

@@ -10,3 +10,3 @@ # Cypress ESLint Plugin [![CircleCI](https://circleci.com/gh/cypress-io/eslint-plugin-cypress/tree/master.svg?style=svg)](https://circleci.com/gh/cypress-io/eslint-plugin-cypress/tree/master)

Prerequisites: [ESLint](https://www.npmjs.com/package/eslint) `v7`, `v8` or `v9`.
This plugin supports the use of [Flat config files](https://eslint.org/docs/latest/use/configure/configuration-files) with ESLint `8.57.0` and above through [@eslint/eslintrc](https://www.npmjs.com/package/@eslint/eslintrc).
This plugin supports the use of [Flat config files](https://eslint.org/docs/latest/use/configure/configuration-files) with ESLint `8.57.0` and above.

@@ -13,0 +13,0 @@ ```sh

@@ -5,6 +5,6 @@ /* global describe, it, expect */

const globals = require('globals')
const config = require('../index.js')
const config = require('../lib/flat.js')
describe('environments globals', () => {
const env = config.environments.globals
describe('globals languageOptions', () => {
const languageOptions = config.configs.globals.languageOptions

@@ -17,8 +17,8 @@ it('should not mutate globals', () => {

it('should include other globals', () => {
expect(env.globals).toEqual(expect.objectContaining(globals.browser))
expect(env.globals).toEqual(expect.objectContaining(globals.mocha))
expect(languageOptions.globals).toEqual(expect.objectContaining(globals.browser))
expect(languageOptions.globals).toEqual(expect.objectContaining(globals.mocha))
})
it('should include cypress globals', () => {
expect(env.globals).toEqual(expect.objectContaining({
expect(languageOptions.globals).toEqual(expect.objectContaining({
cy: false,

@@ -25,0 +25,0 @@ Cypress: false,

@@ -9,28 +9,27 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 6 }
ruleTester.run('assertion-before-screenshot', rule, {
valid: [
{ code: 'cy.get(".some-element"); cy.screenshot();', parserOptions },
{ code: 'cy.get(".some-element").should("exist").screenshot();', parserOptions },
{ code: 'cy.get(".some-element").should("exist").screenshot().click()', parserOptions, errors },
{ code: 'cy.get(".some-element").should("exist"); if(true) cy.screenshot();', parserOptions },
{ code: 'if(true) { cy.get(".some-element").should("exist"); cy.screenshot(); }', parserOptions },
{ code: 'cy.get(".some-element").should("exist"); if(true) { cy.screenshot(); }', parserOptions },
{ code: 'const a = () => { cy.get(".some-element").should("exist"); cy.screenshot(); }', parserOptions, errors },
{ code: 'cy.get(".some-element").should("exist").and("be.visible"); cy.screenshot();', parserOptions },
{ code: 'cy.get(".some-element").contains("Text"); cy.screenshot();', parserOptions },
{ code: 'cy.get(".some-element"); cy.screenshot();' },
{ code: 'cy.get(".some-element").should("exist").screenshot();' },
{ code: 'cy.get(".some-element").should("exist").screenshot().click()' },
{ code: 'cy.get(".some-element").should("exist"); if(true) cy.screenshot();' },
{ code: 'if(true) { cy.get(".some-element").should("exist"); cy.screenshot(); }' },
{ code: 'cy.get(".some-element").should("exist"); if(true) { cy.screenshot(); }' },
{ code: 'const a = () => { cy.get(".some-element").should("exist"); cy.screenshot(); }' },
{ code: 'cy.get(".some-element").should("exist").and("be.visible"); cy.screenshot();' },
{ code: 'cy.get(".some-element").contains("Text"); cy.screenshot();' },
],
invalid: [
{ code: 'cy.screenshot()', parserOptions, errors },
{ code: 'cy.visit("somepage"); cy.screenshot();', parserOptions, errors },
{ code: 'cy.custom(); cy.screenshot()', parserOptions, errors },
{ code: 'cy.get(".some-element").click(); cy.screenshot()', parserOptions, errors },
{ code: 'cy.get(".some-element").click().screenshot()', parserOptions, errors },
{ code: 'if(true) { cy.get(".some-element").click(); cy.screenshot(); }', parserOptions, errors },
{ code: 'cy.get(".some-element").click(); if(true) { cy.screenshot(); }', parserOptions, errors },
{ code: 'cy.get(".some-element"); function a() { cy.screenshot(); }', parserOptions, errors },
{ code: 'cy.get(".some-element"); const a = () => { cy.screenshot(); }', parserOptions, errors },
{ code: 'cy.screenshot()', errors },
{ code: 'cy.visit("somepage"); cy.screenshot();', errors },
{ code: 'cy.custom(); cy.screenshot()', errors },
{ code: 'cy.get(".some-element").click(); cy.screenshot()', errors },
{ code: 'cy.get(".some-element").click().screenshot()', errors },
{ code: 'if(true) { cy.get(".some-element").click(); cy.screenshot(); }', errors },
{ code: 'cy.get(".some-element").click(); if(true) { cy.screenshot(); }', errors },
{ code: 'cy.get(".some-element"); function a() { cy.screenshot(); }', errors },
{ code: 'cy.get(".some-element"); const a = () => { cy.screenshot(); }', errors },
],
})

@@ -9,31 +9,30 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 6 }
ruleTester.run('no-assigning-return-values', rule, {
valid: [
{ code: 'var foo = true;', parserOptions },
{ code: 'let foo = true;', parserOptions },
{ code: 'const foo = true;', parserOptions },
{ code: 'const foo = bar();', parserOptions },
{ code: 'const foo = bar().baz();', parserOptions },
{ code: 'const spy = cy.spy();', parserOptions },
{ code: 'const spy = cy.spy().as();', parserOptions },
{ code: 'const stub = cy.stub();', parserOptions },
{ code: 'const result = cy.now();', parserOptions },
{ code: 'const state = cy.state();', parserOptions },
{ code: 'cy.get("foo");', parserOptions },
{ code: 'cy.contains("foo").click();', parserOptions },
{ code: 'var foo = true;' },
{ code: 'let foo = true;' },
{ code: 'const foo = true;' },
{ code: 'const foo = bar();' },
{ code: 'const foo = bar().baz();' },
{ code: 'const spy = cy.spy();' },
{ code: 'const spy = cy.spy().as();' },
{ code: 'const stub = cy.stub();' },
{ code: 'const result = cy.now();' },
{ code: 'const state = cy.state();' },
{ code: 'cy.get("foo");' },
{ code: 'cy.contains("foo").click();' },
],
invalid: [
{ code: 'let a = cy.get("foo")', parserOptions, errors },
{ code: 'const a = cy.get("foo")', parserOptions, errors },
{ code: 'var a = cy.get("foo")', parserOptions, errors },
{ code: 'let a = cy.get("foo")', errors },
{ code: 'const a = cy.get("foo")', errors },
{ code: 'var a = cy.get("foo")', errors },
{ code: 'let a = cy.contains("foo")', parserOptions, errors },
{ code: 'let a = cy.window()', parserOptions, errors },
{ code: 'let a = cy.wait("@something")', parserOptions, errors },
{ code: 'let a = cy.contains("foo")', errors },
{ code: 'let a = cy.window()', errors },
{ code: 'let a = cy.wait("@something")', errors },
{ code: 'let a = cy.contains("foo").click()', parserOptions, errors },
{ code: 'let a = cy.contains("foo").click()', errors },
],
})

@@ -9,18 +9,16 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
// async functions are an ES2017 feature
const parserOptions = { ecmaVersion: 8 }
ruleTester.run('no-async-before', rule, {
valid: [
{ code: 'before(\'a before case\', () => { cy.get(\'.someClass\'); })', parserOptions },
{ code: 'before(\'a before case\', async () => { await somethingAsync(); })', parserOptions },
{ code: 'async function nonTestFn () { return await somethingAsync(); }', parserOptions },
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }', parserOptions },
{ code: 'before(\'a before case\', () => { cy.get(\'.someClass\'); })' },
{ code: 'before(\'a before case\', async () => { await somethingAsync(); })' },
{ code: 'async function nonTestFn () { return await somethingAsync(); }' },
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }' },
],
invalid: [
{ code: 'before(\'a test case\', async () => { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'beforeEach(\'a test case\', async () => { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'before(\'a test case\', async function () { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'beforeEach(\'a test case\', async function () { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'before(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
{ code: 'beforeEach(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
{ code: 'before(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
{ code: 'beforeEach(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
],
})

@@ -9,18 +9,16 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
// async functions are an ES2017 feature
const parserOptions = { ecmaVersion: 8 }
ruleTester.run('no-async-tests', rule, {
valid: [
{ code: 'it(\'a test case\', () => { cy.get(\'.someClass\'); })', parserOptions },
{ code: 'it(\'a test case\', async () => { await somethingAsync(); })', parserOptions },
{ code: 'async function nonTestFn () { return await somethingAsync(); }', parserOptions },
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }', parserOptions },
{ code: 'it(\'a test case\', () => { cy.get(\'.someClass\'); })' },
{ code: 'it(\'a test case\', async () => { await somethingAsync(); })' },
{ code: 'async function nonTestFn () { return await somethingAsync(); }' },
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }' },
],
invalid: [
{ code: 'it(\'a test case\', async () => { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'test(\'a test case\', async () => { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'it(\'a test case\', async function () { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'test(\'a test case\', async function () { cy.get(\'.someClass\'); })', parserOptions, errors },
{ code: 'it(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
{ code: 'test(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
{ code: 'it(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
{ code: 'test(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
],
})
'use strict'
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const rule = require('../../../lib/rules/no-force')
const RuleTester = require('eslint').RuleTester
const ruleTester = new RuleTester()
const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 2018 }
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
let ruleTester = new RuleTester()
ruleTester.run('no-force', rule, {
valid: [
{ code: `cy.get('button').click()`, parserOptions },
{ code: `cy.get('button').click({multiple: true})`, parserOptions },
{ code: `cy.get('button').dblclick()`, parserOptions },
{ code: `cy.get('input').type('somth')`, parserOptions },
{ code: `cy.get('input').type('somth', {anyoption: true})`, parserOptions },
{ code: `cy.get('input').trigger('click', {anyoption: true})`, parserOptions },
{ code: `cy.get('input').rightclick({anyoption: true})`, parserOptions },
{ code: `cy.get('input').check()`, parserOptions },
{ code: `cy.get('input').select()`, parserOptions },
{ code: `cy.get('input').focus()`, parserOptions },
{ code: `cy.document().trigger("keydown", { ...event })`, parserOptions },
{ code: `cy.get('button').click()` },
{ code: `cy.get('button').click({multiple: true})` },
{ code: `cy.get('button').dblclick()` },
{ code: `cy.get('input').type('somth')` },
{ code: `cy.get('input').type('somth', {anyoption: true})` },
{ code: `cy.get('input').trigger('click', {anyoption: true})` },
{ code: `cy.get('input').rightclick({anyoption: true})` },
{ code: `cy.get('input').check()` },
{ code: `cy.get('input').select()` },
{ code: `cy.get('input').focus()` },
{ code: `cy.document().trigger("keydown", { ...event })` },
],
invalid: [
{ code: `cy.get('button').click({force: true})`, parserOptions, errors },
{ code: `cy.get('button').dblclick({force: true})`, parserOptions, errors },
{ code: `cy.get('input').type('somth', {force: true})`, parserOptions, errors },
{ code: `cy.get('div').find('.foo').type('somth', {force: true})`, parserOptions, errors },
{ code: `cy.get('div').find('.foo').find('.bar').click({force: true})`, parserOptions, errors },
{ code: `cy.get('div').find('.foo').find('.bar').trigger('change', {force: true})`, parserOptions, errors },
{ code: `cy.get('input').trigger('click', {force: true})`, parserOptions, errors },
{ code: `cy.get('input').rightclick({force: true})`, parserOptions, errors },
{ code: `cy.get('input').check({force: true})`, parserOptions, errors },
{ code: `cy.get('input').select({force: true})`, parserOptions, errors },
{ code: `cy.get('input').focus({force: true})`, parserOptions, errors },
{ code: `cy.get('button').click({force: true})`, errors },
{ code: `cy.get('button').dblclick({force: true})`, errors },
{ code: `cy.get('input').type('somth', {force: true})`, errors },
{ code: `cy.get('div').find('.foo').type('somth', {force: true})`, errors },
{ code: `cy.get('div').find('.foo').find('.bar').click({force: true})`, errors },
{ code: `cy.get('div').find('.foo').find('.bar').trigger('change', {force: true})`, errors },
{ code: `cy.get('input').trigger('click', {force: true})`, errors },
{ code: `cy.get('input').rightclick({force: true})`, errors },
{ code: `cy.get('input').check({force: true})`, errors },
{ code: `cy.get('input').select({force: true})`, errors },
{ code: `cy.get('input').focus({force: true})`, errors },
],
})
'use strict'
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const rule = require('../../../lib/rules/no-pause')
const RuleTester = require('eslint').RuleTester
const ruleTester = new RuleTester()
const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 2018 }
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const ruleTester = new RuleTester()
ruleTester.run('no-pause', rule, {
valid: [
{ code: `pause()`, parserOptions },
{ code: `cy.get('button').dblclick()`, parserOptions },
{ code: `pause()` },
{ code: `cy.get('button').dblclick()` },
],
invalid: [
{ code: `cy.pause()`, parserOptions, errors },
{ code: `cy.pause({ log: false })`, parserOptions, errors },
{ code: `cy.get('button').pause()`, parserOptions, errors },
{
code: `cy.get('a').should('have.attr', 'href').and('match', /dashboard/).pause()`,
parserOptions,
errors
}
{ code: `cy.pause()`, errors },
{ code: `cy.pause({ log: false })`, errors },
{ code: `cy.get('button').pause()`, errors },
{ code: `cy.get('a').should('have.attr', 'href').and('match', /dashboard/).pause()`, errors }
],
})

@@ -9,64 +9,40 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 6, sourceType: 'module' }
ruleTester.run('no-unnecessary-waiting', rule, {
valid: [
{ code: 'foo.wait(10)', parserOptions },
{ code: 'foo.wait(10)' },
{ code: 'cy.wait("@someRequest")', parserOptions },
{ code: 'cy.wait("@someRequest", { log: false })', parserOptions },
{ code: 'cy.wait("@someRequest").then((xhr) => xhr)', parserOptions },
{ code: 'cy.wait(["@someRequest", "@anotherRequest"])', parserOptions },
{ code: 'cy.wait("@someRequest")' },
{ code: 'cy.wait("@someRequest", { log: false })' },
{ code: 'cy.wait("@someRequest").then((xhr) => xhr)' },
{ code: 'cy.wait(["@someRequest", "@anotherRequest"])' },
{ code: 'cy.clock(5000)', parserOptions },
{ code: 'cy.scrollTo(0, 10)', parserOptions },
{ code: 'cy.tick(500)', parserOptions },
{ code: 'cy.clock(5000)' },
{ code: 'cy.scrollTo(0, 10)' },
{ code: 'cy.tick(500)' },
{ code: 'const someRequest="@someRequest"; cy.wait(someRequest)', parserOptions, errors },
{ code: 'function customWait (alias = "@someRequest") { cy.wait(alias) }', parserOptions, errors },
{ code: 'const customWait = (alias = "@someRequest") => { cy.wait(alias) }', parserOptions, errors },
{ code: 'function customWait (ms) { cy.wait(ms) }', parserOptions, errors },
{ code: 'const customWait = (ms) => { cy.wait(ms) }', parserOptions, errors },
{ code: 'const someRequest="@someRequest"; cy.wait(someRequest)' },
{ code: 'function customWait (alias = "@someRequest") { cy.wait(alias) }' },
{ code: 'const customWait = (alias = "@someRequest") => { cy.wait(alias) }' },
{ code: 'function customWait (ms) { cy.wait(ms) }' },
{ code: 'const customWait = (ms) => { cy.wait(ms) }' },
{ code: 'import BAR_BAZ from "bar-baz"; cy.wait(BAR_BAZ)', parserOptions },
{ code: 'import { FOO_BAR } from "foo-bar"; cy.wait(FOO_BAR)', parserOptions },
{ code: 'import * as wildcard from "wildcard"; cy.wait(wildcard.value)', parserOptions },
{ code: 'import { NAME as OTHER_NAME } from "rename"; cy.wait(OTHER_NAME)', parserOptions },
// disable the eslint rule
{
code: `
cy.wait(100); // eslint-disable-line no-unnecessary-waiting
`,
parserOptions,
},
{
code: `
/* eslint-disable-next-line no-unnecessary-waiting */
cy.wait(100)
`,
parserOptions,
},
{
code: `
/* eslint-disable no-unnecessary-waiting */
cy.wait(100)
/* eslint-enable no-unnecessary-waiting */
`,
parserOptions,
},
{ code: 'import BAR_BAZ from "bar-baz"; cy.wait(BAR_BAZ)' },
{ code: 'import { FOO_BAR } from "foo-bar"; cy.wait(FOO_BAR)' },
{ code: 'import * as wildcard from "wildcard"; cy.wait(wildcard.value)' },
{ code: 'import { NAME as OTHER_NAME } from "rename"; cy.wait(OTHER_NAME)' },
],
invalid: [
{ code: 'cy.wait(0)', parserOptions, errors },
{ code: 'cy.wait(100)', parserOptions, errors },
{ code: 'cy.wait(5000)', parserOptions, errors },
{ code: 'const someNumber=500; cy.wait(someNumber)', parserOptions, errors },
{ code: 'function customWait (ms = 1) { cy.wait(ms) }', parserOptions, errors },
{ code: 'const customWait = (ms = 1) => { cy.wait(ms) }', parserOptions, errors },
{ code: 'cy.wait(0)', errors },
{ code: 'cy.wait(100)', errors },
{ code: 'cy.wait(5000)', errors },
{ code: 'const someNumber=500; cy.wait(someNumber)', errors },
{ code: 'function customWait (ms = 1) { cy.wait(ms) }', errors },
{ code: 'const customWait = (ms = 1) => { cy.wait(ms) }', errors },
{ code: 'cy.get(".some-element").wait(10)', parserOptions, errors },
{ code: 'cy.get(".some-element").contains("foo").wait(10)', parserOptions, errors },
{ code: 'const customWait = (ms = 1) => { cy.get(".some-element").wait(ms) }', parserOptions, errors },
{ code: 'cy.get(".some-element").wait(10)', errors },
{ code: 'cy.get(".some-element").contains("foo").wait(10)', errors },
{ code: 'const customWait = (ms = 1) => { cy.get(".some-element").wait(ms) }', errors },
],
})

@@ -9,24 +9,23 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 6 }
ruleTester.run('require-data-selectors', rule, {
valid: [
{ code: 'cy.get(\'[data-cy=submit]\').click()', parserOptions },
{ code: 'cy.get(\'[data-QA=submit]\')', parserOptions },
{ code: 'cy.clock(5000)', parserOptions },
{ code: 'cy.scrollTo(0, 10)', parserOptions },
{ code: 'cy.tick(500)', parserOptions },
{ code: 'cy.get(\`[data-cy=${1}]\`)', parserOptions }, // eslint-disable-line no-useless-escape
{ code: 'cy.get("@my-alias")', parserOptions, errors },
{ code: 'cy.get(`@my-alias`)', parserOptions, errors },
{ code: 'cy.get(\'[data-cy=submit]\').click()' },
{ code: 'cy.get(\'[data-QA=submit]\')' },
{ code: 'cy.clock(5000)' },
{ code: 'cy.scrollTo(0, 10)' },
{ code: 'cy.tick(500)' },
{ code: 'cy.get(\`[data-cy=${1}]\`)' }, // eslint-disable-line no-useless-escape
{ code: 'cy.get("@my-alias")' },
{ code: 'cy.get(`@my-alias`)' },
],
invalid: [
{ code: 'cy.get(\'[daedta-cy=submit]\').click()', parserOptions, errors },
{ code: 'cy.get(\'[d-cy=submit]\')', parserOptions, errors },
{ code: 'cy.get(".btn-large").click()', parserOptions, errors },
{ code: 'cy.get(".btn-.large").click()', parserOptions, errors },
{ code: 'cy.get(".a")', parserOptions, errors },
{ code: 'cy.get(\`[daedta-cy=${1}]\`)', parserOptions, errors }, // eslint-disable-line no-useless-escape
{ code: 'cy.get(\'[daedta-cy=submit]\').click()', errors },
{ code: 'cy.get(\'[d-cy=submit]\')', errors },
{ code: 'cy.get(".btn-large").click()', errors },
{ code: 'cy.get(".btn-.large").click()', errors },
{ code: 'cy.get(".a")', errors },
{ code: 'cy.get(\`[daedta-cy=${1}]\`)', errors }, // eslint-disable-line no-useless-escape
],
})

@@ -9,3 +9,2 @@ 'use strict'

const errors = [{ messageId: 'unexpected' }]
const parserOptions = { ecmaVersion: 6 }

@@ -15,44 +14,23 @@ ruleTester.run('action-ends-chain', rule, {

{
code: 'cy.get("new-todo").type("todo A{enter}"); cy.get("new-todo").type("todo B{enter}"); cy.get("new-todo").should("have.class", "active");',
parserOptions,
code: 'cy.get("new-todo").type("todo A{enter}"); cy.get("new-todo").type("todo B{enter}"); cy.get("new-todo").should("have.class", "active");'
},
{
code: 'cy.focused().should("be.visible");',
parserOptions,
},
{
code: 'cy.submitBtn().click();',
parserOptions,
},
{ code: 'cy.focused().should("be.visible");' },
{ code: 'cy.submitBtn().click();' },
],
invalid: [
{ code: 'cy.get("new-todo").type("todo A{enter}").should("have.class", "active");', errors },
{ code: 'cy.get("new-todo").type("todo A{enter}").type("todo B{enter}");', errors },
{ code: 'cy.get("new-todo").focus().should("have.class", "active");', errors },
{
code: 'cy.get("new-todo").type("todo A{enter}").should("have.class", "active");',
parserOptions,
errors,
},
{
code: 'cy.get("new-todo").type("todo A{enter}").type("todo B{enter}");',
parserOptions,
errors,
},
{
code: 'cy.get("new-todo").focus().should("have.class", "active");',
parserOptions,
errors,
},
{
code: 'cy.get("new-todo").customType("todo A{enter}").customClick();',
parserOptions,
options: [{ methods: ['customType', 'customClick'] }],
errors,
options: [{ methods: ['customType', 'customClick'] }],
},
{
code: 'cy.get("new-todo").customPress("Enter").customScroll();',
parserOptions,
options: [{ methods: ['customPress', 'customScroll'] }],
errors,
options: [{ methods: [/customPress/, /customScroll/] }],
},
],
})

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc