You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#!/usr/bin/env bash# Counts ANSI escape sequences in the reporter's output across three# scenarios. Per https://no-color.org/, B should match C (zero).set -e
PW=./node_modules/.bin/playwright
count() { grep -oE $'\x1b\[[^A-Za-z]*[A-Za-z]'| wc -l; }
ENV=(env -i HOME="$HOME" PATH="$PATH" TERM=xterm-256color)
echo"=== A: PFT=1 alone (sanity: expect color + cursor codes) ===""${ENV[@]}" PLAYWRIGHT_FORCE_TTY=1 "$PW"test2>&1| count
echo"=== B: PFT=1 + NO_COLOR=1 (BUG: identical to A — NO_COLOR ignored) ===""${ENV[@]}" PLAYWRIGHT_FORCE_TTY=1 NO_COLOR=1 "$PW"test2>&1| count
echo"=== C: PFT=1 + FORCE_COLOR=0 (works — equivalent should hold for NO_COLOR) ===""${ENV[@]}" PLAYWRIGHT_FORCE_TTY=1 FORCE_COLOR=0 "$PW"test2>&1| count
Expected
Per the NO_COLOR convention — "Command-line software which adds ANSI color to its output by default should check for [NO_COLOR]. When present and not an empty string ..., that software will not add ANSI color" — case B should produce zero ANSI sequences, matching case C.
Actual
A (sanity)
B (NO_COLOR=1)
C (FORCE_COLOR=0)
ANSI count
38
38
0
NO_COLOR=1 has zero effect; the reporter emits color SGR (\x1b[2m, \x1b[32m, etc.) AND cursor control (\x1b[1A, \x1b[2K, \x1b[0G, \x1b[1E).
There's also a Node.js diagnostic warning visible in the output:
(node:NNNN) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
The user didn't set FORCE_COLOR — Playwright sets it internally in lib/runner/index.js lines 787 and 5015 when spawning worker processes. Node then drops NO_COLOR per its own precedence rules.
Worker spawn — FORCE_COLOR: "1" is hardcoded into the worker env (lib/runner/index.js:787,5015 in the bundled output). This overrides any NO_COLOR the user set, per Node's stdlib precedence.
Proposed fix
(1) is a one-liner — add NO_COLOR to the disabling branch in base.ts:
Per the NO_COLOR spec, any non-empty value disables ANSI — including NO_COLOR=0 and NO_COLOR=false — which is why we check !== '' && !== undefined, not truthiness. Honoring this also propagates through the existing screen.stdout = useColors ? originalProcessStdout : new StripAnsiStream(...) path, so cursor codes get stripped on the way out (the #40688 mechanism).
(2) deserves a separate fix — when the user has NO_COLOR set, the worker spawn shouldn't unconditionally set FORCE_COLOR=1. Could be skipped for this issue or paired up; happy to defer.
Version
1.61.0-alpha (post-#40688) and earlier. Reproduces on
@playwright/test@nextand@playwright/test@1.60.0.Steps to reproduce
Setup:
Run:
Expected
Per the NO_COLOR convention — "Command-line software which adds ANSI color to its output by default should check for [NO_COLOR]. When present and not an empty string ..., that software will not add ANSI color" — case B should produce zero ANSI sequences, matching case C.
Actual
NO_COLOR=1)FORCE_COLOR=0)NO_COLOR=1has zero effect; the reporter emits color SGR (\x1b[2m,\x1b[32m, etc.) AND cursor control (\x1b[1A,\x1b[2K,\x1b[0G,\x1b[1E).There's also a Node.js diagnostic warning visible in the output:
The user didn't set
FORCE_COLOR— Playwright sets it internally inlib/runner/index.jslines 787 and 5015 when spawning worker processes. Node then dropsNO_COLORper its own precedence rules.Root cause
Two places:
packages/playwright/src/reporters/base.ts—terminalScreenderivesuseColorsfromisTTY,DEBUG_COLORS, andFORCE_COLOR.NO_COLORis never consulted, souseColors=trueandStripAnsiStream(added in fix(reporter): strip ansi from test stdout when colors are disabled #40688) doesn't engage.Worker spawn —
FORCE_COLOR: "1"is hardcoded into the worker env (lib/runner/index.js:787,5015in the bundled output). This overrides anyNO_COLORthe user set, per Node's stdlib precedence.Proposed fix
(1) is a one-liner — add
NO_COLORto the disabling branch inbase.ts:Per the NO_COLOR spec, any non-empty value disables ANSI — including
NO_COLOR=0andNO_COLOR=false— which is why we check!== '' && !== undefined, not truthiness. Honoring this also propagates through the existingscreen.stdout = useColors ? originalProcessStdout : new StripAnsiStream(...)path, so cursor codes get stripped on the way out (the #40688 mechanism).(2) deserves a separate fix — when the user has
NO_COLORset, the worker spawn shouldn't unconditionally setFORCE_COLOR=1. Could be skipped for this issue or paired up; happy to defer.Relations
StripAnsiStreamwrapping mechanism this fix piggybacks on.PLAYWRIGHT_FORCE_TTYprecedent.