【playwright】pytest-playwright与allure结合,生成报告带有图片和录屏

2023-05-16

依赖的环境

  1. 需要安装allure命令行工具以及allure-pytest插件

  2. pytest-playwright需要升级0.3.0版本,改版本支持如下参数:

Playwright:
 --browser={chromium,firefox,webkit}
                       Browser engine which should be used
 --headed              Run tests in headed mode.
 --browser-channel=BROWSER_CHANNEL
                       Browser channel to be used.
 --slowmo=SLOWMO       Run tests with slow mo
 --device=DEVICE       Device to be emulated.
 --output=OUTPUT       Directory for artifacts produced by tests, defaults to test-results.
 --tracing={on,off,retain-on-failure}
                       Whether to record a trace for each test.
 --video={on,off,retain-on-failure}
                       Whether to record video for each test.
 --screenshot={on,off,only-on-failure}
                       Whether to automatically capture a screenshot after each test.

调整pytest-playwright.py文件

调整该文件的目的是想再使用如下命令:
pytest --video=on --screenshot=on --alluredir=./report/xml
该命令的是执行过程对每个用例进行录屏和截屏,并把执行数据输入到xml中。如果不调整pytest-playwright.py脚本,allure报告中是无法享用录屏和截屏数据,那如何让allure报告中使用该部分数据呢?需要对pytest-playwright.py进行如下调整:

  1. 进入到pytest_playwright安装目录
    在这里插入图片描述
    2.编辑pytest_playwright.py
    在这里插入图片描述
#把截图放入allure报告
allure.attach.file(screenshot_path,name=f"{request.node.name}-{human_readable_status}-{index+1}",attachment_type=allure.attachment_type.PNG)

在这里插入图片描述

#放入视频
allure.attach.file(filepath,name=f"{request.node.name}-{human_readable_status}-{index+1}",attachment_type=allure.attachment_type.WEBM)

在这里插入图片描述
做出如上三部分调整,再次执行allure报告生成会在

pytest  --video=on --screenshot=on --alluredir=./report/xml
allure generate --clean ./report/xml -o ./report/html
allure open ./report/html

Tear down的context展示截图和视频:
在这里插入图片描述

附件

调整的pytest_playwright.py文件

# 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.

import shutil
import os
import sys
import warnings
import allure
from typing import Any, Callable, Dict, Generator, List, Optional

import pytest
from playwright.sync_api import (
    Browser,
    BrowserContext,
    BrowserType,
    Error,
    Page,
    Playwright,
    sync_playwright,
)
from slugify import slugify
import tempfile


artifacts_folder = tempfile.TemporaryDirectory(prefix="playwright-pytest-")


@pytest.fixture(scope="session", autouse=True)
def delete_output_dir(pytestconfig: Any) -> None:
    output_dir = pytestconfig.getoption("--output")
    if os.path.exists(output_dir):
        try:
            shutil.rmtree(output_dir)
        except FileNotFoundError:
            # When running in parallel, another thread may have already deleted the files
            pass


def pytest_generate_tests(metafunc: Any) -> None:
    if "browser_name" in metafunc.fixturenames:
        browsers = metafunc.config.option.browser or ["chromium"]
        metafunc.parametrize("browser_name", browsers, scope="session")


def pytest_configure(config: Any) -> None:
    config.addinivalue_line(
        "markers", "skip_browser(name): mark test to be skipped a specific browser"
    )
    config.addinivalue_line(
        "markers", "only_browser(name): mark test to run only on a specific browser"
    )


# Making test result information available in fixtures
# https://docs.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item: Any) -> Generator[None, Any, None]:
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()

    # set a report attribute for each phase of a call, which can
    # be "setup", "call", "teardown"

    setattr(item, "rep_" + rep.when, rep)


def _get_skiplist(item: Any, values: List[str], value_name: str) -> List[str]:
    skipped_values: List[str] = []
    # Allowlist
    only_marker = item.get_closest_marker(f"only_{value_name}")
    if only_marker:
        skipped_values = values
        skipped_values.remove(only_marker.args[0])

    # Denylist
    skip_marker = item.get_closest_marker(f"skip_{value_name}")
    if skip_marker:
        skipped_values.append(skip_marker.args[0])

    return skipped_values


def pytest_runtest_setup(item: Any) -> None:
    if not hasattr(item, "callspec"):
        return
    browser_name = item.callspec.params.get("browser_name")
    if not browser_name:
        return

    skip_browsers_names = _get_skiplist(
        item, ["chromium", "firefox", "webkit"], "browser"
    )

    if browser_name in skip_browsers_names:
        pytest.skip("skipped for this browser: {}".format(browser_name))


VSCODE_PYTHON_EXTENSION_ID = "ms-python.python"


