Skip to content

Commit 5b24014

Browse files
authored
refactor: strengthen type safety (#1015)
1 parent 984f245 commit 5b24014

12 files changed

+132
-83
lines changed

lib/create-testing-library-rule/detect-testing-library-utils.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -802,8 +802,10 @@ export function detectTestingLibraryUtils<
802802
}
803803

804804
return isNegated
805-
? ABSENCE_MATCHERS.includes(matcher)
806-
: PRESENCE_MATCHERS.includes(matcher);
805+
? ABSENCE_MATCHERS.some((absenceMather) => absenceMather === matcher)
806+
: PRESENCE_MATCHERS.some(
807+
(presenceMather) => presenceMather === matcher
808+
);
807809
};
808810

809811
/**
@@ -821,8 +823,8 @@ export function detectTestingLibraryUtils<
821823
}
822824

823825
return isNegated
824-
? PRESENCE_MATCHERS.includes(matcher)
825-
: ABSENCE_MATCHERS.includes(matcher);
826+
? PRESENCE_MATCHERS.some((presenceMather) => presenceMather === matcher)
827+
: ABSENCE_MATCHERS.some((absenceMather) => absenceMather === matcher);
826828
};
827829

828830
const isMatchingAssert: IsMatchingAssertFn = (node, matcherName) => {

lib/create-testing-library-rule/index.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { ESLintUtils } from '@typescript-eslint/utils';
22

3-
import { getDocsUrl, TestingLibraryPluginDocs } from '../utils';
3+
import {
4+
getDocsUrl,
5+
TestingLibraryPluginDocs,
6+
TestingLibraryPluginRuleModule,
7+
} from '../utils';
48

59
import {
610
DetectionOptions,
@@ -27,11 +31,20 @@ export const createTestingLibraryRule = <
2731
create: EnhancedRuleCreate<TMessageIds, TOptions>;
2832
detectionOptions?: Partial<DetectionOptions>;
2933
}
30-
>) =>
31-
ESLintUtils.RuleCreator<TestingLibraryPluginDocs<TOptions>>(getDocsUrl)({
34+
>): TestingLibraryPluginRuleModule<TMessageIds, TOptions> => {
35+
const rule = ESLintUtils.RuleCreator<TestingLibraryPluginDocs<TOptions>>(
36+
getDocsUrl
37+
)({
3238
...remainingConfig,
3339
create: detectTestingLibraryUtils<TMessageIds, TOptions>(
3440
create,
3541
detectionOptions
3642
),
3743
});
44+
const { docs } = rule.meta;
45+
if (docs === undefined) {
46+
throw new Error('Rule metadata must contain `docs` property');
47+
}
48+
49+
return { ...rule, meta: { ...rule.meta, docs } };
50+
};

lib/rules/no-node-access.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,17 @@ export default createTestingLibraryRule<Options, MessageIds>({
5252
return;
5353
}
5454

55+
const propertyName = ASTUtils.isIdentifier(node.property)
56+
? node.property.name
57+
: null;
58+
5559
if (
56-
ASTUtils.isIdentifier(node.property) &&
57-
ALL_RETURNING_NODES.includes(node.property.name)
60+
propertyName &&
61+
ALL_RETURNING_NODES.some(
62+
(allReturningNode) => allReturningNode === propertyName
63+
)
5864
) {
59-
if (allowContainerFirstChild && node.property.name === 'firstChild') {
65+
if (allowContainerFirstChild && propertyName === 'firstChild') {
6066
return;
6167
}
6268

lib/rules/no-render-in-lifecycle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
6868
type: 'object',
6969
properties: {
7070
allowTestingFrameworkSetupHook: {
71-
enum: TESTING_FRAMEWORK_SETUP_HOOKS,
71+
enum: [...TESTING_FRAMEWORK_SETUP_HOOKS],
7272
type: 'string',
7373
},
7474
},

lib/rules/prefer-explicit-assert.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
9292
properties: {
9393
assertion: {
9494
type: 'string',
95-
enum: PRESENCE_MATCHERS,
95+
enum: [...PRESENCE_MATCHERS],
9696
},
9797
includeFindQueries: { type: 'boolean' },
9898
},
@@ -182,8 +182,14 @@ export default createTestingLibraryRule<Options, MessageIds>({
182182
}
183183

184184
const shouldEnforceAssertion =
185-
(!isNegatedMatcher && PRESENCE_MATCHERS.includes(matcher)) ||
186-
(isNegatedMatcher && ABSENCE_MATCHERS.includes(matcher));
185+
(!isNegatedMatcher &&
186+
PRESENCE_MATCHERS.some(
187+
(presenceMather) => presenceMather === matcher
188+
)) ||
189+
(isNegatedMatcher &&
190+
ABSENCE_MATCHERS.some(
191+
(absenceMather) => absenceMather === matcher
192+
));
187193

188194
if (shouldEnforceAssertion && matcher !== assertion) {
189195
context.report({

lib/utils/index.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ export * from './compat';
22
export * from './file-import';
33
export * from './types';
44

5-
const combineQueries = (variants: string[], methods: string[]): string[] => {
5+
const combineQueries = (
6+
variants: readonly string[],
7+
methods: readonly string[]
8+
): string[] => {
69
const combinedQueries: string[] = [];
710
variants.forEach((variant) => {
811
const variantPrefix = variant.replace('By', '');
@@ -25,14 +28,19 @@ const LIBRARY_MODULES = [
2528
'@testing-library/vue',
2629
'@testing-library/svelte',
2730
'@marko/testing-library',
28-
];
31+
] as const;
2932

30-
const SYNC_QUERIES_VARIANTS = ['getBy', 'getAllBy', 'queryBy', 'queryAllBy'];
31-
const ASYNC_QUERIES_VARIANTS = ['findBy', 'findAllBy'];
33+
const SYNC_QUERIES_VARIANTS = [
34+
'getBy',
35+
'getAllBy',
36+
'queryBy',
37+
'queryAllBy',
38+
] as const;
39+
const ASYNC_QUERIES_VARIANTS = ['findBy', 'findAllBy'] as const;
3240
const ALL_QUERIES_VARIANTS = [
3341
...SYNC_QUERIES_VARIANTS,
3442
...ASYNC_QUERIES_VARIANTS,
35-
];
43+
] as const;
3644

3745
const ALL_QUERIES_METHODS = [
3846
'ByLabelText',
@@ -43,7 +51,7 @@ const ALL_QUERIES_METHODS = [
4351
'ByDisplayValue',
4452
'ByRole',
4553
'ByTestId',
46-
];
54+
] as const;
4755

4856
const SYNC_QUERIES_COMBINATIONS = combineQueries(
4957
SYNC_QUERIES_VARIANTS,
@@ -58,7 +66,7 @@ const ASYNC_QUERIES_COMBINATIONS = combineQueries(
5866
const ALL_QUERIES_COMBINATIONS = [
5967
...SYNC_QUERIES_COMBINATIONS,
6068
...ASYNC_QUERIES_COMBINATIONS,
61-
];
69+
] as const;
6270

6371
const ASYNC_UTILS = ['waitFor', 'waitForElementToBeRemoved'] as const;
6472

@@ -73,7 +81,7 @@ const DEBUG_UTILS = [
7381

7482
const EVENTS_SIMULATORS = ['fireEvent', 'userEvent'] as const;
7583

76-
const TESTING_FRAMEWORK_SETUP_HOOKS = ['beforeEach', 'beforeAll'];
84+
const TESTING_FRAMEWORK_SETUP_HOOKS = ['beforeEach', 'beforeAll'] as const;
7785

7886
const PROPERTIES_RETURNING_NODES = [
7987
'activeElement',
@@ -93,7 +101,7 @@ const PROPERTIES_RETURNING_NODES = [
93101
'previousSibling',
94102
'rootNode',
95103
'scripts',
96-
];
104+
] as const;
97105

98106
const METHODS_RETURNING_NODES = [
99107
'closest',
@@ -104,20 +112,20 @@ const METHODS_RETURNING_NODES = [
104112
'getElementsByTagNameNS',
105113
'querySelector',
106114
'querySelectorAll',
107-
];
115+
] as const;
108116

109117
const ALL_RETURNING_NODES = [
110118
...PROPERTIES_RETURNING_NODES,
111119
...METHODS_RETURNING_NODES,
112-
];
120+
] as const;
113121

114122
const PRESENCE_MATCHERS = [
115123
'toBeOnTheScreen',
116124
'toBeInTheDocument',
117125
'toBeTruthy',
118126
'toBeDefined',
119-
];
120-
const ABSENCE_MATCHERS = ['toBeNull', 'toBeFalsy'];
127+
] as const;
128+
const ABSENCE_MATCHERS = ['toBeNull', 'toBeFalsy'] as const;
121129

122130
export {
123131
combineQueries,

0 commit comments

Comments
 (0)