feat(test runner): allow overriding TTY params
- Move all tty-related craft into `tty.ts`. - Inherit `isTTY` from the runner process into worker process, instead of always pretending `isTTY === true` in the worker. - Respect `env.PLAYWRIGHT_TTY` that overrides tty. Supported: - `0` and `false` to disable tty; - `80` to set columns; - `80x25` to set columns and rows; - `80x25x8` to set columns, rows and color depth.
This commit is contained in:
parent
1539cde034
commit
fc915b68c6
|
|
@ -18,6 +18,7 @@ import util from 'util';
|
|||
import { type SerializedCompilationCache, serializeCompilationCache } from '../transform/compilationCache';
|
||||
import type { ConfigLocation, FullConfigInternal } from './config';
|
||||
import type { ReporterDescription, TestInfoError, TestStatus } from '../../types/test';
|
||||
import type { TTYParams } from './tty';
|
||||
|
||||
export type ConfigCLIOverrides = {
|
||||
forbidOnly?: boolean;
|
||||
|
|
@ -46,15 +47,9 @@ export type SerializedConfig = {
|
|||
compilationCache?: SerializedCompilationCache;
|
||||
};
|
||||
|
||||
export type TtyParams = {
|
||||
rows: number | undefined;
|
||||
columns: number | undefined;
|
||||
colorDepth: number;
|
||||
};
|
||||
|
||||
export type ProcessInitParams = {
|
||||
stdoutParams: TtyParams;
|
||||
stderrParams: TtyParams;
|
||||
stdoutTTY: TTYParams | undefined;
|
||||
stderrTTY: TTYParams | undefined;
|
||||
processName: string;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { WriteStream } from 'tty';
|
||||
import type { EnvProducedPayload, ProcessInitParams, TtyParams } from './ipc';
|
||||
import type { EnvProducedPayload, ProcessInitParams } from './ipc';
|
||||
import { startProfiling, stopProfiling } from 'playwright-core/lib/utils';
|
||||
import type { TestInfoError } from '../../types/test';
|
||||
import { serializeError } from '../util';
|
||||
import { registerESMLoader } from './esmLoaderHost';
|
||||
import { execArgvWithoutExperimentalLoaderOptions } from '../transform/esmUtils';
|
||||
import { setTTYParams } from './tty';
|
||||
|
||||
export type ProtocolRequest = {
|
||||
id: number;
|
||||
|
|
@ -67,8 +67,8 @@ const startingEnv = { ...process.env };
|
|||
process.on('message', async (message: any) => {
|
||||
if (message.method === '__init__') {
|
||||
const { processParams, runnerParams, runnerScript } = message.params as { processParams: ProcessInitParams, runnerParams: any, runnerScript: string };
|
||||
setTtyParams(process.stdout, processParams.stdoutParams);
|
||||
setTtyParams(process.stderr, processParams.stderrParams);
|
||||
setTTYParams(process.stdout, processParams.stdoutTTY);
|
||||
setTTYParams(process.stderr, processParams.stderrTTY);
|
||||
void startProfiling();
|
||||
const { create } = require(runnerScript);
|
||||
processRunner = create(runnerParams) as ProcessRunner;
|
||||
|
|
@ -117,40 +117,3 @@ function sendMessageToParent(message: { method: string, params?: any }) {
|
|||
// Can throw when closing.
|
||||
}
|
||||
}
|
||||
|
||||
function setTtyParams(stream: WriteStream, params: TtyParams) {
|
||||
stream.isTTY = true;
|
||||
if (params.rows)
|
||||
stream.rows = params.rows;
|
||||
if (params.columns)
|
||||
stream.columns = params.columns;
|
||||
stream.getColorDepth = () => params.colorDepth;
|
||||
stream.hasColors = ((count = 16) => {
|
||||
// count is optional and the first argument may actually be env.
|
||||
if (typeof count !== 'number')
|
||||
count = 16;
|
||||
return count <= 2 ** params.colorDepth;
|
||||
})as any;
|
||||
|
||||
// Stubs for the rest of the methods to avoid exceptions in user code.
|
||||
stream.clearLine = (dir: any, callback?: () => void) => {
|
||||
callback?.();
|
||||
return true;
|
||||
};
|
||||
stream.clearScreenDown = (callback?: () => void) => {
|
||||
callback?.();
|
||||
return true;
|
||||
};
|
||||
(stream as any).cursorTo = (x: number, y?: number | (() => void), callback?: () => void) => {
|
||||
if (callback)
|
||||
callback();
|
||||
else if (y instanceof Function)
|
||||
y();
|
||||
return true;
|
||||
};
|
||||
stream.moveCursor = (dx: number, dy: number, callback?: () => void) => {
|
||||
callback?.();
|
||||
return true;
|
||||
};
|
||||
stream.getWindowSize = () => [stream.columns, stream.rows];
|
||||
}
|
||||
|
|
|
|||
121
packages/playwright/src/common/tty.ts
Normal file
121
packages/playwright/src/common/tty.ts
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* Copyright Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { WriteStream } from 'tty';
|
||||
import { colors as realColors } from 'playwright-core/lib/utilsBundle';
|
||||
|
||||
export type TTYParams = {
|
||||
rows: number;
|
||||
columns: number;
|
||||
colorDepth: number;
|
||||
};
|
||||
|
||||
function getTTYParams(stream: WriteStream): TTYParams | undefined {
|
||||
// Explicitly disabled.
|
||||
if (process.env.PLAYWRIGHT_TTY === 'false' || process.env.PLAYWRIGHT_TTY === '0')
|
||||
return;
|
||||
|
||||
// Format is COLUMNS[xROWS[xDEPTH]] similar to xvfb screen.
|
||||
const match = (process.env.PLAYWRIGHT_TTY || '').match(/^(\d+)(?:x(\d+))?(?:x(\d+))?$/);
|
||||
if (!match && !stream.isTTY)
|
||||
return;
|
||||
|
||||
// Use an override from PLAYWRIGHT_TTY or the real value for each.
|
||||
return {
|
||||
columns: match?.[1] ? +match[1] : (stream.isTTY ? stream.columns : 0),
|
||||
rows: match?.[2] ? +match[2] : (stream.isTTY ? stream.rows : 0),
|
||||
colorDepth: match?.[3] ? +match[3] : (stream.isTTY ? (stream.getColorDepth?.() || 8) : 8),
|
||||
};
|
||||
}
|
||||
|
||||
export const stdoutTTY = getTTYParams(process.stdout);
|
||||
export const stderrTTY = getTTYParams(process.stderr);
|
||||
|
||||
let useColors = !!stdoutTTY;
|
||||
if (process.env.DEBUG_COLORS === '0'
|
||||
|| process.env.DEBUG_COLORS === 'false'
|
||||
|| process.env.FORCE_COLOR === '0'
|
||||
|| process.env.FORCE_COLOR === 'false')
|
||||
useColors = false;
|
||||
else if (process.env.DEBUG_COLORS || process.env.FORCE_COLOR)
|
||||
useColors = true;
|
||||
|
||||
export const colors = useColors ? realColors : {
|
||||
bold: (t: string) => t,
|
||||
cyan: (t: string) => t,
|
||||
dim: (t: string) => t,
|
||||
gray: (t: string) => t,
|
||||
green: (t: string) => t,
|
||||
red: (t: string) => t,
|
||||
yellow: (t: string) => t,
|
||||
enabled: false,
|
||||
};
|
||||
|
||||
export function setTTYParams(stream: WriteStream, params: TTYParams | undefined) {
|
||||
if (!params) {
|
||||
stream.isTTY = false;
|
||||
stream.rows = 0;
|
||||
stream.columns = 0;
|
||||
stream.getColorDepth = () => 8;
|
||||
return;
|
||||
}
|
||||
|
||||
stream.isTTY = true;
|
||||
if (params.rows)
|
||||
stream.rows = params.rows;
|
||||
if (params.columns)
|
||||
stream.columns = params.columns;
|
||||
stream.getColorDepth = () => params.colorDepth;
|
||||
stream.hasColors = ((count = 16) => {
|
||||
// count is optional and the first argument may actually be env.
|
||||
if (typeof count !== 'number')
|
||||
count = 16;
|
||||
return count <= 2 ** params.colorDepth;
|
||||
})as any;
|
||||
|
||||
// Stubs for the rest of the methods to avoid exceptions in user code.
|
||||
stream.clearLine = (dir: any, callback?: () => void) => {
|
||||
callback?.();
|
||||
return true;
|
||||
};
|
||||
stream.clearScreenDown = (callback?: () => void) => {
|
||||
callback?.();
|
||||
return true;
|
||||
};
|
||||
(stream as any).cursorTo = (x: number, y?: number | (() => void), callback?: () => void) => {
|
||||
if (callback)
|
||||
callback();
|
||||
else if (y instanceof Function)
|
||||
y();
|
||||
return true;
|
||||
};
|
||||
stream.moveCursor = (dx: number, dy: number, callback?: () => void) => {
|
||||
callback?.();
|
||||
return true;
|
||||
};
|
||||
stream.getWindowSize = () => [stream.columns, stream.rows];
|
||||
}
|
||||
|
||||
export function resizeTTY(columns: number, rows: number) {
|
||||
if (stdoutTTY) {
|
||||
process.stdout.columns = stdoutTTY.columns = columns;
|
||||
process.stdout.rows = stdoutTTY.rows = rows;
|
||||
}
|
||||
if (stderrTTY) {
|
||||
process.stderr.columns = stderrTTY.rows = rows;
|
||||
process.stderr.rows = stderrTTY.columns = columns;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,11 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { colors as realColors, ms as milliseconds, parseStackTraceLine } from 'playwright-core/lib/utilsBundle';
|
||||
import { ms as milliseconds, parseStackTraceLine } from 'playwright-core/lib/utilsBundle';
|
||||
import path from 'path';
|
||||
import type { FullConfig, TestCase, Suite, TestResult, TestError, FullResult, TestStep, Location } from '../../types/testReporter';
|
||||
import { getPackageManagerExecCommand } from 'playwright-core/lib/utils';
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
import { colors, stdoutTTY } from '../common/tty';
|
||||
|
||||
export { colors } from '../common/tty';
|
||||
export type TestResultOutput = { chunk: string | Buffer, type: 'stdout' | 'stderr' };
|
||||
export const kOutputSymbol = Symbol('output');
|
||||
|
||||
|
|
@ -44,28 +47,6 @@ type TestSummary = {
|
|||
fatalErrors: TestError[];
|
||||
};
|
||||
|
||||
export const isTTY = !!process.env.PWTEST_TTY_WIDTH || process.stdout.isTTY;
|
||||
export const ttyWidth = process.env.PWTEST_TTY_WIDTH ? parseInt(process.env.PWTEST_TTY_WIDTH, 10) : process.stdout.columns || 0;
|
||||
let useColors = isTTY;
|
||||
if (process.env.DEBUG_COLORS === '0'
|
||||
|| process.env.DEBUG_COLORS === 'false'
|
||||
|| process.env.FORCE_COLOR === '0'
|
||||
|| process.env.FORCE_COLOR === 'false')
|
||||
useColors = false;
|
||||
else if (process.env.DEBUG_COLORS || process.env.FORCE_COLOR)
|
||||
useColors = true;
|
||||
|
||||
export const colors = useColors ? realColors : {
|
||||
bold: (t: string) => t,
|
||||
cyan: (t: string) => t,
|
||||
dim: (t: string) => t,
|
||||
gray: (t: string) => t,
|
||||
green: (t: string) => t,
|
||||
red: (t: string) => t,
|
||||
yellow: (t: string) => t,
|
||||
enabled: false,
|
||||
};
|
||||
|
||||
export class BaseReporter implements ReporterV2 {
|
||||
config!: FullConfig;
|
||||
suite!: Suite;
|
||||
|
|
@ -145,11 +126,11 @@ export class BaseReporter implements ReporterV2 {
|
|||
}
|
||||
|
||||
protected fitToScreen(line: string, prefix?: string): string {
|
||||
if (!ttyWidth) {
|
||||
if (!stdoutTTY?.columns) {
|
||||
// Guard against the case where we cannot determine available width.
|
||||
return line;
|
||||
}
|
||||
return fitToWidth(line, ttyWidth, prefix);
|
||||
return fitToWidth(line, stdoutTTY.columns, prefix);
|
||||
}
|
||||
|
||||
protected generateStartingMessage() {
|
||||
|
|
@ -491,7 +472,7 @@ export function formatError(error: TestError, highlightCode: boolean): ErrorDeta
|
|||
export function separator(text: string = ''): string {
|
||||
if (text)
|
||||
text += ' ';
|
||||
const columns = Math.min(100, ttyWidth || 100);
|
||||
const columns = Math.min(100, stdoutTTY?.columns || 100);
|
||||
return text + colors.dim('─'.repeat(Math.max(0, columns - text.length)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@
|
|||
*/
|
||||
|
||||
import { ms as milliseconds } from 'playwright-core/lib/utilsBundle';
|
||||
import { colors, BaseReporter, formatError, formatTestTitle, isTTY, stepSuffix, stripAnsiEscapes, ttyWidth } from './base';
|
||||
import { colors, BaseReporter, formatError, formatTestTitle, stepSuffix, stripAnsiEscapes } from './base';
|
||||
import type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';
|
||||
import { stdoutTTY } from '../common/tty';
|
||||
|
||||
// Allow it in the Visual Studio Code Terminal and the new Windows Terminal
|
||||
const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION;
|
||||
|
|
@ -35,7 +36,7 @@ class ListReporter extends BaseReporter {
|
|||
|
||||
constructor(options: { omitFailures?: boolean, printSteps?: boolean } = {}) {
|
||||
super(options);
|
||||
this._printSteps = isTTY && (options.printSteps || !!process.env.PW_TEST_DEBUG_REPORTERS_PRINT_STEPS);
|
||||
this._printSteps = !!stdoutTTY && (options.printSteps || !!process.env.PW_TEST_DEBUG_REPORTERS_PRINT_STEPS);
|
||||
}
|
||||
|
||||
override printsToStdio() {
|
||||
|
|
@ -53,7 +54,7 @@ class ListReporter extends BaseReporter {
|
|||
|
||||
override onTestBegin(test: TestCase, result: TestResult) {
|
||||
super.onTestBegin(test, result);
|
||||
if (!isTTY)
|
||||
if (!stdoutTTY)
|
||||
return;
|
||||
this._maybeWriteNewLine();
|
||||
const index = String(this._resultIndex.size + 1);
|
||||
|
|
@ -80,7 +81,7 @@ class ListReporter extends BaseReporter {
|
|||
return;
|
||||
const testIndex = this._resultIndex.get(result) || '';
|
||||
if (!this._printSteps) {
|
||||
if (isTTY)
|
||||
if (stdoutTTY)
|
||||
this._updateLine(this._testRows.get(test)!, colors.dim(formatTestTitle(this.config, test, step)) + this._retrySuffix(result), this._testPrefix(testIndex, ''));
|
||||
return;
|
||||
}
|
||||
|
|
@ -90,7 +91,7 @@ class ListReporter extends BaseReporter {
|
|||
const stepIndex = `${testIndex}.${ordinal}`;
|
||||
this._stepIndex.set(step, stepIndex);
|
||||
|
||||
if (isTTY) {
|
||||
if (stdoutTTY) {
|
||||
this._maybeWriteNewLine();
|
||||
this._stepRows.set(step, this._lastRow);
|
||||
const prefix = this._testPrefix(stepIndex, '');
|
||||
|
|
@ -106,7 +107,7 @@ class ListReporter extends BaseReporter {
|
|||
|
||||
const testIndex = this._resultIndex.get(result) || '';
|
||||
if (!this._printSteps) {
|
||||
if (isTTY)
|
||||
if (stdoutTTY)
|
||||
this._updateLine(this._testRows.get(test)!, colors.dim(formatTestTitle(this.config, test, step.parent)) + this._retrySuffix(result), this._testPrefix(testIndex, ''));
|
||||
return;
|
||||
}
|
||||
|
|
@ -133,7 +134,7 @@ class ListReporter extends BaseReporter {
|
|||
|
||||
private _updateLineCountAndNewLineFlagForOutput(text: string) {
|
||||
this._needNewLine = text[text.length - 1] !== '\n';
|
||||
if (!ttyWidth)
|
||||
if (!stdoutTTY?.columns)
|
||||
return;
|
||||
for (const ch of text) {
|
||||
if (ch === '\n') {
|
||||
|
|
@ -142,7 +143,7 @@ class ListReporter extends BaseReporter {
|
|||
continue;
|
||||
}
|
||||
++this._lastColumn;
|
||||
if (this._lastColumn > ttyWidth) {
|
||||
if (this._lastColumn > stdoutTTY.columns) {
|
||||
this._lastColumn = 0;
|
||||
++this._lastRow;
|
||||
}
|
||||
|
|
@ -192,7 +193,7 @@ class ListReporter extends BaseReporter {
|
|||
}
|
||||
|
||||
private _updateOrAppendLine(row: number, text: string, prefix: string) {
|
||||
if (isTTY) {
|
||||
if (stdoutTTY) {
|
||||
this._updateLine(row, text, prefix);
|
||||
} else {
|
||||
this._maybeWriteNewLine();
|
||||
|
|
@ -229,8 +230,6 @@ class ListReporter extends BaseReporter {
|
|||
// Go down if needed.
|
||||
if (row !== this._lastRow)
|
||||
process.stdout.write(`\u001B[${this._lastRow - row}E`);
|
||||
if (process.env.PWTEST_TTY_WIDTH)
|
||||
process.stdout.write('\n'); // For testing.
|
||||
}
|
||||
|
||||
private _testPrefix(index: string, statusMark: string) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import type { ProtocolResponse } from '../common/process';
|
|||
import { execArgvWithExperimentalLoaderOptions } from '../transform/esmUtils';
|
||||
import { assert } from 'playwright-core/lib/utils';
|
||||
import { esmLoaderRegistered } from '../common/esmLoaderHost';
|
||||
import { stderrTTY, stdoutTTY } from '../common/tty';
|
||||
|
||||
export type ProcessExitData = {
|
||||
unexpectedly: boolean;
|
||||
|
|
@ -111,20 +112,7 @@ export class ProcessHost extends EventEmitter {
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
const processParams: ProcessInitParams = {
|
||||
stdoutParams: {
|
||||
rows: process.stdout.rows,
|
||||
columns: process.stdout.columns,
|
||||
colorDepth: process.stdout.getColorDepth?.() || 8
|
||||
},
|
||||
stderrParams: {
|
||||
rows: process.stderr.rows,
|
||||
columns: process.stderr.columns,
|
||||
colorDepth: process.stderr.getColorDepth?.() || 8
|
||||
},
|
||||
processName: this._processName
|
||||
};
|
||||
|
||||
const processParams: ProcessInitParams = { stdoutTTY, stderrTTY, processName: this._processName };
|
||||
this.send({
|
||||
method: '__init__', params: {
|
||||
processParams,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import { loadConfig, resolveConfigFile, restartWithExperimentalTsEsm } from '../
|
|||
import { webServerPluginsForConfig } from '../plugins/webServerPlugin';
|
||||
import type { TraceViewerRedirectOptions, TraceViewerServerOptions } from 'playwright-core/lib/server/trace/viewer/traceViewer';
|
||||
import type { TestRunnerPluginRegistration } from '../plugins';
|
||||
import { resizeTTY } from '../common/tty';
|
||||
|
||||
class TestServer {
|
||||
private _configFile: string | undefined;
|
||||
|
|
@ -120,10 +121,7 @@ class TestServerDispatcher implements TestServerInterface {
|
|||
}
|
||||
|
||||
async resizeTerminal(params: Parameters<TestServerInterface['resizeTerminal']>[0]): ReturnType<TestServerInterface['resizeTerminal']> {
|
||||
process.stdout.columns = params.cols;
|
||||
process.stdout.rows = params.rows;
|
||||
process.stderr.columns = params.cols;
|
||||
process.stderr.columns = params.rows;
|
||||
resizeTTY(params.cols, params.rows);
|
||||
}
|
||||
|
||||
async checkBrowsers(): Promise<{ hasBrowsers: boolean; }> {
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ test('merge into list report by default', async ({ runInlineTest, mergeReports }
|
|||
const reportFiles = await fs.promises.readdir(reportDir);
|
||||
reportFiles.sort();
|
||||
expect(reportFiles).toEqual(['report-1.zip', 'report-2.zip', 'report-3.zip']);
|
||||
const { exitCode, output } = await mergeReports(reportDir, { PW_TEST_DEBUG_REPORTERS: '1', PW_TEST_DEBUG_REPORTERS_PRINT_STEPS: '1', PWTEST_TTY_WIDTH: '80' }, { additionalArgs: ['--reporter', 'list'] });
|
||||
const { exitCode, output } = await mergeReports(reportDir, { PW_TEST_DEBUG_REPORTERS: '1', PW_TEST_DEBUG_REPORTERS_PRINT_STEPS: '1', PLAYWRIGHT_TTY: '80x25x8' }, { additionalArgs: ['--reporter', 'list'] });
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const text = stripAnsi(output);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from './playwright-test-fixtures';
|
||||
import { test, expect, stripAnsi } from './playwright-test-fixtures';
|
||||
|
||||
const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION;
|
||||
const POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'ok' : '✓ ';
|
||||
|
|
@ -70,7 +70,7 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
|||
});
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'list' }, { PW_TEST_DEBUG_REPORTERS: '1', PW_TEST_DEBUG_REPORTERS_PRINT_STEPS: '1', PWTEST_TTY_WIDTH: '80' });
|
||||
}, { reporter: 'list' }, { PW_TEST_DEBUG_REPORTERS: '1', PW_TEST_DEBUG_REPORTERS_PRINT_STEPS: '1', PLAYWRIGHT_TTY: '80' });
|
||||
const text = result.output;
|
||||
const lines = text.split('\n').filter(l => l.match(/^\d :/)).map(l => l.replace(/[.\d]+m?s/, 'Xms'));
|
||||
lines.pop(); // Remove last item that contains [v] and time in ms.
|
||||
|
|
@ -105,7 +105,7 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
|||
await test.step('inner 2.2', async () => {});
|
||||
});
|
||||
});`,
|
||||
}, { reporter: 'list' }, { PW_TEST_DEBUG_REPORTERS: '1', PWTEST_TTY_WIDTH: '80' });
|
||||
}, { reporter: 'list' }, { PW_TEST_DEBUG_REPORTERS: '1', PLAYWRIGHT_TTY: '80x25' });
|
||||
const text = result.output;
|
||||
const lines = text.split('\n').filter(l => l.match(/^\d :/)).map(l => l.replace(/[.\d]+m?s/, 'Xms'));
|
||||
lines.pop(); // Remove last item that contains [v] and time in ms.
|
||||
|
|
@ -135,7 +135,7 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
|||
console.log('a'.repeat(80) + 'b'.repeat(20));
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'list' }, { PWTEST_TTY_WIDTH: TTY_WIDTH + '' });
|
||||
}, { reporter: 'list' }, { PLAYWRIGHT_TTY: TTY_WIDTH + '' });
|
||||
|
||||
const renderedText = simpleAnsiRenderer(result.rawOutput, TTY_WIDTH);
|
||||
if (process.platform === 'win32')
|
||||
|
|
@ -154,7 +154,7 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
|||
expect(testInfo.retry).toBe(1);
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'list', retries: '1' }, { PW_TEST_DEBUG_REPORTERS: '1', PWTEST_TTY_WIDTH: '80' });
|
||||
}, { reporter: 'list', retries: '1' }, { PW_TEST_DEBUG_REPORTERS: '1', PLAYWRIGHT_TTY: '80' });
|
||||
const text = result.output;
|
||||
const lines = text.split('\n').filter(l => l.startsWith('0 :') || l.startsWith('1 :')).map(l => l.replace(/\d+(\.\d+)?m?s/, 'XXms'));
|
||||
|
||||
|
|
@ -185,10 +185,10 @@ for (const useIntermediateMergeReport of [false, true] as const) {
|
|||
test.skip('skipped very long name', async () => {
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'list', retries: 0 }, { PWTEST_TTY_WIDTH: '50' });
|
||||
}, { reporter: 'list', retries: 0 }, { PLAYWRIGHT_TTY: '50x20' });
|
||||
expect(result.exitCode).toBe(1);
|
||||
|
||||
const lines = result.output.split('\n').slice(3, 11);
|
||||
const lines = result.rawOutput.split('\n').map(line => line.split('\x1B[22m\x1B[1E')).flat().map(line => stripAnsi(line)).filter(line => line.trim()).slice(1, 9);
|
||||
expect(lines.every(line => line.length <= 50)).toBe(true);
|
||||
|
||||
expect(lines[0]).toBe(` 1 …a.test.ts:3:15 › failure in very long name`);
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ test('should support console colors', async ({ runInlineTest }) => {
|
|||
console.error({ b: false, n: 123, s: 'abc' });
|
||||
});
|
||||
`
|
||||
});
|
||||
}, {}, { PLAYWRIGHT_TTY: '80' });
|
||||
expect(result.output).toContain(`process.stdout.isTTY = true`);
|
||||
expect(result.output).toContain(`process.stderr.isTTY = true`);
|
||||
// The output should have colors.
|
||||
|
|
@ -102,17 +102,22 @@ test('should override hasColors and getColorDepth', async ({ runInlineTest }) =>
|
|||
'a.spec.js': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('console log', () => {
|
||||
console.log('process.stdout.hasColors(1) = ' + process.stdout.hasColors(1));
|
||||
console.log('process.stderr.hasColors(1) = ' + process.stderr.hasColors(1));
|
||||
console.log('process.stdout.getColorDepth() > 0 = ' + (process.stdout.getColorDepth() > 0));
|
||||
console.log('process.stderr.getColorDepth() > 0 = ' + (process.stderr.getColorDepth() > 0));
|
||||
expect(process.stdout.hasColors(1)).toBe(true);
|
||||
expect(process.stdout.isTTY).toBe(true);
|
||||
expect(process.stdout.columns).toBe(60);
|
||||
expect(process.stdout.rows).toBe(15);
|
||||
expect(process.stdout.getColorDepth()).toBe(16);
|
||||
|
||||
expect(process.stderr.hasColors(1)).toBe(true);
|
||||
expect(process.stderr.isTTY).toBe(true);
|
||||
expect(process.stderr.columns).toBe(60);
|
||||
expect(process.stderr.rows).toBe(15);
|
||||
expect(process.stderr.getColorDepth()).toBe(16);
|
||||
});
|
||||
`
|
||||
});
|
||||
expect(result.output).toContain(`process.stdout.hasColors(1) = true`);
|
||||
expect(result.output).toContain(`process.stderr.hasColors(1) = true`);
|
||||
expect(result.output).toContain(`process.stdout.getColorDepth() > 0 = true`);
|
||||
expect(result.output).toContain(`process.stderr.getColorDepth() > 0 = true`);
|
||||
}, {}, { PLAYWRIGHT_TTY: '60x15x16' });
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(1);
|
||||
});
|
||||
|
||||
test('should not throw type error when using assert', async ({ runInlineTest }) => {
|
||||
|
|
@ -152,6 +157,25 @@ test('should provide stubs for tty.WriteStream methods on process.stdout/stderr'
|
|||
checkMethods(process.stderr);
|
||||
});
|
||||
`
|
||||
});
|
||||
}, {}, { PLAYWRIGHT_TTY: '80' });
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should respect PLAYWRIGHT_TTY=0', async ({ runInlineTest }) => {
|
||||
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29422' });
|
||||
|
||||
const result = await runInlineTest({
|
||||
'a.spec.ts': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('passes', () => {
|
||||
expect(process.stdout.isTTY).toBe(false);
|
||||
expect(process.stdout.columns).toBe(0);
|
||||
expect(process.stdout.rows).toBe(0);
|
||||
expect(process.stderr.isTTY).toBe(false);
|
||||
expect(process.stderr.columns).toBe(0);
|
||||
expect(process.stderr.rows).toBe(0);
|
||||
});
|
||||
`
|
||||
}, {}, { PLAYWRIGHT_TTY: '0' });
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue