Skip to content

Commit 5303d3d

Browse files
committed
feat(to-have-length): support optional chaining operator
1 parent 53d348d commit 5303d3d

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

src/rules/__tests__/prefer-to-have-length.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { espreeParser } from './test-utils';
55
const ruleTester = new TSESLint.RuleTester({
66
parser: espreeParser,
77
parserOptions: {
8-
ecmaVersion: 2015,
8+
ecmaVersion: 2020,
99
},
1010
});
1111

@@ -16,6 +16,7 @@ ruleTester.run('prefer-to-have-length', rule, {
1616
'expect(files).toHaveLength(1);',
1717
"expect(files.name).toBe('file');",
1818
"expect(files[`name`]).toBe('file');",
19+
'expect(users[0]?.permissions).toHaveLength(1);',
1920
'expect(result).toBe(true);',
2021
`expect(user.getUserName(5)).resolves.toEqual('Paul')`,
2122
`expect(user.getUserName(5)).rejects.toEqual('Paul')`,
@@ -74,5 +75,10 @@ ruleTester.run('prefer-to-have-length', rule, {
7475
output: 'expect(files).not.toHaveLength(1);',
7576
errors: [{ messageId: 'useToHaveLength', column: 26, line: 1 }],
7677
},
78+
{
79+
code: 'expect(users[0]?.permissions?.length).toBe(1);',
80+
output: 'expect(users[0]?.permissions).toHaveLength(1);',
81+
errors: [{ messageId: 'useToHaveLength', column: 39, line: 1 }],
82+
},
7783
],
7884
});

src/rules/prefer-to-have-length.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
1+
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
22
import {
33
EqualityMatcher,
44
createRule,
@@ -7,6 +7,13 @@ import {
77
parseJestFnCall,
88
} from './utils';
99

10+
const followOptionalChaining = (
11+
expression: TSESTree.CallExpressionArgument,
12+
): TSESTree.CallExpressionArgument =>
13+
expression.type === AST_NODE_TYPES.ChainExpression
14+
? followOptionalChaining(expression.expression)
15+
: expression;
16+
1017
export default createRule({
1118
name: __filename,
1219
meta: {
@@ -41,10 +48,15 @@ export default createRule({
4148
const [argument] = expect.arguments;
4249
const { matcher } = jestFnCall;
4350

51+
if (!EqualityMatcher.hasOwnProperty(getAccessorValue(matcher))) {
52+
return;
53+
}
54+
55+
const expression = followOptionalChaining(argument);
56+
4457
if (
45-
!EqualityMatcher.hasOwnProperty(getAccessorValue(matcher)) ||
46-
argument?.type !== AST_NODE_TYPES.MemberExpression ||
47-
!isSupportedAccessor(argument.property, 'length')
58+
expression?.type !== AST_NODE_TYPES.MemberExpression ||
59+
!isSupportedAccessor(expression.property, 'length')
4860
) {
4961
return;
5062
}
@@ -54,7 +66,10 @@ export default createRule({
5466
return [
5567
// remove the "length" property accessor
5668
fixer.removeRange([
57-
argument.property.range[0] - 1,
69+
expression.property.range[0] -
70+
(expression.parent?.type === AST_NODE_TYPES.ChainExpression
71+
? 2
72+
: 1),
5873
argument.range[1],
5974
]),
6075
// replace the current matcher with "toHaveLength"

0 commit comments

Comments
 (0)