cucumber / cucumber-js

Cucumber for JavaScript
https://cucumber.io
MIT License
5.04k stars 1.09k forks source link

playwright cucumber "attach" function the screenshot and video files attaching to the Cucumber report is not working. #2278

Closed preethinaren closed 1 year ago

preethinaren commented 1 year ago

👓 What did you see?

✅ What did you expect to see?

📦 Which tool/library version are you using?

🔬 How could we reproduce it?

Steps to reproduce the behavior: I am facing same issue. attach function the screenshot and video files attaching to the Cucumber report is not working. can someone please help ? const playwright = require('@playwright/test') const { Before, After, Status, setDefaultTimeout,setWorldConstructor,attach} = require('@cucumber/cucumber') //const { attach } = require('playwright/lib/helper'); const fs = require("fs-extra"); const url = require('../helper/util/test-data/environmentURL.json')

setDefaultTimeout(60000)

class CustomWorld { constructor() { this.screenshotPath = '' this.videoPath = '' } }

setWorldConstructor(CustomWorld)

// Before every scenario, Create new context and page Before(async () => { console.log('Launch Browser') // Giving browser- Chromium and headed mode global.browser = await playwright['chromium'].launch({ headless: false ,slowMo: 1000})

console.log('Create new context and page') global.context = await global.browser.newContext({ recordVideo: { dir: "test-results/videos", }, }); global.page = await global.context.newPage() await global.page.setViewportSize({ width: 1920, height: 1080 }); await global.page.goto(url.defaultURL); await global.page.waitForTimeout(2000); })

// After every scenario, Close context and page After(async (scenario) => { //screenshots let img; let videoPath; const timestamp = new Date().toISOString().replace(/:/g, '-'); const screenshotName = ${scenario.pickle.name}-${timestamp}.png; const videoName = ${scenario.pickle.name}-${timestamp}.webm; if(scenario.result.status === Status.FAILED){ img = await global.page.screenshot({ path: ./test-results/screenshots/${screenshotName}, type: "png", fullPage: true }); this.screenshotPath = img videoPath = await global.page.video().path(); this.videoPath = fs.readFileSync(videoPath) }

console.log('Close context and page') await global.page.close() await global.context.close()

console.log('Close Browser') await global.browser.close() if (this.screenshotPath) { attach(this.screenshotPath, "image/png"); } if (this.videoPath) { attach(this.videoPath, 'video/webm',videoName); } })

📚 Any additional context?


This text was originally generated from a template, then edited by hand. You can modify the template here.

davidjgoss commented 1 year ago

Cucumber doesn’t export an “attach” function, but it’s available on the default World. Your custom world class should extend the default one and then you can call “this.attach”.

Related docs:

preethinaren commented 1 year ago

Hi @davidjgoss I try your solutions, still not working. failed screenshot and video not attach to the "cucumber" report hooks.Js:

const playwright = require('@playwright/test'); const { Before, After, AfterStep, setDefaultTimeout, setWorldConstructor, Status } = require('@cucumber/cucumber'); const { screenshot } = require('playwright-video'); const fs = require("fs-extra"); const url = require('../helper/util/test-data/environmentURL.json');

process.env.ETHEREAL_CACHE = false; setDefaultTimeout(60000);

class CustomWorld { constructor() { this.attachImage = this.attachImage.bind(this); }

attachImage(buffer, mimeType) { const encodedImage = buffer.toString('base64'); return attach(encodedImage, mimeType); } }

setWorldConstructor(CustomWorld);

// Before every scenario, create new context and page Before(async () => { console.log('Launch Browser'); // Giving browser- Chromium and headed mode global.browser = await playwright['chromium'].launch({ headless: false, slowMo: 1000 }); console.log('Create new context and page'); global.context = await global.browser.newContext({ recordVideo: { dir: "test-results/videos", }, }); global.page = await global.context.newPage(); await global.page.setViewportSize({ width: 1920, height: 1080 }); await global.page.goto(url.defaultURL); await global.page.waitForTimeout(2000); });

// After every scenario, capture screenshot and video and close context and page After(async function (scenario) { if (scenario.result.status === Status.FAILED) { const screenshotBuffer = await global.page.screenshot(); const screenshotPath = ./test-results/screenshots/${Date.now()}.png; fs.ensureDirSync('./test-results/screenshots'); fs.writeFileSync(screenshotPath, screenshotBuffer); const videoBuffer = await global.page.video().saveAsVideo(); const videoPath = ./test-results/videos/${Date.now()}.mp4; fs.ensureDirSync('./test-results/videos'); fs.writeFileSync(videoPath, videoBuffer); this.attachImage(screenshotBuffer, 'image/png'); this.attach(videoBuffer, 'video/mp4'); }

console.log('Close context and page'); await global.page.close(); await global.context.close(); console.log('Close Browser'); await global.browser.close(); });

report.js:

const report = require("multiple-cucumber-html-reporter");

report.generate({ jsonDir: "test-results", reportPath: "test-results/reports/", reportName: "Playwright Automation Report", pageTitle: "SliverNest TestAutomation report", displayDuration: false, metadata: { browser: { name: "chrome", version: "XX", }, device: "Local test machine", platform: { name: "Windows", version: "11", }, }, });

preethinaren commented 1 year ago

@davidjgoss could you please help me, do we have any other solutions?

Package.js: "@cucumber/cucumber": "^9.1.0", "@cucumber/pretty-formatter": "^1.0.0", "@playwright/test": "^1.32.3", "multiple-cucumber-html-reporter": "^3.3.0"

