Metadata-Version: 2.1
Name: ui_engine_xin
Version: 0.0.3
Summary: 基于 Playwright 的关键字驱动 UI 自动化测试引擎
Home-page: https://pypi.org/project/ui_engine_xin/
Author: Shawn
Author-email: xiaoh0525@xiaoh.com
Keywords: python,playwright,ui-automation,keyword-driven,testing,uiEngine
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Testing
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: dev
License-File: LICENSE


# UIEngine

基于 Playwright 的关键字驱动 UI 自动化测试引擎。

## 特性

- **关键字驱动**：通过中文/英文关键字编写测试用例，降低使用门槛
- **中英文双注册**：每个关键字同时支持中英文名称，大小写兼容
- **丰富的内置关键字**：覆盖页面操作、元素交互、等待策略、断言、iframe 等场景
- **变量替换**：支持 `${variable}` 语法引用全局变量
- **截图管理**：按套件自动创建截图目录，引擎内最多保留 10 个
- **灵活配置**：支持 dict 和 YAML 两种配置方式

## 安装

```bash
pip install ui-engine
playwright install
```

## 快速开始

```python
from UIEngine import Runner

config = {
    "is_debug": True,                # True=显示浏览器，False=无头模式
    "browser_type": "chromium",
    "host": "http://localhost:8080",
    "global_variable": {
        "username": "admin",
        "password": "123456"
    }
}

suite = {
    "id": "suite_001",
    "name": "登录功能测试",
    "setup_step": [
        {
            "desc": "打开浏览器",
            "keyword": "open_browser",
            "params": {"browser_type": "chromium"}
        },
        {
            "desc": "打开登录页",
            "keyword": "打开页面",           # 中文关键字同样支持
            "params": {"url": "/login"}
        },
    ],
    "cases": [
        {
            "id": "case_001",
            "name": "正确密码登录",
            "skip": False,
            "steps": [
                {
                    "desc": "输入用户名",
                    "keyword": "fill_value",
                    "params": {"locator": "#username", "value": "${username}"}
                },
                {
                    "desc": "输入密码",
                    "keyword": "输入值",      # 中文关键字
                    "params": {"locator": "#password", "value": "${password}"}
                },
                {
                    "desc": "点击登录",
                    "keyword": "click_element",
                    "params": {"locator": "#login-btn"}
                },
                {
                    "desc": "验证登录成功",
                    "keyword": "except_to_have_text",
                    "params": {"locator": ".welcome", "expect_results": "admin"}
                }
            ]
        }
    ]
}

result = Runner(config).run(suite)
print(result)
```

## 关键字列表

### 页面操作

| 英文 | 中文 | 说明 |
|------|------|------|
| `open_url` | `打开页面` | 打开 URL |
| `refresh` | `刷新页面` | 刷新当前页面 |
| `go_back` | `返回上一页` | 浏览器后退 |
| `go_forward` | `前进下一页` | 浏览器前进 |
| `scroll_to_height` | `滚动到高度` | 滚动到指定高度 |
| `execute_script` | `执行脚本` | 执行 JavaScript |
| `download_file` | `下载文件` | 触发并等待文件下载 |
| `accept_dialog` | `接受弹窗` | 接受浏览器弹窗 |
| `dismiss_dialog` | `关闭弹窗` | 关闭浏览器弹窗 |
| `get_page_title` | `获取页面标题` | 获取当前页面标题 |
| `get_page_url` | `获取页面URL` | 获取当前页面 URL |
| `set_viewport_size` | `设置窗口大小` | 设置浏览器视口大小 |

### 元素操作

