【pytest、playwright】allure报告生成视频和图片

news/2024/5/10 16:23:38

目录

1、修改插件pytest_playwright

2、conftest.py配置

3、修改pytest.ini文件

4、运行case

5、注意事项


1、修改插件pytest_playwright

 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
from typing import Any, Callable, Dict, Generator, List, Optionalimport pytest
from playwright.sync_api import (Browser,BrowserContext,BrowserType,Error,Page,Playwright,sync_playwright,
)
from slugify import slugify
import tempfile
import allureartifacts_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 filespassdef 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 plugins
# 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 objectoutcome = yieldrep = 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] = []# Allowlistonly_marker = item.get_closest_marker(f"only_{value_name}")if only_marker:skipped_values = valuesskipped_values.remove(only_marker.args[0])# Denylistskip_marker = item.get_closest_marker(f"skip_{value_name}")if skip_marker:skipped_values.append(skip_marker.args[0])return skipped_valuesdef pytest_runtest_setup(item: Any) -> None:if not hasattr(item, "callspec"):returnbrowser_name = item.callspec.params.get("browser_name")if not browser_name:returnskip_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"] = Falseelif VSCODE_PYTHON_EXTENSION_ID in sys.argv[0] and _is_debugger_attached():# When the VSCode debugger is attached, then launch the browser headed by defaultlaunch_options["headless"] = Falsebrowser_channel_option = pytestconfig.getoption("--browser-channel")if browser_channel_option:launch_options["channel"] = browser_channel_optionslowmo_option = pytestconfig.getoption("--slowmo")if slowmo_option:launch_options["slow_mo"] = slowmo_optionreturn launch_optionsdef _is_debugger_attached() -> bool:pydevd = sys.modules.get("pydevd")if not pydevd or not hasattr(pydevd, "get_global_debugger"):return Falsedebugger = pydevd.get_global_debugger()if not debugger or not hasattr(debugger, "is_attached"):return Falsereturn 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_urlvideo_option = pytestconfig.getoption("--video")capture_video = video_option in ["on", "retain-on-failure"]if capture_video:context_args["record_video_dir"] = artifacts_folder.namereturn context_args@pytest.fixture(scope="session")
def playwright() -> Generator[Playwright, None, None]:pw = sync_playwright().start()yield pwpw.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 browserreturn launch@pytest.fixture(scope="session")
def browser(launch_browser: Callable[[], Browser]) -> Generator[Browser, None, None]:browser = launch_browser()yield browserbrowser.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 failurefailed = request.node.rep_call.failed if hasattr(request.node, "rep_call") else Trueif 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:print("--------------------------111")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")print(f'-----------------{screenshot_path}')try:page.screenshot(timeout=5000, path=screenshot_path)allure.attach.file(screenshot_path,name=f"{request.node.name}-{human_readable_status}-{index + 1}",attachment_type=allure.attachment_type.PNG)except Error:passcontext.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.videoif not video:continuetry:video_path = video.path()file_name = os.path.basename(video_path)file_path = _build_artifact_test_folder(pytestconfig, request, file_name)video.save_as(path=file_path)# 放入视频allure.attach.file(file_path, 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 experiencebrowser_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.",)

主要修改了原插件的哪些内容:

你们搜索这个文件内容,关于allure的内容,都是我们做了修改的~

2、conftest.py配置

删除原本安装的pytest_playwright插件:

在settiings中找到pytest_playwright,点击减号就可以删除了~

3、修改pytest.ini文件

 --tracing=retain-on-failure--screenshot=only-on-failure--video=retain-on-failure

4、运行case

此时运行case,当case失败时,我们可以看到这个目录:

里面就是截图,录屏,以及路由追踪~

5、注意事项

如果conftest.py中配置了如下内容:

 

要保证json文件中有值,否则会报错~


http://www.mrgr.cn/p/21237427

相关文章

政安晨:【Keras机器学习实践要点】(六)—— 使用内置方法进行训练和评估

政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎机器学习 希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正! 本文涵盖使用内置 API 进行训练和验证&#…

libVLC 视频抓图

Windows操作系统提供了多种便捷的截图方式,常见的有以下几种: 全屏截图:通过按下PrtSc键(Print Screen),可以截取整个屏幕的内容。截取的图像会保存在剪贴板中,可以通过CtrlV粘贴到图片编辑工具…

python学习14:python中的表达式

python中的表达式 1.表达式是什么呢? 表达式就是一个具有明确结果的代码语句,如11、type(‘字符串’)、3*5等 在定义变量的时候,如age108,等号右侧的就是表达式,也就是有具体的结果,将结果赋值给了等号左侧的变量 2.…

CCF-CSP认证考试 202212-3 JPEG 解码 100分题解

更多 CSP 认证考试题目题解可以前往:CSP-CCF 认证考试真题题解 原题链接: 202212-3 JPEG 解码 时间限制: 1.0s 内存限制: 512.0MB 问题背景 四年一度的世界杯即将画上尾声。在本次的世界杯比赛中,视频助理裁判&…

Jenkins安装配置部署

Jenkins安装配置部署 一、什么是CI/CD 1.CI(Continuous integration) 中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了 新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码…

