KDTest Playwright Edition - 关键字驱动测试框架,专为 Element Plus/Vue3 优化
Project description
KDTest-Playwright
基于 Playwright 的关键字驱动测试框架,专为 Element Plus/Vue3 优化,兼容原版 kdtest 插件。
目录
安装
# 从 PyPI 安装
pip install kdtest-pw
# 安装 Playwright 浏览器
playwright install chromium
快速开始
1. 创建配置文件 parameters.json
{
"testCaseFile": [
{
"caseFilePath": "testCases.xlsx",
"caseItem": ["Sheet1"]
}
],
"browser": "chromium",
"url": "http://localhost:8080",
"headless": false,
"timeout": 30000
}
2. 创建 Excel 测试用例
| 用例ID | 用例名称 | 描述 | 关键字 | 定位方式 | 定位表达式 | 操作值 |
|---|---|---|---|---|---|---|
| TC001 | 登录测试 | |||||
| 打开网站 | driver_get | http://localhost | ||||
| 输入用户名 | input_text | xpath | //input[@placeholder='账号'] | admin | ||
| 输入密码 | input_text | css | input[type='password'] | 123456 | ||
| 点击登录 | click_btn | css | .el-button--primary | |||
| 验证登录 | text_assert | css | .user-name | admin |
3. 运行测试
# 命令行运行
kdtest-pw -c parameters.json
# 或在 Python 中使用
from kdtest_pw.cli import KDTestRunner
runner = KDTestRunner("parameters.json")
runner.setup()
runner.run()
runner.teardown()
配置文件
parameters.json 完整配置
{
"testCaseFile": [
{
"caseFilePath": "testCases.xlsx",
"caseItem": ["Sheet1", "Sheet2"]
}
],
"browser": "chromium",
"url": "http://localhost:8080",
"headless": false,
"timeout": 30000,
"slowMo": 0,
"viewport": {
"width": 1920,
"height": 1080
},
"video": false,
"screenshot": "only-on-failure",
"trace": false,
"reportDir": "./reports"
}
配置项说明
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
testCaseFile |
Array | 必填 | 测试用例文件列表 |
browser |
String | "chromium" | 浏览器类型:chromium/firefox/webkit |
url |
String | - | 初始 URL |
headless |
Boolean | false | 无头模式 |
timeout |
Number | 30000 | 全局超时时间(ms) |
slowMo |
Number | 0 | 操作延迟(ms),用于调试 |
viewport |
Object | {1920, 1080} | 视口大小 |
video |
Boolean | false | 是否录制视频 |
screenshot |
String | "only-on-failure" | 截图策略 |
trace |
Boolean | false | 是否启用 Trace |
reportDir |
String | "./reports" | 报告输出目录 |
测试用例格式
Excel 列定义
| 列名 | 说明 | 示例 |
|---|---|---|
| 用例ID | 测试用例唯一标识 | TC001 |
| 用例名称 | 测试用例名称 | 登录测试 |
| 描述 | 步骤描述(可选) | 输入用户名 |
| 关键字 | 要执行的关键字 | input_text |
| 定位方式 | 元素定位方式 | xpath/css/id/name |
| 定位表达式 | 元素定位表达式 | //input[@id='username'] |
| 操作值 | 关键字参数 | admin |
定位方式
| 定位方式 | 说明 | 示例 |
|---|---|---|
xpath |
XPath 表达式 | //div[@class='btn'] |
css |
CSS 选择器 | div.btn, #submit |
id |
元素 ID | username |
name |
元素 name 属性 | password |
text |
文本内容 | 登录 |
role |
ARIA 角色 | button |
CLI 命令
运行测试
# 基本运行
kdtest-pw -c parameters.json
# 指定浏览器
kdtest-pw -c parameters.json --browser firefox
# 无头模式
kdtest-pw -c parameters.json --headless
# 慢速模式(调试用)
kdtest-pw -c parameters.json --slow-mo 500
插件管理
# 查看已安装插件
kdtest-pw --unit_show
# 创建新插件
kdtest-pw --unit_new MyPlugin
# 安装插件
kdtest-pw --unit_install /path/to/plugin
# 卸载插件
kdtest-pw --unit_uninstall MyPlugin
其他命令
# 查看帮助
kdtest-pw --help
# 查看版本
kdtest-pw --version
核心关键字
浏览器操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
driver_get |
打开 URL | URL 地址 |
driver_back |
后退 | - |
driver_forward |
前进 | - |
driver_refresh |
刷新页面 | - |
driver_close |
关闭页面 | - |
driver_quit |
退出浏览器 | - |
输入操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
input_text |
清除并输入文本 | 要输入的文本 |
input_append |
追加输入文本 | 要追加的文本 |
input_clear |
清除输入框 | - |
keyBoard_Events |
键盘事件 | Keys.ENTER, Keys.TAB 等 |
点击操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
click_btn |
点击元素 | - |
double_click |
双击元素 | - |
right_click |
右键点击 | - |
hover |
鼠标悬停 | - |
force_click |
强制点击(跳过可见性检查) | - |
等待操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
sleep |
固定等待 | 秒数 |
wait_visible |
等待元素可见 | 超时时间(ms) |
wait_hidden |
等待元素隐藏 | 超时时间(ms) |
wait_enabled |
等待元素可用 | 超时时间(ms) |
断言操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
text_assert |
断言元素文本 | 预期文本 |
text_contains_assert |
断言文本包含 | 预期包含的文本 |
title_assert |
断言页面标题 | 预期标题 |
url_assert |
断言页面 URL | 预期 URL |
element_visible_assert |
断言元素可见 | true/false |
element_count_assert |
断言元素数量 | 预期数量 |
attribute_assert |
断言元素属性 | 属性名=预期值 |
数据操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
get_text |
获取元素文本并存储 | 变量名 |
get_attribute |
获取元素属性并存储 | 属性名,变量名 |
set_variable |
设置变量 | 变量名=值 |
cache_data |
缓存数据 | 键=值 |
Element Plus 组件
| 关键字 | 说明 | 操作值 |
|---|---|---|
el_select |
下拉选择 | 选项文本 |
el_select_multiple |
多选下拉 | 选项1,选项2 |
el_datepicker |
日期选择 | 2024-01-01 |
el_daterange |
日期范围 | 2024-01-01,2024-12-31 |
el_timepicker |
时间选择 | 12:30:00 |
el_dialog_confirm |
对话框确认 | - |
el_dialog_cancel |
对话框取消 | - |
el_message_close |
关闭消息提示 | - |
el_table_click_row |
点击表格行 | 行索引(从0开始) |
el_table_click_cell |
点击表格单元格 | 行索引,列索引 |
el_table_get_cell |
获取单元格文本 | 行索引,列索引,变量名 |
el_tree_click_node |
点击树节点 | 节点文本 |
el_tree_expand |
展开树节点 | 节点文本 |
el_cascader |
级联选择 | 一级/二级/三级 |
el_upload |
文件上传 | 文件路径 |
el_switch |
开关切换 | on/off |
el_checkbox |
复选框 | check/uncheck |
el_radio |
单选框 | 选项文本 |
el_slider |
滑块 | 数值 |
el_form_input |
表单项输入 | label=值 |
el_form_select |
表单项选择 | label=选项 |
el_pagination_goto |
分页跳转 | 页码 |
el_tab_click |
切换标签页 | 标签名 |
菜单导航
方式一:基于配置文件(适用于复杂系统)
| 关键字 | 说明 | 操作值 |
|---|---|---|
menu_load_data |
加载菜单配置 | modularInformation.json 路径 |
menu_navigate |
导航到菜单 | 一级菜单/二级菜单/三级菜单 |
menu_click_first |
点击一级菜单 | 菜单名称 |
menu_click_second |
点击二级菜单 | 一级/二级 |
menu_click_third |
点击三级菜单 | 一级/二级/三级 |
menu_switch_iframe |
切换到 iframe | 一级/二级 |
menu_exit_iframe |
退出 iframe | - |
方式二:基于文本直接定位(适用于 Element Plus 标准菜单)
| 关键字 | 说明 | 操作值 |
|---|---|---|
el_menu_navigate |
导航到菜单(无需配置) | 一级菜单/二级菜单 |
el_menu_click |
点击菜单项 | 菜单项文本 |
el_submenu_expand |
展开子菜单 | 子菜单文本 |
el_submenu_collapse |
收起子菜单 | 子菜单文本 |
el_tabs_click |
点击标签页 | 标签页文本 |
示例:
# 方式一:使用配置文件
menu_load_data | | | ./menuConfig.json
menu_navigate | | | 系统管理/用户管理
# 方式二:直接文本定位(推荐用于 Element Plus)
el_menu_navigate | | | 系统管理/用户管理
el_tabs_click | | | 待处理
Frame 操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
switch_to_frame |
切换到 frame | frame 名称/索引/定位表达式 |
switch_to_parent |
切换到父 frame | - |
switch_to_main |
切换到主文档 | - |
窗口操作
| 关键字 | 说明 | 操作值 |
|---|---|---|
switch_to_window |
切换窗口 | 窗口标题或索引 |
new_tab |
新建标签页 | URL(可选) |
close_tab |
关闭当前标签页 | - |
JavaScript 执行
| 关键字 | 说明 | 操作值 |
|---|---|---|
execute_js |
执行 JavaScript | JS 代码 |
execute_js_on_element |
在元素上执行 JS | JS 代码 |
变量与内置函数
变量引用
${varName} # 从缓存获取变量
${self.param} # 从自定义参数获取
${env.NAME} # 从环境变量获取
${case.field} # 从当前用例数据获取
内置函数
| 函数 | 说明 | 示例 |
|---|---|---|
@today() |
今天日期 | 2024-01-15 |
@today(+7) |
7天后 | 2024-01-22 |
@today(-30) |
30天前 | 2023-12-16 |
@now() |
当前时间 | 2024-01-15 14:30:00 |
@now(%H:%M) |
格式化时间 | 14:30 |
@timestamp() |
时间戳 | 1705301400 |
@random(1,100) |
随机整数 | 42 |
@random_str(8) |
随机字符串 | aB3kF9mN |
@random_phone() |
随机手机号 | 13812345678 |
@random_email() |
随机邮箱 | abc123@test.com |
@random_name() |
随机姓名 | 张三 |
@uuid() |
UUID | 550e8400-e29b... |
@uuid_short() |
短 UUID | 550e8400 |
使用示例
# 在操作值中使用变量
${username}
# 使用内置函数
@today()
@random(1000,9999)
# 组合使用
用户_@random(100,999)
test_@timestamp()@random_str(4)
插件系统
插件目录结构
kdtest-pw 支持两种插件格式:
1. kdtest-pw 原生格式
my_plugin/
├── __init__.py
├── plugin.py # 继承 PluginBase
└── elements.yaml # 元素数据(可选)
2. 原版 kdtest 格式(兼容)
MyPlugin/
├── __init__.py
├── my.ini # [Information] NAME, DETAILE, STATE
├── MyPlugin.py # 主模块,类名与 NAME 一致
├── elementData/
│ ├── elementData.yaml
│ └── modularInformation.json
└── utils/
└── tool.py
创建插件
# 使用 CLI 创建
kdtest-pw --unit_new MyPlugin
生成的结构:
MyPlugin/
├── __init__.py
├── my.ini
├── MyPlugin.py
├── elementData/
│ ├── elementData.yaml
│ └── modularInformation.json
└── utils/
└── tool.py
my.ini 配置
[Information]
NAME = MyPlugin
DETAILE = "插件描述"
STATE = finish
NAME: 插件名称(与主模块类名一致)DETAILE: 插件描述STATE: 状态(finish=启用, disabled=禁用)
插件主模块示例
# MyPlugin.py
class MyPlugin:
"""插件主类"""
def __init__(self):
self.page = None # Playwright Page 将被自动注入
def my_keyword(self, targeting, element, content=None):
"""自定义关键字
Args:
targeting: 定位方式
element: 定位表达式
content: 操作值
"""
if self.page:
locator = self.page.locator(f'{targeting}={element}')
locator.click()
if content:
locator.fill(content)
def another_keyword(self, content):
"""另一个关键字"""
print(f"执行: {content}")
return content
元素数据格式
# elementData/elementData.yaml
login:
username:
- xpath
- //input[@id='username']
password:
- css
- input[type='password']
submit:
- xpath
- //button[@type='submit']
dashboard:
menu:
- css
- .el-menu
user_info:
- id
- userInfo
插件管理命令
# 查看已安装插件
kdtest-pw --unit_show
# 安装插件(从目录)
kdtest-pw --unit_install /path/to/MyPlugin
# 卸载插件
kdtest-pw --unit_uninstall MyPlugin
# 创建新插件模板
kdtest-pw --unit_new NewPlugin
与原版 kdtest 的兼容性
兼容的导入
原版 kdtest 插件中的以下导入会自动适配:
from kdtest import GSTORE, INFO, reset_implicitlyWait
from kdtest import GSDSTORE, MODULEDATA, PRIVATEDATA, CASESDATA
GSTORE 全局存储
# 获取当前 page
page = GSTORE.get('page')
# 获取关键字对象
keyword = GSTORE.get('keyWord')
# 存储/获取数据
GSTORE['myData'] = value
data = GSTORE.get('myData')
INFO 日志函数
INFO("普通信息")
INFO("警告信息", "WARNING")
INFO("错误信息", "ERROR")
reset_implicitlyWait 装饰器
# 作为装饰器
@reset_implicitlyWait(1)
def my_method(self):
pass
# 作为函数
reset_implicitlyWait(10)
主要差异
| 特性 | kdtest (Selenium) | kdtest-pw (Playwright) |
|---|---|---|
| 浏览器驱动 | 需要 WebDriver | 内置浏览器 |
| 等待机制 | 显式/隐式等待 | 自动等待 |
| driver 对象 | self.driver |
self.page |
| 元素定位 | find_element() |
page.locator() |
| Element Plus | 需要额外处理 | 原生支持 |
| 多标签页 | 需要切换句柄 | 原生支持 |
| iframe | switch_to.frame() |
frame_locator() |
| 录制回放 | 无 | 支持 Trace |
| 视频录制 | 无 | 原生支持 |
迁移指南
-
driver → page
# Selenium self.driver.find_element(By.XPATH, '//button').click() # Playwright self.page.locator('xpath=//button').click()
-
元素等待
# Selenium WebDriverWait(driver, 10).until(EC.visibility_of_element_located(...)) # Playwright (自动等待,无需显式等待) self.page.locator('...').click()
-
iframe 切换
# Selenium driver.switch_to.frame('frameName') # Playwright frame = self.page.frame_locator('#frameName') frame.locator('button').click()
高级用法
自定义报告
from kdtest_pw.cli import KDTestRunner
runner = KDTestRunner("parameters.json")
runner.setup()
results = runner.run()
# 自定义报告处理
for case_result in results:
print(f"用例: {case_result['name']}")
print(f"状态: {case_result['status']}")
print(f"耗时: {case_result['duration']}ms")
钩子函数
from kdtest_pw.cli import KDTestRunner
class MyRunner(KDTestRunner):
def on_case_start(self, case_info):
"""用例开始前"""
print(f"开始执行: {case_info['name']}")
def on_case_end(self, case_info, result):
"""用例结束后"""
if result['status'] == 'failed':
self.page.screenshot(path=f"error_{case_info['id']}.png")
def on_step_error(self, step_info, error):
"""步骤出错时"""
print(f"步骤失败: {step_info['keyword']} - {error}")
并行执行
from kdtest_pw.cli import KDTestRunner
from concurrent.futures import ThreadPoolExecutor
def run_case_file(case_file):
config = {
"testCaseFile": [{"caseFilePath": case_file, "caseItem": ["Sheet1"]}],
"browser": "chromium",
"headless": True
}
runner = KDTestRunner(config)
runner.setup()
result = runner.run()
runner.teardown()
return result
# 并行执行多个用例文件
with ThreadPoolExecutor(max_workers=3) as executor:
futures = [
executor.submit(run_case_file, f"cases_{i}.xlsx")
for i in range(3)
]
results = [f.result() for f in futures]
Trace 调试
{
"trace": true,
"traceDir": "./traces"
}
运行后使用 Playwright Trace Viewer 查看:
playwright show-trace traces/trace.zip
视频录制
{
"video": true,
"videoDir": "./videos",
"videoSize": {
"width": 1280,
"height": 720
}
}
项目结构
kdtest_pw/
├── __init__.py
├── cli/
│ └── run.py # CLI 入口和 KDTestRunner
├── compat/
│ └── kdtest_compat.py # 原版 kdtest 兼容层
├── keywords/
│ ├── browser.py # 浏览器操作关键字
│ ├── element.py # 元素操作关键字
│ ├── assertion.py # 断言关键字
│ └── element_plus.py # Element Plus 关键字
├── plugins/
│ ├── plugin_base.py # 插件基类
│ ├── plugin_loader.py # 插件加载器
│ ├── legacy_adapter.py # 原版插件适配器
│ ├── element_plus_plugin/# 内置 Element Plus 插件
│ └── OA_JavaWebUI/ # 用户插件示例
├── reference.py # 全局引用(GSTORE, INFO 等)
└── utils/
├── excel_reader.py # Excel 读取
├── variable_parser.py # 变量解析
└── report_generator.py # 报告生成
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kdtest_playwright-2.0.1.tar.gz.
File metadata
- Download URL: kdtest_playwright-2.0.1.tar.gz
- Upload date:
- Size: 100.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ea36a5963efb36221a39fac7ce1628df6c58072cffe904408142a0b8430655e
|
|
| MD5 |
4a916fe003a7d344192d7c9bb0c436bd
|
|
| BLAKE2b-256 |
db0bb84264859d6aac55163061a3c4e0d18849675bb02755e8c2b9c1f0ec258c
|
File details
Details for the file kdtest_playwright-2.0.1-py3-none-any.whl.
File metadata
- Download URL: kdtest_playwright-2.0.1-py3-none-any.whl
- Upload date:
- Size: 121.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
204ffb785b5ea6a1a38f92fa16d0bb405f9bb92b411b0ac62f456ab7009547e6
|
|
| MD5 |
c3741bd669991b7d764d163e8aeeb5f4
|
|
| BLAKE2b-256 |
5eebb5e7cb2abe0f603438a94ede0adb0e97c487dfd5e5be88760c8ffebadc8c
|