Skip to content

Commit 610b3b9

Browse files
refactor: automatically generate all shareable configs (#358)
* refactor: extract configs into their own files * chore: add generate-configs script * fix: make rules comply with TestingLibraryRuleMeta * chore: automatically generate all configs * refactor: use recommendedConfig instead of recommended in meta docs * fix: add prefix in front of rule names in configs * test: fix createTestingLibraryRule test * chore: resolve remarks * chore: reference running scripts via npm instead of yarn * chore: don't warn on unused variables beginning with _ * docs(CONTRIBUTING): add some explanation about recommendedConfig
1 parent 42d84c9 commit 610b3b9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+407
-107
lines changed

.eslintrc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
},
2424
"rules": {
2525
"no-var": "error",
26-
"@typescript-eslint/explicit-function-return-type": "off"
26+
"@typescript-eslint/explicit-function-return-type": "off",
27+
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }]
2728
}
2829
}

CONTRIBUTING.md

+2-5
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,6 @@ each rule has three files named with its identifier (e.g. `no-debug`):
6363
6464
Additionally, you need to do a couple of extra things:
6565
66-
- Import the new rule in `lib/index.ts` and include it
67-
in `rules` constant (there is a test which will make sure you did
68-
this). Remember to include your rule under corresponding `config` if necessary
69-
(a snapshot test will check this too, but you can update it just running
70-
`npm run test:update`).
7166
- Include your rule in the "Supported Rules" table within the [README.md](./README.md).
7267
Don't forget to include the proper badges if needed and to sort alphabetically the rules for readability.
7368
@@ -105,6 +100,8 @@ If you need some check related to Testing Library which is not available in any
105100
- pass it through `helpers`
106101
- write some generic test within `fake-rule.ts`, which is a dumb rule to be able to test all enhanced behavior from our custom Rule Creator.
107102
103+
Take also into account that we're using our own `recommendedConfig` meta instead of the default `recommended` one. This is done so that our tools can automatically generate (`npm run generate:configs`) our configs.
104+
108105
## Updating existing rules
109106
110107
A couple of things you need to remember when editing already existing rules:

lib/configs/angular.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// THIS CODE WAS AUTOMATICALLY GENERATED
2+
// DO NOT EDIT THIS CODE BY HAND
3+
// YOU CAN REGENERATE IT USING npm run generate:configs
4+
5+
export = {
6+
plugins: ['testing-library'],
7+
rules: {
8+
'testing-library/await-async-query': 'error',
9+
'testing-library/await-async-utils': 'error',
10+
'testing-library/no-await-sync-query': 'error',
11+
'testing-library/no-container': 'error',
12+
'testing-library/no-debug': 'error',
13+
'testing-library/no-dom-import': ['error', 'angular'],
14+
'testing-library/no-node-access': 'error',
15+
'testing-library/no-promise-in-fire-event': 'error',
16+
'testing-library/no-wait-for-empty-callback': 'error',
17+
'testing-library/prefer-find-by': 'error',
18+
'testing-library/prefer-screen-queries': 'error',
19+
'testing-library/render-result-naming-convention': 'error',
20+
},
21+
};

lib/configs/dom.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// THIS CODE WAS AUTOMATICALLY GENERATED
2+
// DO NOT EDIT THIS CODE BY HAND
3+
// YOU CAN REGENERATE IT USING npm run generate:configs
4+
5+
export = {
6+
plugins: ['testing-library'],
7+
rules: {
8+
'testing-library/await-async-query': 'error',
9+
'testing-library/await-async-utils': 'error',
10+
'testing-library/no-await-sync-query': 'error',
11+
'testing-library/no-promise-in-fire-event': 'error',
12+
'testing-library/no-wait-for-empty-callback': 'error',
13+
'testing-library/prefer-find-by': 'error',
14+
'testing-library/prefer-screen-queries': 'error',
15+
},
16+
};

