Skip to content

[Bug]: Reporter ignores NO_COLOR — colors and cursor codes still emitted with NO_COLOR=1 #40904

@williamdes

Description

@williamdes

Version

1.61.0-alpha (post-#40688) and earlier. Reproduces on @playwright/test@next and @playwright/test@1.60.0.

Steps to reproduce

Setup:

mkdir -p /tmp/pw-no-color && cd /tmp/pw-no-color
cat > a.spec.ts <<'EOF'
import { test } from '@playwright/test';
test('one', () => {});
test('two', () => {});
EOF
cat > playwright.config.ts <<'EOF'
import { defineConfig } from '@playwright/test';
export default defineConfig({ reporter: 'list', workers: 1, testDir: '.' });
EOF
npm init -y >/dev/null
npm i -D @playwright/test@next

Run:

#!/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" test 2>&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" test 2>&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" test 2>&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.

Root cause

Two places:

  1. packages/playwright/src/reporters/base.tsterminalScreen derives useColors from isTTY, DEBUG_COLORS, and FORCE_COLOR. NO_COLOR is never consulted, so useColors=true and StripAnsiStream (added in fix(reporter): strip ansi from test stdout when colors are disabled #40688) doesn't engage.

  2. Worker spawnFORCE_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:

if (process.env.DEBUG_COLORS === '0' || process.env.DEBUG_COLORS === 'false' ||
    process.env.FORCE_COLOR === '0' || process.env.FORCE_COLOR === 'false' ||
    (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== ''))
  useColors = false;

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.

Relations

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions