playwright-pytest icon indicating copy to clipboard operation
playwright-pytest copied to clipboard

[FEATURE] Allow attaching screenshot and video into Allure report

Open YusukeIwaki opened this issue 3 years ago • 4 comments

I usually use Allure report with PyTest+Playwright.

Test code (intented to fail)

from playwright.sync_api import Page


def test_github_search(page: Page):
    page.goto('https://github.com/')
    page.focus('input[name="q"]')
    page.keyboard.type('playwright')
    with page.expect_navigation():
        page.keyboard.press('Enter')
    first_item = page.query_selector_all('.repo-list-item')[0]
    assert 'Playwright' in first_item.text_content()

Motivation

I want to store the video for failed tests. I don't want to keep sitting at the laptop for observing flaky test failure :)

So I used to attach video into Allure report. https://zenn.dev/yusukeiwaki/articles/cfda648dc170e5#%E3%83%86%E3%82%B9%E3%83%88%E5%A4%B1%E6%95%97%E6%99%82%E3%81%AE%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88%E3%81%AB%E5%8B%95%E7%94%BB%E3%82%92%E6%B7%BB%E4%BB%98%E3%81%99%E3%82%8B (Sorry in Japanese)

image

When we handle a lot of test cases, it is useful to put screenshot and video into Allure report (not in test-report directory), because it is really hard to find the video file from a list of many files for each failure.

Problem

#70 brought very useful feature. Thank you :)

However it doesn't put video and screenshots into Allure report as attachments. For putting them into Allure report, we still have to write the script like below.

from playwright.sync_api import Page
import pytest
import allure
from slugify import slugify


def pytest_runtest_makereport(item, call) -> None:
    if call.when == "call":
        if call.excinfo is not None and "page" in item.funcargs:
            page: Page = item.funcargs["page"]

            # ref: https://stackoverflow.com/q/29929244
            allure.attach(
                page.screenshot(type='png'),
                name=f"{slugify(item.nodeid)}.png",
                attachment_type=allure.attachment_type.PNG
            )

            video_path = page.video.path()
            page.context.close()  # ensure video saved
            allure.attach(
                open(video_path, 'rb').read(),
                name=f"{slugify(item.nodeid)}.webm",
                attachment_type=allure.attachment_type.WEBM
            )


@pytest.fixture()
def browser_context_args(browser_context_args, tmpdir_factory: pytest.TempdirFactory):
    return {
        **browser_context_args,
        "record_video_dir": tmpdir_factory.mktemp('videos')
    }

Feature Request

Attach screenshot and videos into Allure report when --alluredir is specified (of cource only when --video=on/retain-on-failure or --screenshot=on/retain-on-failure is specified)

YusukeIwaki avatar Sep 24 '21 14:09 YusukeIwaki

@YusukeIwaki curious did you get similar code to work for trace zip file to attach to allure report? and just so understand your code does this only attach video/screenshot on failure? or this actually integrating with --video=on option? from testing think just on failure (is getting to run all as simple as changing if call.excinfo is not None and "page" in item.funcargs to instead be if "page" in item.funcargs ?

ksdaftari avatar Mar 21 '22 04:03 ksdaftari

One thing (and perhaps this question best serviced and asked https://github.com/microsoft/playwright-python) but was thinking that would be nice in general for screenshot/videos/trace if had option to get file so could and just use allure.attach. would have similar code when using selenium that would something like below

allure.attach(driver.get_screenshot_as_png(), name=description, attachment_type=allure.attachment_type.PNG)

ksdaftari avatar Mar 21 '22 04:03 ksdaftari

Hello, it's a kind follow-up if this feature request will be worked on. Thanks!

CB-KevinChow avatar Jun 22 '23 00:06 CB-KevinChow

@YusukeIwaki I saw your article and I like your solution and it does attach screenshot and videos on test failure, however with my current setup in addition to your makereport function, I seem to have a slight conflicting problem. the problem is because it is a session scoped fixture, if one test fails - it disables the rest of the tests in the same file resulting in an error that the target context is already closed, and if I don't closed the context manually like you did in the fixture, the video does not actually get attached, do you have a workaround maybe for this issue?

my current setup:

import os

import allure import pytest from playwright.sync_api import Page from slugify import slugify import json

@pytest.fixture(scope='function', autouse=True) def goto(page, request): base_url = request.config.getoption("--base-url") print("Base URL:", base_url) page.goto(base_url)

@pytest.fixture(scope="session") def playwright_launch_args(): launch_options = {} if os.environ.get('CI'): launch_options['headless'] = True else: launch_options['headless'] = False launch_options['slow_mo'] = 500 return launch_options

@pytest.fixture(scope="session") def playwright_context_args(): return { "viewport": {"width": 1400, "height": 900}, }

@pytest.fixture(scope="session") def browser_type(playwright, request): specified_browser = request.config.getoption("--custom-browser") return playwright[specified_browser]

@pytest.fixture(scope="session") def page_context(browser_type, playwright_launch_args, playwright_context_args): browser = browser_type.launch(**playwright_launch_args) context = browser.new_context(**playwright_context_args, record_video_dir="videos/") yield context context.close() browser.close()

@pytest.fixture(scope="function", autouse=True) def page(page_context): page: Page = page_context.new_page() yield page page.close()

def pytest_runtest_makereport(item, call) -> None: if call.when == "call": if call.excinfo is not None and "page" in item.funcargs: page: Page = item.funcargs["page"] allure.attach( page.screenshot(type='png'), name=f"{slugify(item.nodeid)}.png", attachment_type=allure.attachment_type.PNG ) video_path = page.video.path() page.context.close() # ensure video saved allure.attach( open(video_path, 'rb').read(), name=f"{slugify(item.nodeid)}.webm", attachment_type=allure.attachment_type.WEBM )

Romarionijim avatar Mar 24 '24 09:03 Romarionijim