feat: support clarification message for expect (#11735)

The clarification message is displayed in the HTML report as the name of the step:

![image](https://user-images.githubusercontent.com/746130/151852652-48194140-5ea4-439d-afee-12583a8caf71.png)

It is also shown in terminal output:

![image](https://user-images.githubusercontent.com/746130/151852666-5c956ef1-6e94-4bc2-8e55-b58688dfc7e0.png)

Fixes #7816
This commit is contained in:
Andrey Lushnikov 2022-01-31 18:14:59 -07:00 committed by GitHub
parent 2b55adaafa
commit 2336692e8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 254 additions and 127 deletions

View File

@ -19,6 +19,12 @@ expect(value).not.toEqual(0);
await expect(locator).not.toContainText("some text");
```
You can also specify a custom error message as a second argument to the `expect` function, for example:
```js
expect(value, 'my custom error message').toBe(42);
```
<!-- TOC -->
- [`method: LocatorAssertions.toBeChecked`]
- [`method: LocatorAssertions.toBeDisabled`]

View File

@ -619,3 +619,4 @@ export class SigIntWatcher {
process.off('SIGINT', this._sigintHandler);
}
}

View File

@ -92,7 +92,15 @@ export const printReceivedStringContainExpectedResult = (
// #endregion
export const expect: Expect = expectLibrary as any;
export const expect: Expect = new Proxy(expectLibrary as any, {
apply: function(target: any, thisArg: any, argumentsList: [actual: unknown, message: string|undefined]) {
const message = argumentsList[1];
if (message !== undefined && typeof message !== 'string')
throw new Error('expect(actual, optionalErrorMessage): optional error message must be a string.');
return new Proxy(expectLibrary.call(thisArg, argumentsList[0]), new ExpectMetaInfoProxyHandler(message || ''));
}
});
expectLibrary.setState({ expand: false });
const customMatchers = {
toBeChecked,
@ -118,23 +126,56 @@ const customMatchers = {
toMatchSnapshot,
};
type ExpectMetaInfo = {
message: string;
};
let expectCallMetaInfo: undefined|ExpectMetaInfo = undefined;
class ExpectMetaInfoProxyHandler {
private _message: string;
constructor(message: string) {
this._message = message;
}
get(target: any, prop: any, receiver: any): any {
const value = Reflect.get(target, prop, receiver);
if (typeof value !== 'function')
return new Proxy(value, this);
return (...args: any[]) => {
try {
expectCallMetaInfo = {
message: this._message,
};
const result = value.call(target, ...args);
return result;
} finally {
expectCallMetaInfo = undefined;
}
};
}
}
function wrap(matcherName: string, matcher: any) {
const result = function(this: any, ...args: any[]) {
const testInfo = currentTestInfo();
if (!testInfo)
return matcher.call(this, ...args);
const INTERNAL_STACK_LENGTH = 3;
const INTERNAL_STACK_LENGTH = 4;
// at Object.__PWTRAP__[expect.toHaveText] (...)
// at __EXTERNAL_MATCHER_TRAP__ (...)
// at Object.throwingMatcher [as toHaveText] (...)
// at Proxy.<anonymous>
// at <test function> (...)
const stackLines = new Error().stack!.split('\n').slice(INTERNAL_STACK_LENGTH + 1);
const frame = stackLines[0] ? stackUtils.parseLine(stackLines[0]) : undefined;
const customMessage = expectCallMetaInfo?.message ?? '';
const step = testInfo._addStep({
location: frame && frame.file ? { file: path.resolve(process.cwd(), frame.file), line: frame.line || 0, column: frame.column || 0 } : undefined,
category: 'expect',
title: `expect${this.isNot ? '.not' : ''}.${matcherName}`,
title: customMessage || `expect${this.isNot ? '.not' : ''}.${matcherName}`,
canHaveChildren: true,
forceNoParent: false
});
@ -145,6 +186,25 @@ function wrap(matcherName: string, matcher: any) {
if (!success) {
const message = result.message();
error = { message, stack: message + '\n' + stackLines.join('\n') };
if (customMessage) {
const messageLines = message.split('\n');
// Jest adds something like the following error to all errors:
// expect(received).toBe(expected); // Object.is equality
const uselessMatcherLineIndex = messageLines.findIndex((line: string) => /expect.*\(.*received.*\)/.test(line));
if (uselessMatcherLineIndex !== -1) {
// if there's a newline after the matcher text, then remove it as well.
if (uselessMatcherLineIndex + 1 < messageLines.length && messageLines[uselessMatcherLineIndex + 1].trim() === '')
messageLines.splice(uselessMatcherLineIndex, 2);
else
messageLines.splice(uselessMatcherLineIndex, 1);
}
const newMessage = [
customMessage,
'',
...messageLines,
].join('\n');
result.message = () => newMessage;
}
}
step.complete(error);
return result;

View File

@ -419,9 +419,9 @@ function monotonicTime(): number {
return seconds * 1000 + (nanoseconds / 1000000 | 0);
}
const asciiRegex = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g');
const ansiRegex = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g');
export function stripAnsiEscapes(str: string): string {
return str.replace(asciiRegex, '');
return str.replace(ansiRegex, '');
}
// Leaves enough space for the "suffix" to also fit.
@ -432,8 +432,8 @@ export function fitToScreen(line: string, width: number, suffix?: string): strin
return line;
let m;
let ansiLen = 0;
asciiRegex.lastIndex = 0;
while ((m = asciiRegex.exec(line)) !== null) {
ansiRegex.lastIndex = 0;
while ((m = ansiRegex.exec(line)) !== null) {
const visibleLen = m.index - ansiLen;
if (visibleLen >= width)
break;

View File

@ -197,11 +197,10 @@ function serializeXML(entry: XMLEntry, tokens: string[], stripANSIControlSequenc
// See https://en.wikipedia.org/wiki/Valid_characters_in_XML
const discouragedXMLCharacters = /[\u0001-\u0008\u000b-\u000c\u000e-\u001f\u007f-\u0084\u0086-\u009f]/g;
const ansiControlSequence = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g');
function escape(text: string, stripANSIControlSequences: boolean, isCharacterData: boolean): string {
if (stripANSIControlSequences)
text = text.replace(ansiControlSequence, '');
text = stripAnsiEscapes(text);
const escapeRe = isCharacterData ? /[&<]/g : /[&"<>]/g;
text = text.replace(escapeRe, c => ({ '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' }[c]!));
if (isCharacterData)

View File

@ -28,7 +28,7 @@ type MakeMatchers<T, ReturnValue = T> = PlaywrightTest.Matchers<ReturnValue> &
ExtraMatchers<T, APIResponse, APIResponseMatchers>
export declare type Expect = {
<T = unknown>(actual: T): MakeMatchers<T>;
<T = unknown>(actual: T, message?: string): MakeMatchers<T>;
// Sourced from node_modules/expect/build/types.d.ts
assertions(arg0: number): void;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should fail', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -286,7 +286,7 @@ test('should work with test wrapper', async ({ runInlineTest }) => {
}, { workers: 1, reporter: 'line' });
expect(result.passed).toBe(4);
expect(result.exitCode).toBe(0);
expect(stripAscii(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
expect(stripAnsi(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
'%%a.spec',
'%%helper',
'%%b.spec',
@ -335,7 +335,7 @@ test('should work with test helper', async ({ runInlineTest }) => {
}, { workers: 1, reporter: 'line' });
expect(result.passed).toBe(4);
expect(result.exitCode).toBe(0);
expect(stripAscii(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
expect(stripAnsi(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
'%%a.spec',
'%%helper-a',
'%%b.spec',

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
function monotonicTime(): number {
const [seconds, nanoseconds] = process.hrtime();
@ -46,7 +46,7 @@ test('should work with not defined errors', async ({ runInlineTest }) => {
foo();
`
});
expect(stripAscii(result.output)).toContain('foo is not defined');
expect(stripAnsi(result.output)).toContain('foo is not defined');
expect(result.exitCode).toBe(1);
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should be able to call expect.extend in config', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -67,6 +67,57 @@ test('should not expand huge arrays', async ({ runInlineTest }) => {
expect(result.output.length).toBeLessThan(100000);
});
test('should fail when passed `null` instead of message', async ({ runInlineTest }) => {
const result = await runInlineTest({
'expect-test.spec.ts': `
const { test } = pwt;
test('custom expect message', () => {
test.expect(1+1, null).toEqual(3);
});
`
});
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(stripAnsi(result.output)).toContain(`optional error message must be a string.`);
});
test('should include custom error message', async ({ runInlineTest }) => {
const result = await runInlineTest({
'expect-test.spec.ts': `
const { test } = pwt;
test('custom expect message', () => {
test.expect(1+1, 'one plus one is two!').toEqual(3);
});
`
});
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(stripAnsi(result.output)).toContain([
` Error: one plus one is two!`,
``,
` Expected: 3`,
` Received: 2`,
].join('\n'));
});
test('should include custom error message with web-first assertions', async ({ runInlineTest }) => {
const result = await runInlineTest({
'expect-test.spec.ts': `
const { test } = pwt;
test('custom expect message', async ({page}) => {
await expect(page.locator('x-foo'), 'x-foo must be visible').toBeVisible({timeout: 1});
});
`
});
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.output).toContain([
` Error: x-foo must be visible`,
``,
` Call log:`,
].join('\n'));
});
test('should work with default expect prototype functions', async ({ runTSC }) => {
const result = await runTSC({
'a.spec.ts': `
@ -90,6 +141,16 @@ test('should work with default expect matchers', async ({ runTSC }) => {
expect(result.exitCode).toBe(0);
});
test('should work with expect message', async ({ runTSC }) => {
const result = await runTSC({
'a.spec.ts': `
const { test } = pwt;
test.expect(42, 'this is expect message').toBe(42);
`
});
expect(result.exitCode).toBe(0);
});
test('should work with default expect matchers and esModuleInterop=false', async ({ runTSC }) => {
const result = await runTSC({
'a.spec.ts': `

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, countTimes, stripAscii } from './playwright-test-fixtures';
import { test, expect, countTimes, stripAnsi } from './playwright-test-fixtures';
test('should handle fixture timeout', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -452,6 +452,6 @@ test('should not report fixture teardown error twice', async ({ runInlineTest })
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(result.output).toContain('Error: Oh my error');
expect(stripAscii(result.output)).toContain(`throw new Error('Oh my error')`);
expect(stripAnsi(result.output)).toContain(`throw new Error('Oh my error')`);
expect(countTimes(result.output, 'Oh my error')).toBe(2);
});

View File

@ -17,7 +17,7 @@
import colors from 'colors/safe';
import * as fs from 'fs';
import * as path from 'path';
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
const files = {
'helper.ts': `
@ -91,7 +91,7 @@ test('should write detailed failure result to an output folder', async ({ runInl
});
expect(result.exitCode).toBe(1);
const outputText = stripAscii(result.output);
const outputText = stripAnsi(result.output);
expect(outputText).toContain('Snapshot comparison failed:');
const expectedSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-expected.txt');
const actualSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-actual.txt');
@ -114,7 +114,7 @@ test("doesn\'t create comparison artifacts in an output folder for passed negate
});
expect(result.exitCode).toBe(0);
const outputText = stripAscii(result.output);
const outputText = stripAnsi(result.output);
const expectedSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-expected.txt');
const actualSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-actual.txt');
expect(outputText).not.toContain(`Expected: ${expectedSnapshotArtifactPath}`);
@ -406,7 +406,7 @@ test('should compare different PNG images', async ({ runInlineTest }, testInfo)
`
});
const outputText = stripAscii(result.output);
const outputText = stripAnsi(result.output);
expect(result.exitCode).toBe(1);
expect(outputText).toContain('Snapshot comparison failed:');
const expectedSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-expected.png');
@ -636,7 +636,7 @@ test('should attach expected/actual/diff with snapshot path', async ({ runInline
`
});
const outputText = stripAscii(result.output);
const outputText = stripAnsi(result.output);
const attachments = outputText.split('\n').filter(l => l.startsWith('## ')).map(l => l.substring(3)).map(l => JSON.parse(l))[0];
for (const attachment of attachments)
attachment.path = attachment.path.replace(/\\/g, '/').replace(/.*test-results\//, '');
@ -675,7 +675,7 @@ test('should attach expected/actual/diff', async ({ runInlineTest }, testInfo) =
`
});
const outputText = stripAscii(result.output);
const outputText = stripAnsi(result.output);
const attachments = outputText.split('\n').filter(l => l.startsWith('## ')).map(l => l.substring(3)).map(l => JSON.parse(l))[0];
for (const attachment of attachments)
attachment.path = attachment.path.replace(/\\/g, '/').replace(/.*test-results\//, '');
@ -714,7 +714,7 @@ test('should attach expected/actual and no diff', async ({ runInlineTest }, test
`
});
const outputText = stripAscii(result.output);
const outputText = stripAnsi(result.output);
expect(outputText).toContain('Sizes differ; expected image 2px X 2px, but got 1px X 1px.');
const attachments = outputText.split('\n').filter(l => l.startsWith('## ')).map(l => l.substring(3)).map(l => JSON.parse(l))[0];
for (const attachment of attachments)

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('hooks should work with fixtures', async ({ runInlineTest }) => {
const { results } = await runInlineTest({
@ -546,8 +546,8 @@ test('uncaught error in beforeEach should not be masked by another error', async
});
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toContain('Expected: 2');
expect(stripAscii(result.output)).toContain('Received: 1');
expect(stripAnsi(result.output)).toContain('Expected: 2');
expect(stripAnsi(result.output)).toContain('Received: 1');
});
test('should report error from fixture teardown when beforeAll times out', async ({ runInlineTest }) => {
@ -569,8 +569,8 @@ test('should report error from fixture teardown when beforeAll times out', async
}, { timeout: 1000 });
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toContain('Timeout of 1000ms exceeded in beforeAll hook.');
expect(stripAscii(result.output)).toContain('Error: Oh my!');
expect(stripAnsi(result.output)).toContain('Timeout of 1000ms exceeded in beforeAll hook.');
expect(stripAnsi(result.output)).toContain('Error: Oh my!');
});
test('should not hang and report results when worker process suddenly exits during afterAll', async ({ runInlineTest }) => {
@ -584,6 +584,6 @@ test('should not hang and report results when worker process suddenly exits duri
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(1);
expect(result.output).toContain('Worker process exited unexpectedly');
expect(stripAscii(result.output)).toContain('[1/1] a.spec.js:6:7 passed');
expect(stripAscii(result.output)).toContain('[1/1] a.spec.js:7:12 afterAll');
expect(stripAnsi(result.output)).toContain('[1/1] a.spec.js:6:7 passed');
expect(stripAnsi(result.output)).toContain('[1/1] a.spec.js:7:12 afterAll');
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('max-failures should work', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -143,5 +143,5 @@ test('max-failures should properly shutdown', async ({ runInlineTest }) => {
}, { workers: 1 });
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toContain('expect(false).toBeTruthy()');
expect(stripAnsi(result.output)).toContain('expect(false).toBeTruthy()');
});

View File

@ -243,7 +243,7 @@ const TSCONFIG = {
export { expect } from './stable-test-runner';
const asciiRegex = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g');
export function stripAscii(str: string): string {
export function stripAnsi(str: string): string {
return str.replace(asciiRegex, '');
}

View File

@ -15,7 +15,7 @@
*/
import path from 'path';
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should support toHaveCount', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -80,7 +80,7 @@ test('should support toHaveCount', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(result.passed).toBe(5);
expect(result.failed).toBe(2);
expect(result.exitCode).toBe(1);
@ -109,7 +109,7 @@ test('should support toHaveJSProperty', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('- "c"');
expect(result.passed).toBe(1);
expect(result.failed).toBe(1);
@ -165,7 +165,7 @@ test('should support toHaveJSProperty with builtin types', async ({ runInlineTes
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(result.passed).toBe(3);
expect(result.failed).toBe(3);
expect(result.exitCode).toBe(1);
@ -196,7 +196,7 @@ test('should support toHaveClass', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(locator).toHaveClass');
expect(output).toContain('Expected string: \"foo bar baz\"');
expect(result.passed).toBe(1);
@ -222,7 +222,7 @@ test('should support toHaveClass w/ array', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(received).toHaveClass(expected)');
expect(output).toContain('- /[a-z]az/,');
expect(result.passed).toBe(1);
@ -246,7 +246,7 @@ test('should support toHaveTitle', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(page).toHaveTitle');
expect(output).toContain('Expected string: \"Hello\"');
expect(result.passed).toBe(1);
@ -270,7 +270,7 @@ test('should support toHaveURL', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(page).toHaveURL');
expect(output).toContain('Expected string: \"wrong\"');
expect(result.passed).toBe(1);
@ -304,7 +304,7 @@ test('should support toHaveURL with baseURL from webServer', async ({ runInlineT
};
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(page).toHaveURL');
expect(output).toContain(`Expected string: \"http://localhost:${port}/kek\"`);
expect(result.passed).toBe(1);
@ -327,7 +327,7 @@ test('should respect expect.timeout', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(received).toHaveURL(expected)');
expect(output).toContain('expect.toHaveURL with timeout 1000ms');
expect(result.failed).toBe(1);
@ -345,7 +345,7 @@ test('should log scale the time', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
const tokens = output.split('unexpected value');
// Log scale: 0, 100, 250, 500, 1000, 1000, should be less than 8.
expect(tokens.length).toBeGreaterThan(1);

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should support toHaveText w/ regex', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -37,7 +37,7 @@ test('should support toHaveText w/ regex', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).toHaveText(expected)');
expect(output).toContain('Expected pattern: /Text 2/');
expect(output).toContain('Received string: "Text content"');
@ -68,7 +68,7 @@ test('should support toContainText w/ regex', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).toContainText(expected)');
expect(output).toContain('Expected pattern: /ex2/');
expect(output).toContain('Received string: "Text content"');
@ -107,7 +107,7 @@ test('should support toHaveText w/ text', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).toHaveText(expected)');
expect(output).toContain('Expected string: "Text"');
expect(output).toContain('Received string: "Text content"');
@ -135,7 +135,7 @@ test('should support toHaveText w/ not', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).not.toHaveText(expected)');
expect(output).toContain('Expected string: not "Text content"');
expect(output).toContain('Received string: "Text content');
@ -208,7 +208,7 @@ test('should support toHaveText w/ array', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).toHaveText(expected) // deep equality');
expect(output).toContain('await expect(locator).toHaveText');
expect(output).toContain('- "Extra"');
@ -237,7 +237,7 @@ test('should support toContainText w/ array', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).toContainText(expected)');
expect(output).toContain('await expect(locator).toContainText');
expect(output).toContain('- "Text 2"');
@ -403,8 +403,8 @@ test('should print expected/received before timeout', async ({ runInlineTest })
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
expect(result.output).toContain('Timeout of 2000ms exceeded.');
expect(stripAscii(result.output)).toContain('Expected string: "Text 2"');
expect(stripAscii(result.output)).toContain('Received string: "Text content"');
expect(stripAnsi(result.output)).toContain('Expected string: "Text 2"');
expect(stripAnsi(result.output)).toContain('Received string: "Text content"');
});
test('should print nice error for toHaveText', async ({ runInlineTest }) => {
@ -420,7 +420,7 @@ test('should print nice error for toHaveText', async ({ runInlineTest }) => {
}, { workers: 1, timeout: 2000 });
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Pending operations:');
expect(output).toContain('Error: expect(received).toHaveText(expected)');
expect(output).toContain('Expected string: "Text"');
@ -447,8 +447,8 @@ test('should print expected/received on Ctrl+C', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(130);
expect(result.passed).toBe(0);
expect(result.skipped).toBe(1);
expect(stripAscii(result.output)).toContain('Expected string: "Text 2"');
expect(stripAscii(result.output)).toContain('Received string: "Text content"');
expect(stripAnsi(result.output)).toContain('Expected string: "Text 2"');
expect(stripAnsi(result.output)).toContain('Received string: "Text content"');
});
test('should support not.toHaveText when selector does not match', async ({ runInlineTest }) => {
@ -465,7 +465,7 @@ test('should support not.toHaveText when selector does not match', async ({ runI
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Expected string: not "hello"');
expect(output).toContain('Received string: ""');
expect(output).toContain('waiting for selector "span"');

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should support toBeChecked', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -46,7 +46,7 @@ test('should support toBeChecked', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('Error: expect(received).toBeChecked()');
expect(output).toContain('expect(locator).toBeChecked');
expect(result.passed).toBe(3);
@ -90,7 +90,7 @@ test('should support toBeChecked w/ not', async ({ runInlineTest }) => {
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(result.passed).toBe(2);
expect(result.failed).toBe(3);
expect(result.exitCode).toBe(1);
@ -172,7 +172,7 @@ test('should support toBeEditable, toBeEnabled, toBeDisabled, toBeEmpty', async
expect(result.passed).toBe(8);
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(output).toContain('expect(locator).toBeEnabled({ timeout: 500 }');
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
import fs from 'fs';
import path from 'path';
import { spawnSync } from 'child_process';
@ -306,7 +306,7 @@ test('should report error and pending operations on timeout', async ({ runInline
expect(result.output).toContain('- page.click at a.test.ts:9:16');
expect(result.output).toContain('- page.textContent at a.test.ts:10:16');
expect(result.output).toContain('waiting for selector');
expect(stripAscii(result.output)).toContain(`10 | page.textContent('text=More missing'),`);
expect(stripAnsi(result.output)).toContain(`10 | page.textContent('text=More missing'),`);
});
test('should report error on timeout with shared page', async ({ runInlineTest }, testInfo) => {
@ -330,7 +330,7 @@ test('should report error on timeout with shared page', async ({ runInlineTest }
expect(result.passed).toBe(1);
expect(result.failed).toBe(1);
expect(result.output).toContain('waiting for selector "text=Missing"');
expect(stripAscii(result.output)).toContain(`14 | await page.click('text=Missing');`);
expect(stripAnsi(result.output)).toContain(`14 | await page.click('text=Missing');`);
});
test('should report error and pending operations from beforeAll timeout', async ({ runInlineTest }, testInfo) => {
@ -357,7 +357,7 @@ test('should report error and pending operations from beforeAll timeout', async
expect(result.output).toContain('- page.click at a.test.ts:10:16');
expect(result.output).toContain('- page.textContent at a.test.ts:11:16');
expect(result.output).toContain('waiting for selector');
expect(stripAscii(result.output)).toContain(`11 | page.textContent('text=More missing'),`);
expect(stripAnsi(result.output)).toContain(`11 | page.textContent('text=More missing'),`);
});
test('should not report waitForEventInfo as pending', async ({ runInlineTest }, testInfo) => {
@ -417,7 +417,7 @@ test('should report click error on sigint', async ({ runInlineTest }) => {
expect(result.passed).toBe(0);
expect(result.failed).toBe(0);
expect(result.skipped).toBe(1);
expect(stripAscii(result.output)).toContain(`8 | const promise = page.click('text=Missing');`);
expect(stripAnsi(result.output)).toContain(`8 | const promise = page.click('text=Missing');`);
});
test('should work with video: retain-on-failure', async ({ runInlineTest }, testInfo) => {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
import { ZipFileSystem } from '../../packages/playwright-core/lib/utils/vfs';
import fs from 'fs';
@ -108,8 +108,8 @@ test('should not throw with trace and timeouts', async ({ runInlineTest }, testI
}, { workers: 2 });
expect(result.exitCode).toBe(1);
expect(stripAscii(result.output)).not.toContain('tracing.stopChunk:');
expect(stripAscii(result.output)).not.toContain('tracing.stop:');
expect(stripAnsi(result.output)).not.toContain('tracing.stopChunk:');
expect(stripAnsi(result.output)).not.toContain('tracing.stop:');
});
test('should save sources when requested', async ({ runInlineTest }, testInfo) => {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('render text attachment', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -30,7 +30,7 @@ test('render text attachment', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'line' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain(' attachment #1: attachment (text/plain) ---------------------------------------------------------');
expect(text).toContain(' Hello world');
expect(text).toContain(' ------------------------------------------------------------------------------------------------');
@ -51,7 +51,7 @@ test('render screenshot attachment', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'line' });
const text = stripAscii(result.output).replace(/\\/g, '/');
const text = stripAnsi(result.output).replace(/\\/g, '/');
expect(text).toContain(' attachment #1: screenshot (image/png) ----------------------------------------------------------');
expect(text).toContain(' test-results/a-one/some/path.png');
expect(text).toContain(' ------------------------------------------------------------------------------------------------');
@ -72,7 +72,7 @@ test('render trace attachment', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'line' });
const text = stripAscii(result.output).replace(/\\/g, '/');
const text = stripAnsi(result.output).replace(/\\/g, '/');
expect(text).toContain(' attachment #1: trace (application/zip) ---------------------------------------------------------');
expect(text).toContain(' test-results/a-one/trace.zip');
expect(text).toContain('npx playwright show-trace test-results/a-one/trace.zip');
@ -95,7 +95,7 @@ test(`testInfo.attach errors`, async ({ runInlineTest }) => {
});
`,
}, { reporter: 'line', workers: 1 });
const text = stripAscii(result.output).replace(/\\/g, '/');
const text = stripAnsi(result.output).replace(/\\/g, '/');
expect(text).toMatch(/Error: ENOENT: no such file or directory, copyfile '.*foo.txt.*'/);
expect(text).toContain(`Exactly one of "path" and "body" must be specified`);
expect(result.passed).toBe(0);
@ -112,7 +112,7 @@ test(`testInfo.attach errors with empty path`, async ({ runInlineTest }) => {
});
`,
}, { reporter: 'line', workers: 1 });
expect(stripAscii(result.output)).toMatch(/Error: ENOENT: no such file or directory, copyfile ''/);
expect(stripAnsi(result.output)).toMatch(/Error: ENOENT: no such file or directory, copyfile ''/);
expect(result.exitCode).toBe(1);
});
@ -129,7 +129,7 @@ test(`testInfo.attach error in fixture`, async ({ runInlineTest }) => {
});
`,
}, { reporter: 'line', workers: 1 });
const text = stripAscii(result.output).replace(/\\/g, '/');
const text = stripAnsi(result.output).replace(/\\/g, '/');
expect(text).toMatch(/Error: ENOENT: no such file or directory, copyfile '.*foo.txt.*'/);
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
@ -154,7 +154,7 @@ test(`testInfo.attach success in fixture`, async ({ runInlineTest }) => {
});
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toContain('attachment #1: name (text/plain)');
expect(stripAnsi(result.output)).toContain('attachment #1: name (text/plain)');
});
test(`testInfo.attach allow empty string body`, async ({ runInlineTest }) => {
@ -169,7 +169,7 @@ test(`testInfo.attach allow empty string body`, async ({ runInlineTest }) => {
});
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toMatch(/^.*attachment #1: name \(text\/plain\).*\n.*\n.*------/gm);
expect(stripAnsi(result.output)).toMatch(/^.*attachment #1: name \(text\/plain\).*\n.*\n.*------/gm);
});
test(`testInfo.attach allow empty buffer body`, async ({ runInlineTest }) => {
@ -184,5 +184,5 @@ test(`testInfo.attach allow empty buffer body`, async ({ runInlineTest }) => {
});
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toMatch(/^.*attachment #1: name \(text\/plain\).*\n.*\n.*------/gm);
expect(stripAnsi(result.output)).toMatch(/^.*attachment #1: name \(text\/plain\).*\n.*\n.*------/gm);
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
import * as path from 'path';
test('handle long test names', async ({ runInlineTest }) => {
@ -27,7 +27,7 @@ test('handle long test names', async ({ runInlineTest }) => {
});
`,
});
expect(stripAscii(result.output)).toContain('expect(1).toBe');
expect(stripAnsi(result.output)).toContain('expect(1).toBe');
expect(result.exitCode).toBe(1);
});
@ -138,15 +138,15 @@ test('should print slow tests', async ({ runInlineTest }) => {
});
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(8);
expect(stripAscii(result.output)).toContain(`Slow test file: [foo] dir${path.sep}a.test.js (`);
expect(stripAscii(result.output)).toContain(`Slow test file: [bar] dir${path.sep}a.test.js (`);
expect(stripAscii(result.output)).toContain(`Slow test file: [baz] dir${path.sep}a.test.js (`);
expect(stripAscii(result.output)).toContain(`Slow test file: [qux] dir${path.sep}a.test.js (`);
expect(stripAscii(result.output)).toContain(`Consider splitting slow test files to speed up parallel execution`);
expect(stripAscii(result.output)).not.toContain(`Slow test file: [foo] dir${path.sep}b.test.js (`);
expect(stripAscii(result.output)).not.toContain(`Slow test file: [bar] dir${path.sep}b.test.js (`);
expect(stripAscii(result.output)).not.toContain(`Slow test file: [baz] dir${path.sep}b.test.js (`);
expect(stripAscii(result.output)).not.toContain(`Slow test file: [qux] dir${path.sep}b.test.js (`);
expect(stripAnsi(result.output)).toContain(`Slow test file: [foo] dir${path.sep}a.test.js (`);
expect(stripAnsi(result.output)).toContain(`Slow test file: [bar] dir${path.sep}a.test.js (`);
expect(stripAnsi(result.output)).toContain(`Slow test file: [baz] dir${path.sep}a.test.js (`);
expect(stripAnsi(result.output)).toContain(`Slow test file: [qux] dir${path.sep}a.test.js (`);
expect(stripAnsi(result.output)).toContain(`Consider splitting slow test files to speed up parallel execution`);
expect(stripAnsi(result.output)).not.toContain(`Slow test file: [foo] dir${path.sep}b.test.js (`);
expect(stripAnsi(result.output)).not.toContain(`Slow test file: [bar] dir${path.sep}b.test.js (`);
expect(stripAnsi(result.output)).not.toContain(`Slow test file: [baz] dir${path.sep}b.test.js (`);
expect(stripAnsi(result.output)).not.toContain(`Slow test file: [qux] dir${path.sep}b.test.js (`);
});
test('should not print slow tests', async ({ runInlineTest }) => {
@ -172,7 +172,7 @@ test('should not print slow tests', async ({ runInlineTest }) => {
});
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(4);
expect(stripAscii(result.output)).not.toContain('Slow test');
expect(stripAnsi(result.output)).not.toContain('Slow test');
});
test('should print flaky failures', async ({ runInlineTest }) => {
@ -186,7 +186,7 @@ test('should print flaky failures', async ({ runInlineTest }) => {
}, { retries: '1', reporter: 'list' });
expect(result.exitCode).toBe(0);
expect(result.flaky).toBe(1);
expect(stripAscii(result.output)).toContain('expect(testInfo.retry).toBe(1)');
expect(stripAnsi(result.output)).toContain('expect(testInfo.retry).toBe(1)');
});
test('should print flaky timeouts', async ({ runInlineTest }) => {
@ -201,7 +201,7 @@ test('should print flaky timeouts', async ({ runInlineTest }) => {
}, { retries: '1', reporter: 'list', timeout: '1000' });
expect(result.exitCode).toBe(0);
expect(result.flaky).toBe(1);
expect(stripAscii(result.output)).toContain('Timeout of 1000ms exceeded.');
expect(stripAnsi(result.output)).toContain('Timeout of 1000ms exceeded.');
});
test('should print stack-less errors', async ({ runInlineTest }) => {

View File

@ -15,7 +15,7 @@
*/
import colors from 'colors/safe';
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('render expected', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -52,7 +52,7 @@ test('render unexpected after retry', async ({ runInlineTest }) => {
});
`,
}, { retries: 3 });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain('×××F');
expect(result.output).toContain(colors.red('F'));
expect(result.exitCode).toBe(1);
@ -67,7 +67,7 @@ test('render flaky', async ({ runInlineTest }) => {
});
`,
}, { retries: 3 });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain('×××±');
expect(result.output).toContain(colors.yellow('±'));
expect(text).toContain('1 flaky');

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
import path from 'path';
function relativeFilePath(file: string): string {
@ -32,7 +32,7 @@ test('print GitHub annotations for success', async ({ runInlineTest }) => {
});
`
}, { reporter: 'github' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).not.toContain('::error');
expect(text).toContain('::notice title=🎭 Playwright Run Summary:: 1 passed');
expect(result.exitCode).toBe(0);
@ -47,7 +47,7 @@ test('print GitHub annotations for failed tests', async ({ runInlineTest }, test
});
`
}, { retries: 3, reporter: 'github' }, { GITHUB_WORKSPACE: process.cwd() });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
const testPath = relativeFilePath(testInfo.outputPath('a.test.js'));
expect(text).toContain(`::error file=${testPath},title=a.test.js:6:7 example,line=7,col=23:: 1) a.test.js:6:7 example =======================================================================%0A%0A Retry #1`);
expect(text).toContain(`::error file=${testPath},title=a.test.js:6:7 example,line=7,col=23:: 1) a.test.js:6:7 example =======================================================================%0A%0A Retry #2`);
@ -69,7 +69,7 @@ test('print GitHub annotations for slow tests', async ({ runInlineTest }) => {
});
`
}, { retries: 3, reporter: 'github' }, { GITHUB_WORKSPACE: '' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain('::warning title=Slow Test,file=a.test.js::a.test.js took');
expect(text).toContain('::notice title=🎭 Playwright Run Summary:: 1 passed');
expect(result.exitCode).toBe(0);
@ -88,7 +88,7 @@ test('print GitHub annotations for global error', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'github' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain('::error ::%0AError: Oh my!%0A%0A');
expect(result.exitCode).toBe(1);
});

View File

@ -16,7 +16,7 @@
import * as path from 'path';
import * as fs from 'fs';
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should support spec.ok', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -215,6 +215,6 @@ test('should add dot in addition to file json', async ({ runInlineTest }, testIn
`,
}, { reporter: '' });
expect(result.exitCode).toBe(0);
expect(stripAscii(result.output)).toContain('·');
expect(stripAnsi(result.output)).toContain('·');
expect(fs.existsSync(testInfo.outputPath('a.json'))).toBeTruthy();
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('render unexpected after retry', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -25,7 +25,7 @@ test('render unexpected after retry', async ({ runInlineTest }) => {
});
`,
}, { retries: 3, reporter: 'line' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain('[1/1] a.test.js:6:7 one');
expect(text).toContain('[2/1] (retries) a.test.js:6:7 one (retry #1)');
expect(text).toContain('[3/1] (retries) a.test.js:6:7 one (retry #2)');
@ -48,7 +48,7 @@ test('render flaky', async ({ runInlineTest }) => {
});
`,
}, { retries: 3, reporter: 'line' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
expect(text).toContain('1 flaky');
expect(result.exitCode).toBe(0);
});
@ -64,5 +64,5 @@ test('should print flaky failures', async ({ runInlineTest }) => {
}, { retries: '1', reporter: 'line' });
expect(result.exitCode).toBe(0);
expect(result.flaky).toBe(1);
expect(stripAscii(result.output)).toContain('expect(testInfo.retry).toBe(1)');
expect(stripAnsi(result.output)).toContain('expect(testInfo.retry).toBe(1)');
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('render each test with project name', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -36,7 +36,7 @@ test('render each test with project name', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'list' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
const positiveStatusMarkPrefix = process.platform === 'win32' ? 'ok' : '✓ ';
const negativateStatusMarkPrefix = process.platform === 'win32' ? 'x ' : '✘ ';
expect(text).toContain(`${negativateStatusMarkPrefix} [foo] a.test.ts:6:7 fails`);
@ -64,7 +64,7 @@ test('render steps', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'list' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
const lines = text.split('\n').filter(l => l.startsWith('0 :'));
lines.pop(); // Remove last item that contains [v] and time in ms.
expect(lines).toEqual([
@ -92,7 +92,7 @@ test('render retries', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'list', retries: '1' });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
const lines = text.split('\n').filter(l => l.startsWith('0 :') || l.startsWith('1 :')).map(l => l.replace(/[\dm]+s/, 'XXms'));
const positiveStatusMarkPrefix = process.platform === 'win32' ? 'ok' : '✓ ';
const negativateStatusMarkPrefix = process.platform === 'win32' ? 'x ' : '✘ ';
@ -122,7 +122,7 @@ test('should truncate long test names', async ({ runInlineTest }) => {
});
`,
}, { reporter: 'list', retries: 0 }, { PWTEST_TTY_WIDTH: 50, PWTEST_SKIP_TEST_OUTPUT: undefined });
const text = stripAscii(result.output);
const text = stripAnsi(result.output);
const positiveStatusMarkPrefix = process.platform === 'win32' ? 'ok' : '✓ ';
const negativateStatusMarkPrefix = process.platform === 'win32' ? 'x ' : '✘ ';
expect(text).toContain(`${negativateStatusMarkPrefix} [foo] a.test.ts:6:7 fails very`);

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should retry failures', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -72,7 +72,7 @@ test('should retry timeout', async ({ runInlineTest }) => {
expect(exitCode).toBe(1);
expect(passed).toBe(0);
expect(failed).toBe(1);
expect(stripAscii(output).split('\n')[2]).toBe('××T');
expect(stripAnsi(output).split('\n')[2]).toBe('××T');
});
test('should fail on unexpected pass with retries', async ({ runInlineTest }) => {
@ -103,7 +103,7 @@ test('should retry unexpected pass', async ({ runInlineTest }) => {
expect(exitCode).toBe(1);
expect(passed).toBe(0);
expect(failed).toBe(1);
expect(stripAscii(output).split('\n')[2]).toBe('××F');
expect(stripAnsi(output).split('\n')[2]).toBe('××F');
});
test('should not retry expected failure', async ({ runInlineTest }) => {
@ -123,7 +123,7 @@ test('should not retry expected failure', async ({ runInlineTest }) => {
expect(exitCode).toBe(0);
expect(passed).toBe(2);
expect(failed).toBe(0);
expect(stripAscii(output).split('\n')[2]).toBe('··');
expect(stripAnsi(output).split('\n')[2]).toBe('··');
});
test('should retry unhandled rejection', async ({ runInlineTest }) => {
@ -141,7 +141,7 @@ test('should retry unhandled rejection', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
expect(stripAscii(result.output).split('\n')[2]).toBe('××F');
expect(stripAnsi(result.output).split('\n')[2]).toBe('××F');
expect(result.output).toContain('Unhandled rejection');
});
@ -162,7 +162,7 @@ test('should retry beforeAll failure', async ({ runInlineTest }) => {
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
expect(result.skipped).toBe(1);
expect(stripAscii(result.output).split('\n')[2]).toBe('×°×°F°');
expect(stripAnsi(result.output).split('\n')[2]).toBe('×°×°F°');
expect(result.output).toContain('BeforeAll is bugged!');
});
@ -184,6 +184,6 @@ test('should retry worker fixture setup failure', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
expect(stripAscii(result.output).split('\n')[2]).toBe('××F');
expect(stripAnsi(result.output).split('\n')[2]).toBe('××F');
expect(result.output).toContain('worker setup is bugged!');
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import path from 'path';
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('it should not allow multiple tests with the same name per suite', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -194,7 +194,7 @@ test('should not stall when workers are available', async ({ runInlineTest }) =>
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(2);
expect(result.failed).toBe(1);
expect(stripAscii(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
expect(stripAnsi(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
'%%fails-1-started',
'%%passes-2-started',
'%%fails-1-done',

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('should work directly', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -84,7 +84,7 @@ test('should throw outside test', async ({ runInlineTest }) => {
test('test 1', async ({title}) => {});
`,
});
const output = stripAscii(result.output);
const output = stripAnsi(result.output);
expect(result.exitCode).toBe(1);
expect(output).toContain('test.info() can only be called while test is running');
});

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, stripAscii } from './playwright-test-fixtures';
import { test, expect, stripAnsi } from './playwright-test-fixtures';
test('test modifiers should work', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -331,5 +331,5 @@ test('modifier timeout should be reported', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(result.output).toContain('Error: Timeout of 2000ms exceeded while running skip modifier');
expect(stripAscii(result.output)).toContain('6 | test.skip(async () => new Promise(() => {}));');
expect(stripAnsi(result.output)).toContain('6 | test.skip(async () => new Promise(() => {}));');
});