From f609cb6819164b820ca7941c7132766273205cd6 Mon Sep 17 00:00:00 2001 From: camc314 <18101008+camc314@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:44:11 +0000 Subject: [PATCH] fix(linter/prefer-expect-type-of): handle computed elements in fixer correctly (#18890) Handle computed modifier access (e.g. ["not"]) in prefer-expect-type-of autofix and add regression test. --- .../src/rules/vitest/prefer_expect_type_of.rs | 18 ++++++++++++++++-- .../vitest_prefer_expect_type_of.snap | 7 +++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/oxc_linter/src/rules/vitest/prefer_expect_type_of.rs b/crates/oxc_linter/src/rules/vitest/prefer_expect_type_of.rs index ff913cfbc7032..6d43e1dcc5d97 100644 --- a/crates/oxc_linter/src/rules/vitest/prefer_expect_type_of.rs +++ b/crates/oxc_linter/src/rules/vitest/prefer_expect_type_of.rs @@ -9,7 +9,7 @@ use oxc_span::{GetSpan, Span}; use crate::{ context::LintContext, rule::Rule, - utils::{PossibleJestNode, parse_expect_jest_fn_call}, + utils::{MemberExpressionElement, PossibleJestNode, parse_expect_jest_fn_call}, }; fn prefer_expect_type_of_diagnostic(span: Span, help: &str) -> OxcDiagnostic { @@ -129,7 +129,16 @@ impl PreferExpectTypeOf { let modifier_text = expect_call.modifiers().iter().fold(String::new(), |mut acc, modifier| { use std::fmt::Write; - write!(&mut acc, ".{}", ctx.source_range(modifier.span)).unwrap(); + match modifier.element { + // `.not` + MemberExpressionElement::IdentName(_) => { + write!(&mut acc, ".{}", ctx.source_range(modifier.span)).unwrap(); + } + // `["not"]`, `[not]`, `[`not`]`, etc. + MemberExpressionElement::Expression(_) => { + write!(&mut acc, "[{}]", ctx.source_range(modifier.span)).unwrap(); + } + } acc }); @@ -171,6 +180,7 @@ fn test() { r#"expect(typeof fn).toBe("function")"#, r#"expect(typeof value).toEqual("string")"#, r#"expect(typeof value).not.toBe("string")"#, + r#"expect(typeof value)["not"].toBe("string")"#, ]; let fix = vec![ @@ -181,6 +191,10 @@ fn test() { (r#"expect(typeof fn).toBe("function")"#, "expectTypeOf(fn).toBeFunction()"), (r#"expect(typeof value).toEqual("string")"#, "expectTypeOf(value).toBeString()"), (r#"expect(typeof value).not.toBe("string")"#, "expectTypeOf(value).not.toBeString()"), + ( + r#"expect(typeof value)["not"].toBe("string")"#, + r#"expectTypeOf(value)["not"].toBeString()"#, + ), ]; Tester::new(PreferExpectTypeOf::NAME, PreferExpectTypeOf::PLUGIN, pass, fail) diff --git a/crates/oxc_linter/src/snapshots/vitest_prefer_expect_type_of.snap b/crates/oxc_linter/src/snapshots/vitest_prefer_expect_type_of.snap index a034a54b4d1cf..25c5476a5b6ff 100644 --- a/crates/oxc_linter/src/snapshots/vitest_prefer_expect_type_of.snap +++ b/crates/oxc_linter/src/snapshots/vitest_prefer_expect_type_of.snap @@ -49,3 +49,10 @@ source: crates/oxc_linter/src/tester.rs · ─────────────────────────────────────── ╰──── help: Substitute the assertion with `expectTypeOf(value).not.toBeString()`. + + ⚠ eslint-plugin-vitest(prefer-expect-type-of): Type assertions should be done using `expectTypeOf`. + ╭─[prefer_expect_type_of.tsx:1:1] + 1 │ expect(typeof value)["not"].toBe("string") + · ────────────────────────────────────────── + ╰──── + help: Substitute the assertion with `expectTypeOf(value)["not"].toBeString()`.