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,
+ },
+ },
+ ],
+ })),
+ ],
+});