lib/configs/index.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { join } from 'path';
2+
3+
import type { TSESLint } from '@typescript-eslint/experimental-utils';
4+
5+
import {
6+
importDefault,
7+
SUPPORTED_TESTING_FRAMEWORKS,
8+
SupportedTestingFramework,
9+
} from '../utils';
10+
11+
export type LinterConfigRules = Record<string, TSESLint.Linter.RuleEntry>;
12+
13+
const configsDir = __dirname;
14+
15+
const getConfigForFramework = (framework: SupportedTestingFramework) =>
16+
importDefault<LinterConfigRules>(join(configsDir, framework));
17+
18+
export default SUPPORTED_TESTING_FRAMEWORKS.reduce(
19+
(allConfigs, framework) => ({
20+
...allConfigs,
21+
[framework]: getConfigForFramework(framework),
22+
}),
23+
{}
24+
) as Record<SupportedTestingFramework, LinterConfigRules>;

lib/configs/react.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// THIS CODE WAS AUTOMATICALLY GENERATED
2+
// DO NOT EDIT THIS CODE BY HAND
3+
// YOU CAN REGENERATE IT USING npm run generate:configs
4+
5+
export = {
6+
plugins: ['testing-library'],
7+
rules: {
8+
'testing-library/await-async-query': 'error',
9+
'testing-library/await-async-utils': 'error',
10+
'testing-library/no-await-sync-query': 'error',
11+
'testing-library/no-container': 'error',
12+
'testing-library/no-debug': 'error',
13+
'testing-library/no-dom-import': ['error', 'react'],
14+
'testing-library/no-node-access': 'error',
15+
'testing-library/no-promise-in-fire-event': 'error',
16+
'testing-library/no-wait-for-empty-callback': 'error',
17+
'testing-library/prefer-find-by': 'error',
18+
'testing-library/prefer-screen-queries': 'error',
19+
'testing-library/render-result-naming-convention': 'error',
20+
},
21+
};

lib/configs/vue.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// THIS CODE WAS AUTOMATICALLY GENERATED
2+
// DO NOT EDIT THIS CODE BY HAND
3+
// YOU CAN REGENERATE IT USING npm run generate:configs
4+
5+
export = {
6+
plugins: ['testing-library'],
7+
rules: {
8+
'testing-library/await-async-query': 'error',
9+
'testing-library/await-async-utils': 'error',
10+
'testing-library/await-fire-event': 'error',
11+
'testing-library/no-await-sync-query': 'error',
12+
'testing-library/no-container': 'error',
13+
'testing-library/no-debug': 'error',
14+
'testing-library/no-dom-import': ['error', 'vue'],
15+
'testing-library/no-node-access': 'error',
16+
'testing-library/no-promise-in-fire-event': 'error',
17+
'testing-library/no-wait-for-empty-callback': 'error',
18+
'testing-library/prefer-find-by': 'error',
19+
'testing-library/prefer-screen-queries': 'error',
20+
'testing-library/render-result-naming-convention': 'error',
21+
},
22+
};
+12-8
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,25 @@
11
import { ESLintUtils, TSESLint } from '@typescript-eslint/experimental-utils';
22

3-
import { getDocsUrl } from '../utils';
3+
import { getDocsUrl, TestingLibraryRuleMeta } from '../utils';
44

55
import {
66
DetectionOptions,
77
detectTestingLibraryUtils,
88
EnhancedRuleCreate,
99
} from './detect-testing-library-utils';
1010