| 英文 | 中文 | 说明 |
|------|------|------|
| `click_element` | `点击元素` | 单击元素 |
| `double_click` | `双击` | 双击元素 |
| `fill_value` | `输入值` | 输入框填值 |
| `type_text` | `输入文本` | 模拟逐字符输入 |
| `clear` | `清空输入框` | 清空输入框 |
| `hover` | `悬停` | 鼠标悬停 |
| `focus_element` | `聚焦元素` | 聚焦元素 |
| `check` | `勾选` | 勾选复选框 |
| `uncheck` | `取消勾选` | 取消勾选 |
| `select_option` | `选择选项` | 下拉框选择 |
| `select_multiple_options` | `多选下拉` | 下拉框多选 |
| `drag_and_drop` | `拖拽` | 拖拽元素 |
| `upload_file` | `上传文件` | 上传文件 |
| `scroll_to_element` | `滚动到元素` | 滚动至元素可见 |
| `highlight_element` | `高亮元素` | 高亮元素（调试用） |
| `get_text` | `获取文本` | 获取元素文本 |
| `get_attribute` | `获取属性` | 获取元素属性 |
| `get_input_value` | `获取输入值` | 获取输入框值 |
| `get_element_count` | `获取元素数量` | 获取匹配元素数量 |
| `is_visible` | `是否可见` | 查询元素可见性 |
| `is_hidden` | `是否隐藏` | 查询元素隐藏 |
| `is_enabled` | `是否可用` | 查询元素可用性 |
| `is_checked` | `是否选中` | 查询元素选中状态 |

### 鼠标键盘

| 英文 | 中文 | 说明 |
|------|------|------|
| `mouse_click` | `鼠标点击` | 坐标点击 |
| `move_mouse` | `移动鼠标` | 坐标移动 |
| `long_click` | `长按` | 长按元素 |
| `right_click` | `右键点击` | 右键点击元素 |
| `press_key` | `按键` | 键盘按键 |
| `press_type` | `键盘输入` | 键盘输入文本 |

### 等待

| 英文 | 中文 | 说明 |
|------|------|------|
| `wait_for_time` | `强制等待` | 固定等待 |
| `wait_for_load` | `等待加载` | 等待页面加载 |
| `wait_for_network` | `等待网络` | 等待网络空闲 |
| `wait_for_element` | `等待元素` | 等待元素可见 |
| `wait_for_element_hidden` | `等待元素消失` | 等待元素不可见 |
| `wait_for_url` | `等待URL` | 等待 URL 匹配 |

### 断言

| 英文 | 中文 | 说明 |
|------|------|------|
| `assert_page_title` | `断言标题` | 断言页面标题 |
| `assert_page_url` | `断言URL` | 断言页面 URL |
| `except_to_have_text` | `断言有文本` | 断言元素文本 |
| `except_to_have_value` | `断言有值` | 断言元素值 |
| `except_to_be_visible` | `断言可见` | 断言元素可见 |
| `except_to_be_hidden` | `断言隐藏` | 断言元素隐藏 |
| `except_to_be_enabled` | `断言可用` | 断言元素可用 |
| `except_to_be_checked` | `断言选中` | 断言元素选中 |

### iframe

| 英文 | 中文 | 说明 |
|------|------|------|
| `frame_click_element` | `框架点击` | iframe 内点击 |
| `frame_fill_value` | `框架输入` | iframe 内输入 |
| `switch_to_frame` | `切换iframe` | 切换到 iframe |
| `switch_to_main_frame` | `切回主页面` | 切回主页面 |

## 动态注册关键字

```python
from UIEngine import KeyWordManager

# 注册中英文关键字
KeyWordManager.register_keyword(
    ["custom_login", "自定义登录"],
    '''
def custom_login(self, username, password):
    self.page.locator("#user").fill(username)
    self.page.locator("#pass").fill(password)
    self.page.locator("#submit").click()
    '''
)
```

## 配置

支持 dict 和 YAML 两种方式：

```python
# dict 方式
config = {
    "browser_type": "chromium",
    "is_debug": True,
    "host": "http://localhost:8080",
    "global_variable": {"username": "admin"}
}

# YAML 文件方式
config = "config.yaml"

result = Runner(config).run(suite)
```

## License

MIT
