From 2336692e8aadd84dea44298f5c7a47a90989624f Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Mon, 31 Jan 2022 18:14:59 -0700 Subject: [PATCH] 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 --- docs/src/test-assertions-js.md | 6 ++ packages/playwright-core/src/utils/utils.ts | 1 + packages/playwright-test/src/expect.ts | 66 ++++++++++++++++++- .../playwright-test/src/reporters/base.ts | 8 +-- .../playwright-test/src/reporters/junit.ts | 3 +- .../playwright-test/types/testExpect.d.ts | 2 +- tests/playwright-test/basic.spec.ts | 6 +- tests/playwright-test/exit-code.spec.ts | 4 +- tests/playwright-test/expect.spec.ts | 63 +++++++++++++++++- tests/playwright-test/fixture-errors.spec.ts | 4 +- tests/playwright-test/golden.spec.ts | 14 ++-- tests/playwright-test/hooks.spec.ts | 14 ++-- tests/playwright-test/max-failures.spec.ts | 4 +- .../playwright-test-fixtures.ts | 2 +- .../playwright.expect.misc.spec.ts | 22 +++---- .../playwright.expect.text.spec.ts | 26 ++++---- .../playwright.expect.true.spec.ts | 8 +-- tests/playwright-test/playwright.spec.ts | 10 +-- .../playwright-test/playwright.trace.spec.ts | 6 +- .../reporter-attachment.spec.ts | 20 +++--- tests/playwright-test/reporter-base.spec.ts | 28 ++++---- tests/playwright-test/reporter-dot.spec.ts | 6 +- tests/playwright-test/reporter-github.spec.ts | 10 +-- tests/playwright-test/reporter-json.spec.ts | 4 +- tests/playwright-test/reporter-line.spec.ts | 8 +-- tests/playwright-test/reporter-list.spec.ts | 10 +-- tests/playwright-test/retry.spec.ts | 14 ++-- tests/playwright-test/runner.spec.ts | 4 +- tests/playwright-test/test-info.spec.ts | 4 +- tests/playwright-test/test-modifiers.spec.ts | 4 +- 30 files changed, 254 insertions(+), 127 deletions(-) diff --git a/docs/src/test-assertions-js.md b/docs/src/test-assertions-js.md index 0bb53da7eb..cd541bc31e 100644 --- a/docs/src/test-assertions-js.md +++ b/docs/src/test-assertions-js.md @@ -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); +``` + - [`method: LocatorAssertions.toBeChecked`] - [`method: LocatorAssertions.toBeDisabled`] diff --git a/packages/playwright-core/src/utils/utils.ts b/packages/playwright-core/src/utils/utils.ts index ab06bf399d..683f39c156 100644 --- a/packages/playwright-core/src/utils/utils.ts +++ b/packages/playwright-core/src/utils/utils.ts @@ -619,3 +619,4 @@ export class SigIntWatcher { process.off('SIGINT', this._sigintHandler); } } + diff --git a/packages/playwright-test/src/expect.ts b/packages/playwright-test/src/expect.ts index 6a5638ad16..4524848567 100644 --- a/packages/playwright-test/src/expect.ts +++ b/packages/playwright-test/src/expect.ts @@ -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. // at (...) 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; diff --git a/packages/playwright-test/src/reporters/base.ts b/packages/playwright-test/src/reporters/base.ts index 8d4a52d38c..4371c5ca14 100644 --- a/packages/playwright-test/src/reporters/base.ts +++ b/packages/playwright-test/src/reporters/base.ts @@ -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; diff --git a/packages/playwright-test/src/reporters/junit.ts b/packages/playwright-test/src/reporters/junit.ts index a4fa9bc5e2..c53081bae0 100644 --- a/packages/playwright-test/src/reporters/junit.ts +++ b/packages/playwright-test/src/reporters/junit.ts @@ -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 => ({ '&': '&', '"': '"', '<': '<', '>': '>' }[c]!)); if (isCharacterData) diff --git a/packages/playwright-test/types/testExpect.d.ts b/packages/playwright-test/types/testExpect.d.ts index 03ddc17685..76b0417b9f 100644 --- a/packages/playwright-test/types/testExpect.d.ts +++ b/packages/playwright-test/types/testExpect.d.ts @@ -28,7 +28,7 @@ type MakeMatchers = PlaywrightTest.Matchers & ExtraMatchers export declare type Expect = { - (actual: T): MakeMatchers; + (actual: T, message?: string): MakeMatchers; // Sourced from node_modules/expect/build/types.d.ts assertions(arg0: number): void; diff --git a/tests/playwright-test/basic.spec.ts b/tests/playwright-test/basic.spec.ts index 4a292db233..074a409896 100644 --- a/tests/playwright-test/basic.spec.ts +++ b/tests/playwright-test/basic.spec.ts @@ -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', diff --git a/tests/playwright-test/exit-code.spec.ts b/tests/playwright-test/exit-code.spec.ts index 40c366f853..7c7577e26e 100644 --- a/tests/playwright-test/exit-code.spec.ts +++ b/tests/playwright-test/exit-code.spec.ts @@ -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); }); diff --git a/tests/playwright-test/expect.spec.ts b/tests/playwright-test/expect.spec.ts index 08df44249e..f91c2c3fc6 100644 --- a/tests/playwright-test/expect.spec.ts +++ b/tests/playwright-test/expect.spec.ts @@ -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': ` diff --git a/tests/playwright-test/fixture-errors.spec.ts b/tests/playwright-test/fixture-errors.spec.ts index 22800c0999..4b108d4ce1 100644 --- a/tests/playwright-test/fixture-errors.spec.ts +++ b/tests/playwright-test/fixture-errors.spec.ts @@ -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); }); diff --git a/tests/playwright-test/golden.spec.ts b/tests/playwright-test/golden.spec.ts index c1800bade0..e1dfba4920 100644 --- a/tests/playwright-test/golden.spec.ts +++ b/tests/playwright-test/golden.spec.ts @@ -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) diff --git a/tests/playwright-test/hooks.spec.ts b/tests/playwright-test/hooks.spec.ts index 47593c7a17..03cd189a72 100644 --- a/tests/playwright-test/hooks.spec.ts +++ b/tests/playwright-test/hooks.spec.ts @@ -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'); }); diff --git a/tests/playwright-test/max-failures.spec.ts b/tests/playwright-test/max-failures.spec.ts index 7f67e9181c..b6463eb5f8 100644 --- a/tests/playwright-test/max-failures.spec.ts +++ b/tests/playwright-test/max-failures.spec.ts @@ -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()'); }); diff --git a/tests/playwright-test/playwright-test-fixtures.ts b/tests/playwright-test/playwright-test-fixtures.ts index 0923092042..79030894e9 100644 --- a/tests/playwright-test/playwright-test-fixtures.ts +++ b/tests/playwright-test/playwright-test-fixtures.ts @@ -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, ''); } diff --git a/tests/playwright-test/playwright.expect.misc.spec.ts b/tests/playwright-test/playwright.expect.misc.spec.ts index 7c1c4e9ac9..5af9c06875 100644 --- a/tests/playwright-test/playwright.expect.misc.spec.ts +++ b/tests/playwright-test/playwright.expect.misc.spec.ts @@ -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); diff --git a/tests/playwright-test/playwright.expect.text.spec.ts b/tests/playwright-test/playwright.expect.text.spec.ts index 5908eb6690..02c942556c 100644 --- a/tests/playwright-test/playwright.expect.text.spec.ts +++ b/tests/playwright-test/playwright.expect.text.spec.ts @@ -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"'); diff --git a/tests/playwright-test/playwright.expect.true.spec.ts b/tests/playwright-test/playwright.expect.true.spec.ts index e80fb6d01e..0328e4bf34 100644 --- a/tests/playwright-test/playwright.expect.true.spec.ts +++ b/tests/playwright-test/playwright.expect.true.spec.ts @@ -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 }'); }); diff --git a/tests/playwright-test/playwright.spec.ts b/tests/playwright-test/playwright.spec.ts index 1c1cdde31f..8a14eb4a11 100644 --- a/tests/playwright-test/playwright.spec.ts +++ b/tests/playwright-test/playwright.spec.ts @@ -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) => { diff --git a/tests/playwright-test/playwright.trace.spec.ts b/tests/playwright-test/playwright.trace.spec.ts index 4206991472..4b2ae28fb7 100644 --- a/tests/playwright-test/playwright.trace.spec.ts +++ b/tests/playwright-test/playwright.trace.spec.ts @@ -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) => { diff --git a/tests/playwright-test/reporter-attachment.spec.ts b/tests/playwright-test/reporter-attachment.spec.ts index ade6795ba6..bfc12005e8 100644 --- a/tests/playwright-test/reporter-attachment.spec.ts +++ b/tests/playwright-test/reporter-attachment.spec.ts @@ -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); }); diff --git a/tests/playwright-test/reporter-base.spec.ts b/tests/playwright-test/reporter-base.spec.ts index faa9c4b018..259ee871f2 100644 --- a/tests/playwright-test/reporter-base.spec.ts +++ b/tests/playwright-test/reporter-base.spec.ts @@ -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 }) => { diff --git a/tests/playwright-test/reporter-dot.spec.ts b/tests/playwright-test/reporter-dot.spec.ts index 6af251995b..5571c42763 100644 --- a/tests/playwright-test/reporter-dot.spec.ts +++ b/tests/playwright-test/reporter-dot.spec.ts @@ -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'); diff --git a/tests/playwright-test/reporter-github.spec.ts b/tests/playwright-test/reporter-github.spec.ts index a7f242c6b9..44a2ef3e7e 100644 --- a/tests/playwright-test/reporter-github.spec.ts +++ b/tests/playwright-test/reporter-github.spec.ts @@ -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); }); diff --git a/tests/playwright-test/reporter-json.spec.ts b/tests/playwright-test/reporter-json.spec.ts index d1626dfd56..fa2ed96c46 100644 --- a/tests/playwright-test/reporter-json.spec.ts +++ b/tests/playwright-test/reporter-json.spec.ts @@ -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(); }); diff --git a/tests/playwright-test/reporter-line.spec.ts b/tests/playwright-test/reporter-line.spec.ts index c2f8c48da4..4f56b39119 100644 --- a/tests/playwright-test/reporter-line.spec.ts +++ b/tests/playwright-test/reporter-line.spec.ts @@ -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)'); }); diff --git a/tests/playwright-test/reporter-list.spec.ts b/tests/playwright-test/reporter-list.spec.ts index 216ef64740..a060da3441 100644 --- a/tests/playwright-test/reporter-list.spec.ts +++ b/tests/playwright-test/reporter-list.spec.ts @@ -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`); diff --git a/tests/playwright-test/retry.spec.ts b/tests/playwright-test/retry.spec.ts index af989a1f0e..d37f04dd4f 100644 --- a/tests/playwright-test/retry.spec.ts +++ b/tests/playwright-test/retry.spec.ts @@ -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!'); }); diff --git a/tests/playwright-test/runner.spec.ts b/tests/playwright-test/runner.spec.ts index df287a26a7..143cd84fbe 100644 --- a/tests/playwright-test/runner.spec.ts +++ b/tests/playwright-test/runner.spec.ts @@ -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', diff --git a/tests/playwright-test/test-info.spec.ts b/tests/playwright-test/test-info.spec.ts index a69019c908..27e676c173 100644 --- a/tests/playwright-test/test-info.spec.ts +++ b/tests/playwright-test/test-info.spec.ts @@ -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'); }); diff --git a/tests/playwright-test/test-modifiers.spec.ts b/tests/playwright-test/test-modifiers.spec.ts index 4133b597a6..8c2af4deea 100644 --- a/tests/playwright-test/test-modifiers.spec.ts +++ b/tests/playwright-test/test-modifiers.spec.ts @@ -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(() => {}));'); });