【保姆级教程】使用SeaTunnel同步Kafka的数据到ClickHouse

1.Apache SeaTunnel依赖地址 2.SeaTunnel官网的Source/Sink模板 3.SeaTunnel的GitHub地址 在官网下载安装包之后,(注意:别下载apache-seatunnel-incubating-2.1.0-bin.tar.gz版本,依赖和功能都没有。)要使用apache-seatunnel-2.3…

一个基于.NET Core构建的简单、跨平台、模块化的商城系统

商城后台管理端功能 商品:分类、品牌、单位、选项(销售属性)、属性、属性模板、属性组。 销售:订单、物流。 内容:首页配置、评论、回复。 配置:国家、用户、仓库、运费、高级设置。 系统:系…

标定系列——预备知识-OpenCV中实现Rodrigues变换的函数(二)

标定系列——预备知识-OpenCV中实现Rodrigues变换的函数(二) 说明记录 说明 简单介绍罗德里格斯变换以及OpenCV中的实现函数 记录

2024年云计算使用报告,89%组织用多云,25%广泛使用生成式AI,45%需要跨云数据集成,节省成本是云首要因素

备注:本文来自Flexera2024年的云现状调研报告的翻译。原报告地址: https://info.flexera.com/CM-REPORT-State-of-the-Cloud Flexera是一家专注于做SaaS的IT解决方案公司,有30年发展历史,5万名客户,1300名员工。Flex…

设计模式之建造者模式精讲

也叫生成器模式。将一个复杂的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 在建造者模式中,有如下4个角色: 抽象建造者(Builder):用于规范产品的各个组成部分,并进行抽象&…

【前端学习——css篇】1.css的盒模型

https://github.com/febobo/web-interview 1.css的盒模型 html中的所有元素都是一个盒子,组成包括:内容content、内边距padding、边框border、外边距margin content,即实际内容,显示文本和图像 boreder,即边框&#…

书生浦语大模型实战营第一课笔记

书生浦语大模型全链路开源体系 课程笔记大模型的发展趋势InternLM2的主要亮点模型到应用的典型流程全链路的开源工具 InternLM2技术报告笔记大型语言模型的发展InternEvoModel Structure训练数据 课程笔记 第一节课主要对大模型进行介绍,特别是书生浦语大模型的发展…

每日一题 --- 链表相交[力扣][Go]

链表相交 题目:面试题 02.07. 链表相交 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 图示两个链表在节点 c1 开始相交**:** 题目数据 保证 整个链式结…

Windows直接运行python程序

Windows直接运行python程序 一、新建bat脚本二、新建vbs脚本 一、新建bat脚本 新建bat批处理脚本,写入以下内容 echo off call conda activate pytorch python app.pyecho off:在此语句后所有运行的命令都不显示命令行本身,但是本身的指令是…

【软考---系统架构设计师】网络规划与设计

目录 一、需求分析 二、通信规范分析 三、逻辑网络设计 四、物理网络设计 五、实施阶段 六、分层设计 网络规划与设计大致分为五步: (1)需求分析 (2)通信规范分析 (3)逻辑网络设计 &#x…

HTTP 请求走私实现以及攻击案例

HTTP 请求走私实现以及攻击案例。 HTTP请求走私(HTTP Request Smuggling)是一种Web安全漏洞,它涉及到HTTP协议的不安全实现,特别是在处理多个HTTP请求时。这种漏洞可以被利用在多种场景中,导致不同的安全问题。以下是一些主要的漏洞和应用场景: 1. 缓存投毒(Cache Pois…

使用patchelf解决vscode远程连接不支持低版本glibc的问题

使用patchelf解决vscode远程连接不支持低版本glibc的问题 目录 使用patchelf解决vscode远程连接不支持低版本glibc的问题1. 动态链接库下载2. 用 patchelf 修改 vscode-server 依赖的 glibc 版本 VScode 1.86 版本的 remote 要求 glibc 2.28 及以上,于是在各种旧版本…

数据链路层协议之以太网协议

以太网协议是通过网线/光纤进行通信。这和通过wifi(无线),通过移动流量(4G/5G)通信不一样。以太网,横跨数据链路层和物理层 一.以太网数据帧格式 包括了帧头载荷(IP数据报)帧尾。 1.目的地址 源地址 分别…

MFC标签设计工具 图片控件上,移动鼠标显示图片控件内的鼠标xy的水平和垂直辅助线要在标签模板上加上文字、条型码、二维码 找准坐标和字体大小 源码

需求:要在标签模板上加上文字、条型码、二维码 找准坐标和字体大小 我生成标签时,需要对齐和 调文字字体大小。这工具微调 能快速知道位置 和字体大小。 标签设计(点击图片,上下左右箭头移动 或-调字体) 已经够用了,滚动条还没完…

mac-git上传至github(ssh版本,个人tokens总出错)

第一步 git clone https://github.com/用户名/项目名.git 第二步 cd 项目名 第三步 将本地的文件移动到项目下 第四步 git add . 第五步 git commit -m "添加****文件夹" 第六步 git push origin main 报错: 采用ssh验证 本地文件链接公钥 …