Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] is there a way to take screenshots at the exact moment of the failure? #14854

Closed
watson28 opened this issue Jun 14, 2022 · 15 comments · Fixed by #15159
Closed

[Question] is there a way to take screenshots at the exact moment of the failure? #14854

watson28 opened this issue Jun 14, 2022 · 15 comments · Fixed by #15159
Assignees

Comments

@watson28
Copy link

watson28 commented Jun 14, 2022

Playwright supports the ability to take screenshots on failed tests: https://playwright.dev/docs/test-configuration#automatic-screenshots.

However, we need to take screenshots at the exact moment of the failure and not after the test cycle. The reason is that we have afterEach/ afterAll hooks that change the states of the page, and after their execution, the issue is no longer visible.

Is there a way to achieve this, or can it be added as a new feature?

@watson28 watson28 changed the title [Question] is there a way to take screenshot at the exact moment of the failure? [Question] is there a way to take screenshots at the exact moment of the failure? Jun 14, 2022
@dimkin-eu
Copy link

+1 for this feature ( yes, I know, 👍 is enough, but :) )

@dgozman
Copy link
Contributor

dgozman commented Jun 14, 2022

There is nothing built-in for this. However, it is easy to write an afterEach hook that does this. Just make sure to put this hook before all other hooks.

/ example.spec.ts
import { test, expect } from '@playwright/test';

test.afterEach(async ({ page }, testInfo) => {
  if (testInfo.status !== testInfo.expectedStatus) {
    // Get a unique place for the screenshot.
    const screenshotPath = testInfo.outputPath(`failure.png`);
    // Add it to the report.
    testInfo.attachments.push({ name: 'screenshot', path: screenshotPath, contentType: 'image/png' });
    // Take the screenshot itself.
    await page.screenshot({ path: screenshotPath, timeout: 5000 });
  }
});

test('my test', async ({ page }) => {
  // ...
});

@dimkin-eu
Copy link

if one has many specs - this will be a sad copy-paste :(
any ideas to create something like wdio's before/after hooks?

@dgozman
Copy link
Contributor

dgozman commented Jun 14, 2022

if one has many specs - this will be a sad copy-paste :(

You can make it two lines per test file :)

// helper.ts
import type { TestInfo } from '@playwright/test';

export async function screenshotOnFailure({ page }: { page: Page }, testInfo: TestInfo) {
  if (testInfo.status !== testInfo.expectedStatus) {
    // Get a unique place for the screenshot.
    const screenshotPath = testInfo.outputPath(`failure.png`);
    // Add it to the report.
    testInfo.attachments.push({ name: 'screenshot', path: screenshotPath, contentType: 'image/png' });
    // Take the screenshot itself.
    await page.screenshot({ path: screenshotPath, timeout: 5000 });
  }
}

// example.spec.ts

import { screenshotOnFailure } from './helper';
test.afterEach(screenshotOnFailure);

@watson28
Copy link
Author

thanks for the workaround!

but is there a particular reason for the current behavior? for me, the screenshot option only-on-failure will make more sense to work at the exact moment of the failure and not afterward. I feel that should be the default behavior or at least supported as a new option.
That will avoid those conflicts of not being able to take the screenshot of the failure if you have defined after* hooks.

@dgozman
Copy link
Contributor

dgozman commented Jun 15, 2022

@watson28 It makes sense, but is a bit more nuanced. For example, if failure happens during the afterEach hook, then we should probably screenshot at that moment. I'll see what we can do.

@arsenpapoyan
Copy link

Hello, I apologize in advance if my question is not related to this topic.
What if all my test assertions are expect.soft, and when one of them fails the execution continues and the screenshot is taken at the end, thus that is not a fail but just a screenshot of the last action.
How can I get exact screenshot on failure in this case?

@cj-larsen
Copy link

For anyone looking for an alternative solution, Playwright offers a screenshot option that can be set under the use: { ... } section in the config.ts

use: {
    /* Screenshot on failure. */
    screenshot: "only-on-failure",
  }

@dimkin-eu
Copy link

@cj-larsen this is what the author doesn't want - it makes the screen at the very end, not the exact fail moment

@DiamondStalker
Copy link

For anyone looking for an alternative solution, Playwright offers a screenshot option that can be set under the use: { ... } section in the config.ts

use: {
    /* Screenshot on failure. */
    screenshot: "only-on-failure",
  }

Of all the possible solutions this was the only one able to solve my problem exactly the way I needed it.

@arsenpapoyan
Copy link

Let me explain in detail.
This is my config:
use: { screenshot: "only-on-failure", }

Test:

test("Screenshot only on failure", async ({ page }) => {

    await page.goto("https://playwright.dev/");

    await expect.soft(page.locator(".getStarted_Sjon")).toHaveText("Get start");

    await page.locator(".getStarted_Sjon").click();

    await expect.soft(page.locator(".theme-doc-markdown.markdown h1")).toHaveText("Install");

    await page.locator("//a[.='Release notes']").click();

    await expect.soft(page.locator(".theme-doc-markdown.markdown h1")).toHaveText("Release notes");

});

The first two fail, but the test is not stopped because all expects are soft.
Only one screenshot is taken and attached, but not in case of failure, but at the end of the test, that is, at the last action.
Please find the attached Allure report.

image

@corsin-ragettli
Copy link

corsin-ragettli commented Feb 26, 2024

is there a way to take a fullPage screenshot while using

{
  use: {
    screenshot: 'only-on-failure'
  }
}

?

@balpreetK
Copy link

hi , i also have same issue as arsenpapoyan described above.
We cannot leverage .soft in our tests coz of screenshots not being able to be taken at that exact failing moment.
Any solutions will be appreciated

@jake4take
Copy link

jake4take commented Apr 9, 2024

Hi! ✌️ @dgozman

Sorry, but I don't understand why you can not do a screenshot on the expect.soft as like on the expect failure.
I think it is the main feature for the fast and fulfilment testing
Maybe you can advise another realization for configure expect.soft (maybe create a custom assertion) to solve this significant omission?

@BenceSzalai
Copy link

BenceSzalai commented Oct 13, 2024

You use test.info().errors.length to check if there were any errors at any point.
If there were you know that a previous expect has failed.
If you keep a running count of the errors, you can check after any expect.soft if it has failed or not.
Whenever you detect the previous failed expect.soft has failed, you can make a screenshot using await page.screenshot() and put it in a file or attach to the report (await testInfo.attach('screenshot', { body: screenshot, contentType: 'image/png' });).
You can wrap that logic in a function that you only write once and import and reuse, e.g. expectSoft().

I'm not saying having this a default behaviour would not be nice, but it can be put in place.

Am I missing something here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants