From fa1d7da090e22d76ef351f2ddc20e54e67e43ea3 Mon Sep 17 00:00:00 2001 From: Wenzhe Wang Date: Sat, 2 Sep 2023 14:37:15 +0800 Subject: [PATCH] feat(linter): add eslint-plugin-jest/no-conditional-expect rule (#832) port [no-conditional-expect](https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-conditional-expect.md) --- crates/oxc_linter/src/rules.rs | 2 + .../src/rules/jest/no_commented_out_tests.rs | 2 +- .../src/rules/jest/no_conditional_expect.rs | 812 ++++++++++++++++++ .../src/snapshots/no_commented_out_tests.snap | 44 +- .../src/snapshots/no_conditional_expect.snap | 410 +++++++++ 5 files changed, 1247 insertions(+), 23 deletions(-) create mode 100644 crates/oxc_linter/src/rules/jest/no_conditional_expect.rs create mode 100644 crates/oxc_linter/src/snapshots/no_conditional_expect.snap diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 94d15e93c..e8763d8b4 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -94,6 +94,7 @@ mod jest { pub mod expect_expect; pub mod no_alias_methods; pub mod no_commented_out_tests; + pub mod no_conditional_expect; pub mod no_disabled_tests; pub mod no_focused_tests; pub mod no_test_prefixes; @@ -188,5 +189,6 @@ oxc_macros::declare_all_lint_rules! { jest::no_commented_out_tests, jest::expect_expect, jest::no_alias_methods, + jest::no_conditional_expect, unicorn::no_instanceof_array, } diff --git a/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs b/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs index 7ac80e242..7bf88a350 100644 --- a/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs +++ b/crates/oxc_linter/src/rules/jest/no_commented_out_tests.rs @@ -9,7 +9,7 @@ use regex::Regex; use crate::{context::LintContext, rule::Rule}; #[derive(Debug, Error, Diagnostic)] -#[error("Some tests seem to be commented")] +#[error("eslint(jest/no-commented-out-tests): Some tests seem to be commented")] #[diagnostic(severity(warning), help("Remove or uncomment this comment"))] struct NoCommentedOutTestsDiagnostic(#[label] pub Span); diff --git a/crates/oxc_linter/src/rules/jest/no_conditional_expect.rs b/crates/oxc_linter/src/rules/jest/no_conditional_expect.rs new file mode 100644 index 000000000..22b2c8fa2 --- /dev/null +++ b/crates/oxc_linter/src/rules/jest/no_conditional_expect.rs @@ -0,0 +1,812 @@ +use oxc_ast::{ast::Expression, AstKind}; +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::Error, +}; +use oxc_macros::declare_oxc_lint; +use oxc_span::Span; + +use crate::{ + context::LintContext, + jest_ast_util::{is_type_of_jest_fn_call, JestFnKind, JestGeneralFnKind}, + rule::Rule, + AstNode, +}; + +#[derive(Debug, Error, Diagnostic)] +#[error("eslint(jest/no-conditional-expect): Unexpected conditional expect")] +#[diagnostic(severity(warning), help("Avoid calling `expect` conditionally`"))] +struct NoConditionalExpectDiagnostic(#[label] pub Span); + +#[derive(Debug, Default, Clone)] +pub struct NoConditionalExpect; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule prevents the use of expect in conditional blocks, such as ifs & catch(s). + /// This includes using expect in callbacks to functions named catch, which are assumed to be promises. + /// + /// ### Why is this bad? + /// + /// Jest only considers a test to have failed if it throws an error, meaning if calls to assertion functions like expect occur in conditional code such as a catch statement, tests can end up passing but not actually test anything. + /// Additionally, conditionals tend to make tests more brittle and complex, as they increase the amount of mental thinking needed to understand what is actually being tested. + /// + /// ### Example + /// ```javascript + /// it('foo', () => { + /// doTest && expect(1).toBe(2); + /// }); + /// + /// it('bar', () => { + /// if (!skipTest) { + /// expect(1).toEqual(2); + /// } + /// }); + /// + /// it('throws an error', async () => { + // await foo().catch(error => expect(error).toBeInstanceOf(error)); + // }); + /// ``` + NoConditionalExpect, + correctness +); + +impl Rule for NoConditionalExpect { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + if let AstKind::CallExpression(call_expr) = node.kind() { + if !is_type_of_jest_fn_call(call_expr, node, ctx, &[JestFnKind::Expect]) { + return; + } + + let has_condition_or_catch = check_parents(node, ctx, false); + if has_condition_or_catch { + ctx.diagnostic(NoConditionalExpectDiagnostic(call_expr.span)); + } + } + } +} + +fn check_parents<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>, in_conditional: bool) -> bool { + let Some(parent) = ctx.nodes().parent_node(node.id()) else { + return false; + }; + + match parent.kind() { + AstKind::CallExpression(call_expr) => { + if is_type_of_jest_fn_call( + call_expr, + parent, + ctx, + &[JestFnKind::General(JestGeneralFnKind::Test)], + ) { + return in_conditional; + } + + if let Expression::MemberExpression(member_expr) = &call_expr.callee { + if member_expr.static_property_name() == Some("catch") { + return check_parents(parent, ctx, true); + } + } + } + AstKind::CatchClause(_) + | AstKind::SwitchStatement(_) + | AstKind::IfStatement(_) + | AstKind::ConditionalExpression(_) + | AstKind::LogicalExpression(_) => return check_parents(parent, ctx, true), + AstKind::Function(function) => { + let Some(ident) = &function.id else { + return false; + }; + let symbol_table = ctx.semantic().symbols(); + let Some(symbol_id) = ident.symbol_id.get() else { + return false; + }; + + return symbol_table.get_resolved_references(symbol_id).any(|reference| { + let Some(parent) = ctx.nodes().parent_node(reference.node_id()) else { + return false; + }; + + check_parents(parent, ctx, in_conditional) + }); + } + AstKind::Program(_) => return false, + _ => {} + } + + check_parents(parent, ctx, in_conditional) +} + +#[allow(clippy::too_many_lines)] +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + ( + " + it('foo', () => { + expect(1).toBe(2); + }); + ", + None, + ), + ( + " + it('foo', () => { + expect(!true).toBe(false); + }); + ", + None, + ), + ( + " + it('foo', () => { + process.env.FAIL && setNum(1); + expect(num).toBe(2); + }); + ", + None, + ), + ( + " + function getValue() { + let num = 2; + process.env.FAIL && setNum(1); + return num; + } + it('foo', () => { + expect(getValue()).toBe(2); + }); + ", + None, + ), + ( + " + it('foo', () => { + process.env.FAIL || setNum(1); + expect(num).toBe(2); + }); + ", + None, + ), + ( + " + function getValue() { + let num = 2; + process.env.FAIL || setNum(1); + return num; + } + it('foo', () => { + expect(getValue()).toBe(2); + }); + ", + None, + ), + ( + " + it('foo', () => { + const num = process.env.FAIL ? 1 : 2; + expect(num).toBe(2); + }); + ", + None, + ), + ( + " + function getValue() { + return process.env.FAIL ? 1 : 2 + } + + it('foo', () => { + expect(getValue()).toBe(2); + }); + ", + None, + ), + ( + " + it('foo', () => { + let num; + + switch(process.env.FAIL) { + case true: + num = 1; + break; + case false: + num = 2; + break; + } + + expect(num).toBe(2); + }); + ", + None, + ), + ( + " + function getValue() { + switch(process.env.FAIL) { + case true: + return 1; + case false: + return 2; + } + } + + it('foo', () => { + expect(getValue()).toBe(2); + }); + ", + None, + ), + ( + " + it('foo', () => { + let num = 2; + + if(process.env.FAIL) { + num = 1; + } + + expect(num).toBe(2); + }); + ", + None, + ), + ( + " + function getValue() { + if(process.env.FAIL) { + return 1; + } + return 2; + } + + it('foo', () => { + expect(getValue()).toBe(2); + }); + ", + None, + ), + ( + " + it('foo', () => { + try { + // do something + } catch { + // ignore errors + } finally { + expect(something).toHaveBeenCalled(); + } + }); + ", + None, + ), + ( + " + it('foo', () => { + try { + // do something + } catch { + // ignore errors + } + + expect(something).toHaveBeenCalled(); + }); + ", + None, + ), + ( + " + function getValue() { + try { + // do something + } catch { + // ignore errors + } finally { + expect(something).toHaveBeenCalled(); + } + } + it('foo', getValue); + ", + None, + ), + ( + " + function getValue() { + try { + process.env.FAIL.toString(); + + return 1; + } catch { + return 2; + } + } + + it('foo', () => { + expect(getValue()).toBe(2); + }); + ", + None, + ), + ( + " + it('works', async () => { + try { + await Promise.resolve().then(() => { + throw new Error('oh noes!'); + }); + } catch { + // ignore errors + } finally { + expect(something).toHaveBeenCalled(); + } + }); + ", + None, + ), + ( + " + it('works', async () => { + await doSomething().catch(error => error); + + expect(error).toBeInstanceOf(Error); + }); + ", + None, + ), + ( + " + it('works', async () => { + try { + await Promise.resolve().then(() => { + throw new Error('oh noes!'); + }); + } catch { + // ignore errors + } + + expect(something).toHaveBeenCalled(); + }); + ", + None, + ), + ]; + + let fail = vec![ + ( + " + it('foo', () => { + something && expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it('foo', () => { + a || b && expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it('foo', () => { + (a || b) && expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it('foo', () => { + a || (b && expect(something).toHaveBeenCalled()); + }) + ", + None, + ), + ( + " + it('foo', () => { + a && b && expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it('foo', () => { + a && b || expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it('foo', () => { + (a && b) || expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + function getValue() { + something && expect(something).toHaveBeenCalled(); + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('foo', () => { + something || expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it.each``('foo', () => { + something || expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it.each()('foo', () => { + something || expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + function getValue() { + something || expect(something).toHaveBeenCalled(); + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('foo', () => { + something ? expect(something).toHaveBeenCalled() : noop(); + }) + ", + None, + ), + ( + " + function getValue() { + something ? expect(something).toHaveBeenCalled() : noop(); + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('foo', () => { + something ? noop() : expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it.each``('foo', () => { + something ? noop() : expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + it.each()('foo', () => { + something ? noop() : expect(something).toHaveBeenCalled(); + }) + ", + None, + ), + ( + " + function getValue() { + something ? noop() : expect(something).toHaveBeenCalled(); + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('foo', () => { + switch(something) { + case 'value': + break; + default: + expect(something).toHaveBeenCalled(); + } + }) + ", + None, + ), + ( + " + it('foo', () => { + switch(something) { + case 'value': + expect(something).toHaveBeenCalled(); + default: + break; + } + }) + ", + None, + ), + ( + " + it.each``('foo', () => { + switch(something) { + case 'value': + expect(something).toHaveBeenCalled(); + default: + break; + } + }) + ", + None, + ), + ( + " + it.each()('foo', () => { + switch(something) { + case 'value': + expect(something).toHaveBeenCalled(); + default: + break; + } + }) + ", + None, + ), + ( + " + function getValue() { + switch(something) { + case 'value': + break; + default: + expect(something).toHaveBeenCalled(); + } + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('foo', () => { + if(doSomething) { + expect(something).toHaveBeenCalled(); + } + }) + ", + None, + ), + ( + " + it('foo', () => { + if(!doSomething) { + // do nothing + } else { + expect(something).toHaveBeenCalled(); + } + }) + ", + None, + ), + ( + " + it.each``('foo', () => { + if(!doSomething) { + // do nothing + } else { + expect(something).toHaveBeenCalled(); + } + }) + ", + None, + ), + ( + " + it.each()('foo', () => { + if(!doSomething) { + // do nothing + } else { + expect(something).toHaveBeenCalled(); + } + }) + ", + None, + ), + ( + " + function getValue() { + if(doSomething) { + expect(something).toHaveBeenCalled(); + } + } + + it('foo', getValue); + ", + None, + ), + ( + " + function getValue() { + if(!doSomething) { + // do nothing + } else { + expect(something).toHaveBeenCalled(); + } + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('foo', () => { + try { + + } catch (err) { + expect(err).toMatch('Error'); + } + }) + ", + None, + ), + ( + " + it.each``('foo', () => { + try { + + } catch (err) { + expect(err).toMatch('Error'); + } + }) + ", + None, + ), + ( + " + it.each()('foo', () => { + try { + + } catch (err) { + expect(err).toMatch('Error'); + } + }) + ", + None, + ), + ( + " + it.skip.each``('foo', () => { + try { + + } catch (err) { + expect(err).toMatch('Error'); + } + }) + ", + None, + ), + ( + " + it.skip.each()('foo', () => { + try { + + } catch (err) { + expect(err).toMatch('Error'); + } + }) + ", + None, + ), + ( + " + function getValue() { + try { + // do something + } catch { + expect(something).toHaveBeenCalled(); + } + } + + it('foo', getValue); + ", + None, + ), + ( + " + it('works', async () => { + await Promise.resolve() + .then(() => { throw new Error('oh noes!'); }) + .catch(error => expect(error).toBeInstanceOf(Error)); + }); + ", + None, + ), + ( + " + it('works', async () => { + await Promise.resolve() + .then(() => { throw new Error('oh noes!'); }) + .catch(error => expect(error).toBeInstanceOf(Error)) + .then(() => { throw new Error('oh noes!'); }) + .catch(error => expect(error).toBeInstanceOf(Error)) + .then(() => { throw new Error('oh noes!'); }) + .catch(error => expect(error).toBeInstanceOf(Error)); + }); + ", + None, + ), + ( + " + it('works', async () => { + await Promise.resolve() + .catch(error => expect(error).toBeInstanceOf(Error)) + .catch(error => expect(error).toBeInstanceOf(Error)) + .catch(error => expect(error).toBeInstanceOf(Error)); + }); + ", + None, + ), + ( + " + it('works', async () => { + await Promise.resolve() + .catch(error => expect(error).toBeInstanceOf(Error)) + .then(() => { throw new Error('oh noes!'); }) + .then(() => { throw new Error('oh noes!'); }) + .then(() => { throw new Error('oh noes!'); }); + }); + ", + None, + ), + ( + " + it('works', async () => { + await somePromise + .then(() => { throw new Error('oh noes!'); }) + .catch(error => expect(error).toBeInstanceOf(Error)); + }); + ", + None, + ), + ( + " + it('works', async () => { + await somePromise.catch(error => expect(error).toBeInstanceOf(Error)); + }); + ", + None, + ), + ]; + + Tester::new(NoConditionalExpect::NAME, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/no_commented_out_tests.snap b/crates/oxc_linter/src/snapshots/no_commented_out_tests.snap index a7be9d211..6f6c63b85 100644 --- a/crates/oxc_linter/src/snapshots/no_commented_out_tests.snap +++ b/crates/oxc_linter/src/snapshots/no_commented_out_tests.snap @@ -2,105 +2,105 @@ source: crates/oxc_linter/src/tester.rs expression: no_commented_out_tests --- - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // fdescribe('foo', function () {}) · ───────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // describe['skip']('foo', function () {}) · ──────────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // describe['skip']('foo', function () {}) · ──────────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // it.skip('foo', function () {}) · ─────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // it.only('foo', function () {}) · ─────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // it.concurrent('foo', function () {}) · ───────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // it['skip']('foo', function () {}) · ────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // test.skip('foo', function () {}) · ───────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // test.concurrent('foo', function () {}) · ─────────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // test['skip']('foo', function () {}) · ──────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // xdescribe('foo', function () {}) · ───────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // xit('foo', function () {}) · ─────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // fit('foo', function () {}) · ─────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // xtest('foo', function () {}) · ───────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ 2 │ // test( @@ -110,7 +110,7 @@ expression: no_commented_out_tests ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ 2 │ ╭─▶ /* test @@ -122,42 +122,42 @@ expression: no_commented_out_tests ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // it('has title but no callback') · ──────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // it() · ───── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // test.someNewMethodThatMightBeAddedInTheFuture() · ──────────────────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // test['someNewMethodThatMightBeAddedInTheFuture']() · ─────────────────────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:1:1] 1 │ // test('has title but no callback') · ────────────────────────────────── ╰──── help: Remove or uncomment this comment - ⚠ Some tests seem to be commented + ⚠ eslint(jest/no-commented-out-tests): Some tests seem to be commented ╭─[no_commented_out_tests.tsx:2:1] 2 │ foo() 3 │ ╭─▶ /* diff --git a/crates/oxc_linter/src/snapshots/no_conditional_expect.snap b/crates/oxc_linter/src/snapshots/no_conditional_expect.snap new file mode 100644 index 000000000..aa47181c6 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/no_conditional_expect.snap @@ -0,0 +1,410 @@ +--- +source: crates/oxc_linter/src/tester.rs +expression: no_conditional_expect +--- + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ something && expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ a || b && expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ (a || b) && expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ a || (b && expect(something).toHaveBeenCalled()); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ a && b && expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ a && b || expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ (a && b) || expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ function getValue() { + 3 │ something && expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ something || expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it.each``('foo', () => { + 3 │ something || expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it.each()('foo', () => { + 3 │ something || expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ function getValue() { + 3 │ something || expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ something ? expect(something).toHaveBeenCalled() : noop(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ function getValue() { + 3 │ something ? expect(something).toHaveBeenCalled() : noop(); + · ──────────────────────────────────── + 4 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('foo', () => { + 3 │ something ? noop() : expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it.each``('foo', () => { + 3 │ something ? noop() : expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it.each()('foo', () => { + 3 │ something ? noop() : expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ function getValue() { + 3 │ something ? noop() : expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 4 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:6:1] + 6 │ default: + 7 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 8 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ case 'value': + 5 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 6 │ default: + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ case 'value': + 5 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 6 │ default: + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ case 'value': + 5 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 6 │ default: + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:6:1] + 6 │ default: + 7 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 8 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:3:1] + 3 │ if(doSomething) { + 4 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 5 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } else { + 6 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } else { + 6 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } else { + 6 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:3:1] + 3 │ if(doSomething) { + 4 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 5 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } else { + 6 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } catch (err) { + 6 │ expect(err).toMatch('Error'); + · ──────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } catch (err) { + 6 │ expect(err).toMatch('Error'); + · ──────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } catch (err) { + 6 │ expect(err).toMatch('Error'); + · ──────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } catch (err) { + 6 │ expect(err).toMatch('Error'); + · ──────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } catch (err) { + 6 │ expect(err).toMatch('Error'); + · ──────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ } catch { + 6 │ expect(something).toHaveBeenCalled(); + · ──────────────────────────────────── + 7 │ } + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ .then(() => { throw new Error('oh noes!'); }) + 5 │ .catch(error => expect(error).toBeInstanceOf(Error)); + · ─────────────────────────────────── + 6 │ }); + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:8:1] + 8 │ .then(() => { throw new Error('oh noes!'); }) + 9 │ .catch(error => expect(error).toBeInstanceOf(Error)); + · ─────────────────────────────────── + 10 │ }); + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:6:1] + 6 │ .then(() => { throw new Error('oh noes!'); }) + 7 │ .catch(error => expect(error).toBeInstanceOf(Error)) + · ─────────────────────────────────── + 8 │ .then(() => { throw new Error('oh noes!'); }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ .then(() => { throw new Error('oh noes!'); }) + 5 │ .catch(error => expect(error).toBeInstanceOf(Error)) + · ─────────────────────────────────── + 6 │ .then(() => { throw new Error('oh noes!'); }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:5:1] + 5 │ .catch(error => expect(error).toBeInstanceOf(Error)) + 6 │ .catch(error => expect(error).toBeInstanceOf(Error)); + · ─────────────────────────────────── + 7 │ }); + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ .catch(error => expect(error).toBeInstanceOf(Error)) + 5 │ .catch(error => expect(error).toBeInstanceOf(Error)) + · ─────────────────────────────────── + 6 │ .catch(error => expect(error).toBeInstanceOf(Error)); + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:3:1] + 3 │ await Promise.resolve() + 4 │ .catch(error => expect(error).toBeInstanceOf(Error)) + · ─────────────────────────────────── + 5 │ .catch(error => expect(error).toBeInstanceOf(Error)) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:3:1] + 3 │ await Promise.resolve() + 4 │ .catch(error => expect(error).toBeInstanceOf(Error)) + · ─────────────────────────────────── + 5 │ .then(() => { throw new Error('oh noes!'); }) + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:4:1] + 4 │ .then(() => { throw new Error('oh noes!'); }) + 5 │ .catch(error => expect(error).toBeInstanceOf(Error)); + · ─────────────────────────────────── + 6 │ }); + ╰──── + help: Avoid calling `expect` conditionally` + + ⚠ eslint(jest/no-conditional-expect): Unexpected conditional expect + ╭─[no_conditional_expect.tsx:2:1] + 2 │ it('works', async () => { + 3 │ await somePromise.catch(error => expect(error).toBeInstanceOf(Error)); + · ─────────────────────────────────── + 4 │ }); + ╰──── + help: Avoid calling `expect` conditionally` + +