@@ -314,27 +314,45 @@ fn should_skip_vitest_arg(arg: &str) -> bool {
314314 arg == "run" || arg. starts_with ( "--json" ) || arg. starts_with ( "--watch" )
315315}
316316
317- /// Strip jest args that conflict with the injected `--no-watch --json`.
318- /// `--reporters` is a yargs array flag: the space-separated form consumes
319- /// every following non-flag token, so those values must be dropped with the
320- /// flag — leaving them behind turns reporter names (`default`, ...) into
321- /// positional test-name filters and jest silently runs the wrong test set.
322- /// `--watch`/`--watchAll` are boolean and matched exactly, so value-carrying
323- /// flags like `--watchPathIgnorePatterns` are forwarded intact.
317+ /// Strip jest args that conflict with the injected `--no-watch --json`,
318+ /// consuming exactly the tokens jest's own yargs parsing would bind to them:
319+ /// - `--reporters` and `--reporters=<v>` are greedy array flags: every
320+ /// following token up to the next `-`-prefixed one is a reporter value and
321+ /// is dropped with the flag — left behind, it becomes a positional
322+ /// test-name filter and jest silently runs the wrong test set.
323+ /// - `--reporter` (not a jest flag) binds at most one following non-flag
324+ /// token under yargs unknown-option rules; only that token is dropped.
325+ /// - `--reporter=<v>` binds no following token; only the flag is dropped.
326+ /// - `run`, `--json`, `--watch`, `--watchAll` (and their `=` forms) are
327+ /// boolean/bare and dropped alone; every other token — including
328+ /// value-carrying flags like `--watchPathIgnorePatterns` — is forwarded
329+ /// intact.
330+ /// - `--` and everything after it are forwarded verbatim: jest treats all
331+ /// following tokens as positionals, so no strip rule may apply to them.
324332fn strip_jest_conflicting_args ( args : & [ String ] ) -> Vec < String > {
325333 let mut out = Vec :: new ( ) ;
326334 let mut iter = args. iter ( ) . peekable ( ) ;
327335 while let Some ( arg) = iter. next ( ) {
328- if arg == "--reporters" || arg == "--reporter" {
336+ if arg == "--" {
337+ out. push ( arg. clone ( ) ) ;
338+ out. extend ( iter. cloned ( ) ) ;
339+ break ;
340+ }
341+ if arg == "--reporters" || arg. starts_with ( "--reporters=" ) {
329342 while iter. peek ( ) . is_some_and ( |next| !next. starts_with ( '-' ) ) {
330343 iter. next ( ) ;
331344 }
332345 continue ;
333346 }
347+ if arg == "--reporter" {
348+ if iter. peek ( ) . is_some_and ( |next| !next. starts_with ( '-' ) ) {
349+ iter. next ( ) ;
350+ }
351+ continue ;
352+ }
334353 if arg == "run"
335354 || arg == "--json"
336355 || arg. starts_with ( "--json=" )
337- || arg. starts_with ( "--reporters=" )
338356 || arg. starts_with ( "--reporter=" )
339357 || arg == "--watch"
340358 || arg. starts_with ( "--watch=" )
@@ -674,11 +692,48 @@ Scope: all 6 workspace projects
674692 }
675693
676694 #[ test]
677- fn test_strip_jest_reporters_equals_form ( ) {
678- let result = strip_jest_conflicting_args ( & args ( & [ "--reporters=default" , "sum.test.ts" ] ) ) ;
695+ fn test_strip_jest_reporters_equals_form_is_greedy_too ( ) {
696+ // yargs array flags stay greedy in the equals form: jest binds
697+ // `jest-junit` (and any following non-flag token) to --reporters,
698+ // so forwarding it would turn it into a test-name filter.
699+ let result = strip_jest_conflicting_args ( & args ( & [
700+ "--reporters=default" ,
701+ "jest-junit" ,
702+ "--coverage" ,
703+ ] ) ) ;
704+ assert_eq ! ( result, args( & [ "--coverage" ] ) ) ;
705+ }
706+
707+ #[ test]
708+ fn test_strip_jest_singular_reporter_consumes_at_most_one_value ( ) {
709+ // --reporter is not a jest flag; yargs binds at most one value to an
710+ // unknown option, so the test filter after it must survive.
711+ let result =
712+ strip_jest_conflicting_args ( & args ( & [ "--reporter" , "default" , "sum.test.ts" ] ) ) ;
713+ assert_eq ! ( result, args( & [ "sum.test.ts" ] ) ) ;
714+ }
715+
716+ #[ test]
717+ fn test_strip_jest_singular_reporter_equals_form_binds_no_value ( ) {
718+ let result = strip_jest_conflicting_args ( & args ( & [ "--reporter=verbose" , "sum.test.ts" ] ) ) ;
679719 assert_eq ! ( result, args( & [ "sum.test.ts" ] ) ) ;
680720 }
681721
722+ #[ test]
723+ fn test_strip_jest_reporters_stops_at_double_dash_terminator ( ) {
724+ let result =
725+ strip_jest_conflicting_args ( & args ( & [ "--reporters" , "default" , "--" , "sum.test.ts" ] ) ) ;
726+ assert_eq ! ( result, args( & [ "--" , "sum.test.ts" ] ) ) ;
727+ }
728+
729+ #[ test]
730+ fn test_strip_jest_everything_after_double_dash_is_positional ( ) {
731+ // jest treats all tokens after `--` as positionals — even ones that
732+ // look like strippable flags must be forwarded verbatim.
733+ let result = strip_jest_conflicting_args ( & args ( & [ "--watch" , "--" , "run" , "--json" ] ) ) ;
734+ assert_eq ! ( result, args( & [ "--" , "run" , "--json" ] ) ) ;
735+ }
736+
682737 #[ test]
683738 fn test_strip_jest_watch_flags_are_boolean ( ) {
684739 // --watch/--watchAll never consume a value; the following token is a
0 commit comments