diff --git a/README.md b/README.md index 350ec79b..e834f74d 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ To enable this configuration use the `extends` property in your | [no-manual-cleanup](docs/rules/no-manual-cleanup.md) | Disallow the use of `cleanup` | | | | [no-wait-for-empty-callback](docs/rules/no-wait-for-empty-callback.md) | Disallow empty callbacks for `waitFor` and `waitForElementToBeRemoved` | | | | [prefer-explicit-assert](docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than just `getBy*` queries | | | +| [prefer-screen-queries](docs/rules/prefer-screen-queries.md) | Suggest using screen while using queries | | | | [prefer-wait-for](docs/rules/prefer-wait-for.md) | Use `waitFor` instead of deprecated wait methods | | ![fixable-badge][] | [build-badge]: https://img.shields.io/travis/testing-library/eslint-plugin-testing-library?style=flat-square diff --git a/docs/rules/prefer-screen-queries.md b/docs/rules/prefer-screen-queries.md new file mode 100644 index 00000000..3fd22976 --- /dev/null +++ b/docs/rules/prefer-screen-queries.md @@ -0,0 +1,30 @@ +# Suggest using screen while using queries (prefer-screen-queries) + +## Rule Details + +DOM Testing Library (and other Testing Library frameworks built on top of it) exports a `screen` object which has every query (and a `debug` method). This works better with autocomplete and makes each test a little simpler to write and maintain. +This rule aims to force writing tests using queries directly from `screen` object rather than destructuring them from `render` result. + +Examples of **incorrect** code for this rule: + +```js +// calling a query from the `render` method +const { getByText } = render(); +getByText('foo'); + +const utils = render(); +utils.getByText('foo'); +``` + +Examples of **correct** code for this rule: + +```js +import { screen } from '@testing-library/any-framework'; + +render(); +screen.getByText('foo'); +``` + +## Further Reading + +- [`screen` documentation](https://testing-library.com/docs/dom-testing-library/api-queries#screen) diff --git a/lib/index.js b/lib/index.js index 4589eb2c..d5874718 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,6 +12,7 @@ const rules = { 'no-manual-cleanup': require('./rules/no-manual-cleanup'), 'no-wait-for-empty-callback': require('./rules/no-wait-for-empty-callback'), 'prefer-explicit-assert': require('./rules/prefer-explicit-assert'), + 'prefer-screen-queries': require('./rules/prefer-screen-queries'), 'prefer-wait-for': require('./rules/prefer-wait-for'), }; diff --git a/lib/rules/prefer-screen-queries.js b/lib/rules/prefer-screen-queries.js new file mode 100644 index 00000000..7aa86155 --- /dev/null +++ b/lib/rules/prefer-screen-queries.js @@ -0,0 +1,40 @@ +'use strict'; + +const { getDocsUrl, ALL_QUERIES_COMBINATIONS } = require('../utils'); + +const ALL_QUERIES_COMBINATIONS_REGEXP = ALL_QUERIES_COMBINATIONS.join('|'); + +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'Suggest using screen while using queries', + category: 'Best Practices', + recommended: false, + url: getDocsUrl('prefer-screen-queries'), + }, + messages: { + preferScreenQueries: + 'Use screen to query DOM elements, `screen.{{ name }}`', + }, + fixable: null, + schema: [], + }, + + create: function(context) { + function reportInvalidUsage(node) { + context.report({ + node, + messageId: 'preferScreenQueries', + data: { + name: node.name, + }, + }); + } + + return { + [`CallExpression > Identifier[name=/^${ALL_QUERIES_COMBINATIONS_REGEXP}$/]`]: reportInvalidUsage, + [`MemberExpression[object.name!="screen"] > Identifier[name=/^${ALL_QUERIES_COMBINATIONS_REGEXP}$/]`]: reportInvalidUsage, + }; + }, +}; diff --git a/lib/utils.js b/lib/utils.js index ad332a44..4cccecfc 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -44,8 +44,8 @@ const ASYNC_QUERIES_COMBINATIONS = combineQueries( ); const ALL_QUERIES_COMBINATIONS = [ - SYNC_QUERIES_COMBINATIONS, - ASYNC_QUERIES_COMBINATIONS, + ...SYNC_QUERIES_COMBINATIONS, + ...ASYNC_QUERIES_COMBINATIONS, ]; const ASYNC_UTILS = [ diff --git a/tests/lib/rules/prefer-screen-queries.js b/tests/lib/rules/prefer-screen-queries.js new file mode 100644 index 00000000..a0f5ebef --- /dev/null +++ b/tests/lib/rules/prefer-screen-queries.js @@ -0,0 +1,50 @@ +'use strict'; + +const rule = require('../../../lib/rules/prefer-screen-queries'); +const { ALL_QUERIES_COMBINATIONS } = require('../../../lib/utils'); +const RuleTester = require('eslint').RuleTester; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } }); +ruleTester.run('prefer-screen-queries', rule, { + valid: [ + ...ALL_QUERIES_COMBINATIONS.map(queryMethod => ({ + code: `screen.${queryMethod}()`, + })), + { + code: `otherFunctionShouldNotThrow()`, + }, + { + code: `component.otherFunctionShouldNotThrow()`, + }, + ], + + invalid: [ + ...ALL_QUERIES_COMBINATIONS.map(queryMethod => ({ + code: `${queryMethod}()`, + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + })), + + ...ALL_QUERIES_COMBINATIONS.map(queryMethod => ({ + code: `component.${queryMethod}()`, + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + })), + ], +});