11-
// These 2 types are copied from @typescript-eslint/experimental-utils
12-
type CreateRuleMetaDocs = Omit<TSESLint.RuleMetaDataDocs, 'url'>;
13-
type CreateRuleMeta<TMessageIds extends string> = {
14-
docs: CreateRuleMetaDocs;
15-
} & Omit<TSESLint.RuleMetaData<TMessageIds>, 'docs'>;
16-
1711
export function createTestingLibraryRule<
1812
TOptions extends readonly unknown[],
1913
TMessageIds extends string,
2014
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
2115
>({
2216
create,
2317
detectionOptions = {},
18+
meta,
2419
...remainingConfig
2520
}: Readonly<{
2621
name: string;
27-
meta: CreateRuleMeta<TMessageIds>;
22+
meta: TestingLibraryRuleMeta<TMessageIds, TOptions>;
2823
defaultOptions: Readonly<TOptions>;
2924
detectionOptions?: Partial<DetectionOptions>;
3025
create: EnhancedRuleCreate<TOptions, TMessageIds, TRuleListener>;
@@ -35,5 +30,14 @@ export function createTestingLibraryRule<
3530
create,
3631
detectionOptions
3732
),
33+
meta: {
34+
...meta,
35+
docs: {
36+
...meta.docs,
37+
// We're using our own recommendedConfig meta to tell our build tools
38+
// if the rule is recommended on a config basis
39+
recommended: false,
40+
},
41+
},
3842
});
3943
}

lib/index.ts

+2-56
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,7 @@
1+
import configs from './configs';
12
import rules from './rules';
23

3-
const domRules = {
4-
'testing-library/await-async-query': 'error',
5-
'testing-library/await-async-utils': 'error',
6-
'testing-library/no-await-sync-query': 'error',
7-
'testing-library/no-promise-in-fire-event': 'error',
8-
'testing-library/no-wait-for-empty-callback': 'error',
9-
'testing-library/prefer-find-by': 'error',
10-
'testing-library/prefer-screen-queries': 'error',
11-
};
12-
13-
const angularRules = {
14-
...domRules,
15-
'testing-library/no-container': 'error',
16-
'testing-library/no-debug': 'error',
17-
'testing-library/no-dom-import': ['error', 'angular'],
18-
'testing-library/no-node-access': 'error',
19-
'testing-library/render-result-naming-convention': 'error',
20-
};
21-
22-
const reactRules = {
23-
...domRules,
24-
'testing-library/no-container': 'error',
25-
'testing-library/no-debug': 'error',
26-
'testing-library/no-dom-import': ['error', 'react'],
27-
'testing-library/no-node-access': 'error',
28-
'testing-library/render-result-naming-convention': 'error',
29-
};
30-
31-
const vueRules = {
32-
...domRules,
33-
'testing-library/await-fire-event': 'error',
34-
'testing-library/no-container': 'error',
35-
'testing-library/no-debug': 'error',
36-
'testing-library/no-dom-import': ['error', 'vue'],
37-
'testing-library/no-node-access': 'error',
38-
'testing-library/render-result-naming-convention': 'error',
39-
};
40-
414
export = {
5+
configs,
426
rules,
43-
configs: {
44-
dom: {
45-
plugins: ['testing-library'],
46-
rules: domRules,
47-
},
48-
angular: {
49-
plugins: ['testing-library'],
50-
rules: angularRules,
51-
},
52-
react: {
53-
plugins: ['testing-library'],
54-
rules: reactRules,
55-
},
56-
vue: {
57-
plugins: ['testing-library'],
58-
rules: vueRules,
59-
},
60-
},
617
};

