diff --git a/README.md b/README.md index d9ea34cc..93a7d028 100644 --- a/README.md +++ b/README.md @@ -179,43 +179,56 @@ To enable this configuration use the `extends` property in your } ``` +### Marko + +Enforces recommended rules for Marko Testing Library. + +To enable this configuration use the `extends` property in your +`.eslintrc` config file: + +```json +{ + "extends": ["plugin:testing-library/marko"] +} +``` + ## Supported Rules **Key**: 🔧 = fixable -**Configurations**: ![dom-badge][] = dom, ![angular-badge][] = angular, ![react-badge][] = react, ![vue-badge][] = vue - -| Name | Description | 🔧 | Included in configurations | -| ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | --- | ----------------------------------------------------------------- | -| [`testing-library/await-async-query`](./docs/rules/await-async-query.md) | Enforce promises from async queries to be handled | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/await-async-utils`](./docs/rules/await-async-utils.md) | Enforce promises from async utils to be awaited properly | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/await-fire-event`](./docs/rules/await-fire-event.md) | Enforce promises from `fireEvent` methods to be handled | | ![vue-badge][] | -| [`testing-library/consistent-data-testid`](./docs/rules/consistent-data-testid.md) | Ensures consistent usage of `data-testid` | | | -| [`testing-library/no-await-sync-events`](./docs/rules/no-await-sync-events.md) | Disallow unnecessary `await` for sync events | | | -| [`testing-library/no-await-sync-query`](./docs/rules/no-await-sync-query.md) | Disallow unnecessary `await` for sync queries | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-container`](./docs/rules/no-container.md) | Disallow the use of `container` methods | | ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-debugging-utils`](./docs/rules/no-debugging-utils.md) | Disallow the use of debugging utilities like `debug` | | ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-dom-import`](./docs/rules/no-dom-import.md) | Disallow importing from DOM Testing Library | 🔧 | ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-global-regexp-flag-in-query`](./docs/rules/no-global-regexp-flag-in-query.md) | Disallow the use of the global RegExp flag (/g) in queries | 🔧 | | -| [`testing-library/no-manual-cleanup`](./docs/rules/no-manual-cleanup.md) | Disallow the use of `cleanup` | | | -| [`testing-library/no-node-access`](./docs/rules/no-node-access.md) | Disallow direct Node access | | ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-promise-in-fire-event`](./docs/rules/no-promise-in-fire-event.md) | Disallow the use of promises passed to a `fireEvent` method | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-render-in-setup`](./docs/rules/no-render-in-setup.md) | Disallow the use of `render` in testing frameworks setup functions | | ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-unnecessary-act`](./docs/rules/no-unnecessary-act.md) | Disallow wrapping Testing Library utils or empty callbacks in `act` | | ![react-badge][] | -| [`testing-library/no-wait-for-empty-callback`](./docs/rules/no-wait-for-empty-callback.md) | Disallow empty callbacks for `waitFor` and `waitForElementToBeRemoved` | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-wait-for-multiple-assertions`](./docs/rules/no-wait-for-multiple-assertions.md) | Disallow the use of multiple `expect` calls inside `waitFor` | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-wait-for-side-effects`](./docs/rules/no-wait-for-side-effects.md) | Disallow the use of side effects in `waitFor` | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/no-wait-for-snapshot`](./docs/rules/no-wait-for-snapshot.md) | Ensures no snapshot is generated inside of a `waitFor` call | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/prefer-explicit-assert`](./docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than standalone queries | | | -| [`testing-library/prefer-find-by`](./docs/rules/prefer-find-by.md) | Suggest using `find(All)By*` query instead of `waitFor` + `get(All)By*` to wait for elements | 🔧 | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/prefer-presence-queries`](./docs/rules/prefer-presence-queries.md) | Ensure appropriate `get*`/`query*` queries are used with their respective matchers | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/prefer-query-by-disappearance`](./docs/rules/prefer-query-by-disappearance.md) | Suggest using `queryBy*` queries when waiting for disappearance | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/prefer-screen-queries`](./docs/rules/prefer-screen-queries.md) | Suggest using `screen` while querying | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | -| [`testing-library/prefer-user-event`](./docs/rules/prefer-user-event.md) | Suggest using `userEvent` over `fireEvent` for simulating user interactions | | | -| [`testing-library/prefer-wait-for`](./docs/rules/prefer-wait-for.md) | Use `waitFor` instead of deprecated wait methods | 🔧 | | -| [`testing-library/render-result-naming-convention`](./docs/rules/render-result-naming-convention.md) | Enforce a valid naming for return value from `render` | | ![angular-badge][] ![react-badge][] ![vue-badge][] | +**Configurations**: ![dom-badge][] = dom, ![angular-badge][] = angular, ![react-badge][] = react, ![vue-badge][] = vue, ![marko-badge][] = marko + +| Name | Description | 🔧 | Included in configurations | +| ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | --- | ---------------------------------------------------------------------------------- | +| [`testing-library/await-async-query`](./docs/rules/await-async-query.md) | Enforce promises from async queries to be handled | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/await-async-utils`](./docs/rules/await-async-utils.md) | Enforce promises from async utils to be awaited properly | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/await-fire-event`](./docs/rules/await-fire-event.md) | Enforce promises from `fireEvent` methods to be handled | | ![vue-badge][] ![marko-badge][] | +| [`testing-library/consistent-data-testid`](./docs/rules/consistent-data-testid.md) | Ensures consistent usage of `data-testid` | | | +| [`testing-library/no-await-sync-events`](./docs/rules/no-await-sync-events.md) | Disallow unnecessary `await` for sync events | | | +| [`testing-library/no-await-sync-query`](./docs/rules/no-await-sync-query.md) | Disallow unnecessary `await` for sync queries | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-container`](./docs/rules/no-container.md) | Disallow the use of `container` methods | | ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-debugging-utils`](./docs/rules/no-debugging-utils.md) | Disallow the use of debugging utilities like `debug` | | ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-dom-import`](./docs/rules/no-dom-import.md) | Disallow importing from DOM Testing Library | 🔧 | ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-global-regexp-flag-in-query`](./docs/rules/no-global-regexp-flag-in-query.md) | Disallow the use of the global RegExp flag (/g) in queries | 🔧 | | +| [`testing-library/no-manual-cleanup`](./docs/rules/no-manual-cleanup.md) | Disallow the use of `cleanup` | | | +| [`testing-library/no-node-access`](./docs/rules/no-node-access.md) | Disallow direct Node access | | ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-promise-in-fire-event`](./docs/rules/no-promise-in-fire-event.md) | Disallow the use of promises passed to a `fireEvent` method | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-render-in-setup`](./docs/rules/no-render-in-setup.md) | Disallow the use of `render` in testing frameworks setup functions | | ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-unnecessary-act`](./docs/rules/no-unnecessary-act.md) | Disallow wrapping Testing Library utils or empty callbacks in `act` | | ![react-badge][] ![marko-badge][] | +| [`testing-library/no-wait-for-empty-callback`](./docs/rules/no-wait-for-empty-callback.md) | Disallow empty callbacks for `waitFor` and `waitForElementToBeRemoved` | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-wait-for-multiple-assertions`](./docs/rules/no-wait-for-multiple-assertions.md) | Disallow the use of multiple `expect` calls inside `waitFor` | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-wait-for-side-effects`](./docs/rules/no-wait-for-side-effects.md) | Disallow the use of side effects in `waitFor` | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/no-wait-for-snapshot`](./docs/rules/no-wait-for-snapshot.md) | Ensures no snapshot is generated inside of a `waitFor` call | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/prefer-explicit-assert`](./docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than standalone queries | | | +| [`testing-library/prefer-find-by`](./docs/rules/prefer-find-by.md) | Suggest using `find(All)By*` query instead of `waitFor` + `get(All)By*` to wait for elements | 🔧 | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/prefer-presence-queries`](./docs/rules/prefer-presence-queries.md) | Ensure appropriate `get*`/`query*` queries are used with their respective matchers | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/prefer-query-by-disappearance`](./docs/rules/prefer-query-by-disappearance.md) | Suggest using `queryBy*` queries when waiting for disappearance | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/prefer-screen-queries`](./docs/rules/prefer-screen-queries.md) | Suggest using `screen` while querying | | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | +| [`testing-library/prefer-user-event`](./docs/rules/prefer-user-event.md) | Suggest using `userEvent` over `fireEvent` for simulating user interactions | | | +| [`testing-library/prefer-wait-for`](./docs/rules/prefer-wait-for.md) | Use `waitFor` instead of deprecated wait methods | 🔧 | | +| [`testing-library/render-result-naming-convention`](./docs/rules/render-result-naming-convention.md) | Enforce a valid naming for return value from `render` | | ![angular-badge][] ![react-badge][] ![vue-badge][] ![marko-badge][] | @@ -420,3 +433,4 @@ This project follows the [all-contributors](https://github.com/all-contributors/ [angular-badge]: https://img.shields.io/badge/-Angular-black?style=flat-square&logo=angular&logoColor=white&labelColor=DD0031&color=black [react-badge]: https://img.shields.io/badge/-React-black?style=flat-square&logo=react&logoColor=white&labelColor=61DAFB&color=black [vue-badge]: https://img.shields.io/badge/-Vue-black?style=flat-square&logo=vue.js&logoColor=white&labelColor=4FC08D&color=black +[marko-badge]: https://img.shields.io/badge/-Marko-black?style=flat-square&logo=marko&logoColor=white&labelColor=2596BE&color=black diff --git a/docs/rules/await-fire-event.md b/docs/rules/await-fire-event.md index 65e28594..f88ca68f 100644 --- a/docs/rules/await-fire-event.md +++ b/docs/rules/await-fire-event.md @@ -12,6 +12,7 @@ methods. > > - `@testing-library/vue` (supported by this plugin) > - `@testing-library/svelte` (not supported yet by this plugin) +> - `@marko/testing-library` (supported by this plugin) Examples of **incorrect** code for this rule: diff --git a/docs/rules/no-dom-import.md b/docs/rules/no-dom-import.md index a7ba4e1b..fb453b25 100644 --- a/docs/rules/no-dom-import.md +++ b/docs/rules/no-dom-import.md @@ -76,3 +76,4 @@ With the configuration above, if the user imports from `@testing-library/dom` or - [Angular Testing Library API](https://testing-library.com/docs/angular-testing-library/api) - [React Testing Library API](https://testing-library.com/docs/react-testing-library/api) - [Vue Testing Library API](https://testing-library.com/docs/vue-testing-library/api) +- [Marko Testing Library API](https://testing-library.com/docs/marko-testing-library/api) diff --git a/docs/rules/no-unnecessary-act.md b/docs/rules/no-unnecessary-act.md index 49bc122d..c5919e92 100644 --- a/docs/rules/no-unnecessary-act.md +++ b/docs/rules/no-unnecessary-act.md @@ -5,6 +5,7 @@ > - `@testing-library/react` (supported by this plugin) > - `@testing-library/preact` (not supported yet by this plugin) > - `@testing-library/svelte` (not supported yet by this plugin) +> - `@marko/testing-library` (supported by this plugin) ## Rule Details diff --git a/lib/configs/marko.ts b/lib/configs/marko.ts new file mode 100644 index 00000000..3df1ce9c --- /dev/null +++ b/lib/configs/marko.ts @@ -0,0 +1,29 @@ +// THIS CODE WAS AUTOMATICALLY GENERATED +// DO NOT EDIT THIS CODE BY HAND +// YOU CAN REGENERATE IT USING npm run generate:configs + +export = { + plugins: ['testing-library'], + rules: { + 'testing-library/await-async-query': 'error', + 'testing-library/await-async-utils': 'error', + 'testing-library/await-fire-event': 'error', + 'testing-library/no-await-sync-query': 'error', + 'testing-library/no-container': 'error', + 'testing-library/no-debugging-utils': 'error', + 'testing-library/no-dom-import': ['error', 'marko'], + 'testing-library/no-node-access': 'error', + 'testing-library/no-promise-in-fire-event': 'error', + 'testing-library/no-render-in-setup': 'error', + 'testing-library/no-unnecessary-act': 'error', + 'testing-library/no-wait-for-empty-callback': 'error', + 'testing-library/no-wait-for-multiple-assertions': 'error', + 'testing-library/no-wait-for-side-effects': 'error', + 'testing-library/no-wait-for-snapshot': 'error', + 'testing-library/prefer-find-by': 'error', + 'testing-library/prefer-presence-queries': 'error', + 'testing-library/prefer-query-by-disappearance': 'error', + 'testing-library/prefer-screen-queries': 'error', + 'testing-library/render-result-naming-convention': 'error', + }, +}; diff --git a/lib/rules/await-async-query.ts b/lib/rules/await-async-query.ts index d981644f..31cb1b30 100644 --- a/lib/rules/await-async-query.ts +++ b/lib/rules/await-async-query.ts @@ -25,6 +25,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/await-async-utils.ts b/lib/rules/await-async-utils.ts index c0999d4f..71d22ab5 100644 --- a/lib/rules/await-async-utils.ts +++ b/lib/rules/await-async-utils.ts @@ -24,6 +24,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/await-fire-event.ts b/lib/rules/await-fire-event.ts index b9858aea..19a9a53e 100644 --- a/lib/rules/await-fire-event.ts +++ b/lib/rules/await-fire-event.ts @@ -24,6 +24,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/consistent-data-testid.ts b/lib/rules/consistent-data-testid.ts index ed462367..42333fe8 100644 --- a/lib/rules/consistent-data-testid.ts +++ b/lib/rules/consistent-data-testid.ts @@ -23,6 +23,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/no-await-sync-events.ts b/lib/rules/no-await-sync-events.ts index 9fa3e761..4202cd91 100644 --- a/lib/rules/no-await-sync-events.ts +++ b/lib/rules/no-await-sync-events.ts @@ -29,6 +29,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/no-await-sync-query.ts b/lib/rules/no-await-sync-query.ts index 99baf668..25daffa5 100644 --- a/lib/rules/no-await-sync-query.ts +++ b/lib/rules/no-await-sync-query.ts @@ -18,6 +18,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-container.ts b/lib/rules/no-container.ts index 540d67a5..56400f2e 100644 --- a/lib/rules/no-container.ts +++ b/lib/rules/no-container.ts @@ -25,6 +25,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-debugging-utils.ts b/lib/rules/no-debugging-utils.ts index 819075f4..ce39e6c0 100644 --- a/lib/rules/no-debugging-utils.ts +++ b/lib/rules/no-debugging-utils.ts @@ -32,6 +32,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-dom-import.ts b/lib/rules/no-dom-import.ts index abefbf21..299a73f3 100644 --- a/lib/rules/no-dom-import.ts +++ b/lib/rules/no-dom-import.ts @@ -23,6 +23,7 @@ export default createTestingLibraryRule({ angular: ['error', 'angular'], react: ['error', 'react'], vue: ['error', 'vue'], + marko: ['error', 'marko'], }, }, messages: { @@ -46,7 +47,11 @@ export default createTestingLibraryRule({ moduleName: string ) { if (framework) { - const correctModuleName = moduleName.replace('dom', framework); + // marko TL is called @marko/testing-library + const correctModuleName = + framework === 'marko' + ? moduleName.replace('dom-', `@${framework}/`) + : moduleName.replace('dom', framework); context.report({ node, messageId: 'noDomImportFramework', diff --git a/lib/rules/no-global-regexp-flag-in-query.ts b/lib/rules/no-global-regexp-flag-in-query.ts index 13ef6d41..ed2400e6 100644 --- a/lib/rules/no-global-regexp-flag-in-query.ts +++ b/lib/rules/no-global-regexp-flag-in-query.ts @@ -25,6 +25,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/no-manual-cleanup.ts b/lib/rules/no-manual-cleanup.ts index b7c02ca1..8c915bd1 100644 --- a/lib/rules/no-manual-cleanup.ts +++ b/lib/rules/no-manual-cleanup.ts @@ -30,6 +30,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/no-node-access.ts b/lib/rules/no-node-access.ts index 41e2b596..7777463f 100644 --- a/lib/rules/no-node-access.ts +++ b/lib/rules/no-node-access.ts @@ -18,6 +18,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-promise-in-fire-event.ts b/lib/rules/no-promise-in-fire-event.ts index aca6a19b..bbaf1d65 100644 --- a/lib/rules/no-promise-in-fire-event.ts +++ b/lib/rules/no-promise-in-fire-event.ts @@ -25,6 +25,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index ad4fe705..7ea5f4be 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -55,6 +55,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-unnecessary-act.ts b/lib/rules/no-unnecessary-act.ts index a9cd0eec..8c3fc10a 100644 --- a/lib/rules/no-unnecessary-act.ts +++ b/lib/rules/no-unnecessary-act.ts @@ -28,6 +28,7 @@ export default createTestingLibraryRule({ angular: false, react: 'error', vue: false, + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-wait-for-empty-callback.ts b/lib/rules/no-wait-for-empty-callback.ts index b90e0b22..1932cc8d 100644 --- a/lib/rules/no-wait-for-empty-callback.ts +++ b/lib/rules/no-wait-for-empty-callback.ts @@ -23,6 +23,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-wait-for-multiple-assertions.ts b/lib/rules/no-wait-for-multiple-assertions.ts index 938f7a02..614ad2e1 100644 --- a/lib/rules/no-wait-for-multiple-assertions.ts +++ b/lib/rules/no-wait-for-multiple-assertions.ts @@ -22,6 +22,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-wait-for-side-effects.ts b/lib/rules/no-wait-for-side-effects.ts index 990fa474..82f17895 100644 --- a/lib/rules/no-wait-for-side-effects.ts +++ b/lib/rules/no-wait-for-side-effects.ts @@ -25,6 +25,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/no-wait-for-snapshot.ts b/lib/rules/no-wait-for-snapshot.ts index 21704c2c..2818b4f4 100644 --- a/lib/rules/no-wait-for-snapshot.ts +++ b/lib/rules/no-wait-for-snapshot.ts @@ -24,6 +24,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/prefer-explicit-assert.ts b/lib/rules/prefer-explicit-assert.ts index 663bbbd1..155ab0c5 100644 --- a/lib/rules/prefer-explicit-assert.ts +++ b/lib/rules/prefer-explicit-assert.ts @@ -74,6 +74,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/prefer-find-by.ts b/lib/rules/prefer-find-by.ts index be5d33f8..8e7bb296 100644 --- a/lib/rules/prefer-find-by.ts +++ b/lib/rules/prefer-find-by.ts @@ -57,6 +57,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/prefer-presence-queries.ts b/lib/rules/prefer-presence-queries.ts index 2fcc6b3f..534ea8cb 100644 --- a/lib/rules/prefer-presence-queries.ts +++ b/lib/rules/prefer-presence-queries.ts @@ -23,6 +23,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/prefer-query-by-disappearance.ts b/lib/rules/prefer-query-by-disappearance.ts index bf3e3493..d34565ea 100644 --- a/lib/rules/prefer-query-by-disappearance.ts +++ b/lib/rules/prefer-query-by-disappearance.ts @@ -28,6 +28,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/prefer-screen-queries.ts b/lib/rules/prefer-screen-queries.ts index 6889ecdd..55acafad 100644 --- a/lib/rules/prefer-screen-queries.ts +++ b/lib/rules/prefer-screen-queries.ts @@ -45,6 +45,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/rules/prefer-user-event.ts b/lib/rules/prefer-user-event.ts index 29f3220c..b722eacb 100644 --- a/lib/rules/prefer-user-event.ts +++ b/lib/rules/prefer-user-event.ts @@ -76,6 +76,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/prefer-wait-for.ts b/lib/rules/prefer-wait-for.ts index ea4e1726..d181b105 100644 --- a/lib/rules/prefer-wait-for.ts +++ b/lib/rules/prefer-wait-for.ts @@ -31,6 +31,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/lib/rules/render-result-naming-convention.ts b/lib/rules/render-result-naming-convention.ts index 7b189e6e..d2aeea08 100644 --- a/lib/rules/render-result-naming-convention.ts +++ b/lib/rules/render-result-naming-convention.ts @@ -29,6 +29,7 @@ export default createTestingLibraryRule({ angular: 'error', react: 'error', vue: 'error', + marko: 'error', }, }, messages: { diff --git a/lib/utils/index.ts b/lib/utils/index.ts index 55997e11..400fae42 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -23,6 +23,7 @@ const LIBRARY_MODULES = [ '@testing-library/preact', '@testing-library/vue', '@testing-library/svelte', + '@marko/testing-library', ]; const SYNC_QUERIES_VARIANTS = ['getBy', 'getAllBy', 'queryBy', 'queryAllBy']; diff --git a/lib/utils/types.ts b/lib/utils/types.ts index 4908ccf9..728e2d94 100644 --- a/lib/utils/types.ts +++ b/lib/utils/types.ts @@ -30,6 +30,7 @@ export const SUPPORTED_TESTING_FRAMEWORKS = [ 'angular', 'react', 'vue', + 'marko', ] as const; export type SupportedTestingFramework = typeof SUPPORTED_TESTING_FRAMEWORKS[number]; diff --git a/tests/__snapshots__/index.test.ts.snap b/tests/__snapshots__/index.test.ts.snap index d800dee4..3a191824 100644 --- a/tests/__snapshots__/index.test.ts.snap +++ b/tests/__snapshots__/index.test.ts.snap @@ -49,6 +49,36 @@ Object { "testing-library/prefer-screen-queries": "error", }, }, + "marko": Object { + "plugins": Array [ + "testing-library", + ], + "rules": Object { + "testing-library/await-async-query": "error", + "testing-library/await-async-utils": "error", + "testing-library/await-fire-event": "error", + "testing-library/no-await-sync-query": "error", + "testing-library/no-container": "error", + "testing-library/no-debugging-utils": "error", + "testing-library/no-dom-import": Array [ + "error", + "marko", + ], + "testing-library/no-node-access": "error", + "testing-library/no-promise-in-fire-event": "error", + "testing-library/no-render-in-setup": "error", + "testing-library/no-unnecessary-act": "error", + "testing-library/no-wait-for-empty-callback": "error", + "testing-library/no-wait-for-multiple-assertions": "error", + "testing-library/no-wait-for-side-effects": "error", + "testing-library/no-wait-for-snapshot": "error", + "testing-library/prefer-find-by": "error", + "testing-library/prefer-presence-queries": "error", + "testing-library/prefer-query-by-disappearance": "error", + "testing-library/prefer-screen-queries": "error", + "testing-library/render-result-naming-convention": "error", + }, + }, "react": Object { "plugins": Array [ "testing-library", diff --git a/tests/create-testing-library-rule.test.ts b/tests/create-testing-library-rule.test.ts index 8861cafd..bac90142 100644 --- a/tests/create-testing-library-rule.test.ts +++ b/tests/create-testing-library-rule.test.ts @@ -10,7 +10,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: nothing related to Testing Library at all import { shallow } from 'enzyme'; - + const wrapper = shallow(); `, }, @@ -18,7 +18,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: nothing related to Testing Library at all (require version) const { shallow } = require('enzyme'); - + const wrapper = shallow(); `, }, @@ -26,7 +26,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: render imported from other than custom module import { render } from '@somewhere/else' - + const utils = render(); `, settings: { @@ -37,7 +37,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: render imported from other than custom module (require version) const { render } = require('@somewhere/else') - + const utils = render(); `, settings: { @@ -116,7 +116,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render enabled - method not containing "render" import { somethingElse } from '@somewhere/else' - + const utils = somethingElse() `, }, @@ -125,7 +125,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render disabled - method not matching valid render import { customRender } from '@somewhere/else' - + const utils = customRender() `, }, @@ -134,7 +134,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render enabled, but module disabled - not coming from TL import { render } from 'somewhere-else' - + const utils = render() `, }, @@ -157,7 +157,7 @@ ruleTester.run(RULE_NAME, rule, { // case: aggressive module disabled and render coming from non-related module import * as somethingElse from '@somewhere/else' import { render } from '@testing-library/react' - + // somethingElse.render is not coming from any module related to TL const utils = somethingElse.render() `, @@ -169,7 +169,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render disabled - method not matching custom-renders import { renderWithProviders } from '@somewhere/else' - + const utils = renderWithProviders() `, }, @@ -180,7 +180,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render switched off import { renderWithProviders } from '@somewhere/else' - + const utils = renderWithProviders() `, }, @@ -372,7 +372,7 @@ ruleTester.run(RULE_NAME, rule, { import { render } from 'other-utils' import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render() renderWithRedux() getBySomethingElse('foo') @@ -392,7 +392,7 @@ ruleTester.run(RULE_NAME, rule, { import { render } from 'other-utils' import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render() renderWithRedux() getBySomethingElse('foo') @@ -407,13 +407,13 @@ ruleTester.run(RULE_NAME, rule, { `// edge case when setting jest-dom up in jest config file - using require require('@testing-library/jest-dom') - + foo() `, `// edge case when setting jest-dom up in jest config file - using import import '@testing-library/jest-dom' - + foo() `, ], @@ -431,7 +431,7 @@ ruleTester.run(RULE_NAME, rule, { // case: render imported from any module by default (aggressive reporting) import { render } from '@somewhere/else' import { somethingElse } from 'another-module' - + const utils = render(); `, errors: [ @@ -448,7 +448,24 @@ ruleTester.run(RULE_NAME, rule, { import { render } from '@testing-library/react' import { somethingElse } from 'another-module' const foo = require('bar') - + + const utils = render(); + `, + errors: [ + { + line: 7, + column: 21, + messageId: 'renderError', + }, + ], + }, + { + code: ` + // case: render imported from Testing Library module + import { render } from '@marko/testing-library' + import { somethingElse } from 'another-module' + const foo = require('bar') + const utils = render(); `, errors: [ @@ -465,7 +482,7 @@ ruleTester.run(RULE_NAME, rule, { const { render } = require('@testing-library/react') import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render(); `, errors: [ @@ -482,7 +499,7 @@ ruleTester.run(RULE_NAME, rule, { import { render } from 'test-utils' import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render(); `, settings: { @@ -502,7 +519,7 @@ ruleTester.run(RULE_NAME, rule, { const { render } = require('test-utils') import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render(); `, settings: { @@ -523,7 +540,7 @@ ruleTester.run(RULE_NAME, rule, { import { render } from '@testing-library/react' import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render(); `, settings: { @@ -544,7 +561,7 @@ ruleTester.run(RULE_NAME, rule, { const { render } = require('@testing-library/react') import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render(); `, settings: { @@ -622,7 +639,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render enabled - Testing Library render import { render } from '@testing-library/react' - + const utils = render() `, errors: [{ line: 5, column: 21, messageId: 'renderError' }], @@ -631,7 +648,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render enabled - Testing Library render wildcard imported import * as rtl from '@testing-library/react' - + const utils = rtl.render() `, errors: [{ line: 5, column: 25, messageId: 'renderError' }], @@ -640,7 +657,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render enabled - any method containing "render" import { someRender } from '@somewhere/else' - + const utils = someRender() `, errors: [{ line: 5, column: 21, messageId: 'renderError' }], @@ -650,7 +667,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render disabled - Testing Library render import { render } from '@testing-library/react' - + const utils = render() `, errors: [{ line: 5, column: 21, messageId: 'renderError' }], @@ -662,7 +679,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render disabled - valid custom render import { customRender } from 'test-utils' - + const utils = customRender() `, errors: [{ line: 5, column: 21, messageId: 'renderError' }], @@ -674,7 +691,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive render disabled - default render from custom module import { render } from 'test-utils' - + const utils = render() `, errors: [{ line: 5, column: 21, messageId: 'renderError' }], @@ -684,7 +701,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` // case: aggressive module disabled and render wildcard-imported from related module import * as rtl from '@testing-library/react' - + const utils = rtl.render() `, errors: [{ line: 5, column: 25, messageId: 'renderError' }], @@ -698,7 +715,7 @@ ruleTester.run(RULE_NAME, rule, { import { render } from 'test-utils' import { somethingElse } from 'another-module' const foo = require('bar') - + const utils = render(); `, errors: [{ line: 7, column: 21, messageId: 'renderError' }], @@ -777,7 +794,7 @@ ruleTester.run(RULE_NAME, rule, { 'testing-library/utils-module': 'test-utils', }, code: ` - // case: aggressive reporting disabled - waitFor from wildcard import related to TL + // case: aggressive reporting disabled - waitFor from wildcard import related to TL import * as tl from 'test-utils' tl.waitFor(() => {}) `, @@ -993,13 +1010,13 @@ ruleTester.run(RULE_NAME, rule, { // case: aggressive reporting disabled - matching all custom settings import { renderWithRedux, waitFor, screen } from 'test-utils' import { findByComplexText } from 'custom-queries' - + const { getByRole, getAllByIcon } = renderWithRedux() const el = getByRole('button') const iconButtons = getAllByIcon('search') waitFor(() => {}) findByComplexText('foo') - + `, errors: [ { line: 6, column: 43, messageId: 'renderError' }, @@ -1024,7 +1041,7 @@ ruleTester.run(RULE_NAME, rule, { // case: built-in utils reported when all aggressive reporting completely switched off import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event' - + const utils = render(); const el = utils.getByText('foo'); screen.findByRole('button'); diff --git a/tests/fake-rule.ts b/tests/fake-rule.ts index 02cad182..58320162 100644 --- a/tests/fake-rule.ts +++ b/tests/fake-rule.ts @@ -31,6 +31,7 @@ export default createTestingLibraryRule({ angular: false, react: false, vue: false, + marko: false, }, }, messages: { diff --git a/tests/index.test.ts b/tests/index.test.ts index 8bb777fc..46dde63b 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -58,7 +58,13 @@ it("should have run 'generate:configs' script when changing config rules", async it('should export configs that refer to actual rules', () => { const allConfigs = plugin.configs; - expect(Object.keys(allConfigs)).toEqual(['dom', 'angular', 'react', 'vue']); + expect(Object.keys(allConfigs)).toEqual([ + 'dom', + 'angular', + 'react', + 'vue', + 'marko', + ]); const allConfigRules = Object.values(allConfigs) .map((config) => Object.keys(config.rules)) .reduce((previousValue, currentValue) => [ diff --git a/tests/lib/rules/await-async-query.test.ts b/tests/lib/rules/await-async-query.test.ts index d207c7d7..0fc56c67 100644 --- a/tests/lib/rules/await-async-query.test.ts +++ b/tests/lib/rules/await-async-query.test.ts @@ -14,21 +14,27 @@ const ruleTester = createRuleTester(); interface TestCode { code: string; isAsync?: boolean; + testingFramework: string; } -function createTestCode({ code, isAsync = true }: TestCode) { +function createTestCode({ + code, + isAsync = true, + testingFramework = '@testing-library/react', +}: TestCode) { return ` - import { render } from '@testing-library/react' - test("An example test",${isAsync ? ' async ' : ' '}() => { - ${code} - }) - `; + import { render } from '${testingFramework}' + test("An example test",${isAsync ? ' async ' : ' '}() => { + ${code} + }) + `; } interface TestCaseParams { isAsync?: boolean; combinations?: string[]; errors?: TSESLint.TestCaseError<'asyncQueryWrapper' | 'awaitAsyncQuery'>[]; + testingFramework?: string; } function createTestCase( @@ -40,15 +46,19 @@ function createTestCase( { combinations = ALL_ASYNC_COMBINATIONS_TO_TEST, isAsync, + testingFramework = '', }: TestCaseParams = {} ) { return combinations.map((query) => { const test = getTest(query); return typeof test === 'string' - ? { code: createTestCode({ code: test, isAsync }), errors: [] } + ? { + code: createTestCode({ code: test, isAsync, testingFramework }), + errors: [], + } : { - code: createTestCode({ code: test.code, isAsync }), + code: createTestCode({ code: test.code, isAsync, testingFramework }), errors: test.errors, }; }); @@ -75,6 +85,11 @@ ruleTester.run(RULE_NAME, rule, { // async screen queries declaration are valid ...createTestCase((query) => `await screen.${query}('foo')`), + // async @marko/testing-library screen queries declaration are valid + ...createTestCase((query) => `await screen.${query}('foo')`, { + testingFramework: '@marko/testing-library', + }), + // async queries are valid with await operator ...createTestCase( (query) => ` @@ -121,7 +136,7 @@ ruleTester.run(RULE_NAME, rule, { ...createTestCase( (query) => ` doSomething() - + await Promise.all([ ${query}('foo'), ${query}('bar'), @@ -133,7 +148,7 @@ ruleTester.run(RULE_NAME, rule, { ...createTestCase( (query) => ` doSomething() - + Promise.all([ ${query}('foo'), ${query}('bar'), @@ -145,7 +160,7 @@ ruleTester.run(RULE_NAME, rule, { ...createTestCase( (query) => ` doSomething() - + await Promise.allSettled([ ${query}('foo'), ${query}('bar'), @@ -157,7 +172,7 @@ ruleTester.run(RULE_NAME, rule, { ...createTestCase( (query) => ` doSomething() - + Promise.allSettled([ ${query}('foo'), ${query}('bar'), @@ -281,19 +296,19 @@ ruleTester.run(RULE_NAME, rule, { `// issue #359 import { render, screen } from 'mocks/test-utils' import userEvent from '@testing-library/user-event' - + const testData = { name: 'John Doe', email: 'john@doe.com', password: 'extremeSecret', } - + const selectors = { username: () => screen.findByRole('textbox', { name: /username/i }), email: () => screen.findByRole('textbox', { name: /e-mail/i }), password: () => screen.findByLabelText(/password/i), } - + test('this is a valid case', async () => { render() userEvent.type(await selectors.username(), testData.name) @@ -324,6 +339,20 @@ ruleTester.run(RULE_NAME, rule, { errors: [{ messageId: 'awaitAsyncQuery', line: 6, column: 21 }], } as const) ), + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: `// async queries for @marko/testing-library without await operator or then method are not valid + import { render } from '@marko/testing-library' + + test("An example test", async () => { + doSomething() + const foo = ${query}('foo') + }); + `, + errors: [{ messageId: 'awaitAsyncQuery', line: 6, column: 21 }], + } as const) + ), ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( (query) => ({ @@ -483,19 +512,19 @@ ruleTester.run(RULE_NAME, rule, { code: `// similar to issue #359 but forcing an error in no-awaited wrapper import { render, screen } from 'mocks/test-utils' import userEvent from '@testing-library/user-event' - + const testData = { name: 'John Doe', email: 'john@doe.com', password: 'extremeSecret', } - + const selectors = { username: () => screen.findByRole('textbox', { name: /username/i }), email: () => screen.findByRole('textbox', { name: /e-mail/i }), password: () => screen.findByLabelText(/password/i), } - + test('this is a valid case', async () => { render() userEvent.type(selectors.username(), testData.name) // <-- unhandled here diff --git a/tests/lib/rules/await-fire-event.test.ts b/tests/lib/rules/await-fire-event.test.ts index 2369539f..7199cc00 100644 --- a/tests/lib/rules/await-fire-event.test.ts +++ b/tests/lib/rules/await-fire-event.test.ts @@ -29,6 +29,14 @@ ruleTester.run(RULE_NAME, rule, { }) `, })), + ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ + code: ` + import { fireEvent } from '@marko/testing-library' + test('await promise from fire event method is valid', async () => { + await fireEvent.${fireEventMethod}(getByLabelText('username')) + }) + `, + })), ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ code: ` import { fireEvent } from '@testing-library/vue' @@ -94,7 +102,7 @@ ruleTester.run(RULE_NAME, rule, { doSomething() return fireEvent.${fireEventMethod}(getByLabelText('username')) } - + await triggerEvent() }) `, @@ -132,7 +140,7 @@ ruleTester.run(RULE_NAME, rule, { doSomething() return fireEvent.focus(getByLabelText('username')) } - + const reassignedFunction = triggerEvent }) `, @@ -159,6 +167,26 @@ ruleTester.run(RULE_NAME, rule, { ], } as const) ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` + import { fireEvent } from '@marko/testing-library' + test('unhandled promise from fire event method is invalid', async () => { + fireEvent.${fireEventMethod}(getByLabelText('username')) + }) + `, + errors: [ + { + line: 4, + column: 9, + endColumn: 19 + fireEventMethod.length, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), ...COMMON_FIRE_EVENT_METHODS.map( (fireEventMethod) => ({ diff --git a/tests/lib/rules/no-await-sync-query.test.ts b/tests/lib/rules/no-await-sync-query.test.ts index fb01165d..e9e80d5a 100644 --- a/tests/lib/rules/no-await-sync-query.test.ts +++ b/tests/lib/rules/no-await-sync-query.test.ts @@ -95,7 +95,7 @@ ruleTester.run(RULE_NAME, rule, { // ... await someOtherAsyncFunction(); }; - + await chooseElementFromSomewhere('someTextToUseInAQuery', getAllByLabelText); `, @@ -235,6 +235,18 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ messageId: 'noAwaitSyncQuery', line: 4, column: 38 }], }, + // sync query awaited and related to testing library module + // with custom module setting is not valid + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { screen } from '@marko/testing-library' + () => { + const element = await screen.getByRole('button') + } + `, + errors: [{ messageId: 'noAwaitSyncQuery', line: 4, column: 38 }], + }, // sync query awaited and related to custom module is not valid { settings: { 'testing-library/utils-module': 'test-utils' }, diff --git a/tests/lib/rules/no-container.test.ts b/tests/lib/rules/no-container.test.ts index c28d3071..1128b9cb 100644 --- a/tests/lib/rules/no-container.test.ts +++ b/tests/lib/rules/no-container.test.ts @@ -57,6 +57,15 @@ ruleTester.run(RULE_NAME, rule, { const button = container.querySelector('.btn-primary'); `, }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { render as renamed } from '@marko/testing-library' + import { render } from 'somewhere-else' + const { container } = render(); + const button = container.querySelector('.btn-primary'); + `, + }, { settings: { 'testing-library/custom-renders': ['customRender', 'renderWithRedux'], @@ -116,7 +125,25 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from '@testing-library/react' - + + const setup = () => render() + + const { container } = setup() + const button = container.querySelector('.btn-primary'); + `, + errors: [ + { + line: 7, + column: 24, + messageId: 'noContainer', + }, + ], + }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { render } from '@marko/testing-library' + const setup = () => render() const { container } = setup() diff --git a/tests/lib/rules/no-debugging-utils.test.ts b/tests/lib/rules/no-debugging-utils.test.ts index 56814597..11b61d8a 100644 --- a/tests/lib/rules/no-debugging-utils.test.ts +++ b/tests/lib/rules/no-debugging-utils.test.ts @@ -154,9 +154,21 @@ ruleTester.run(RULE_NAME, rule, { code: ` import { render as testingRender } from '@testing-library/react' import { render } from 'somewhere-else' - + const { debug } = render(element) - + + somethingElse() + debug() + `, + }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { render as testingRender } from '@marko/testing-library' + import { render } from 'somewhere-else' + + const { debug } = render(element) + somethingElse() debug() `, @@ -166,10 +178,10 @@ ruleTester.run(RULE_NAME, rule, { code: ` import { render as testingRender } from '@testing-library/react' import { render } from 'somewhere-else' - + const { debug } = render(element) const { debug: testingDebug } = testingRender(element) - + somethingElse() debug() `, @@ -575,9 +587,9 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from 'aggressive-reporting' - + const { debug } = render(element) - + somethingElse() debug() `, @@ -587,9 +599,21 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from '@testing-library/react' - + const { debug } = render(element) - + + somethingElse() + debug() + `, + errors: [{ line: 7, column: 7, messageId: 'noDebug' }], + }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { render } from '@marko/testing-library' + + const { debug } = render(element) + somethingElse() debug() `, @@ -599,9 +623,9 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from 'test-utils' - + const { debug: renamed } = render(element) - + somethingElse() renamed() `, @@ -611,9 +635,9 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from '@testing-library/react' - + const utils = render(element) - + somethingElse() utils.debug() `, @@ -626,9 +650,9 @@ ruleTester.run(RULE_NAME, rule, { }, code: `// aggressive reporting disabled, custom render set import { testingRender } from 'test-utils' - + const { debug: renamedDebug } = testingRender(element) - + somethingElse() renamedDebug() `, @@ -638,7 +662,7 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from '@testing-library/react' - + const utils = render(element) const { debug: renamedDestructuredDebug } = console const { debug } = console diff --git a/tests/lib/rules/no-dom-import.test.ts b/tests/lib/rules/no-dom-import.test.ts index 4dfc0623..520659e5 100644 --- a/tests/lib/rules/no-dom-import.test.ts +++ b/tests/lib/rules/no-dom-import.test.ts @@ -21,6 +21,7 @@ ruleTester.run(RULE_NAME, rule, { 'const { fireEvent } = require("@testing-library/react")', 'require("react-testing-library")', 'require("@testing-library/react")', + 'require("@marko/testing-library")', { code: 'import { fireEvent } from "test-utils"', settings: { 'testing-library/utils-module': 'test-utils' }, @@ -66,6 +67,19 @@ ruleTester.run(RULE_NAME, rule, { ], output: `import { fireEvent } from "react-testing-library"`, }, + { + code: 'import { fireEvent } from "dom-testing-library"', + options: ['marko'], + errors: [ + { + messageId: 'noDomImportFramework', + data: { + module: '@marko/testing-library', + }, + }, + ], + output: `import { fireEvent } from "@marko/testing-library"`, + }, // Single quote or double quotes should not be replaced { code: `import { fireEvent } from 'dom-testing-library'`, diff --git a/tests/lib/rules/no-node-access.test.ts b/tests/lib/rules/no-node-access.test.ts index 39d172a4..f73a6b10 100644 --- a/tests/lib/rules/no-node-access.test.ts +++ b/tests/lib/rules/no-node-access.test.ts @@ -8,7 +8,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { screen } from '@testing-library/react'; - + const buttonText = screen.getByText('submit'); `, }, @@ -29,10 +29,18 @@ ruleTester.run(RULE_NAME, rule, { expect(firstChild).toBeInTheDocument() `, }, + { + code: ` + import { screen } from '@marko/testing-library'; + + const firstChild = screen.getByText('submit'); + expect(firstChild).toBeInTheDocument() + `, + }, { code: ` import { screen } from '@testing-library/react'; - + const { getByText } = screen; const button = getByRole('button'); expect(button).toHaveTextContent('submit'); @@ -98,7 +106,26 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { screen } from '@testing-library/react'; - + + const button = document.getElementById('submit-btn').closest('button'); + `, + errors: [ + { + line: 4, + column: 33, + messageId: 'noNodeAccess', + }, + { + line: 4, + column: 62, + messageId: 'noNodeAccess', + }, + ], + }, + { + code: ` + import { screen } from '@marko/testing-library'; + const button = document.getElementById('submit-btn').closest('button'); `, errors: [ @@ -131,7 +158,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { screen } from '@testing-library/react'; - + screen.getByText('submit').closest('button'); `, errors: [ @@ -146,7 +173,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { screen } from '@testing-library/react'; - + expect(screen.getByText('submit').closest('button').textContent).toBe('Submit'); `, errors: [ @@ -159,8 +186,8 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { render } from '@testing-library/react'; - + import { render } from '@testing-library/react'; + const { getByText } = render() getByText('submit').closest('button'); `, @@ -193,7 +220,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { screen } from '@testing-library/react'; - + const buttonText = screen.getByText('submit'); const button = buttonText.closest('button'); `, @@ -202,7 +229,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const { getByText } = render() const buttonText = getByText('submit'); const button = buttonText.closest('button'); @@ -218,7 +245,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const { getByText } = render() const button = getByText('submit').closest('button'); `, @@ -227,7 +254,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { screen } from '@testing-library/react'; - + function getExampleDOM() { const container = document.createElement('div'); container.innerHTML = \` diff --git a/tests/lib/rules/no-unnecessary-act.test.ts b/tests/lib/rules/no-unnecessary-act.test.ts index 997570ae..7f1dbcf9 100644 --- a/tests/lib/rules/no-unnecessary-act.test.ts +++ b/tests/lib/rules/no-unnecessary-act.test.ts @@ -119,6 +119,67 @@ const validTestCases: ValidTestCase[] = [ }); `, }, + { + code: `// case: Marko TL act wrapping non-Marko TL calls + import { act } from '@marko/testing-library' + + test('valid case', async () => { + act(() => { + stuffThatDoesNotUseRTL(); + }); + + act(function() { + a = stuffThatDoesNotUseRTL(); + }); + + act(function() { + a = await stuffThatDoesNotUseRTL(); + }); + + await act(async () => { + await stuffThatDoesNotUseRTL(); + }); + + await act(async () => { + await stuffThatDoesNotUseRTL; + }); + + await act(() => stuffThatDoesNotUseRTL); + + act(() => stuffThatDoesNotUseRTL); + + act(() => { + return stuffThatDoesNotUseRTL + }); + + act(async function() { + await stuffThatDoesNotUseRTL; + }); + + await act(async function() { + await stuffThatDoesNotUseRTL; + }); + + act(async function() { + return stuffThatDoesNotUseRTL; + }); + + act(function() { + stuffThatDoesNotUseRTL(); + const a = foo(); + }); + + act(function() { + return stuffThatDoesNotUseRTL(); + }); + + act(() => stuffThatDoesNotUseRTL()); + + act(() => stuffThatDoesNotUseRTL()).then(() => {}) + act(stuffThatDoesNotUseRTL().then(() => {})) + }); + `, + }, { code: `// case: RTU act wrapping non-RTL import { act } from 'react-dom/test-utils' @@ -319,6 +380,86 @@ const invalidTestCases: InvalidTestCase[] = [ }, ], }, + { + code: `// case: Marko TL act wrapping Marko TL calls - callbacks with body (BlockStatement) + import { act, fireEvent, screen, render, waitFor, waitForElementToBeRemoved } from '@marko/testing-library' + import userEvent from '@testing-library/user-event' + + test('invalid case', async () => { + act(() => { + fireEvent.click(el); + }); + + await act(async () => { + waitFor(() => {}); + }); + + await act(async () => { + waitForElementToBeRemoved(el); + }); + + act(function() { + const blah = screen.getByText('blah'); + }); + + act(function() { + render(something); + }); + + await act(() => { + const button = findByRole('button') + }); + + act(() => { + userEvent.click(el) + }); + + act(() => { + waitFor(); + const element = screen.getByText('blah'); + userEvent.click(element) + }); + }); + `, + errors: [ + { messageId: 'noUnnecessaryActTestingLibraryUtil', line: 6, column: 9 }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 10, + column: 15, + }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 14, + column: 15, + }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 18, + column: 9, + }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 22, + column: 9, + }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 26, + column: 15, + }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 30, + column: 9, + }, + { + messageId: 'noUnnecessaryActTestingLibraryUtil', + line: 34, + column: 9, + }, + ], + }, { settings: { 'testing-library/utils-module': 'test-utils', diff --git a/tests/lib/rules/no-wait-for-empty-callback.test.ts b/tests/lib/rules/no-wait-for-empty-callback.test.ts index d9dae719..e2743772 100644 --- a/tests/lib/rules/no-wait-for-empty-callback.test.ts +++ b/tests/lib/rules/no-wait-for-empty-callback.test.ts @@ -47,6 +47,14 @@ ruleTester.run(RULE_NAME, rule, { waitFor(() => {}) `, }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { waitFor as renamedWaitFor } from '@marko/testing-library' + import { waitFor } from 'somewhere-else' + waitFor(() => {}) + `, + }, ], invalid: [ @@ -86,6 +94,26 @@ ruleTester.run(RULE_NAME, rule, { ], } as const) ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { ${m} } from '@marko/testing-library'; + ${m}(() => {}); + `, + errors: [ + { + line: 3, + column: 16 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), ...ALL_WAIT_METHODS.map( (m) => ({ diff --git a/tests/lib/rules/no-wait-for-multiple-assertions.test.ts b/tests/lib/rules/no-wait-for-multiple-assertions.test.ts index 84a3f4be..c2cc878c 100644 --- a/tests/lib/rules/no-wait-for-multiple-assertions.test.ts +++ b/tests/lib/rules/no-wait-for-multiple-assertions.test.ts @@ -40,6 +40,17 @@ ruleTester.run(RULE_NAME, rule, { }) `, }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: `// Aggressive Reporting disabled - waitFor renamed + import { waitFor as renamedWaitFor } from '@marko/testing-library' + import { waitFor } from 'somewhere-else' + await waitFor(() => { + expect(a).toEqual('a') + expect(b).toEqual('b') + }) + `, + }, // this needs to be check by other rule { code: ` @@ -116,6 +127,19 @@ ruleTester.run(RULE_NAME, rule, { { line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' }, ], }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: `// Aggressive Reporting disabled + import { waitFor } from '@marko/testing-library' + await waitFor(() => { + expect(a).toEqual('a') + expect(b).toEqual('b') + }) + `, + errors: [ + { line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' }, + ], + }, { settings: { 'testing-library/utils-module': 'test-utils' }, code: `// Aggressive Reporting disabled diff --git a/tests/lib/rules/no-wait-for-side-effects.test.ts b/tests/lib/rules/no-wait-for-side-effects.test.ts index e5102126..e4238513 100644 --- a/tests/lib/rules/no-wait-for-side-effects.test.ts +++ b/tests/lib/rules/no-wait-for-side-effects.test.ts @@ -7,13 +7,19 @@ ruleTester.run(RULE_NAME, rule, { valid: [ { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; + await waitFor(() => expect(a).toEqual('a')) + `, + }, + { + code: ` + import { waitFor } from '@marko/testing-library'; await waitFor(() => expect(a).toEqual('a')) `, }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { expect(a).toEqual('a') }) @@ -21,7 +27,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => { console.log('testing-library') expect(b).toEqual('b') @@ -30,7 +36,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { console.log('testing-library') expect(b).toEqual('b') @@ -39,19 +45,19 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => {}) `, }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() {}) `, }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => { // testing }) @@ -59,7 +65,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { // testing }) @@ -67,7 +73,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; fireEvent.keyDown(input, {key: 'ArrowDown'}) await waitFor(() => { expect(b).toEqual('b') @@ -76,7 +82,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; fireEvent.keyDown(input, {key: 'ArrowDown'}) await waitFor(function() { expect(b).toEqual('b') @@ -85,7 +91,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; userEvent.click(button) await waitFor(function() { expect(b).toEqual('b') @@ -95,7 +101,7 @@ ruleTester.run(RULE_NAME, rule, { { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` - import { waitFor } from 'somewhere-else'; + import { waitFor } from 'somewhere-else'; await waitFor(function() { fireEvent.keyDown(input, {key: 'ArrowDown'}) expect(b).toEqual('b') @@ -105,12 +111,12 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { waitFor } from '@testing-library/react'; - + anotherFunction(() => { fireEvent.keyDown(input, {key: 'ArrowDown'}); userEvent.click(button); }); - + test('side effects in functions other than waitFor are valid', () => { fireEvent.keyDown(input, {key: 'ArrowDown'}) userEvent.click(button) @@ -311,6 +317,13 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 29, messageId: 'noSideEffectsWaitFor' }], }, + { + code: ` + import { waitFor } from '@marko/testing-library'; + await waitFor(() => render()) + `, + errors: [{ line: 3, column: 29, messageId: 'noSideEffectsWaitFor' }], + }, { code: ` import { waitFor } from '@testing-library/react'; @@ -541,7 +554,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor, fireEvent as renamedFireEvent } from '@testing-library/react'; + import { waitFor, fireEvent as renamedFireEvent } from '@testing-library/react'; await waitFor(() => { renamedFireEvent.keyDown(input, {key: 'ArrowDown'}) }) @@ -551,7 +564,7 @@ ruleTester.run(RULE_NAME, rule, { { settings: { 'testing-library/utils-module': '~/test-utils' }, code: ` - import { waitFor, fireEvent } from '~/test-utils'; + import { waitFor, fireEvent } from '~/test-utils'; await waitFor(() => { fireEvent.keyDown(input, {key: 'ArrowDown'}) }) @@ -560,7 +573,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => { expect(b).toEqual('b') fireEvent.keyDown(input, {key: 'ArrowDown'}) @@ -570,7 +583,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => { fireEvent.keyDown(input, {key: 'ArrowDown'}) expect(b).toEqual('b') @@ -580,7 +593,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { fireEvent.keyDown(input, {key: 'ArrowDown'}) }) @@ -589,7 +602,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { expect(b).toEqual('b') fireEvent.keyDown(input, {key: 'ArrowDown'}) @@ -599,7 +612,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { fireEvent.keyDown(input, {key: 'ArrowDown'}) expect(b).toEqual('b') @@ -627,7 +640,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { waitFor } from '@testing-library/react'; - import renamedUserEvent from '@testing-library/user-event' + import renamedUserEvent from '@testing-library/user-event' await waitFor(() => { renamedUserEvent.click(button) }) @@ -638,7 +651,7 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': '~/test-utils' }, code: ` import { waitFor } from '~/test-utils'; - import userEvent from '@testing-library/user-event' + import userEvent from '@testing-library/user-event' await waitFor(() => { userEvent.click(); }) @@ -647,7 +660,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => { expect(b).toEqual('b') userEvent.click(button) @@ -657,7 +670,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(() => { userEvent.click(button) expect(b).toEqual('b') @@ -667,7 +680,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { userEvent.click(button) }) @@ -676,7 +689,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { expect(b).toEqual('b') userEvent.click(button) @@ -686,7 +699,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: ` - import { waitFor } from '@testing-library/react'; + import { waitFor } from '@testing-library/react'; await waitFor(function() { userEvent.click(button) expect(b).toEqual('b') @@ -701,7 +714,7 @@ ruleTester.run(RULE_NAME, rule, { import { waitFor, fireEvent as renamedFireEvent, screen } from '~/test-utils'; import userEvent from '@testing-library/user-event' import { fireEvent } from 'somewhere-else' - + test('check all mixed', async () => { const button = await screen.findByRole('button') await waitFor(() => { diff --git a/tests/lib/rules/prefer-query-by-disappearance.test.ts b/tests/lib/rules/prefer-query-by-disappearance.test.ts index 3f9d5460..a987a5fa 100644 --- a/tests/lib/rules/prefer-query-by-disappearance.test.ts +++ b/tests/lib/rules/prefer-query-by-disappearance.test.ts @@ -15,6 +15,14 @@ ruleTester.run(RULE_NAME, rule, { await waitForElementToBeRemoved(button) `, }, + { + code: ` + import { screen } from '@marko/testing-library'; + + const button = screen.getByRole('button') + await waitForElementToBeRemoved(button) + `, + }, { code: ` import { screen } from '@testing-library/react'; @@ -221,6 +229,20 @@ ruleTester.run(RULE_NAME, rule, { }, ], }, + { + code: ` + import { screen, waitForElementToBeRemoved } from '@marko/testing-library'; + + await waitForElementToBeRemoved(() => screen.getByText("hello")) + `, + errors: [ + { + messageId: 'preferQueryByDisappearance', + line: 4, + column: 41, + }, + ], + }, { code: ` import { screen, waitForElementToBeRemoved } from '@testing-library/react'; diff --git a/tests/lib/rules/prefer-screen-queries.test.ts b/tests/lib/rules/prefer-screen-queries.test.ts index c94a1474..5b264897 100644 --- a/tests/lib/rules/prefer-screen-queries.test.ts +++ b/tests/lib/rules/prefer-screen-queries.test.ts @@ -266,6 +266,26 @@ ruleTester.run(RULE_NAME, rule, { ], } as const) ), + ...ALL_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + import { render as testingLibraryRender} from '@marko/testing-library' + const { ${queryMethod} } = testingLibraryRender(foo) + ${queryMethod}()`, + errors: [ + { + line: 4, + column: 9, + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), ...ALL_QUERIES_COMBINATIONS.map( (queryMethod) => ({ @@ -416,16 +436,16 @@ ruleTester.run(RULE_NAME, rule, { { code: ` // issue #367 - example A import { render } from '@testing-library/react'; - + function setup() { return render(
); } - + it('foo', async () => { const { getByText } = await setup(); expect(getByText('foo')).toBeInTheDocument(); }); - + it('bar', () => { const { getByText } = setup(); expect(getByText('foo')).toBeInTheDocument(); @@ -453,16 +473,16 @@ ruleTester.run(RULE_NAME, rule, { { code: ` // issue #367 - example B import { render } from '@testing-library/react'; - + function setup() { return render(
); } - + it('foo', () => { const { getByText } = setup(); expect(getByText('foo')).toBeInTheDocument(); }); - + it('bar', () => { const results = setup(); const { getByText } = results; diff --git a/tests/lib/rules/render-result-naming-convention.test.ts b/tests/lib/rules/render-result-naming-convention.test.ts index 51b9e023..61d17a54 100644 --- a/tests/lib/rules/render-result-naming-convention.test.ts +++ b/tests/lib/rules/render-result-naming-convention.test.ts @@ -10,7 +10,17 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + + test('should not report straight destructured render result', () => { + const { rerender, getByText } = render(); + const button = getByText('some button'); + }); + `, + }, + { + code: ` + import { render } from '@marko/testing-library'; + test('should not report straight destructured render result', () => { const { rerender, getByText } = render(); const button = getByText('some button'); @@ -20,7 +30,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import * as RTL from '@testing-library/react'; - + test('should not report straight destructured render result from wildcard import', () => { const { rerender, getByText } = RTL.render(); const button = getByText('some button'); @@ -30,7 +40,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + test('should not report straight render result called "utils"', async () => { const utils = render(); await utils.findByRole('button'); @@ -40,7 +50,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + test('should not report straight render result called "view"', async () => { const view = render(); await view.findByRole('button'); @@ -50,9 +60,9 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const setup = () => render(); - + test('should not report destructured render result from wrapping function', () => { const { rerender, getByText } = setup(); const button = getByText('some button'); @@ -62,9 +72,9 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const setup = () => render(); - + test('should not report render result called "utils" from wrapping function', async () => { const utils = setup(); await utils.findByRole('button'); @@ -74,9 +84,9 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const setup = () => render(); - + test('should not report render result called "view" from wrapping function', async () => { const view = setup(); await view.findByRole('button'); @@ -87,7 +97,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` import { screen } from '@testing-library/react'; import { customRender } from 'test-utils'; - + test('should not report straight destructured render result from custom render', () => { const { unmount } = customRender(); const button = screen.getByText('some button'); @@ -98,7 +108,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { customRender } from 'test-utils'; - + test('should not report render result called "view" from custom render', async () => { const view = customRender(); await view.findByRole('button'); @@ -109,7 +119,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { customRender } from 'test-utils'; - + test('should not report render result called "utils" from custom render', async () => { const utils = customRender(); await utils.findByRole('button'); @@ -120,7 +130,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const setup = () => { // this one must have a valid name const view = render(); @@ -139,7 +149,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` import { render as testingLibraryRender } from '@testing-library/react'; import { render } from '@somewhere/else' - + const setup = () => render(); test('aggressive reporting disabled - should not report nested render not related to TL', () => { @@ -156,7 +166,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` import { customRender as myRender } from 'test-utils'; import { customRender } from 'non-related' - + const setup = () => { return customRender(); }; @@ -177,7 +187,7 @@ ruleTester.run(RULE_NAME, rule, { code: ` import { customRender as myRender } from 'test-utils'; import { render } from 'non-related' - + const setup = () => { return render(); }; @@ -198,7 +208,27 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + + test('should report straight render result called "wrapper"', async () => { + const wrapper = render(); + await wrapper.findByRole('button'); + }); + `, + errors: [ + { + messageId: 'renderResultNamingConvention', + data: { + renderResultName: 'wrapper', + }, + line: 5, + column: 17, + }, + ], + }, + { + code: ` + import { render } from '@marko/testing-library'; + test('should report straight render result called "wrapper"', async () => { const wrapper = render(); await wrapper.findByRole('button'); @@ -218,7 +248,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import * as RTL from '@testing-library/react'; - + test('should report straight render result called "wrapper" from wildcard import', () => { const wrapper = RTL.render(); const button = wrapper.getByText('some button'); @@ -238,7 +268,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + test('should report straight render result called "component"', async () => { const component = render(); await component.findByRole('button'); @@ -258,7 +288,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + test('should report straight render result called "notValidName"', async () => { const notValidName = render(); await notValidName.findByRole('button'); @@ -275,7 +305,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render as testingLibraryRender } from '@testing-library/react'; - + test('should report renamed render result called "wrapper"', async () => { const wrapper = testingLibraryRender(); await wrapper.findByRole('button'); @@ -295,7 +325,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/react'; - + const setup = () => { // this one must have a valid name const wrapper = render(); @@ -323,7 +353,7 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from '@testing-library/react'; - + const setup = () => render(); test('aggressive reporting disabled - should report nested render from TL package', () => { @@ -346,7 +376,7 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from 'test-utils'; - + function setup() { doSomethingElse(); return render() @@ -454,7 +484,7 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render as testingLibraryRender } from '@testing-library/react'; - + const setup = () => { return testingLibraryRender(); }; @@ -479,7 +509,7 @@ ruleTester.run(RULE_NAME, rule, { settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render as testingLibraryRender } from '@testing-library/react'; - + const setup = () => { return testingLibraryRender(); }; @@ -509,7 +539,7 @@ ruleTester.run(RULE_NAME, rule, { }, code: ` import { customRender as myRender } from 'test-utils'; - + const setup = () => { return myRender(); };