mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
- Add browser-compatible test files (no npm required) - recorder.test.browser.js: 8 tests for microphone and HTTP detection - tools.test.browser.js: 5 tests for Live2D actions and error handling - Add test runner (test-runner.html) with built-in test framework - Add null safety checks in tools.js for DOM element access - Add documentation (English and Chinese versions) - README_TESTS.md / README_TESTS_CN.md: Complete test guide - QUICK_START_TEST.md / QUICK_START_TEST_CN.md: Quick start guides - Total: 13 unit tests covering microphone detection, HTTP detection, Live2D actions, and error handling
112 lines
3.9 KiB
Markdown
112 lines
3.9 KiB
Markdown
# 单元测试指南
|
||
|
||
本目录包含 xiaozhi 测试页面模块的单元测试。
|
||
|
||
## 摘要
|
||
|
||
- **测试总数:** 13 个单元测试
|
||
- **测试文件:** 2 个浏览器兼容的测试文件
|
||
- **测试运行器:** 基于浏览器(无需 npm)
|
||
- **测试覆盖:** 麦克风检测、HTTP 检测、Live2D 动作、错误处理
|
||
|
||
## 测试文件
|
||
|
||
- `js/core/audio/recorder.test.browser.js` - 浏览器兼容的麦克风可用性检测和 HTTP 非本地访问检测测试
|
||
- `js/core/mcp/tools.test.browser.js` - 浏览器兼容的 MCP 工具和 Live2D 动作执行测试
|
||
|
||
**注意:** `.browser.js` 版本无需任何 npm 依赖。它们使用内置在 `test-runner.html` 中的简单测试框架。
|
||
|
||
## 运行测试
|
||
|
||
### 基于浏览器的测试运行器(无需 npm!)
|
||
|
||
1. 启动本地服务器:
|
||
```bash
|
||
cd main/xiaozhi-server/test
|
||
python -m http.server 8007
|
||
```
|
||
|
||
2. 在浏览器中打开 `http://localhost:8007/test-runner.html`
|
||
|
||
3. 点击 "▶ Run All Tests"(运行所有测试)按钮
|
||
|
||
就这么简单!无需 npm,无需 package.json,无需任何依赖。
|
||
|
||
## 测试覆盖
|
||
|
||
### `recorder.test.browser.js`
|
||
- ✅ `checkMicrophoneAvailability()` - 当麦克风可用时返回 true
|
||
- ✅ `checkMicrophoneAvailability()` - 当麦克风不可用时返回 false
|
||
- ✅ `checkMicrophoneAvailability()` - 当浏览器不支持 getUserMedia 时返回 false
|
||
- ✅ `isHttpNonLocalhost()` - 对于 HTTP 非本地访问返回 true
|
||
- ✅ `isHttpNonLocalhost()` - 对于 localhost 返回 false
|
||
- ✅ `isHttpNonLocalhost()` - 对于 127.0.0.1 返回 false
|
||
- ✅ `isHttpNonLocalhost()` - 对于私有 IP 地址返回 false
|
||
- ✅ `isHttpNonLocalhost()` - 对于 HTTPS 协议返回 false
|
||
|
||
### `tools.test.browser.js`
|
||
- ✅ `executeMcpTool('live2d.smile')` - 执行 FlickUp 动作
|
||
- ✅ `executeMcpTool('live2d.wave')` - 执行 Tap 动作
|
||
- ✅ `executeMcpTool('live2d.action')` - 执行自定义动作
|
||
- ✅ `executeMcpTool()` - 优雅处理缺失的 Live2D 管理器
|
||
- ✅ `executeMcpTool()` - 优雅处理未知工具
|
||
|
||
## 编写新测试
|
||
|
||
添加新功能时,创建一个遵循以下模式的 `.browser.js` 测试文件:
|
||
|
||
```javascript
|
||
// your-module.test.browser.js
|
||
import { yourFunction } from './your-module.js';
|
||
|
||
describe('您的功能', () => {
|
||
beforeEach(() => {
|
||
// 设置模拟并重置状态
|
||
vi.clearAllMocks();
|
||
});
|
||
|
||
test('应该执行某些操作', () => {
|
||
// 准备
|
||
const input = 'test';
|
||
|
||
// 执行
|
||
const result = yourFunction(input);
|
||
|
||
// 断言
|
||
expect(result).toBe('expected');
|
||
});
|
||
});
|
||
```
|
||
|
||
## 模拟指南
|
||
|
||
- 使用 `vi.fn()` 创建函数模拟
|
||
- 使用 `vi.fn().mockResolvedValue(value)` 创建解析的异步模拟
|
||
- 使用 `vi.fn().mockRejectedValue(error)` 创建拒绝的异步模拟
|
||
- 在 `beforeEach` 中使用 `vi.clearAllMocks()` 重置状态
|
||
- 模拟浏览器 API(`navigator`、`window.location`、`localStorage`、`fetch`)
|
||
- 需要时模拟 DOM 元素(`document.getElementById` 等)
|
||
|
||
## 可用的测试函数
|
||
|
||
浏览器测试框架提供:
|
||
- `describe(name, fn)` - 定义测试套件
|
||
- `test(name, fn)` - 定义测试用例
|
||
- `beforeEach(fn)` - 在每个测试之前运行
|
||
- `afterEach(fn)` - 在每个测试之后运行
|
||
- `expect(actual)` - 断言对象,包含:
|
||
- `.toBe(expected)` - 严格相等
|
||
- `.toHaveBeenCalled()` - 函数已被调用
|
||
- `.toHaveBeenCalledWith(...args)` - 函数已使用特定参数调用
|
||
- `.toContain(substring)` - 字符串包含子字符串
|
||
- `vi.fn(impl?)` - 创建模拟函数
|
||
- `vi.clearAllMocks()` - 清除所有模拟
|
||
|
||
## 注意事项
|
||
|
||
- 测试使用 ES 模块(`import`/`export`)
|
||
- 测试直接在浏览器中运行(无需 Node.js)
|
||
- 无需 npm 依赖 - 所有内容都是自包含的
|
||
- 测试运行器(`test-runner.html`)包含一个简单的测试框架
|
||
- 点击 "Run All Tests"(运行所有测试)时自动加载测试
|