michael-lloyd-morris commented 1 year ago

You're still using a CustomWorld that is not extending from the default world. Please read the referenced documentation.

preethinaren commented 1 year ago

@michael-lloyd-morris and @davidjgoss Thank you for the reply, please help me with other issue. with below code: I see screenshot and video attach to cucumber report but when we have test like scenario outline with table , Cucumber JSON report fails to generate report status as fail when test actually fail in console but reporting is saying test is passed.

code: const playwright = require('@playwright/test') const { Before, After, Status, setDefaultTimeout, BeforeAll, AfterAll } = require('@cucumber/cucumber') const fs = require("fs-extra"); const url = require('../helper/util/test-data/environmentURL.json') process.env.ETHEREAL_CACHE=false; setDefaultTimeout(60000)

// To launch the browser before all the scenarios BeforeAll(async () => { console.log('Launch Browser') // Giving browser- Chromium and headed mode process.env.ETHEREAL_CACHE = false; global.browser = await playwright['chromium'].launch({ headless: false }) })

// Before every scenario, Create new context and page Before(async () => { console.log('Create new context and page') global.context = await global.browser.newContext({ recordVideo: { dir: "test-results/videos", }, }); global.page = await global.context.newPage() await global.page.setViewportSize({ width: 1920, height: 1080 }); await global.page.goto(url.defaultURL); await global.page.waitForTimeout(2000); })

// After every scenario, Close context and page After(async function (testCase) { if (testCase.result.status === Status.FAILED) { var base64String = await getScreenshotOfError(); const buffer = Buffer.from(base64String, 'base64'); this.attach(buffer, 'image/png');

// Get the video path
const videoPath = await global.page.video().path();
// Read the video file as a buffer
const videoBuffer = await fs.readFile(videoPath);
// Attach the video buffer as an attachment to the test case
this.attach(videoBuffer, 'video/mp4');

} await global.page.close() await global.context.close() })

// To close the browser after all the scenarios AfterAll(async () => { console.log('Close Browser') await global.browser.close() })

async function getScreenshotOfError() { // Capture a screenshot of the current page const screenshotBuffer = await global.page.screenshot({ fullPage: true });

// Encode the screenshot buffer as a base64-encoded string const base64Screenshot = screenshotBuffer.toString('base64');

// Return the base64-encoded string return base64Screenshot; }

Package.json "devDependencies": { "@cucumber/cucumber": "^9.1.0", "@cucumber/pretty-formatter": "^1.0.0", "@playwright/test": "^1.33.0", "multiple-cucumber-html-reporter": "^3.3.0" },

feature file: Scenario Outline: HomeSeeker Signup Wizard using location Given navigate to get started page and click on HomeSeeker button Then user enters HomeSeeker Location "" and "" Then create dynamic SMPT emailID using nodemailer and create HomeSeeker account and click on token url to verify the account Then Fill out the tell us about yourself section and upload profile photo for HomeSeeker Then Fill out the tell us about yourself section and enter gender details "", and enter sexual orientation details "",and enter DOB "" Then Answer the question for Do you smoke? "" and Do you have pets? "" and select workscedule "" Then Fill out the tell us about your ideal roommate section, and enter expecting housemate age "", and enter expecting housemategenderoption "" with gender details"" and sexual orientation options "" with sexual orientation detail "" Then Fill out the tell us about your ideal roomate for, Are you okay with smoking? "" and Are you okay with smoking? "" and Are you okay with pets in the house? "" Then Fill out the tell us about your rental preferences section, What is your search radius? "" and What is your desired lease length? "" and What is your rental budget? "" Then Go to the review section, create your profile page section and click on publish my profile button Then Verify the success the message, You've just listed your profile! is displayed Examples: | HSLocation | City |gender |sexualorientation |DOB |smokeoptions |petsoptions|workscedule |HMage |genderoption|orientationoption|smoke |firearms |pets | lease |radius |budget| | Denver CO, USA | Denver | Male | Heterosexual | >=65 | Yes | Yes | Mon - Fri |18 - 29 | Yes | Yes | Yes |Yes |Yes | 3 months | 15 miles | 900 | | Los Angeles CA, USA | Los Angeles | Female| Homosexual | 40-50 | No | No | Nights |30 - 39 | Yes | Yes | No |No |No | 6 months | 25 miles | 800 | | Portland OR, USA | Portland | Other | Other | >=18 to 30 | Outside smoker only| Yes | Retired |40 - 49 | Yes | Yes | No Preference|No Preference|No Preference| 9 months | 50 miles | 1000 | | Colorado Springs CO, USA| Colorado Springs| Male | Prefer not to disclose | >=65 | Yes | No | Other |50 - 64 | No | No | Yes |Yes |Yes | One year | 15 miles | 1500 | | Cañon City CO, USA | Cañon City | Female| Prefer not to disclose | 40-50 | No | Yes | Prefer not to disclose|65 and up | No | No | No |No |No | More than a year| 25 miles | 2000 | | Dallas TX, USA | Dallas | Other | Prefer not to disclose | >=18 to 30 | Outside smoker only| No | Retired |No preference| No | No | No Preference|No Preference|No Preference| 3 months | 50 miles | 700 |

davidjgoss commented 1 year ago

It's hard to know as your step code isn't posted here, only hooks. I've seen users run into issues before combining Cucumber with Playwright Test, because ultimately they're both test runners and are expecting to own the context.

I'm going to close this now, because GitHub issues aren't really how we do support. I'd recommend joining the Slack and posting in #help-cucumber-js.