From 5ab24d98407ab024b28a9d618e45569c45ee295a Mon Sep 17 00:00:00 2001 From: Berkin Anik Date: Fri, 11 Nov 2022 00:45:22 +0300 Subject: [PATCH] fix(prefer-in-document): handle `toHaveLength` without any arguments and with trailing commas (#276) * fix(prefer-in-document): crash when on matcher args in toHaveLength * fix(prefer-in-document): properly remove all matcher args and commas * fix(prefer-in-document): update comment on comma removal logic --- src/__tests__/lib/rules/prefer-in-document.js | 80 +++++++++++++++++++ src/rules/prefer-in-document.js | 13 ++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/__tests__/lib/rules/prefer-in-document.js b/src/__tests__/lib/rules/prefer-in-document.js index 5e0bd4b..adc3a8b 100644 --- a/src/__tests__/lib/rules/prefer-in-document.js +++ b/src/__tests__/lib/rules/prefer-in-document.js @@ -51,6 +51,10 @@ const valid = [ expect(foo).not.toHaveLength(0)`, `let foo; expect(foo).toHaveLength(1);`, + `let foo; + expect(foo).toHaveLength()`, + `let foo; + expect(foo).toHaveLength(1, 2, 3)`, `expect(screen.notAQuery('foo-bar')).toHaveLength(1)`, `expect(screen.getAllByText('foo-bar')).toHaveLength(2)`, `import foo from "./foo"; @@ -99,6 +103,82 @@ const valid = [ expect(element).toBeInTheDocument`, ]; const invalid = [ + invalidCase( + `expect(screen.getByText('foo')).toHaveLength()`, + `expect(screen.getByText('foo')).not.toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getAllByText('foo')).toHaveLength()`, + `expect(screen.getByText('foo')).not.toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getByRole('foo')).toHaveLength()`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength()`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getByRole('foo')).toHaveLength(0,2,3)`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(0,2,3,)`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getByRole('foo')).toHaveLength(1,2,3)`, + `expect(screen.getByRole('foo')).toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(1,2,3,)`, + `expect(screen.getByRole('foo')).toBeInTheDocument()` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(0//comment +)`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument(//comment +)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(1,//comment +)`, + `expect(screen.getByRole('foo')).toBeInTheDocument(//comment +)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(0,2,3//comment +)`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument(//comment +)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(1,2,3,//comment +)`, + `expect(screen.getByRole('foo')).toBeInTheDocument(//comment +)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(0,2,//comment +3,4)`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument(//comment +)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(1,2,//comment +3,4,)`, + `expect(screen.getByRole('foo')).toBeInTheDocument(//comment +)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(0,2/*comment*/,3)`, + `expect(screen.getByRole('foo')).not.toBeInTheDocument(/*comment*/)` + ), + invalidCase( + `expect(screen.getAllByRole('foo')).toHaveLength(1,2,/*comment*/3,)`, + `expect(screen.getByRole('foo')).toBeInTheDocument(/*comment*/)` + ), invalidCase( `expect(screen.getByText('foo')).toHaveLength(1)`, `expect(screen.getByText('foo')).toBeInTheDocument()` diff --git a/src/rules/prefer-in-document.js b/src/rules/prefer-in-document.js index 8c22611..d9a5618 100644 --- a/src/rules/prefer-in-document.js +++ b/src/rules/prefer-in-document.js @@ -40,7 +40,12 @@ function usesToBeOrToEqualWithNull(matcherNode, matcherArguments) { } function usesToHaveLengthZero(matcherNode, matcherArguments) { - return matcherNode.name === "toHaveLength" && matcherArguments[0].value === 0; + // matcherArguments.length === 0: toHaveLength() will cause jest matcher error + // matcherArguments[0].value: toHaveLength(0, ...) means zero length + return ( + matcherNode.name === "toHaveLength" && + (matcherArguments.length === 0 || matcherArguments[0].value === 0) + ); } export const create = (context) => { @@ -117,6 +122,12 @@ export const create = (context) => { // Remove any arguments in the matcher for (const argument of Array.from(matcherArguments)) { + const sourceCode = context.getSourceCode(); + const token = sourceCode.getTokenAfter(argument); + if (token.value === "," && token.type === "Punctuator") { + // Remove commas if toHaveLength had more than one argument or a trailing comma + operations.push(fixer.replaceText(token, "")); + } operations.push(fixer.remove(argument)); }