@pytest.fixture(scope="session")
def browser_type_launch_args(pytestconfig: Any) -> Dict:
    launch_options = {}
    headed_option = pytestconfig.getoption("--headed")
    if headed_option:
        launch_options["headless"] = False
    elif VSCODE_PYTHON_EXTENSION_ID in sys.argv[0] and _is_debugger_attached():
        # When the VSCode debugger is attached, then launch the browser headed by default
        launch_options["headless"] = False
    browser_channel_option = pytestconfig.getoption("--browser-channel")
    if browser_channel_option:
        launch_options["channel"] = browser_channel_option
    slowmo_option = pytestconfig.getoption("--slowmo")
    if slowmo_option:
        launch_options["slow_mo"] = slowmo_option
    return launch_options


def _is_debugger_attached() -> bool:
    pydevd = sys.modules.get("pydevd")
    if not pydevd or not hasattr(pydevd, "get_global_debugger"):
        return False
    debugger = pydevd.get_global_debugger()
    if not debugger or not hasattr(debugger, "is_attached"):
        return False
    return debugger.is_attached()


def _build_artifact_test_folder(
    pytestconfig: Any, request: pytest.FixtureRequest, folder_or_file_name: str
) -> str:
    output_dir = pytestconfig.getoption("--output")
    return os.path.join(output_dir, slugify(request.node.nodeid), folder_or_file_name)


@pytest.fixture(scope="session")
def browser_context_args(
    pytestconfig: Any,
    playwright: Playwright,
    device: Optional[str],
) -> Dict:
    context_args = {}
    if device:
        context_args.update(playwright.devices[device])
    base_url = pytestconfig.getoption("--base-url")
    if base_url:
        context_args["base_url"] = base_url

    video_option = pytestconfig.getoption("--video")
    capture_video = video_option in ["on", "retain-on-failure"]
    if capture_video:
        context_args["record_video_dir"] = artifacts_folder.name

    return context_args


@pytest.fixture(scope="session")
def playwright() -> Generator[Playwright, None, None]:
    pw = sync_playwright().start()
    yield pw
    pw.stop()


@pytest.fixture(scope="session")
def browser_type(playwright: Playwright, browser_name: str) -> BrowserType:
    return getattr(playwright, browser_name)


@pytest.fixture(scope="session")
def launch_browser(
    browser_type_launch_args: Dict,
    browser_type: BrowserType,
) -> Callable[..., Browser]:
    def launch(**kwargs: Dict) -> Browser:
        launch_options = {**browser_type_launch_args, **kwargs}
        browser = browser_type.launch(**launch_options)
        return browser

    return launch


@pytest.fixture(scope="session")
def browser(launch_browser: Callable[[], Browser]) -> Generator[Browser, None, None]:
    browser = launch_browser()
    yield browser
    browser.close()
    artifacts_folder.cleanup()


@pytest.fixture
def context(
    browser: Browser,
    browser_context_args: Dict,
    pytestconfig: Any,
    request: pytest.FixtureRequest,
) -> Generator[BrowserContext, None, None]:
    pages: List[Page] = []
    context = browser.new_context(**browser_context_args)
    context.on("page", lambda page: pages.append(page))

    tracing_option = pytestconfig.getoption("--tracing")
    capture_trace = tracing_option in ["on", "retain-on-failure"]
    if capture_trace:
        context.tracing.start(
            name=slugify(request.node.nodeid),
            screenshots=True,
            snapshots=True,
            sources=True,
        )

    yield context

    # If requst.node is missing rep_call, then some error happened during execution
    # that prevented teardown, but should still be counted as a failure
    failed = request.node.rep_call.failed if hasattr(request.node, "rep_call") else True

    if capture_trace:
        retain_trace = tracing_option == "on" or (
            failed and tracing_option == "retain-on-failure"
        )
        if retain_trace:
            trace_path = _build_artifact_test_folder(pytestconfig, request, "trace.zip")
            context.tracing.stop(path=trace_path)
        else:
            context.tracing.stop()

    screenshot_option = pytestconfig.getoption("--screenshot")
    capture_screenshot = screenshot_option == "on" or (
        failed and screenshot_option == "only-on-failure"
    )
    if capture_screenshot:
        for index, page in enumerate(pages):
            human_readable_status = "failed" if failed else "finished"
            screenshot_path = _build_artifact_test_folder(
                pytestconfig, request, f"test-{human_readable_status}-{index+1}.png"
            )
            try:
                page.screenshot(timeout=5000, path=screenshot_path)
                #把截图放入allure报告
                allure.attach.file(screenshot_path,name=f"{request.node.name}-{human_readable_status}-{index+1}",attachment_type=allure.attachment_type.PNG)
            except Error:
                pass

    context.close()

    video_option = pytestconfig.getoption("--video")
    preserve_video = video_option == "on" or (
        failed and video_option == "retain-on-failure"
    )
    if preserve_video:
        for page in pages:
            video = page.video
            if not video:
                continue
            try:
                video_path = video.path()
                file_name = os.path.basename(video_path)
                filepath = _build_artifact_test_folder(pytestconfig, request, file_name)
                video.save_as(
                    path=filepath
                )
                #放入视频
                allure.attach.file(filepath,name=f"{request.node.name}-{human_readable_status}-{index+1}",attachment_type=allure.attachment_type.WEBM)
            except Error:
                # Silent catch empty videos.
                pass