lib/rules/await-async-query.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
1919
docs: {
2020
description: 'Enforce promises from async queries to be handled',
2121
category: 'Best Practices',
22-
recommended: 'warn',
22+
recommendedConfig: {
23+
dom: 'error',
24+
angular: 'error',
25+
react: 'error',
26+
vue: 'error',
27+
},
2328
},
2429
messages: {
2530
awaitAsyncQuery: 'promise returned from {{ name }} query must be handled',

lib/rules/await-async-utils.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
1919
docs: {
2020
description: 'Enforce promises from async utils to be handled',
2121
category: 'Best Practices',
22-
recommended: 'warn',
22+
recommendedConfig: {
23+
dom: 'error',
24+
angular: 'error',
25+
react: 'error',
26+
vue: 'error',
27+
},
2328
},
2429
messages: {
2530
awaitAsyncUtil: 'Promise returned from `{{ name }}` must be handled',

lib/rules/await-fire-event.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
1919
docs: {
2020
description: 'Enforce promises from fire event methods to be handled',
2121
category: 'Best Practices',
22-
recommended: false,
22+
recommendedConfig: {
23+
dom: false,
24+
angular: false,
25+
react: false,
26+
vue: 'error',
27+
},
2328
},
2429
messages: {
2530
awaitFireEvent:

lib/rules/consistent-data-testid.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
1919
docs: {
2020
description: 'Ensures consistent usage of `data-testid`',
2121
category: 'Best Practices',
22-
recommended: false,
22+
recommendedConfig: {
23+
dom: false,
24+
angular: false,
25+
react: false,
26+
vue: false,
27+
},
2328
},
2429
messages: {
2530
consistentDataTestId: '`{{attr}}` "{{value}}" should match `{{regex}}`',

lib/rules/index.ts

+7-10
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ import { join, parse } from 'path';
33

44
import { TSESLint } from '@typescript-eslint/experimental-utils';
55

6-
type RuleModule = TSESLint.RuleModule<string, unknown[]>;
6+
import { importDefault, TestingLibraryRuleMeta } from '../utils';
77

8-
// Copied from https://github.com/babel/babel/blob/b35c78f08dd854b08575fc66ebca323fdbc59dab/packages/babel-helpers/src/helpers.js#L615-L619
9-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10-
const interopRequireDefault = (obj: any): { default: unknown } =>
11-
obj?.__esModule ? obj : { default: obj };
12-
13-
const importDefault = (moduleName: string) =>
14-
// eslint-disable-next-line @typescript-eslint/no-var-requires
15-
interopRequireDefault(require(moduleName)).default;
8+
type RuleModule = TSESLint.RuleModule<string, unknown[]> & {
9+
meta: TestingLibraryRuleMeta<string, unknown[]> & {
10+
recommended: false;
11+
};
12+
};
1613

1714
const rulesDir = __dirname;
1815
const excludedFiles = ['index'];
@@ -23,7 +20,7 @@ export default readdirSync(rulesDir)
2320
.reduce<Record<string, RuleModule>>(
2421
(allRules, ruleName) => ({
2522
...allRules,
26-
[ruleName]: importDefault(join(rulesDir, ruleName)) as RuleModule,
23+
[ruleName]: importDefault<RuleModule>(join(rulesDir, ruleName)),
2724
}),
2825
{}
2926
);

lib/rules/no-await-sync-events.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
2121
docs: {
2222
description: 'Disallow unnecessary `await` for sync events',
2323
category: 'Best Practices',
24-
recommended: 'error',
24+
recommendedConfig: {
25+
dom: false,
26+
angular: false,
27+
react: false,
28+
vue: false,
29+
},
2530
},
2631
messages: {
2732
noAwaitSyncEvents:

lib/rules/no-await-sync-query.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
1313
docs: {
1414
description: 'Disallow unnecessary `await` for sync queries',
1515
category: 'Best Practices',
16-
recommended: 'error',
16+
recommendedConfig: {
17+
dom: 'error',
18+
angular: 'error',
19+
react: 'error',
20+
vue: 'error',
21+
},
1722
},
1823
messages: {
1924
noAwaitSyncQuery:

lib/rules/no-container.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
2020
docs: {
2121
description: 'Disallow the use of container methods',
2222
category: 'Best Practices',
23-
recommended: 'error',
23+
recommendedConfig: {
24+
dom: false,
25+
angular: 'error',
26+
react: 'error',
27+
vue: 'error',
28+
},
2429
},
2530
messages: {
2631
noContainer:

lib/rules/no-debug.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
2222
docs: {
2323
description: 'Disallow unnecessary debug usages in the tests',
2424
category: 'Best Practices',
25-
recommended: 'warn',
25+
recommendedConfig: {
26+
dom: false,
27+
angular: 'error',
28+
react: 'error',
29+
vue: 'error',
30+
},
2631
},
2732
messages: {
2833
noDebug: 'Unexpected debug statement',

0 commit comments

Comments
 (0)