Skip to content

Commit abfe5e8

Browse files
committed
fix: enable TS strict mode
1 parent 91abe97 commit abfe5e8

28 files changed

+161
-110
lines changed

lib/detect-testing-library-utils.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ export function detectTestingLibraryUtils<
135135

136136
// Init options based on shared ESLint settings
137137
const customModule = context.settings['testing-library/utils-module'];
138-
const customRenders = context.settings['testing-library/custom-renders'];
138+
const customRenders =
139+
context.settings['testing-library/custom-renders'] ?? [];
139140

140141
/**
141142
* Small method to extract common checks to determine whether a node is
@@ -169,6 +170,10 @@ export function detectTestingLibraryUtils<
169170
referenceNodeIdentifier
170171
);
171172

173+
if (!importedUtilSpecifier) {
174+
return false;
175+
}
176+
172177
const originalNodeName =
173178
isImportSpecifier(importedUtilSpecifier) &&
174179
importedUtilSpecifier.local.name !== importedUtilSpecifier.imported.name
@@ -314,7 +319,8 @@ export function detectTestingLibraryUtils<
314319
(identifierNodeName, originalNodeName) => {
315320
return (
316321
(validNames as string[]).includes(identifierNodeName) ||
317-
(validNames as string[]).includes(originalNodeName)
322+
(!!originalNodeName &&
323+
(validNames as string[]).includes(originalNodeName))
318324
);
319325
}
320326
);
@@ -367,9 +373,10 @@ export function detectTestingLibraryUtils<
367373
return false;
368374
}
369375

370-
const parentMemberExpression:
371-
| TSESTree.MemberExpression
372-
| undefined = isMemberExpression(node.parent) ? node.parent : undefined;
376+
const parentMemberExpression: TSESTree.MemberExpression | undefined =
377+
node.parent && isMemberExpression(node.parent)
378+
? node.parent
379+
: undefined;
373380

374381
if (!parentMemberExpression) {
375382
return false;
@@ -414,9 +421,10 @@ export function detectTestingLibraryUtils<
414421
return false;
415422
}
416423

417-
const parentMemberExpression:
418-
| TSESTree.MemberExpression
419-
| undefined = isMemberExpression(node.parent) ? node.parent : undefined;
424+
const parentMemberExpression: TSESTree.MemberExpression | undefined =
425+
node.parent && isMemberExpression(node.parent)
426+
? node.parent
427+
: undefined;
420428

421429
if (!parentMemberExpression) {
422430
return false;
@@ -480,6 +488,9 @@ export function detectTestingLibraryUtils<
480488
};
481489

482490
const isRenderVariableDeclarator: IsRenderVariableDeclaratorFn = (node) => {
491+
if (!node.init) {
492+
return false;
493+
}
483494
const initIdentifierNode = getDeepestIdentifierNode(node.init);
484495

485496
if (!initIdentifierNode) {
@@ -548,7 +559,7 @@ export function detectTestingLibraryUtils<
548559
const node = getCustomModuleImportNode() ?? getTestingLibraryImportNode();
549560

550561
if (!node) {
551-
return null;
562+
return undefined;
552563
}
553564

554565
if (isImportDeclaration(node)) {
@@ -705,6 +716,7 @@ export function detectTestingLibraryUtils<
705716
// check only if custom module import not found yet so we avoid
706717
// to override importedCustomModuleNode after it's found
707718
if (
719+
customModule &&
708720
!importedCustomModuleNode &&
709721
String(node.source.value).endsWith(customModule)
710722
) {
@@ -744,6 +756,7 @@ export function detectTestingLibraryUtils<
744756
!importedCustomModuleNode &&
745757
args.some(
746758
(arg) =>
759+
customModule &&
747760
isLiteral(arg) &&
748761
typeof arg.value === 'string' &&
749762
arg.value.endsWith(customModule)
@@ -779,11 +792,11 @@ export function detectTestingLibraryUtils<
779792
allKeys.forEach((instruction) => {
780793
enhancedRuleInstructions[instruction] = (node) => {
781794
if (instruction in detectionInstructions) {
782-
detectionInstructions[instruction](node);
795+
detectionInstructions[instruction]?.(node);
783796
}
784797

785798
if (canReportErrors() && ruleInstructions[instruction]) {
786-
return ruleInstructions[instruction](node);
799+
return ruleInstructions[instruction]?.(node);
787800
}
788801
};
789802
});

lib/node-utils.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ export function isCallExpression(
4242
}
4343

4444
export function isNewExpression(
45-
node: TSESTree.Node
45+
node: TSESTree.Node | null | undefined
4646
): node is TSESTree.NewExpression {
4747
return node?.type === 'NewExpression';
4848
}
4949

5050
export function isMemberExpression(
51-
node: TSESTree.Node
51+
node: TSESTree.Node | null | undefined
5252
): node is TSESTree.MemberExpression {
5353
return node?.type === AST_NODE_TYPES.MemberExpression;
5454
}
@@ -60,31 +60,31 @@ export function isLiteral(
6060
}
6161

6262
export function isImportSpecifier(
63-
node: TSESTree.Node
63+
node: TSESTree.Node | null | undefined
6464
): node is TSESTree.ImportSpecifier {
6565
return node?.type === AST_NODE_TYPES.ImportSpecifier;
6666
}
6767

6868
export function isImportNamespaceSpecifier(
69-
node: TSESTree.Node
69+
node: TSESTree.Node | null | undefined
7070
): node is TSESTree.ImportNamespaceSpecifier {
7171
return node?.type === AST_NODE_TYPES.ImportNamespaceSpecifier;
7272
}
7373

7474
export function isImportDefaultSpecifier(
75-
node: TSESTree.Node
75+
node: TSESTree.Node | null | undefined
7676
): node is TSESTree.ImportDefaultSpecifier {
7777
return node?.type === AST_NODE_TYPES.ImportDefaultSpecifier;
7878
}
7979

8080
export function isBlockStatement(
81-
node: TSESTree.Node
81+
node: TSESTree.Node | null | undefined
8282
): node is TSESTree.BlockStatement {
8383
return node?.type === AST_NODE_TYPES.BlockStatement;
8484
}
8585

8686
export function isObjectPattern(
87-
node: TSESTree.Node
87+
node: TSESTree.Node | null | undefined
8888
): node is TSESTree.ObjectPattern {
8989
return node?.type === AST_NODE_TYPES.ObjectPattern;
9090
}
@@ -96,13 +96,13 @@ export function isProperty(
9696
}
9797

9898
export function isJSXAttribute(
99-
node: TSESTree.Node
99+
node: TSESTree.Node | null | undefined
100100
): node is TSESTree.JSXAttribute {
101101
return node?.type === AST_NODE_TYPES.JSXAttribute;
102102
}
103103

104104
export function isExpressionStatement(
105-
node: TSESTree.Node
105+
node: TSESTree.Node | null | undefined
106106
): node is TSESTree.ExpressionStatement {
107107
return node?.type === AST_NODE_TYPES.ExpressionStatement;
108108
}
@@ -137,7 +137,7 @@ export function findClosestCallExpressionNode(
137137
export function findClosestCallNode(
138138
node: TSESTree.Node,
139139
name: string
140-
): TSESTree.CallExpression {
140+
): TSESTree.CallExpression | null {
141141
if (!node.parent) {
142142
return null;
143143
}
@@ -208,12 +208,12 @@ export function hasChainedThen(node: TSESTree.Node): boolean {
208208
const parent = node.parent;
209209

210210
// wait(...).then(...)
211-
if (isCallExpression(parent)) {
211+
if (isCallExpression(parent) && parent.parent) {
212212
return hasThenProperty(parent.parent);
213213
}
214214

215215
// promise.then(...)
216-
return hasThenProperty(parent);
216+
return !!parent && hasThenProperty(parent);
217217
}
218218

219219
export function isPromiseIdentifier(
@@ -252,6 +252,7 @@ export function isPromisesArrayResolved(node: TSESTree.Node): boolean {
252252
}
253253

254254
return (
255+
!!closestCallExpression.parent &&
255256
isArrayExpression(closestCallExpression.parent) &&
256257
isCallExpression(closestCallExpression.parent.parent) &&
257258
(isPromiseAll(closestCallExpression.parent.parent) ||
@@ -281,6 +282,9 @@ export function isPromiseHandled(nodeIdentifier: TSESTree.Identifier): boolean {
281282
);
282283

283284
for (const node of suspiciousNodes) {
285+
if (!node || !node.parent) {
286+
continue;
287+
}
284288
if (ASTUtils.isAwaitExpression(node.parent)) {
285289
return true;
286290
}
@@ -449,7 +453,10 @@ export function getReferenceNode(
449453
| TSESTree.MemberExpression
450454
| TSESTree.Identifier
451455
): TSESTree.CallExpression | TSESTree.MemberExpression | TSESTree.Identifier {
452-
if (isMemberExpression(node.parent) || isCallExpression(node.parent)) {
456+
if (
457+
node.parent &&
458+
(isMemberExpression(node.parent) || isCallExpression(node.parent))
459+
) {
453460
return getReferenceNode(node.parent);
454461
}
455462

@@ -518,9 +525,10 @@ export function getAssertNodeInfo(
518525
let matcher = ASTUtils.getPropertyName(node);
519526
const isNegated = matcher === 'not';
520527
if (isNegated) {
521-
matcher = isMemberExpression(node.parent)
522-
? ASTUtils.getPropertyName(node.parent)
523-
: null;
528+
matcher =
529+
node.parent && isMemberExpression(node.parent)
530+
? ASTUtils.getPropertyName(node.parent)
531+
: null;
524532
}
525533

526534
if (!matcher) {
@@ -539,6 +547,7 @@ export function hasClosestExpectResolvesRejects(node: TSESTree.Node): boolean {
539547
if (
540548
isCallExpression(node) &&
541549
ASTUtils.isIdentifier(node.callee) &&
550+
node.parent &&
542551
isMemberExpression(node.parent) &&
543552
node.callee.name === 'expect'
544553
) {

lib/rules/await-async-query.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export default createTestingLibraryRule<Options, MessageIds>({
2626
asyncQueryWrapper:
2727
'promise returned from {{ name }} wrapper over async query must be handled',
2828
},
29-
fixable: null,
3029
schema: [],
3130
},
3231
defaultOptions: [],
@@ -52,7 +51,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
5251
true
5352
);
5453

55-
if (!closestCallExpressionNode) {
54+
if (!closestCallExpressionNode || !closestCallExpressionNode.parent) {
5655
return;
5756
}
5857

lib/rules/await-async-utils.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export default createTestingLibraryRule<Options, MessageIds>({
2626
asyncUtilWrapper:
2727
'Promise returned from {{ name }} wrapper over async util must be handled',
2828
},
29-
fixable: null,
3029
schema: [],
3130
},
3231
defaultOptions: [],
@@ -53,7 +52,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
5352
true
5453
);
5554

56-
if (!closestCallExpression) {
55+
if (!closestCallExpression || !closestCallExpression.parent) {
5756
return;
5857
}
5958

lib/rules/await-fire-event.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export default createTestingLibraryRule<Options, MessageIds>({
2727
fireEventWrapper:
2828
'Promise returned from `fireEvent.{{ wrapperName }}` wrapper over fire event method must be handled',
2929
},
30-
fixable: null,
3130
schema: [],
3231
},
3332
defaultOptions: [],
@@ -67,7 +66,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
6766
true
6867
);
6968

70-
if (!closestCallExpression) {
69+
if (!closestCallExpression || !closestCallExpression.parent) {
7170
return;
7271
}
7372

lib/rules/consistent-data-testid.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
3030
messages: {
3131
consistentDataTestId: '`{{attr}}` "{{value}}" should match `{{regex}}`',
3232
},
33-
fixable: null,
3433
schema: [
3534
{
3635
type: 'object',
@@ -72,7 +71,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
7271

7372
function getFileNameData() {
7473
const splitPath = getFilename().split('/');
75-
const fileNameWithExtension = splitPath.pop();
74+
const fileNameWithExtension = splitPath.pop() ?? '';
7675
const parent = splitPath.pop();
7776
const fileName = fileNameWithExtension.split('.').shift();
7877

@@ -85,17 +84,18 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
8584
return new RegExp(testIdPattern.replace(FILENAME_PLACEHOLDER, fileName));
8685
}
8786

88-
function isTestIdAttribute(name: string) {
87+
function isTestIdAttribute(name: string): boolean {
8988
if (typeof attr === 'string') {
9089
return attr === name;
9190
} else {
92-
return attr.includes(name);
91+
return attr?.includes(name) ?? false;
9392
}
9493
}
9594

9695
return {
9796
JSXIdentifier: (node) => {
9897
if (
98+
!node.parent ||
9999
!isJSXAttribute(node.parent) ||
100100
!isLiteral(node.parent.value) ||
101101
!isTestIdAttribute(node.name)
@@ -105,7 +105,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
105105

106106
const value = node.parent.value.value;
107107
const { fileName } = getFileNameData();
108-
const regex = getTestIdValidator(fileName);
108+
const regex = getTestIdValidator(fileName ?? '');
109109

110110
if (value && typeof value === 'string' && !regex.test(value)) {
111111
context.report({

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export default createTestingLibraryRule<Options, MessageIds>({
2727
noAwaitSyncEvents:
2828
'`{{ name }}` is sync and does not need `await` operator',
2929
},
30-
fixable: null,
3130
schema: [],
3231
},
3332
defaultOptions: [],
@@ -60,11 +59,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
6059
isObjectExpression(lastArg) &&
6160
lastArg.properties.some(
6261
(property) =>
63-
isProperty(property) &&
64-
ASTUtils.isIdentifier(property.key) &&
65-
property.key.name === 'delay' &&
66-
isLiteral(property.value) &&
67-
property.value.value > 0
62+
(isProperty(property) &&
63+
ASTUtils.isIdentifier(property.key) &&
64+
property.key.name === 'delay' &&
65+
isLiteral(property.value) &&
66+
property.value.value) ??
67+
0 > 0
6868
);
6969

7070
const simulateEventFunctionName = simulateEventFunctionIdentifier.name;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export default createTestingLibraryRule<Options, MessageIds>({
2222
noAwaitSyncQuery:
2323
'`{{ name }}` query is sync so it does not need to be awaited',
2424
},
25-
fixable: null,
2625
schema: [],
2726
},
2827
defaultOptions: [],

0 commit comments

Comments
 (0)