Your solution is effective, but let me add important background information:
The core problem is the sad reality that up to at least PowerShell 7.2 an extra, manual layer of \
-escaping of embedded "
characters is required in arguments passed to external programs. This may get fixed in a future version, which may require opt-in. See this answer for details.
In your particular case, the problem is apparently compounded by having to perform this escaping twice, because two calls are involved: first, to npm
, which then relays some of the arguments it received to jest
.
Ultimately, what you want jest
to see verbatim, after it has parsed its own command line (on Windows) is the following string:
--collectCoverageFrom='["**/ExampleComponent.tsx"]'
As an aside: Your bash
command does not achieve that, because the '
have syntactic function (as they do in PowerShell) and are removed by bash
before the resulting string is passed on.
If the PowerShell bug weren't in the picture, you'd use the following:
npm t '--' ExampleComponent --collectCoverageFrom='''["**/ExampleComponent.tsx"]'''
Note the ''
embedded in the overall '...'
verbatim string, which are escaped '
chars. to be included verbatim in the string.
Alternatively, you could use "..."
for the outer quoting, which then requires you to escaped the embedded "
chars. as `"
(or ""
[1]):
npm t '--' ExampleComponent --collectCoverageFrom="'[`"**/ExampleComponent.tsx`"]'"
Note, however, that such double-quoted strings are expandable strings, i.e. subject to string interpolation. It's generally better to use verbatim strings ('...'
) for strings that do not require interpolation, for conceptual clarity and to prevent potentially unwanted interpolation (not a concern here, given that the string contains no meant-to-be verbatim $
or `
characters).
With no bug regarding embedded "
characters present, there is also no problem with relaying arguments - irrespective of the number of times this is performed.
In fact, if you're on PowerShell 7.2, you can make this work, but only if you explicitly enable the PSNativeCommandArgumentPassing
experimental feature:
Enable-ExperimentalFeature PSNativeCommandArgumentPassing
- Then start a new session for the change to take effect.
- In the new session, run
$PSNativeCommandArgumentPassing = 'Standard'
so as to also apply the fix to batch files (*.cmd
, *.bat
), which is necessary because the npm
CLI is implemented as one.
- This unfortunate need for an additional, per-session step is the result of a highly unfortunate design decision to by default (value
'Windows'
) exempt batch files and WSH script files (JScript, VBScript) from the fix, instead of applying target scripting engine-appropriate fixes automatically - see the conversation in GitHub issue #15143
Run Disable-ExperimentalFeature PSNativeCommandArgumentPassing
later to disable it again.
With the bug present:
The embedded "
characters in your string require manual \
-escaping, due to the bug - irrespective of whether you use a '...'
or a "..."
string:
If only one call were involved, this means:
# Note the \-escaped "
npm t '--' ExampleComponent --collectCoverageFrom='''[\"**/ExampleComponent.tsx\"]'''
This would make npm
see the desired verbatim string.
- Because
npm
then relays the argument in question to jest
, an additional round of escaping must be applied:
# Note the \-escaped ", preceded by an \-escaped \
npm t '--' ExampleComponent --collectCoverageFrom='''[\\\"**/ExampleComponent.tsx\\\"]'''
That is:
- The call to
npm
effectively turns the \"
to "
- Because the argument is then relayed it must again be manually
\
-escaped, so that the "
chars. are also preserved in the call to jest
.
- By prepending
\\
- i.e. an escaped \
to - \"
(\\\"
), npm
ends up seeing verbatim \"
, which, when relayed via PowerShell, makes jest
see just "
, as desired.
[1] While ""
works fine inside "..."
, it works only there. By contrast, `"
uses PowerShell's general escape character, the backtick (`
) - and having to remember only that one character, irrespective of context, reduces the memory burden for the user.