2023-05-10 08:53:01 +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 .
* /
2023-05-19 02:28:28 +08:00
import { test , expect , retries } from './ui-mode-fixtures' ;
test . describe . configure ( { mode : 'parallel' , retries } ) ;
2023-05-10 08:53:01 +08:00
2023-08-21 05:47:18 +08:00
test ( 'should contain text attachment' , async ( { runUITest } ) = > {
2023-05-10 08:53:01 +08:00
const { page } = await runUITest ( {
'a.test.ts' : `
import { test } from '@playwright/test' ;
test ( 'attach test' , async ( ) = > {
2024-07-31 21:20:36 +08:00
// Attach two files with the same content and different names,
// to make sure each is downloaded with an intended name.
2024-07-10 00:58:59 +08:00
await test . info ( ) . attach ( 'file attachment' , { path : __filename } ) ;
2024-07-31 21:20:36 +08:00
await test . info ( ) . attach ( 'file attachment 2' , { path : __filename } ) ;
2024-07-10 00:58:59 +08:00
await test . info ( ) . attach ( 'text attachment' , { body : 'hi tester!' , contentType : 'text/plain' } ) ;
2023-05-10 08:53:01 +08:00
} ) ;
` ,
} ) ;
await page . getByText ( 'attach test' ) . click ( ) ;
await page . getByTitle ( 'Run all' ) . click ( ) ;
await expect ( page . getByTestId ( 'status-line' ) ) . toHaveText ( '1/1 passed (100%)' ) ;
await page . getByText ( 'Attachments' ) . click ( ) ;
2024-07-10 00:58:59 +08:00
await page . locator ( '.tab-attachments' ) . getByText ( 'text attachment' ) . click ( ) ;
await expect ( page . locator ( '.tab-attachments' ) ) . toContainText ( 'hi tester!' ) ;
2024-07-31 21:20:36 +08:00
await page . locator ( '.tab-attachments' ) . getByText ( 'file attachment' ) . first ( ) . click ( ) ;
2024-07-10 00:58:59 +08:00
await expect ( page . locator ( '.tab-attachments' ) ) . not . toContainText ( 'attach test' ) ;
2024-07-31 21:20:36 +08:00
{
const downloadPromise = page . waitForEvent ( 'download' ) ;
await page . getByRole ( 'link' , { name : 'download' } ) . first ( ) . click ( ) ;
const download = await downloadPromise ;
expect ( download . suggestedFilename ( ) ) . toBe ( 'file attachment' ) ;
expect ( ( await readAllFromStream ( await download . createReadStream ( ) ) ) . toString ( ) ) . toContain ( 'attach test' ) ;
}
{
const downloadPromise = page . waitForEvent ( 'download' ) ;
await page . getByRole ( 'link' , { name : 'download' } ) . nth ( 1 ) . click ( ) ;
const download = await downloadPromise ;
expect ( download . suggestedFilename ( ) ) . toBe ( 'file attachment 2' ) ;
expect ( ( await readAllFromStream ( await download . createReadStream ( ) ) ) . toString ( ) ) . toContain ( 'attach test' ) ;
}
2023-05-10 08:53:01 +08:00
} ) ;
2023-05-12 07:32:32 +08:00
2023-08-21 05:47:18 +08:00
test ( 'should contain binary attachment' , async ( { runUITest } ) = > {
2023-05-12 07:32:32 +08:00
const { page } = await runUITest ( {
'a.test.ts' : `
import { test } from '@playwright/test' ;
test ( 'attach test' , async ( ) = > {
2023-08-21 05:47:18 +08:00
await test . info ( ) . attach ( 'data' , { body : Buffer.from ( [ 1 , 2 , 3 ] ) , contentType : 'application/octet-stream' } ) ;
2023-05-12 07:32:32 +08:00
} ) ;
` ,
} ) ;
await page . getByText ( 'attach test' ) . click ( ) ;
await page . getByTitle ( 'Run all' ) . click ( ) ;
await expect ( page . getByTestId ( 'status-line' ) ) . toHaveText ( '1/1 passed (100%)' ) ;
await page . getByText ( 'Attachments' ) . click ( ) ;
2023-08-17 16:57:28 +08:00
const downloadPromise = page . waitForEvent ( 'download' ) ;
2024-07-10 00:58:59 +08:00
await page . getByRole ( 'link' , { name : 'download' } ) . click ( ) ;
2023-08-17 16:57:28 +08:00
const download = await downloadPromise ;
2023-08-21 05:47:18 +08:00
expect ( download . suggestedFilename ( ) ) . toBe ( 'data' ) ;
expect ( await readAllFromStream ( await download . createReadStream ( ) ) ) . toEqual ( Buffer . from ( [ 1 , 2 , 3 ] ) ) ;
2023-05-12 07:32:32 +08:00
} ) ;
2023-08-17 16:57:28 +08:00
2023-08-21 05:47:18 +08:00
test ( 'should contain string attachment' , async ( { runUITest } ) = > {
2023-08-17 16:57:28 +08:00
const { page } = await runUITest ( {
'a.test.ts' : `
import { test } from '@playwright/test' ;
test ( 'attach test' , async ( ) = > {
2023-08-21 05:47:18 +08:00
await test . info ( ) . attach ( 'note' , { body : 'text42' } ) ;
2023-08-17 16:57:28 +08:00
} ) ;
` ,
} ) ;
await page . getByText ( 'attach test' ) . click ( ) ;
await page . getByTitle ( 'Run all' ) . click ( ) ;
await expect ( page . getByTestId ( 'status-line' ) ) . toHaveText ( '1/1 passed (100%)' ) ;
await page . getByText ( 'Attachments' ) . click ( ) ;
2025-05-23 00:49:37 +08:00
await page . getByText ( 'note' , { exact : true } ) . click ( ) ;
2023-08-17 16:57:28 +08:00
const downloadPromise = page . waitForEvent ( 'download' ) ;
2024-07-09 02:16:14 +08:00
await page . locator ( '.expandable-title' , { hasText : 'note' } ) . getByRole ( 'link' ) . click ( ) ;
2023-08-17 16:57:28 +08:00
const download = await downloadPromise ;
2023-08-21 05:47:18 +08:00
expect ( download . suggestedFilename ( ) ) . toBe ( 'note' ) ;
expect ( ( await readAllFromStream ( await download . createReadStream ( ) ) ) . toString ( ) ) . toEqual ( 'text42' ) ;
2023-08-17 16:57:28 +08:00
} ) ;
2024-08-02 00:27:45 +08:00
test ( 'should linkify string attachments' , async ( { runUITest , server } ) = > {
server . setRoute ( '/one.html' , ( req , res ) = > res . end ( ) ) ;
server . setRoute ( '/two.html' , ( req , res ) = > res . end ( ) ) ;
server . setRoute ( '/three.html' , ( req , res ) = > res . end ( ) ) ;
const { page } = await runUITest ( {
'a.test.ts' : `
import { test } from '@playwright/test' ;
test ( 'attach test' , async ( ) = > {
await test . info ( ) . attach ( 'Inline url: ${server.PREFIX + ' / one . html '}' ) ;
await test . info ( ) . attach ( 'Second' , { body : 'Inline link ${server.PREFIX + ' / two . html '} to be highlighted.' } ) ;
await test . info ( ) . attach ( 'Third' , { body : '[markdown link](${server.PREFIX + ' / three . html '})' , contentType : 'text/markdown' } ) ;
} ) ;
` ,
} ) ;
await page . getByText ( 'attach test' ) . click ( ) ;
await page . getByTitle ( 'Run all' ) . click ( ) ;
await expect ( page . getByTestId ( 'status-line' ) ) . toHaveText ( '1/1 passed (100%)' ) ;
await page . getByText ( 'Attachments' ) . click ( ) ;
const attachmentsPane = page . locator ( '.attachments-tab' ) ;
{
const url = server . PREFIX + '/one.html' ;
const promise = page . waitForEvent ( 'popup' ) ;
await attachmentsPane . getByText ( url ) . click ( ) ;
const popup = await promise ;
await expect ( popup ) . toHaveURL ( url ) ;
}
{
2024-11-06 17:22:15 +08:00
await attachmentsPane . getByLabel ( 'Second' ) . click ( ) ;
2024-08-02 00:27:45 +08:00
const url = server . PREFIX + '/two.html' ;
const promise = page . waitForEvent ( 'popup' ) ;
await attachmentsPane . getByText ( url ) . click ( ) ;
const popup = await promise ;
await expect ( popup ) . toHaveURL ( url ) ;
}
{
2024-11-06 17:22:15 +08:00
await attachmentsPane . getByLabel ( 'Third' ) . click ( ) ;
2024-08-02 00:27:45 +08:00
const url = server . PREFIX + '/three.html' ;
const promise = page . waitForEvent ( 'popup' ) ;
await attachmentsPane . getByText ( '[markdown link]' ) . click ( ) ;
const popup = await promise ;
await expect ( popup ) . toHaveURL ( url ) ;
}
} ) ;
2024-11-06 17:22:15 +08:00
test ( 'should link from attachment step to attachments view' , async ( { runUITest } ) = > {
const { page } = await runUITest ( {
'a.test.ts' : `
import { test } from '@playwright/test' ;
test ( 'attach test' , async ( ) = > {
for ( let i = 0 ; i < 100 ; i ++ )
await test . info ( ) . attach ( 'spacer-' + i ) ;
await test . info ( ) . attach ( 'my-attachment' , { body : 'bar' } ) ;
} ) ;
` ,
} ) ;
await page . getByText ( 'attach test' ) . click ( ) ;
await page . getByTitle ( 'Run all' ) . click ( ) ;
await expect ( page . getByTestId ( 'status-line' ) ) . toHaveText ( '1/1 passed (100%)' ) ;
await page . getByRole ( 'tab' , { name : 'Attachments' } ) . click ( ) ;
const panel = page . getByRole ( 'tabpanel' , { name : 'Attachments' } ) ;
const attachment = panel . getByLabel ( 'my-attachment' ) ;
await page . getByRole ( 'treeitem' , { name : 'attach "spacer-1"' } ) . getByLabel ( 'Open Attachment' ) . click ( ) ;
await expect ( attachment ) . not . toBeInViewport ( ) ;
await page . getByRole ( 'treeitem' , { name : 'attach "my-attachment"' } ) . getByLabel ( 'Open Attachment' ) . click ( ) ;
await expect ( attachment ) . toBeInViewport ( ) ;
} ) ;
2025-08-26 16:26:40 +08:00
test ( 'attachments from inside boxed fixture should be visible' , { annotation : { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/37147' } } , async ( { runUITest } ) = > {
const { page } = await runUITest ( {
'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 } ) = > { } ) ;
` ,
} , { reporter : 'line' } , { } ) ;
await page . getByText ( 'my test' ) . click ( ) ;
await page . getByTitle ( 'Run all' ) . click ( ) ;
await expect ( page . getByTestId ( 'status-line' ) ) . toHaveText ( '1/1 passed (100%)' ) ;
await page . getByRole ( 'treeitem' , { name : 'attach "my attachment"' } ) . getByLabel ( 'Open Attachment' ) . click ( ) ;
await expect ( page . getByRole ( 'tabpanel' , { name : 'Attachments' } ) ) . toMatchAriaSnapshot ( `
- tabpanel :
- button / my attachment /
` );
} ) ;
2023-08-17 16:57:28 +08:00
function readAllFromStream ( stream : NodeJS.ReadableStream ) : Promise < Buffer > {
return new Promise ( resolve = > {
const chunks : Buffer [ ] = [ ] ;
stream . on ( 'data' , chunk = > chunks . push ( chunk ) ) ;
stream . on ( 'end' , ( ) = > resolve ( Buffer . concat ( chunks ) ) ) ;
} ) ;
}