@pytest.fixture
def page(context: BrowserContext) -> Generator[Page, None, None]:
    page = context.new_page()
    yield page


@pytest.fixture(scope="session")
def is_webkit(browser_name: str) -> bool:
    return browser_name == "webkit"


@pytest.fixture(scope="session")
def is_firefox(browser_name: str) -> bool:
    return browser_name == "firefox"


@pytest.fixture(scope="session")
def is_chromium(browser_name: str) -> bool:
    return browser_name == "chromium"


@pytest.fixture(scope="session")
def browser_name(pytestconfig: Any) -> Optional[str]:
    # When using unittest.TestCase it won't use pytest_generate_tests
    # For that we still try to give the user a slightly less feature-rich experience
    browser_names = pytestconfig.getoption("--browser")
    if len(browser_names) == 0:
        return "chromium"
    if len(browser_names) == 1:
        return browser_names[0]
    warnings.warn(
        "When using unittest.TestCase specifying multiple browsers is not supported"
    )
    return browser_names[0]


@pytest.fixture(scope="session")
def browser_channel(pytestconfig: Any) -> Optional[str]:
    return pytestconfig.getoption("--browser-channel")


@pytest.fixture(scope="session")
def device(pytestconfig: Any) -> Optional[str]:
    return pytestconfig.getoption("--device")


def pytest_addoption(parser: Any) -> None:
    group = parser.getgroup("playwright", "Playwright")
    group.addoption(
        "--browser",
        action="append",
        default=[],
        help="Browser engine which should be used",
        choices=["chromium", "firefox", "webkit"],
    )
    group.addoption(
        "--headed",
        action="store_true",
        default=False,
        help="Run tests in headed mode.",
    )
    group.addoption(
        "--browser-channel",
        action="store",
        default=None,
        help="Browser channel to be used.",
    )
    group.addoption(
        "--slowmo",
        default=0,
        type=int,
        help="Run tests with slow mo",
    )
    group.addoption(
        "--device", default=None, action="store", help="Device to be emulated."
    )
    group.addoption(
        "--output",
        default="test-results",
        help="Directory for artifacts produced by tests, defaults to test-results.",
    )
    group.addoption(
        "--tracing",
        default="off",
        choices=["on", "off", "retain-on-failure"],
        help="Whether to record a trace for each test.",
    )
    group.addoption(
        "--video",
        default="off",
        choices=["on", "off", "retain-on-failure"],
        help="Whether to record video for each test.",
    )
    group.addoption(
        "--screenshot",
        default="off",
        choices=["on", "off", "only-on-failure"],
        help="Whether to automatically capture a screenshot after each test.",
    )
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【playwright】pytest-playwright与allure结合,生成报告带有图片和录屏 的相关文章

