2021-09-01 22:20:28 +03: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-03-30 00:19:31 +03:00
import fs from 'fs' ;
2022-06-17 18:09:49 +03:00
import path from 'path' ;
2022-08-10 01:53:11 +03:00
import url from 'url' ;
2022-06-19 01:47:26 +03:00
import { test as baseTest , expect , createImage , stripAnsi } from './playwright-test-fixtures' ;
2022-04-07 00:57:14 +03:00
import type { HttpServer } from '../../packages/playwright-core/lib/utils/httpServer' ;
2021-10-23 21:23:39 +03:00
import { startHtmlReportServer } from '../../packages/playwright-test/lib/reporters/html' ;
2022-04-08 06:18:22 +03:00
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync' ;
2021-09-01 22:20:28 +03:00
2021-10-15 01:48:05 +03:00
const test = baseTest . extend < { showReport : ( ) = > Promise < void > } > ( {
showReport : async ( { page } , use , testInfo ) = > {
2022-02-16 05:05:20 +03:00
let server : HttpServer | undefined ;
2021-10-15 01:48:05 +03:00
await use ( async ( ) = > {
const reportFolder = testInfo . outputPath ( 'playwright-report' ) ;
2021-10-23 21:23:39 +03:00
server = startHtmlReportServer ( reportFolder ) ;
2021-10-15 01:48:05 +03:00
const location = await server . start ( ) ;
await page . goto ( location ) ;
} ) ;
2022-02-16 05:05:20 +03:00
await server ? . stop ( ) ;
2021-10-15 01:48:05 +03:00
}
} ) ;
2021-11-10 02:12:37 +03:00
test . use ( { channel : 'chrome' } ) ;
2021-11-02 02:14:52 +03:00
test ( 'should generate report' , async ( { runInlineTest , showReport , page } ) = > {
2021-09-15 02:26:31 +03:00
await runInlineTest ( {
'playwright.config.ts' : `
module .exports = { name : 'project-name' } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { } ) = > { } ) ;
test ( 'fails' , async ( { } ) = > {
expect ( 1 ) . toBe ( 2 ) ;
} ) ;
2021-11-02 02:14:52 +03:00
test ( 'skipped' , async ( { } ) = > {
2021-09-15 02:26:31 +03:00
test . skip ( 'Does not work' )
} ) ;
test ( 'flaky' , async ( { } , testInfo ) = > {
expect ( testInfo . retry ) . toBe ( 1 ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' , retries : 1 } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-09-15 02:26:31 +03:00
2021-11-02 02:14:52 +03:00
await showReport ( ) ;
await expect ( page . locator ( '.subnav-item:has-text("All") .counter' ) ) . toHaveText ( '4' ) ;
await expect ( page . locator ( '.subnav-item:has-text("Passed") .counter' ) ) . toHaveText ( '1' ) ;
await expect ( page . locator ( '.subnav-item:has-text("Failed") .counter' ) ) . toHaveText ( '1' ) ;
await expect ( page . locator ( '.subnav-item:has-text("Flaky") .counter' ) ) . toHaveText ( '1' ) ;
await expect ( page . locator ( '.subnav-item:has-text("Skipped") .counter' ) ) . toHaveText ( '1' ) ;
2021-12-13 01:56:12 +03:00
await expect ( page . locator ( '.test-file-test-outcome-unexpected >> text=fails' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( '.test-file-test-outcome-flaky >> text=flaky' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( '.test-file-test-outcome-expected >> text=passes' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( '.test-file-test-outcome-skipped >> text=skipped' ) ) . toBeVisible ( ) ;
2022-03-23 02:28:04 +03:00
2022-12-23 02:57:55 +03:00
await expect ( page . getByTestId ( 'overall-duration' ) , 'should contain humanized total time with at most 1 decimal place' ) . toContainText ( /^Total time: \d+(\.\d)?(ms|s|m)$/ ) ;
2023-01-10 19:11:38 +03:00
await expect ( page . getByTestId ( 'project-name' ) , 'should contain project name' ) . toContainText ( 'project-name' ) ;
2022-12-21 01:13:10 +03:00
2022-03-23 02:28:04 +03:00
await expect ( page . locator ( '.metadata-view' ) ) . not . toBeVisible ( ) ;
2021-09-15 02:26:31 +03:00
} ) ;
2022-03-30 00:19:31 +03:00
2021-11-18 05:03:13 +03:00
test ( 'should not throw when attachment is missing' , async ( { runInlineTest , page , showReport } , testInfo ) = > {
2021-09-01 22:20:28 +03:00
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = { preserveOutput : 'failures-only' } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { page } , testInfo ) = > {
const screenshot = testInfo . outputPath ( 'screenshot.png' ) ;
await page . screenshot ( { path : screenshot } ) ;
testInfo . attachments . push ( { name : 'screenshot' , path : screenshot , contentType : 'image/png' } ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-09-01 22:20:28 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
2021-11-18 05:03:13 +03:00
await showReport ( ) ;
await page . click ( 'text=passes' ) ;
await page . locator ( 'text=Missing attachment "screenshot"' ) . click ( ) ;
2022-08-18 21:12:33 +03:00
const screenshotFile = testInfo . outputPath ( 'test-results' , 'a-passes' , 'screenshot.png' ) ;
2022-01-06 20:29:55 +03:00
await expect ( page . locator ( '.attachment-body' ) ) . toHaveText ( ` Attachment file ${ screenshotFile } is missing ` ) ;
2021-09-01 22:20:28 +03:00
} ) ;
2021-10-15 01:48:05 +03:00
test ( 'should include image diff' , async ( { runInlineTest , page , showReport } ) = > {
const expected = Buffer . from ( 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAAhVJREFUeJzt07ERwCAQwLCQ/Xd+FuDcQiFN4MZrZuYDjv7bAfAyg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAiEDVPZBYx6ffy+AAAAAElFTkSuQmCC' , 'base64' ) ;
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = { use : { viewport : { width : 200 , height : 200 } } } ;
` ,
'a.test.js-snapshots/expected-linux.png' : expected ,
'a.test.js-snapshots/expected-darwin.png' : expected ,
'a.test.js-snapshots/expected-win32.png' : expected ,
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } , testInfo ) = > {
await page . setContent ( '<html>Hello World</html>' ) ;
const screenshot = await page . screenshot ( ) ;
await expect ( screenshot ) . toMatchSnapshot ( 'expected.png' ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-10-15 01:48:05 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
2022-01-05 20:04:08 +03:00
await expect ( page . locator ( 'text=Image mismatch' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( 'text=Snapshot mismatch' ) ) . toHaveCount ( 0 ) ;
2022-04-02 01:27:51 +03:00
const set = new Set ( ) ;
2021-12-13 01:56:12 +03:00
const imageDiff = page . locator ( 'data-testid=test-result-image-mismatch' ) ;
2022-04-02 01:27:51 +03:00
const expectedImage = imageDiff . locator ( 'img' ) . first ( ) ;
const actualImage = imageDiff . locator ( 'img' ) . last ( ) ;
await expect ( expectedImage ) . toHaveAttribute ( 'src' , /.*png/ ) ;
await expect ( actualImage ) . toHaveAttribute ( 'src' , /.*png/ ) ;
set . add ( await expectedImage . getAttribute ( 'src' ) ) ;
set . add ( await actualImage . getAttribute ( 'src' ) ) ;
expect ( set . size , 'Should be two images overlaid' ) . toBe ( 2 ) ;
const sliderElement = imageDiff . locator ( 'data-testid=test-result-image-mismatch-grip' ) ;
2022-04-02 04:11:15 +03:00
await expect . poll ( ( ) = > sliderElement . evaluate ( e = > e . style . left ) , 'Actual slider is on the right' ) . toBe ( '590px' ) ;
2022-04-02 01:27:51 +03:00
2022-04-01 00:11:34 +03:00
await imageDiff . locator ( 'text="Expected"' ) . click ( ) ;
2022-04-02 01:27:51 +03:00
set . add ( await expectedImage . getAttribute ( 'src' ) ) ;
set . add ( await actualImage . getAttribute ( 'src' ) ) ;
expect ( set . size ) . toBe ( 2 ) ;
2022-04-02 04:11:15 +03:00
await expect . poll ( ( ) = > sliderElement . evaluate ( e = > e . style . left ) , 'Expected slider is on the left' ) . toBe ( '350px' ) ;
2022-04-02 01:27:51 +03:00
2022-04-01 00:11:34 +03:00
await imageDiff . locator ( 'text="Diff"' ) . click ( ) ;
2022-04-02 01:27:51 +03:00
set . add ( await imageDiff . locator ( 'img' ) . getAttribute ( 'src' ) ) ;
expect ( set . size , 'Should be three images altogether' ) . toBe ( 3 ) ;
2021-10-15 01:48:05 +03:00
} ) ;
2022-03-11 19:46:13 +03:00
test ( 'should include multiple image diffs' , async ( { runInlineTest , page , showReport } ) = > {
const IMG_WIDTH = 200 ;
const IMG_HEIGHT = 200 ;
const redImage = createImage ( IMG_WIDTH , IMG_HEIGHT , 255 , 0 , 0 ) ;
const whiteImage = createImage ( IMG_WIDTH , IMG_HEIGHT , 255 , 255 , 255 ) ;
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = {
2022-11-10 02:29:07 +03:00
snapshotPathTemplate : '__screenshots__/{testFilePath}/{arg}{ext}' ,
2022-03-11 19:46:13 +03:00
use : { viewport : { width : $ { IMG_WIDTH } , height : $ { IMG_HEIGHT } } }
} ;
` ,
'__screenshots__/a.test.js/fails-1.png' : redImage ,
'__screenshots__/a.test.js/fails-2.png' : whiteImage ,
'__screenshots__/a.test.js/fails-3.png' : redImage ,
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } , testInfo ) = > {
testInfo . snapshotSuffix = '' ;
2022-04-14 23:22:42 +03:00
await expect . soft ( page ) . toHaveScreenshot ( { timeout : 1000 } ) ;
await expect . soft ( page ) . toHaveScreenshot ( { timeout : 1000 } ) ;
await expect . soft ( page ) . toHaveScreenshot ( { timeout : 1000 } ) ;
2022-03-11 19:46:13 +03:00
} ) ;
` ,
2022-06-02 01:22:43 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-03-11 19:46:13 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
await expect ( page . locator ( 'text=Image mismatch' ) ) . toHaveCount ( 2 ) ;
await expect ( page . locator ( 'text=Snapshot mismatch' ) ) . toHaveCount ( 0 ) ;
await expect ( page . locator ( 'text=Screenshots' ) ) . toHaveCount ( 0 ) ;
for ( let i = 0 ; i < 2 ; ++ i ) {
const imageDiff = page . locator ( 'data-testid=test-result-image-mismatch' ) . nth ( i ) ;
2022-04-02 01:27:51 +03:00
const image = imageDiff . locator ( 'img' ) . first ( ) ;
2022-03-11 19:46:13 +03:00
await expect ( image ) . toHaveAttribute ( 'src' , /.*png/ ) ;
}
} ) ;
2022-04-01 00:11:34 +03:00
test ( 'should include image diffs for same expectation' , async ( { runInlineTest , page , showReport } ) = > {
const expected = Buffer . from ( 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAAhVJREFUeJzt07ERwCAQwLCQ/Xd+FuDcQiFN4MZrZuYDjv7bAfAyg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAiEDVPZBYx6ffy+AAAAAElFTkSuQmCC' , 'base64' ) ;
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = { use : { viewport : { width : 200 , height : 200 } } } ;
` ,
'a.test.js-snapshots/expected-linux.png' : expected ,
'a.test.js-snapshots/expected-darwin.png' : expected ,
'a.test.js-snapshots/expected-win32.png' : expected ,
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } , testInfo ) = > {
await page . setContent ( '<html>Hello World</html>' ) ;
const screenshot = await page . screenshot ( ) ;
await expect . soft ( screenshot ) . toMatchSnapshot ( 'expected.png' ) ;
await expect . soft ( screenshot ) . toMatchSnapshot ( 'expected.png' ) ;
await expect . soft ( screenshot ) . toMatchSnapshot ( 'expected.png' ) ;
} ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
await expect ( page . locator ( 'data-testid=test-result-image-mismatch' ) ) . toHaveCount ( 3 ) ;
await expect ( page . locator ( 'text=Image mismatch:' ) ) . toHaveText ( [
'Image mismatch: expected.png' ,
'Image mismatch: expected.png-1' ,
'Image mismatch: expected.png-2' ,
] ) ;
} ) ;
2022-03-11 19:46:13 +03:00
test ( 'should include image diff when screenshot failed to generate due to animation' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = { use : { viewport : { width : 200 , height : 200 } } } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } , testInfo ) = > {
testInfo . snapshotSuffix = '' ;
await page . evaluate ( ( ) = > {
setInterval ( ( ) = > {
document . body . textContent = Date . now ( ) ;
} , 50 ) ;
} ) ;
2022-04-14 23:22:42 +03:00
await expect . soft ( page ) . toHaveScreenshot ( { timeout : 1000 } ) ;
2022-03-11 19:46:13 +03:00
} ) ;
` ,
2022-06-02 01:22:43 +03:00
} , { 'reporter' : 'dot,html' , 'update-snapshots' : true } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-03-11 19:46:13 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
await expect ( page . locator ( 'text=Image mismatch' ) ) . toHaveCount ( 1 ) ;
await expect ( page . locator ( 'text=Snapshot mismatch' ) ) . toHaveCount ( 0 ) ;
2022-03-12 09:40:28 +03:00
await expect ( page . locator ( '.chip-header' , { hasText : 'Screenshots' } ) ) . toHaveCount ( 0 ) ;
2022-03-11 19:46:13 +03:00
const imageDiff = page . locator ( 'data-testid=test-result-image-mismatch' ) ;
const image = imageDiff . locator ( 'img' ) ;
2022-04-02 01:27:51 +03:00
await expect ( image . first ( ) ) . toHaveAttribute ( 'src' , /.*png/ ) ;
await expect ( image . last ( ) ) . toHaveAttribute ( 'src' , /.*png/ ) ;
const previousSrc = await image . first ( ) . getAttribute ( 'src' ) ;
const actualSrc = await image . last ( ) . getAttribute ( 'src' ) ;
2022-04-01 00:11:34 +03:00
await imageDiff . locator ( 'text="Previous"' ) . click ( ) ;
await imageDiff . locator ( 'text="Diff"' ) . click ( ) ;
2022-03-11 19:46:13 +03:00
const diffSrc = await image . getAttribute ( 'src' ) ;
const set = new Set ( [ previousSrc , actualSrc , diffSrc ] ) ;
expect ( set . size ) . toBe ( 3 ) ;
} ) ;
2022-01-05 20:04:08 +03:00
test ( 'should not include image diff with non-images' , async ( { runInlineTest , page , showReport } ) = > {
const expected = Buffer . from ( 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAAhVJREFUeJzt07ERwCAQwLCQ/Xd+FuDcQiFN4MZrZuYDjv7bAfAyg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAgEg0AwCASDQDAIBINAMAiEDVPZBYx6ffy+AAAAAElFTkSuQmCC' , 'base64' ) ;
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = { use : { viewport : { width : 200 , height : 200 } } } ;
` ,
'a.test.js-snapshots/expected-linux' : expected ,
'a.test.js-snapshots/expected-darwin' : expected ,
'a.test.js-snapshots/expected-win32' : expected ,
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } , testInfo ) = > {
await page . setContent ( '<html>Hello World</html>' ) ;
const screenshot = await page . screenshot ( ) ;
await expect ( screenshot ) . toMatchSnapshot ( 'expected' ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-01-05 20:04:08 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
await expect ( page . locator ( 'text=Image mismatch' ) ) . toHaveCount ( 0 ) ;
await expect ( page . locator ( 'img' ) ) . toHaveCount ( 0 ) ;
2022-03-31 03:42:08 +03:00
await expect ( page . locator ( 'a' , { hasText : 'expected-actual' } ) ) . toBeVisible ( ) ;
await expect ( page . locator ( 'a' , { hasText : 'expected-expected' } ) ) . toBeVisible ( ) ;
2022-01-05 20:04:08 +03:00
} ) ;
2021-10-15 01:48:05 +03:00
test ( 'should include screenshot on failure' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = {
use : {
viewport : { width : 200 , height : 200 } ,
screenshot : 'only-on-failure' ,
}
} ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } ) = > {
await page . setContent ( '<html>Failed state</html>' ) ;
await expect ( true ) . toBeFalsy ( ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-10-15 01:48:05 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
await expect ( page . locator ( 'text=Screenshots' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( 'img' ) ) . toBeVisible ( ) ;
const src = await page . locator ( 'img' ) . getAttribute ( 'src' ) ;
expect ( src ) . toBeTruthy ( ) ;
} ) ;
2021-10-16 02:15:06 +03:00
test ( 'should include stdio' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } ) = > {
console . log ( 'First line' ) ;
console . log ( 'Second line' ) ;
console . error ( 'Third line' ) ;
await expect ( true ) . toBeFalsy ( ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-10-16 02:15:06 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
await page . locator ( 'text=stdout' ) . click ( ) ;
2022-01-06 20:29:55 +03:00
await expect ( page . locator ( '.attachment-body' ) ) . toHaveText ( 'First line\nSecond line' ) ;
2021-10-16 02:15:06 +03:00
await page . locator ( 'text=stderr' ) . click ( ) ;
2022-01-06 20:29:55 +03:00
await expect ( page . locator ( '.attachment-body' ) . nth ( 1 ) ) . toHaveText ( 'Third line' ) ;
2021-10-16 02:15:06 +03:00
} ) ;
2021-10-19 07:37:19 +03:00
test ( 'should highlight error' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'a.test.js' : `
const { test } = pwt ;
test ( 'fails' , async ( { page } ) = > {
await expect ( true ) . toBeFalsy ( ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-10-19 07:37:19 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . failed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
2021-12-13 01:56:12 +03:00
await expect ( page . locator ( '.test-result-error-message span:has-text("received")' ) . nth ( 1 ) ) . toHaveCSS ( 'color' , 'rgb(204, 0, 0)' ) ;
2021-10-19 07:37:19 +03:00
} ) ;
2021-10-23 21:23:39 +03:00
test ( 'should show trace source' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'playwright.config.js' : `
module .exports = { use : { trace : 'on' } } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { page } ) = > {
await page . evaluate ( '2 + 2' ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-10-23 21:23:39 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=passes' ) ;
await page . click ( 'img' ) ;
await page . click ( '.action-title >> text=page.evaluate' ) ;
await page . click ( 'text=Source' ) ;
2022-11-02 01:04:30 +03:00
await expect ( page . locator ( '.CodeMirror-line' ) ) . toContainText ( [
2021-10-23 21:23:39 +03:00
/const.*pwt;/ ,
/page\.evaluate/
] ) ;
await expect ( page . locator ( '.source-line-running' ) ) . toContainText ( 'page.evaluate' ) ;
await expect ( page . locator ( '.stack-trace-frame' ) ) . toContainText ( [
/a.test.js:[\d]+/ ,
] ) ;
await expect ( page . locator ( '.stack-trace-frame.selected' ) ) . toContainText ( 'a.test.js' ) ;
} ) ;
2021-11-02 07:23:35 +03:00
test ( 'should show trace title' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'playwright.config.js' : `
module .exports = { use : { trace : 'on' } } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { page } ) = > {
await page . evaluate ( '2 + 2' ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-11-02 07:23:35 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=passes' ) ;
await page . click ( 'img' ) ;
await expect ( page . locator ( '.workbench .title' ) ) . toHaveText ( 'a.test.js:6 › passes' ) ;
} ) ;
2021-12-08 03:47:47 +03:00
2022-02-16 20:09:42 +03:00
test ( 'should show multi trace source' , async ( { runInlineTest , page , server , showReport } ) = > {
const result = await runInlineTest ( {
'playwright.config.js' : `
module .exports = { use : { trace : 'on' } } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { playwright , page } ) = > {
await page . evaluate ( '2 + 2' ) ;
const request = await playwright . request . newContext ( ) ;
await request . get ( '${server.EMPTY_PAGE}' ) ;
await request . dispose ( ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-02-16 20:09:42 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=passes' ) ;
// Expect one image-link to trace viewer and 2 separate download links
await expect ( page . locator ( 'img' ) ) . toHaveCount ( 1 ) ;
await expect ( page . locator ( 'a' , { hasText : 'trace' } ) ) . toHaveText ( [ 'trace-1' , 'trace-2' ] ) ;
await page . click ( 'img' ) ;
await page . click ( '.action-title >> text=page.evaluate' ) ;
await page . click ( 'text=Source' ) ;
await expect ( page . locator ( '.source-line-running' ) ) . toContainText ( 'page.evaluate' ) ;
await page . click ( '.action-title >> text=apiRequestContext.get' ) ;
await page . click ( 'text=Source' ) ;
await expect ( page . locator ( '.source-line-running' ) ) . toContainText ( 'request.get' ) ;
} ) ;
2022-08-10 01:53:11 +03:00
test ( 'should warn user when viewing via file:// protocol' , async ( { runInlineTest , page , showReport } , testInfo ) = > {
const result = await runInlineTest ( {
'playwright.config.js' : `
module .exports = { use : { trace : 'on' } } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { page } ) = > {
await page . evaluate ( '2 + 2' ) ;
} ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
await test . step ( 'view via server' , async ( ) = > {
await showReport ( ) ;
await page . locator ( '[title="View trace"]' ) . click ( ) ;
await expect ( page . locator ( 'body' ) ) . toContainText ( 'Action does not have snapshots' , { useInnerText : true } ) ;
await expect ( page . locator ( 'dialog' ) ) . toBeHidden ( ) ;
} ) ;
await test . step ( 'view via local file://' , async ( ) = > {
const reportFolder = testInfo . outputPath ( 'playwright-report' ) ;
await page . goto ( url . pathToFileURL ( path . join ( reportFolder , 'index.html' ) ) . toString ( ) ) ;
await page . locator ( '[title="View trace"]' ) . click ( ) ;
await expect ( page . locator ( 'dialog' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( 'dialog' ) ) . toContainText ( 'must be loaded over' ) ;
} ) ;
} ) ;
2023-01-10 03:17:06 +03:00
test ( 'should show failed and timed out steps and hooks' , async ( { runInlineTest , page , showReport } ) = > {
2021-12-08 03:47:47 +03:00
const result = await runInlineTest ( {
'playwright.config.js' : `
2021-12-14 00:32:53 +03:00
module .exports = { timeout : 3000 } ;
2021-12-08 03:47:47 +03:00
` ,
'a.test.js' : `
const { test } = pwt ;
2022-03-18 05:33:01 +03:00
test . beforeAll ( ( ) = > {
console . log ( 'beforeAll 1' ) ;
} ) ;
test . beforeAll ( ( ) = > {
console . log ( 'beforeAll 2' ) ;
} ) ;
test . beforeEach ( ( ) = > {
console . log ( 'beforeEach 1' ) ;
} ) ;
test . beforeEach ( ( ) = > {
console . log ( 'beforeEach 2' ) ;
} ) ;
test . afterEach ( ( ) = > {
console . log ( 'afterEach 1' ) ;
} ) ;
test . afterAll ( ( ) = > {
console . log ( 'afterAll 1' ) ;
} ) ;
2021-12-08 03:47:47 +03:00
test ( 'fails' , async ( { page } ) = > {
2023-01-10 03:17:06 +03:00
await test . step ( 'outer error' , async ( ) = > {
await test . step ( 'inner error' , async ( ) = > {
expect . soft ( 1 ) . toBe ( 2 ) ;
} ) ;
} ) ;
2021-12-08 03:47:47 +03:00
await test . step ( 'outer step' , async ( ) = > {
await test . step ( 'inner step' , async ( ) = > {
await new Promise ( ( ) = > { } ) ;
} ) ;
} ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-12-08 03:47:47 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
expect ( result . passed ) . toBe ( 0 ) ;
await showReport ( ) ;
await page . click ( 'text=fails' ) ;
2023-01-10 03:17:06 +03:00
await page . click ( '.tree-item:has-text("outer error") >> text=outer error' ) ;
await page . click ( '.tree-item:has-text("outer error") >> .tree-item >> text=inner error' ) ;
await expect ( page . locator ( '.tree-item:has-text("outer error") svg.color-text-danger' ) ) . toHaveCount ( 3 ) ;
await expect ( page . locator ( '.tree-item:has-text("expect.soft.toBe"):not(:has-text("inner"))' ) ) . toBeVisible ( ) ;
2021-12-08 03:47:47 +03:00
await page . click ( 'text=outer step' ) ;
await expect ( page . locator ( '.tree-item:has-text("outer step") svg.color-text-danger' ) ) . toHaveCount ( 2 ) ;
await expect ( page . locator ( '.tree-item:has-text("inner step") svg.color-text-danger' ) ) . toHaveCount ( 2 ) ;
2023-01-10 03:17:06 +03:00
2022-03-18 05:33:01 +03:00
await page . click ( 'text=Before Hooks' ) ;
await expect ( page . locator ( '.tree-item:has-text("Before Hooks") .tree-item' ) ) . toContainText ( [
/beforeAll hook/ ,
/beforeAll hook/ ,
/beforeEach hook/ ,
/beforeEach hook/ ,
] ) ;
await page . locator ( 'text=beforeAll hook' ) . nth ( 1 ) . click ( ) ;
await expect ( page . locator ( 'text=console.log(\'beforeAll 2\');' ) ) . toBeVisible ( ) ;
await page . click ( 'text=After Hooks' ) ;
await expect ( page . locator ( '.tree-item:has-text("After Hooks") .tree-item' ) ) . toContainText ( [
/afterEach hook/ ,
/afterAll hook/ ,
] ) ;
2021-12-08 03:47:47 +03:00
} ) ;
2021-12-08 05:35:06 +03:00
test ( 'should render annotations' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'playwright.config.js' : `
module .exports = { timeout : 1500 } ;
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'skipped test' , async ( { page } ) = > {
test . skip ( true , 'I am not interested in this test' ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-12-08 05:35:06 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . skipped ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text=skipped test' ) ;
await expect ( page . locator ( '.test-case-annotation' ) ) . toHaveText ( 'skip: I am not interested in this test' ) ;
} ) ;
2021-12-08 19:51:44 +03:00
test ( 'should render text attachments as text' , async ( { runInlineTest , page , showReport } ) = > {
const result = await runInlineTest ( {
'a.test.js' : `
const { test } = pwt ;
test ( 'passing' , async ( { page } , testInfo ) = > {
testInfo . attachments . push ( {
name : 'example.txt' ,
contentType : 'text/plain' ,
body : Buffer.from ( 'foo' ) ,
} ) ;
testInfo . attachments . push ( {
name : 'example.json' ,
contentType : 'application/json' ,
body : Buffer.from ( JSON . stringify ( { foo : 1 } ) ) ,
} ) ;
testInfo . attachments . push ( {
name : 'example-utf16.txt' ,
contentType : 'text/plain, charset=utf16le' ,
body : Buffer.from ( 'utf16 encoded' , 'utf16le' ) ,
} ) ;
testInfo . attachments . push ( {
name : 'example-null.txt' ,
contentType : 'text/plain, charset=utf16le' ,
body : null ,
} ) ;
} ) ;
` ,
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-12-08 19:51:44 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
await showReport ( ) ;
2022-03-11 19:46:13 +03:00
await page . locator ( 'text=passing' ) . click ( ) ;
await page . locator ( 'text=example.txt' ) . click ( ) ;
await page . locator ( 'text=example.json' ) . click ( ) ;
await page . locator ( 'text=example-utf16.txt' ) . click ( ) ;
2022-01-06 20:29:55 +03:00
await expect ( page . locator ( '.attachment-body' ) ) . toHaveText ( [ 'foo' , '{"foo":1}' , 'utf16 encoded' ] ) ;
2021-12-08 19:51:44 +03:00
} ) ;
2021-12-28 20:56:34 +03:00
2022-06-17 18:09:49 +03:00
test ( 'should use file-browser friendly extensions for buffer attachments based on contentType' , async ( { runInlineTest } , testInfo ) = > {
const result = await runInlineTest ( {
'a.test.js' : `
const { test } = pwt ;
test ( 'passing' , async ( { page } , testInfo ) = > {
await testInfo . attach ( 'screenshot' , { body : await page . screenshot ( ) , contentType : 'image/png' } ) ;
await testInfo . attach ( 'some-pdf' , { body : Buffer.from ( 'foo' ) , contentType : 'application/pdf' } ) ;
await testInfo . attach ( 'madeup-contentType' , { body : Buffer.from ( 'bar' ) , contentType : 'madeup' } ) ;
await testInfo . attach ( 'screenshot-that-already-has-an-extension-with-madeup.png' , { body : Buffer.from ( 'a' ) , contentType : 'madeup' } ) ;
await testInfo . attach ( 'screenshot-that-already-has-an-extension-with-correct-contentType.png' , { body : Buffer.from ( 'c' ) , contentType : 'image/png' } ) ;
await testInfo . attach ( 'example.ext with spaces' , { body : Buffer.from ( 'b' ) , contentType : 'madeup' } ) ;
} ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
const files = await fs . promises . readdir ( path . join ( testInfo . outputPath ( 'playwright-report' ) , 'data' ) ) ;
expect ( new Set ( files ) ) . toEqual ( new Set ( [
'f6aa9785bc9c7b8fd40c3f6ede6f59112a939527.png' , // screenshot
'0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33.pdf' , // some-pdf
'62cdb7020ff920e5aa642c3d4066950dd1f01f4d.dat' , // madeup-contentType
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8.png' , // screenshot-that-already-has-an-extension-with-madeup.png
'84a516841ba77a5b4648de2cd0dfcb30ea46dbb4.png' , // screenshot-that-already-has-an-extension-with-correct-contentType.png
'e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98.ext-with-spaces' , // example.ext with spaces
] ) ) ;
} ) ;
2021-12-28 20:56:34 +03:00
test ( 'should strikethough textual diff' , async ( { runInlineTest , showReport , page } ) = > {
const result = await runInlineTest ( {
'helper.ts' : `
export const test = pwt . test . extend ( {
auto : [ async ( { } , run , testInfo ) = > {
testInfo . snapshotSuffix = '' ;
await run ( ) ;
} , { auto : true } ]
} ) ;
` ,
'a.spec.js-snapshots/snapshot.txt' : ` old ` ,
'a.spec.js' : `
const { test } = require ( './helper' ) ;
test ( 'is a test' , ( { } ) = > {
expect ( 'new' ) . toMatchSnapshot ( 'snapshot.txt' ) ;
} ) ;
`
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-12-28 20:56:34 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text="is a test"' ) ;
const stricken = await page . locator ( 'css=strike' ) . innerText ( ) ;
expect ( stricken ) . toBe ( 'old' ) ;
} ) ;
test ( 'should strikethough textual diff with commonalities' , async ( { runInlineTest , showReport , page } ) = > {
const result = await runInlineTest ( {
'helper.ts' : `
export const test = pwt . test . extend ( {
auto : [ async ( { } , run , testInfo ) = > {
testInfo . snapshotSuffix = '' ;
await run ( ) ;
} , { auto : true } ]
} ) ;
` ,
'a.spec.js-snapshots/snapshot.txt' : ` oldcommon ` ,
'a.spec.js' : `
const { test } = require ( './helper' ) ;
test ( 'is a test' , ( { } ) = > {
expect ( 'newcommon' ) . toMatchSnapshot ( 'snapshot.txt' ) ;
} ) ;
`
2022-02-24 23:39:28 +03:00
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2021-12-28 20:56:34 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . click ( 'text="is a test"' ) ;
const stricken = await page . locator ( 'css=strike' ) . innerText ( ) ;
expect ( stricken ) . toBe ( 'old' ) ;
} ) ;
2022-01-04 04:29:54 +03:00
test ( 'should differentiate repeat-each test cases' , async ( { runInlineTest , showReport , page } ) = > {
test . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/10859' } ) ;
const result = await runInlineTest ( {
'a.spec.js' : `
const { test } = pwt ;
test ( 'sample' , async ( { } , testInfo ) = > {
if ( testInfo . repeatEachIndex === 2 )
throw new Error ( 'ouch' ) ;
} ) ;
`
2022-02-24 23:39:28 +03:00
} , { 'reporter' : 'dot,html' , 'repeat-each' : 3 } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-01-04 04:29:54 +03:00
expect ( result . exitCode ) . toBe ( 1 ) ;
await showReport ( ) ;
await page . locator ( 'text=sample' ) . first ( ) . click ( ) ;
await expect ( page . locator ( 'text=ouch' ) ) . toBeVisible ( ) ;
await page . locator ( 'text=All' ) . first ( ) . click ( ) ;
await page . locator ( 'text=sample' ) . nth ( 1 ) . click ( ) ;
await expect ( page . locator ( 'text=Before Hooks' ) ) . toBeVisible ( ) ;
await expect ( page . locator ( 'text=ouch' ) ) . toBeHidden ( ) ;
} ) ;
2022-01-04 08:17:17 +03:00
test ( 'should group similar / loop steps' , async ( { runInlineTest , showReport , page } ) = > {
test . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/10098' } ) ;
const result = await runInlineTest ( {
'a.spec.js' : `
const { test } = pwt ;
test ( 'sample' , async ( { } , testInfo ) = > {
for ( let i = 0 ; i < 10 ; ++ i )
expect ( 1 ) . toBe ( 1 ) ;
for ( let i = 0 ; i < 20 ; ++ i )
expect ( 2 ) . toEqual ( 2 ) ;
} ) ;
`
2022-02-24 23:39:28 +03:00
} , { 'reporter' : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-01-04 08:17:17 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
await showReport ( ) ;
await page . locator ( 'text=sample' ) . first ( ) . click ( ) ;
await expect ( page . locator ( '.tree-item-title' ) ) . toContainText ( [
/expect\.toBe.*10/ ,
/expect\.toEqual.*20/ ,
] ) ;
} ) ;
2022-02-01 22:01:52 +03:00
test ( 'open tests from required file' , async ( { runInlineTest , showReport , page } ) = > {
test . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/11742' } ) ;
const result = await runInlineTest ( {
'inner.js' : `
const { test , expect } = pwt ;
test ( 'sample' , async ( { } ) = > { expect ( 2 ) . toBe ( 2 ) ; } ) ;
` ,
'a.spec.js' : ` require('./inner') `
2022-02-24 23:39:28 +03:00
} , { 'reporter' : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
2022-02-01 22:01:52 +03:00
expect ( result . exitCode ) . toBe ( 0 ) ;
await showReport ( ) ;
2022-02-02 00:04:54 +03:00
await expect ( page . locator ( 'text=a.spec.js' ) ) . toBeVisible ( ) ;
2022-02-01 22:01:52 +03:00
await page . locator ( 'text=sample' ) . first ( ) . click ( ) ;
await expect ( page . locator ( '.tree-item-title' ) ) . toContainText ( [
/expect\.toBe/ ,
] ) ;
} ) ;
2022-03-23 02:28:04 +03:00
2022-05-03 02:28:14 +03:00
test . describe ( 'gitCommitInfo plugin' , ( ) = > {
test ( 'should include metadata' , async ( { runInlineTest , showReport , page } ) = > {
const beforeRunPlaywrightTest = async ( { baseDir } : { baseDir : string } ) = > {
const execGit = async ( args : string [ ] ) = > {
const { code , stdout , stderr } = await spawnAsync ( 'git' , args , { stdio : 'pipe' , cwd : baseDir } ) ;
if ( ! ! code )
throw new Error ( ` Non-zero exit of: \ n $ git ${ args . join ( ' ' ) } \ nConsole: \ nstdout: \ n ${ stdout } \ n \ nstderr: \ n ${ stderr } \ n \ n ` ) ;
return ;
} ;
await execGit ( [ 'init' ] ) ;
await execGit ( [ 'config' , '--local' , 'user.email' , 'shakespeare@example.local' ] ) ;
await execGit ( [ 'config' , '--local' , 'user.name' , 'William' ] ) ;
await execGit ( [ 'add' , '*.ts' ] ) ;
await execGit ( [ 'commit' , '-m' , 'awesome commit message' ] ) ;
2022-03-23 02:28:04 +03:00
} ;
2022-05-03 02:28:14 +03:00
const result = await runInlineTest ( {
'uncommitted.txt' : ` uncommitted file ` ,
2022-05-04 00:25:56 +03:00
'playwright.config.ts' : ` export default {}; ` ,
2022-05-03 02:28:14 +03:00
'example.spec.ts' : `
2022-05-04 00:25:56 +03:00
import { gitCommitInfo } from '@playwright/test/lib/plugins' ;
const { test , _addRunnerPlugin } = pwt ;
_addRunnerPlugin ( gitCommitInfo ( ) ) ;
2022-05-03 02:28:14 +03:00
test ( 'sample' , async ( { } ) = > { expect ( 2 ) . toBe ( 2 ) ; } ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' , GITHUB_REPOSITORY : 'microsoft/playwright-example-for-test' , GITHUB_RUN_ID : 'example-run-id' , GITHUB_SERVER_URL : 'https://playwright.dev' , GITHUB_SHA : 'example-sha' } , undefined , beforeRunPlaywrightTest ) ;
await showReport ( ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
await page . click ( 'text=awesome commit message' ) ;
await expect . soft ( page . locator ( 'data-test-id=revision.id' ) ) . toContainText ( /^[a-f\d]+$/i ) ;
await expect . soft ( page . locator ( 'data-test-id=revision.id >> a' ) ) . toHaveAttribute ( 'href' , 'https://playwright.dev/microsoft/playwright-example-for-test/commit/example-sha' ) ;
await expect . soft ( page . locator ( 'data-test-id=revision.timestamp' ) ) . toContainText ( /AM|PM/ ) ;
await expect . soft ( page . locator ( 'text=awesome commit message' ) ) . toHaveCount ( 2 ) ;
await expect . soft ( page . locator ( 'text=William' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'text=shakespeare@example.local' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'text=CI/CD Logs' ) ) . toHaveAttribute ( 'href' , 'https://playwright.dev/microsoft/playwright-example-for-test/actions/runs/example-run-id' ) ;
await expect . soft ( page . locator ( 'text=Report generated on' ) ) . toContainText ( /AM|PM/ ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-chip' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-error' ) ) . not . toBeVisible ( ) ;
} ) ;
2022-04-08 23:22:14 +03:00
2022-03-23 02:28:04 +03:00
2022-05-03 02:28:14 +03:00
test ( 'should use explicitly supplied metadata' , async ( { runInlineTest , showReport , page } ) = > {
const result = await runInlineTest ( {
'uncommitted.txt' : ` uncommitted file ` ,
'playwright.config.ts' : `
2022-05-04 00:25:56 +03:00
export default { } ;
2022-05-03 02:28:14 +03:00
` ,
'example.spec.ts' : `
2022-05-04 00:25:56 +03:00
import { gitCommitInfo } from '@playwright/test/lib/plugins' ;
const { test , _addRunnerPlugin } = pwt ;
_addRunnerPlugin ( gitCommitInfo ( {
info : {
'revision.id' : '1234567890' ,
'revision.subject' : 'a better subject' ,
'revision.timestamp' : new Date ( ) ,
'revision.author' : 'William' ,
'revision.email' : 'shakespeare@example.local' ,
} ,
} ) ) ;
2022-05-03 02:28:14 +03:00
test ( 'sample' , async ( { } ) = > { expect ( 2 ) . toBe ( 2 ) ; } ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' , GITHUB_REPOSITORY : 'microsoft/playwright-example-for-test' , GITHUB_RUN_ID : 'example-run-id' , GITHUB_SERVER_URL : 'https://playwright.dev' , GITHUB_SHA : 'example-sha' } , undefined ) ;
await showReport ( ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
await page . click ( 'text=a better subject' ) ;
await expect . soft ( page . locator ( 'data-test-id=revision.id' ) ) . toContainText ( /^[a-f\d]+$/i ) ;
await expect . soft ( page . locator ( 'data-test-id=revision.id >> a' ) ) . toHaveAttribute ( 'href' , 'https://playwright.dev/microsoft/playwright-example-for-test/commit/example-sha' ) ;
await expect . soft ( page . locator ( 'data-test-id=revision.timestamp' ) ) . toContainText ( /AM|PM/ ) ;
await expect . soft ( page . locator ( 'text=a better subject' ) ) . toHaveCount ( 2 ) ;
await expect . soft ( page . locator ( 'text=William' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'text=shakespeare@example.local' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'text=CI/CD Logs' ) ) . toHaveAttribute ( 'href' , 'https://playwright.dev/microsoft/playwright-example-for-test/actions/runs/example-run-id' ) ;
await expect . soft ( page . locator ( 'text=Report generated on' ) ) . toContainText ( /AM|PM/ ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-chip' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-error' ) ) . not . toBeVisible ( ) ;
} ) ;
2022-03-23 02:28:04 +03:00
2022-05-03 02:28:14 +03:00
test ( 'should not have metadata by default' , async ( { runInlineTest , showReport , page } ) = > {
const result = await runInlineTest ( {
'uncommitted.txt' : ` uncommitted file ` ,
'playwright.config.ts' : `
2022-05-04 00:25:56 +03:00
export default { } ;
2022-05-03 02:28:14 +03:00
` ,
'example.spec.ts' : `
const { test } = pwt ;
test ( 'my sample test' , async ( { } ) = > { expect ( 2 ) . toBe ( 2 ) ; } ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } , undefined ) ;
await showReport ( ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
await expect . soft ( page . locator ( 'text="my sample test"' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-error' ) ) . not . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-chip' ) ) . not . toBeVisible ( ) ;
} ) ;
test ( 'should not include metadata if user supplies invalid values via metadata field' , async ( { runInlineTest , showReport , page } ) = > {
const result = await runInlineTest ( {
'uncommitted.txt' : ` uncommitted file ` ,
'playwright.config.ts' : `
2022-05-04 00:25:56 +03:00
export default {
2022-05-03 02:28:14 +03:00
metadata : {
'revision.timestamp' : 'hi' ,
} ,
2022-05-04 00:25:56 +03:00
} ;
2022-05-03 02:28:14 +03:00
` ,
'example.spec.ts' : `
const { test } = pwt ;
test ( 'my sample test' , async ( { } ) = > { expect ( 2 ) . toBe ( 2 ) ; } ) ;
` ,
} , { reporter : 'dot,html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } ) ;
await showReport ( ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
await expect . soft ( page . locator ( 'text="my sample test"' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-error' ) ) . toBeVisible ( ) ;
await expect . soft ( page . locator ( 'data-test-id=metadata-chip' ) ) . not . toBeVisible ( ) ;
} ) ;
2022-03-23 02:28:04 +03:00
} ) ;
2022-06-19 01:47:26 +03:00
test ( 'should report clashing folders' , async ( { runInlineTest } ) = > {
const result = await runInlineTest ( {
'playwright.config.ts' : `
module .exports = {
reporter : [ [ 'html' , { outputFolder : 'test-results/html-report' } ] ]
}
` ,
'a.test.js' : `
const { test } = pwt ;
test ( 'passes' , async ( { } ) = > {
} ) ;
` ,
} , { } , { } , { usesCustomReporters : true } ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
const output = stripAnsi ( result . output ) ;
expect ( output ) . toContain ( 'Configuration Error' ) ;
expect ( output ) . toContain ( 'html-report' ) ;
} ) ;
2022-09-26 21:01:43 +03:00
test . describe ( 'report location' , ( ) = > {
test ( 'with config should create report relative to config' , async ( { runInlineTest } , testInfo ) = > {
const result = await runInlineTest ( {
'nested/project/playwright.config.ts' : `
module .exports = { reporter : [ [ 'html' , { outputFolder : '../my-report/' } ] ] } ;
` ,
'nested/project/a.test.js' : `
const { test } = pwt ;
test ( 'one' , async ( { } ) = > {
expect ( 1 ) . toBe ( 1 ) ;
} ) ;
` ,
} , { reporter : '' , config : './nested/project/playwright.config.ts' } ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( fs . existsSync ( testInfo . outputPath ( path . join ( 'nested' , 'my-report' , 'index.html' ) ) ) ) . toBeTruthy ( ) ;
} ) ;
test ( 'without config should create relative to package.json' , async ( { runInlineTest } , testInfo ) = > {
const result = await runInlineTest ( {
'foo/package.json' : ` { "name": "foo" } ` ,
// unused config along "search path"
'foo/bar/playwright.config.js' : `
module .exports = { projects : [ { } ] } ;
` ,
'foo/bar/baz/tests/a.spec.js' : `
const { test } = pwt ;
const fs = require ( 'fs' ) ;
test ( 'pass' , ( { } , testInfo ) = > {
} ) ;
`
} , { 'reporter' : 'html' } , { PW_TEST_HTML_REPORT_OPEN : 'never' } , {
cwd : 'foo/bar/baz/tests' ,
usesCustomOutputDir : true
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
expect ( fs . existsSync ( testInfo . outputPath ( 'playwright-report' ) ) ) . toBe ( false ) ;
expect ( fs . existsSync ( testInfo . outputPath ( 'foo' , 'playwright-report' ) ) ) . toBe ( true ) ;
expect ( fs . existsSync ( testInfo . outputPath ( 'foo' , 'bar' , 'playwright-report' ) ) ) . toBe ( false ) ;
expect ( fs . existsSync ( testInfo . outputPath ( 'foo' , 'bar' , 'baz' , 'tests' , 'playwright-report' ) ) ) . toBe ( false ) ;
} ) ;
test ( 'with env var should create relative to cwd' , async ( { runInlineTest } , testInfo ) = > {
const result = await runInlineTest ( {
'foo/package.json' : ` { "name": "foo" } ` ,
// unused config along "search path"
'foo/bar/playwright.config.js' : `
module .exports = { projects : [ { } ] } ;
` ,
'foo/bar/baz/tests/a.spec.js' : `
const { test } = pwt ;
const fs = require ( 'fs' ) ;
test ( 'pass' , ( { } , testInfo ) = > {
} ) ;
`
} , { 'reporter' : 'html' } , { 'PW_TEST_HTML_REPORT_OPEN' : 'never' , 'PLAYWRIGHT_HTML_REPORT' : '../my-report' } , {
cwd : 'foo/bar/baz/tests' ,
usesCustomOutputDir : true
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
expect ( result . passed ) . toBe ( 1 ) ;
expect ( fs . existsSync ( testInfo . outputPath ( 'foo' , 'bar' , 'baz' , 'my-report' ) ) ) . toBe ( true ) ;
} ) ;
} ) ;