2021-09-14 09:07:40 +08:00
/ * *
* Copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2022-11-04 04:54:51 +08:00
import path from 'path' ;
2023-02-08 07:11:44 +08:00
import { test , expect } from './playwright-test-fixtures' ;
2021-09-14 09:07:40 +08:00
test ( 'render text attachment' , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2021-09-14 09:07:40 +08:00
test ( 'one' , async ( { } , testInfo ) = > {
testInfo . attachments . push ( {
name : 'attachment' ,
body : Buffer.from ( 'Hello world' ) ,
contentType : 'text/plain'
} ) ;
expect ( 1 ) . toBe ( 0 ) ;
} ) ;
` ,
} , { reporter : 'line' } ) ;
2023-02-08 07:11:44 +08:00
const text = result . output ;
2023-02-08 07:56:39 +08:00
expect ( text ) . toContain ( ' attachment #1: attachment (text/plain) ─────────────────────────────────────────────────────────' ) ;
2021-09-14 09:07:40 +08:00
expect ( text ) . toContain ( ' Hello world' ) ;
2023-02-08 07:56:39 +08:00
expect ( text ) . toContain ( ' ────────────────────────────────────────────────────────────────────────────────────────────────' ) ;
2021-09-14 09:07:40 +08:00
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;
test ( 'render screenshot attachment' , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2021-09-14 09:07:40 +08:00
test ( 'one' , async ( { } , testInfo ) = > {
testInfo . attachments . push ( {
name : 'screenshot' ,
path : testInfo.outputPath ( 'some/path.png' ) ,
contentType : 'image/png'
} ) ;
expect ( 1 ) . toBe ( 0 ) ;
} ) ;
` ,
} , { reporter : 'line' } ) ;
2023-02-08 07:11:44 +08:00
const text = result . output . replace ( /\\/g , '/' ) ;
2023-02-08 07:56:39 +08:00
expect ( text ) . toContain ( ' attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────' ) ;
2021-09-14 09:07:40 +08:00
expect ( text ) . toContain ( ' test-results/a-one/some/path.png' ) ;
2023-02-08 07:56:39 +08:00
expect ( text ) . toContain ( ' ────────────────────────────────────────────────────────────────────────────────────────────────' ) ;
2021-09-14 09:07:40 +08:00
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;
test ( 'render trace attachment' , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2021-09-14 09:07:40 +08:00
test ( 'one' , async ( { } , testInfo ) = > {
testInfo . attachments . push ( {
name : 'trace' ,
2024-09-17 21:32:30 +08:00
path : testInfo.outputPath ( 'my dir with space' , 'trace.zip' ) ,
2021-09-14 09:07:40 +08:00
contentType : 'application/zip'
} ) ;
expect ( 1 ) . toBe ( 0 ) ;
} ) ;
` ,
} , { reporter : 'line' } ) ;
2023-02-08 07:11:44 +08:00
const text = result . output . replace ( /\\/g , '/' ) ;
2023-02-08 07:56:39 +08:00
expect ( text ) . toContain ( ' attachment #1: trace (application/zip) ─────────────────────────────────────────────────────────' ) ;
2024-09-17 21:32:30 +08:00
expect ( text ) . toContain ( ' test-results/a-one/my dir with space/trace.zip' ) ;
expect ( text ) . toContain ( 'npx playwright show-trace "test-results/a-one/my dir with space/trace.zip"' ) ;
2023-02-08 07:56:39 +08:00
expect ( text ) . toContain ( ' ────────────────────────────────────────────────────────────────────────────────────────────────' ) ;
2021-09-14 09:07:40 +08:00
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;
2021-11-24 01:30:53 +08:00
2022-01-06 08:39:33 +08:00
test ( ` testInfo.attach errors ` , async ( { runInlineTest } ) = > {
2021-11-24 01:30:53 +08:00
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2022-01-06 08:39:33 +08:00
test ( 'fail1' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'name' , { path : 'foo.txt' } ) ;
2021-11-24 01:30:53 +08:00
} ) ;
2022-01-06 08:39:33 +08:00
test ( 'fail2' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'name' , { path : 'foo.txt' , body : 'bar' } ) ;
2021-11-24 01:30:53 +08:00
} ) ;
2022-01-06 08:39:33 +08:00
test ( 'fail3' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'name' , { } ) ;
2021-11-24 01:30:53 +08:00
} ) ;
` ,
} , { reporter : 'line' , workers : 1 } ) ;
2023-02-08 07:11:44 +08:00
const text = result . output . replace ( /\\/g , '/' ) ;
2022-01-14 02:38:47 +08:00
expect ( text ) . toMatch ( /Error: ENOENT: no such file or directory, copyfile '.*foo.txt.*'/ ) ;
2022-01-06 08:39:33 +08:00
expect ( text ) . toContain ( ` Exactly one of "path" and "body" must be specified ` ) ;
2024-07-18 00:30:49 +08:00
expect ( result . passed ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 2 ) ;
2021-11-24 01:30:53 +08:00
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;
2022-01-14 02:38:47 +08:00
2022-01-25 07:06:36 +08:00
test ( ` testInfo.attach errors with empty path ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2022-01-25 07:06:36 +08:00
test ( 'fail' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'name' , { path : '' } ) ;
} ) ;
` ,
} , { reporter : 'line' , workers : 1 } ) ;
2023-02-08 07:11:44 +08:00
expect ( result . output ) . toMatch ( /Error: ENOENT: no such file or directory, copyfile ''/ ) ;
2022-01-25 07:06:36 +08:00
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;
2022-01-14 02:38:47 +08:00
test ( ` testInfo.attach error in fixture ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test as base , expect } from '@playwright/test' ;
const test = base . extend ( {
2022-01-14 02:38:47 +08:00
fixture : async ( { } , use , testInfo ) = > {
await use ( ) ;
await testInfo . attach ( 'name' , { path : 'foo.txt' } ) ;
} ,
} ) ;
test ( 'fail1' , async ( { fixture } ) = > {
} ) ;
` ,
} , { reporter : 'line' , workers : 1 } ) ;
2023-02-08 07:11:44 +08:00
const text = result . output . replace ( /\\/g , '/' ) ;
2022-01-14 02:38:47 +08:00
expect ( text ) . toMatch ( /Error: ENOENT: no such file or directory, copyfile '.*foo.txt.*'/ ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . passed ) . toBe ( 0 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
} ) ;
test ( ` testInfo.attach success in fixture ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test as base , expect } from '@playwright/test' ;
const test = base . extend ( {
2022-01-14 02:38:47 +08:00
fixture : async ( { } , use , testInfo ) = > {
const filePath = testInfo . outputPath ( 'foo.txt' ) ;
require ( 'fs' ) . writeFileSync ( filePath , 'hello' ) ;
await use ( ) ;
await testInfo . attach ( 'name' , { path : filePath } ) ;
} ,
} ) ;
test ( 'success' , async ( { fixture } ) = > {
expect ( true ) . toBe ( false ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:11:44 +08:00
expect ( result . output ) . toContain ( 'attachment #1: name (text/plain)' ) ;
2022-01-14 02:38:47 +08:00
} ) ;
2022-01-18 10:47:24 +08:00
test ( ` testInfo.attach allow empty string body ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2022-01-18 10:47:24 +08:00
test ( 'success' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'name' , { body : '' , contentType : 'text/plain' } ) ;
expect ( 0 ) . toBe ( 1 ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:56:39 +08:00
expect ( result . output ) . toMatch ( /^.*attachment #1: name \(text\/plain\).*\n.*\n.*──────/gm ) ;
2022-01-18 10:47:24 +08:00
} ) ;
2024-07-18 00:30:49 +08:00
test ( ` testInfo.attach allow without options ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
test ( 'success' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'Full name' ) ;
expect ( 0 ) . toBe ( 1 ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
expect ( result . output ) . toMatch ( /^.*attachment #1: Full name \(text\/plain\).*\n.*──────/gm ) ;
} ) ;
2022-01-18 10:47:24 +08:00
test ( ` testInfo.attach allow empty buffer body ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test , expect } from '@playwright/test' ;
2022-01-18 10:47:24 +08:00
test ( 'success' , async ( { } , testInfo ) = > {
await testInfo . attach ( 'name' , { body : Buffer.from ( '' ) , contentType : 'text/plain' } ) ;
expect ( 0 ) . toBe ( 1 ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:56:39 +08:00
expect ( result . output ) . toMatch ( /^.*attachment #1: name \(text\/plain\).*\n.*\n.*──────/gm ) ;
2022-01-18 10:47:24 +08:00
} ) ;
2022-11-04 04:54:51 +08:00
test ( ` testInfo.attach use name as prefix ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test as base , expect } from '@playwright/test' ;
const test = base . extend ( {
2022-11-04 04:54:51 +08:00
fixture : async ( { } , use , testInfo ) = > {
const filePath = testInfo . outputPath ( 'foo.txt' ) ;
require ( 'fs' ) . writeFileSync ( filePath , 'hello' ) ;
await use ( ) ;
await testInfo . attach ( 'some random string' , { path : filePath } ) ;
} ,
} ) ;
test ( 'success' , async ( { fixture } ) = > {
expect ( true ) . toBe ( false ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:11:44 +08:00
expect ( result . output ) . toContain ( 'attachment #1: some random string (text/plain)' ) ;
expect ( result . output ) . toContain ( 'some-random-string-' ) ;
2022-11-04 04:54:51 +08:00
} ) ;
test ( ` testInfo.attach name should be sanitized ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test as base , expect } from '@playwright/test' ;
const test = base . extend ( {
2022-11-04 04:54:51 +08:00
fixture : async ( { } , use , testInfo ) = > {
const filePath = testInfo . outputPath ( 'foo.txt' ) ;
require ( 'fs' ) . writeFileSync ( filePath , 'hello' ) ;
await use ( ) ;
await testInfo . attach ( '../../../test' , { path : filePath } ) ;
} ,
} ) ;
test ( 'success' , async ( { fixture } ) = > {
expect ( true ) . toBe ( false ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:11:44 +08:00
expect ( result . output ) . toContain ( 'attachment #1: ../../../test (text/plain)' ) ;
2023-07-14 02:03:02 +08:00
expect ( result . output ) . toContain ( ` attachments ${ path . sep } -test ` ) ;
2022-11-04 04:54:51 +08:00
} ) ;
test ( ` testInfo.attach name can be empty string ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test as base , expect } from '@playwright/test' ;
const test = base . extend ( {
2022-11-04 04:54:51 +08:00
fixture : async ( { } , use , testInfo ) = > {
const filePath = testInfo . outputPath ( 'foo.txt' ) ;
require ( 'fs' ) . writeFileSync ( filePath , 'hello' ) ;
await use ( ) ;
await testInfo . attach ( '' , { path : filePath } ) ;
} ,
} ) ;
test ( 'success' , async ( { fixture } ) = > {
expect ( true ) . toBe ( false ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:11:44 +08:00
expect ( result . output ) . toContain ( 'attachment #1: (text/plain)' ) ;
expect ( result . output ) . toContain ( ` attachments ${ path . sep } - ` ) ;
2022-11-04 04:54:51 +08:00
} ) ;
test ( ` testInfo.attach throw if name is not string ` , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
2023-02-15 11:20:56 +08:00
'a.test.ts' : `
import { test as base , expect } from '@playwright/test' ;
const test = base . extend ( {
2022-11-04 04:54:51 +08:00
fixture : async ( { } , use , testInfo ) = > {
const filePath = testInfo . outputPath ( 'foo.txt' ) ;
require ( 'fs' ) . writeFileSync ( filePath , 'hello' ) ;
await use ( ) ;
await testInfo . attach ( false , { path : filePath } ) ;
} ,
} ) ;
test ( 'success' , async ( { fixture } ) = > {
expect ( true ) . toBe ( true ) ;
} ) ;
` ,
} ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
2023-02-08 07:11:44 +08:00
expect ( result . output ) . toContain ( '"name" should be string.' ) ;
2022-11-04 04:54:51 +08:00
} ) ;
2023-02-14 02:28:34 +08:00
test ( 'render text attachment with multiple lines' , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
'a.test.js' : `
2023-02-15 11:20:56 +08:00
const { test , expect } = require ( '@playwright/test' ) ;
2023-02-14 02:28:34 +08:00
test ( 'one' , async ( { } , testInfo ) = > {
testInfo . attachments . push ( {
name : 'attachment' ,
body : Buffer.from ( 'First line\\nSecond line\\nThird line' ) ,
contentType : 'text/plain'
} ) ;
expect ( 1 ) . toBe ( 0 ) ;
} ) ;
` ,
} , { reporter : 'line' } ) ;
const text = result . output ;
expect ( text ) . toContain ( ' attachment #1: attachment (text/plain) ─────────────────────────────────────────────────────────' ) ;
expect ( text ) . toContain ( ' First line' ) ;
expect ( text ) . toContain ( ' Second line' ) ;
expect ( text ) . toContain ( ' Third line' ) ;
expect ( text ) . toContain ( ' ────────────────────────────────────────────────────────────────────────────────────────────────' ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;
2025-08-26 16:26:40 +08:00
test ( 'attaching inside boxed fixture should not log error' , { annotation : { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/37147' } } , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
'a.test.ts' : `
import { test as base } from '@playwright/test' ;
const test = base . extend < { myFixture : void } > ( {
myFixture : [ async ( { } , use , testInfo ) = > {
await testInfo . attach ( 'my attachment' , {
body : 'foo' ,
contentType : 'text/plain' ,
} ) ;
await use ( ) ;
} , { box : true } ] ,
} ) ;
test ( 'my test' , ( { myFixture } ) = > {
expect ( 1 ) . toBe ( 0 ) ;
} ) ;
` ,
} , { reporter : 'line' } , { } ) ;
const text = result . output ;
expect ( text ) . toContain ( ' attachment #1: my attachment (text/plain) ──────────────────────────────────────────────────────' ) ;
expect ( text ) . toContain ( ' foo' ) ;
expect ( text ) . toContain ( ' ────────────────────────────────────────────────────────────────────────────────────────────────' ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
} ) ;