随机推荐

  • 深度学习之 人脸识别(1) 人脸预处理

    人脸识别分两个部分 xff1a 第一步 xff1a 人脸图片预处理 xff0c 即检测图片中人脸并裁剪成指定尺寸的人脸图 第二步 xff1a 人脸识别 xff0c 包括模型训练 目标人脸分类训练 预测目标人脸 1 人脸检测原理 人脸识别 x
  • 制作自己的个人网站方法

    随着个人创业的流行 xff0c 很多个人也需要一个比较详细的网站来展示自己 xff0c 开展个人业务 xff0c 或者积累粉丝等等 那么怎么制作自己的个人网站呢 xff1f 又该怎么制作得更个性好看 xff1f 下面就跟大家分享下制作方法
  • 傻瓜书,VMware里的Ubuntu

    转自 xff1a http bbs cnw com cn thread 136057 1 1 html 傻瓜书 xff0c VMware里的Ubuntu 0 预备知识 什么是Ubuntu 如果不了解这一点 xff0c 本文的内容似乎与您无关
  • 痞子衡单片机排行榜(2022Q4)

    痞子衡单片机排行榜 2022Q4 继2020年开办的 痞子衡嵌入式半月刊 之后 xff0c 从2023年1月份开始痞子衡将为大家带来新项目 痞子衡单片机排行榜 一年分四季 xff0c 每个季度发布一期 xff0c 以MCU主频和Corema
  • [pdf]使用spire读取PDF的文字和图片

    概述 最近在梳理某项目的数据标准 xff0c 从标准网下载了很多PDF格式的标准文件 xff0c 需要提取文字和图片 xff0c 所以写了个程序提取 xff1b 本文使用了免费版的Spire 约束 免费版的Spire一次只能提取PDF的10
  • JetPack系列之ViewBinding

    viewBinding的作用启用视图绑定Activity中使用视图绑定Framgent中使用视图绑定与findViewById相比 viewBinding的作用 启用视图绑定之后 xff0c 系统会为每个xml生成一个绑定类 xff0c 我
  • 正则表达式记录

    去掉所有非1到9或者字母的其它字符 private static String dealWithVersion String versionArg String regex 61 34 1 9a zA Z 34 versionArg 61
  • 批量kill掉带有某些标识的进程的shell命令

    微信公众号 xff1a WELTest 分享一个常用命令 xff0c 批量杀掉一批进程 xff0c 这里以tomcat为例 xff1a ps ef grep tomcat awk 39 print 2 39 xargs kill 9 命令解
  • 【VUE】renren-fast-vue跳过验证码及使用mock数据单独添加一个页面

    效果图 解决办法 1 使用官方演示系统数据 1 把代理打开设置为True 2 在修改config目录下的index js的target值为 xff1a http demo open renren io renren fast server
  • 【软件测试】以闭环思维解决BUG复现率高问题

    bug复现率 要求复现BUG数 总bug数 背景 软件测试中提Bug 作为每个测试人员都应该遇到过 那每个测试人员可能也会遇到不停帮开发复现Bug的问题 如果Bug复现对环境要求不高 那复现成本还是比较低的 那如果环境复杂 那复现成本还是比
  • 自动化测试:功能移植之存储过程数据正确性验证

    自动化测试 功能移植之存储过程数据正确性验证 背景说明 系统架构的变更及调整 会引相同功能在不同架构上的移植工作 功能移植工作会产生多种变式 每种变式的测试策略是不一致的 本文主要讨论的变式为 业务不发生变动 只进行代码移植 结果表结构与原
  • docker mysql:5.6镜像安装mysqlreport、pt-query-digest

    更新debian源 echo 34 deb http ftp cn debian org debian stretch main 34 gt etc apt sources list echo 34 deb http ftp cn debi
  • 性能测试:模型趋势预测,让生产性能预测

    随着系统复杂度的提升 系统架构复杂度 部署规模也在逐步提升 这对性能测试测试 分析都带来挑战 古语有云 兵马未动粮草先行 针对测试而言测试环境及数据就是 粮草 性能测试如果环境 数据差异较大 性能测试出来的结果对生产指导意义就不是很大 那如
  • 【python黑帽子2】netcat.py编写及使用说明

    环境信息 python3 9 12 IDE为 xff1a vscode 源码 书中源码注意点 xff1a send函数中的if recv len lt 4096需要调整为if recv len lt 2 xff1a 该出的recv len值
  • 【Python黑帽子】proxy.py脚本

    span class token comment coding 61 utf 8 span span class token keyword import span sys span class token keyword import s
  • 【Jmeter】跨线程组共享数据

    背景 在性能测试中 xff0c 经常会遇见使用多线程组的情况 xff0c 例如用户登陆成功后 xff0c 对某个查询接口使用500个线程来进行压测 xff0c 这个时候就需要使用多线程组 设计说明 首先 xff0c 需要使用setUp Th
  • 【playwright】使用pytest-playwright执行用例时频繁打开浏览器

    背景说明 安装pytest playwright之后 xff0c 执行多个用例频繁打开浏览器 xff0c 而且无法给对应的fixture的scope设置为session 原因说明 pytest playwright定义了fixture的sc
  • (转)注册JNI函数的两种方式

    原文地址 http blog csdn net wwj 748 article details 52347341 前言 前面介绍过如何实现在Android Studio中制作我们自己的so库 xff0c 相信大家看过之后基本清楚如何在And
  • 【playwright】使用playwright实现拖动功能

    思路说明 使用locator定位到要拖动滑块元素 xff0c 如元素名叫ele 获取元素ele的bounding box含4分属性值 xff1a x xff0c y xff0c width xff0c height 把鼠标移动到元素ele的
  • 【playwright】pytest-playwright与allure结合,生成报告带有图片和录屏

    依赖的环境 需要安装allure命令行工具以及allure pytest插件 pytest playwright需要升级0 3 0版本 xff0c 改版本支持如下参数 xff1a Playwright browser 61 chromium