Files
lotteryLaravel/e2e/README.md
kang 6ec9634704
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
feat: 添加E2E测试环境配置支持
添加LOTTERY_E2E环境变量来控制E2E测试相关功能,
包括绕过验证码、登录限制和钱包API URL验证,
同时更新composer.json以包含E2E专用的提供者和服务。
2026-06-18 14:42:22 +08:00

209 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# lotterLaravel E2E 测试
> 端到端测试,**真实** Postgres + Redis + Laravel + Reverb与 Feature 测试SQLite 内存库 + mock解耦。
## 与 Feature 测试的边界
| 维度 | Feature | E2E这套 |
|------|---------|------------|
| 数据库 | SQLite `:memory:` + `RefreshDatabase`(事务回滚) | 真 PGdocker compose 15432事务落库 |
| Redis | `array` 驱动(不真连) | 真 Redis16379Lua/广播全真实 |
| 队列 | `sync`(同步执行) | `redis`(异步,启 `queue:work` |
| 鉴权 | `actingAs` 直接注入 | 真 HTTP 调 `auth/login` 拿 token |
| 广播 | `Event::fake()` 拦截 | 真走 Reverb8080 |
| 入口 | `app()->handle($request)` | 真 `php artisan serve`8000 |
| 时延 | 数百 ms | 数十秒(启服务、跑 migrate |
| 跑哪 | 每次 push / PR | 上线前 + 重大改动后 |
**业务逻辑**交给 Feature**部署/启动/集成**问题归 e2e。
## 目录结构
```
e2e/
├── docker-compose.yml # postgres + redis仅 e2e 用)
├── .env.e2e # 模板 .env
├── package.json # playwright 依赖
├── playwright.config.ts
├── tests/ # 测试用例API mode
│ ├── fixtures.ts # 共享 HTTP 客户端 / login / 拿 draw
│ ├── api/
│ │ ├── _helper.spec.ts
│ │ ├── 01.health.spec.ts
│ │ ├── 02.player-auth.spec.ts
│ │ ├── 03.wallet-ticket.spec.ts
│ │ ├── 04.admin-auth.spec.ts
│ │ ├── 05.wallet-transfer.spec.ts # 转账 + 幂等 + 1001/1010
│ │ ├── 06.wallet-logs.spec.ts # 流水一致性 + 过滤 + 分页
│ │ ├── 07.admin-player.spec.ts # 创建/冻结/解冻玩家
│ │ ├── 08.draw-publish-settle.spec.ts # 开奖结算派彩poll无 skip
│ │ ├── 09.credit-bet.spec.ts # 信用盘下注
│ │ ├── 10.agent-settlement.spec.ts # 代理账期关账
│ │ ├── 11.sso-mainsite.spec.ts # SSO + 主站 mock 异常 + happy path
│ │ ├── 12.broadcast.spec.ts # Reverb balance.update
│ │ ├── 13.credit-settlement-win.spec.ts # 信用盘中奖释额
│ │ ├── 14.settlement-payment.spec.ts # 账期 confirm + 收付
│ │ ├── 15.reconcile-job.spec.ts # pending_reconcile 扫描
│ │ ├── _helper.ts # 共享步骤
│ │ └── helpers/draw-settlement.ts # 结算流水线
│ └── ui/
│ ├── admin-login.spec.ts
│ └── front-login-hall.spec.ts
├── database/seeders/
│ └── E2EPlayerSeeder.php # 建可登录玩家E2E\Seeders 命名空间)
├── routes/e2e.php # 仅 /api/v1/_e2e/* 路由
├── providers/
│ └── E2EServiceProvider.php # 仅在 LOTTERY_E2E=true 时挂载路由
├── scripts/
│ ├── run.sh # 一键起 stack + mock + UI + playwright
│ └── mock-wallet-server.mjs # 主站钱包 mock5555
└── README.md # 本文件
# E2E 控制器(仅路由被挂载才暴露,物理上位于 app/ 下便于 Laravel 自动加载)
app/Http/Controllers/Api/V1/E2E/
├── E2ECaptchaPeekController.php # captcha bypass 提示
├── E2EPlayerStateController.php # 玩家 reset / set-balance / unlock / inspect
├── E2EDrawController.php # close-now / finish-cooldown / tick
├── E2EInspectController.php # credit-ledger / wallet-txns / ticket-items
└── E2EProvisionController.php # credit-player / SSO mint / wallet mock 配置
# E2E 服务提供者注册入口(仅 E2E 时注册)
bootstrap/providers.php # 在末尾追加 E2EServiceProvider
# 生产代码最小入侵点
app/Services/AdminCaptchaService.php # 多了一个 `LOTTERY_E2E_BYPASS` 分支env 关闭时不生效)
composer.json # autoload-dev 加 E2E\Seeders\, E2E\Providers\
```
## 前置依赖
- DockerDocker Desktop / OrbStack / Colima 任一)
- Node.js 20+(跑 Playwright
- PHP 8.3+、Composer
- 第一次跑:`npx playwright install chromium`(自动;本仓库 e2e 用 API 模式不依赖浏览器壳,但安装包仍需)
## 一键跑macOS / Linux
```bash
./e2e/scripts/run.sh
```
会自动:
1. `docker compose up -d`PG :15432 + Redis :16379
2. 等 PG/Redis health
3. `composer install`(缺 vendor 时)
4. 复制 `e2e/.env.e2e``.env`,注入强随机 `LOTTERY_NATIVE_JWT_SECRET` / `REVERB_APP_SECRET`
5. `php artisan key:generate`(缺时)
6. **`php artisan lottery:db-init --fresh`** ⚠️ 重建 `lottery_e2e` 库(**只**作用于此库,绝不碰其他库)
7.`E2EPlayerSeeder`(建可登录玩家)
8.`php artisan serve`8000`queue:work redis`(默认队列)、`reverb:start`8080
9. `npx playwright install chromium`(首次)
10. `npx playwright test`
跑完按 Ctrl+C 自动停 serve/queue/reverb。`docker compose down -v` 自行决定(脚本不删 volume下次跑快
## 单独跑(不重起 stack
```bash
# 起 stack不跑测试
docker compose -f e2e/docker-compose.yml up -d
DB_DATABASE=lottery_e2e php artisan serve --port=8000
DB_DATABASE=lottery_e2e php artisan queue:work redis
DB_DATABASE=lottery_e2e php artisan reverb:start --port=8080
# 跑测试
cd e2e
PLAYWRIGHT_API_URL=http://127.0.0.1:8000 \
E2E_PLAYER_USERNAME=demo_player E2E_PLAYER_PASSWORD=12345678 \
npx playwright test --headed # 想要 UI 调试时
```
## e2e 账号
| 角色 | 账号 | 密码 |
|------|------|------|
| 超管 | `admin` | `12345678` |
## e2e 玩家账号
| 字段 | 值 |
|------|---|
| `site_code` | `demo` |
| `username` | `demo_player` |
| `password` | `12345678` |
| `auth_source` | `lottery_native` |
| `funding_mode` | `wallet` |
| 初始余额 | `1,250,000 minor`NPR 125.00,由 `DEV_SEED_WALLET_BALANCE_MINOR` 改) |
## 覆盖矩阵(截至当前)
| 链路 | spec | 用例数 | 状态 |
|------|------|--------|------|
| 健康/ping/captcha/公开接口 | 01.health | 4 | ✅ |
| 玩家登录 / 失败 / 锁定 | 02.player-auth | 4 | ✅ |
| 玩家钱包 + 下注 + 幂等 | 03.wallet-ticket | 3 | ✅ |
| 超管登录 / dashboard / 401 | 04.admin-auth | 3 | ✅ |
| 玩家 transfer-in/out + 1001/1010 | 05.wallet-transfer | 7 (+2 skip) | ✅ |
| 钱包流水一致性 + 过滤 + 分页 | 06.wallet-logs | 4 | ✅ |
| 超管创建/冻结/解冻/查玩家 | 07.admin-player | 6 | ✅ |
| 开奖+结算+派彩 完整链路 | 08.draw-publish-settle | 1 | ✅ 确定性 poll |
| 信用盘下注占用授信 | 09.credit-bet | 1 | ✅ |
| 代理账期关账出账单 | 10.agent-settlement | 1 | ✅ |
| SSO JWT + 主站钱包异常 + happy path | 11.sso-mainsite | 4 | ✅ |
| Reverb balance.update | 12.broadcast | 1 | ✅ |
| 信用盘中奖释额 game_settlement_win | 13.credit-settlement-win | 1 | ✅ |
| 账期 confirm + 登记收付闭环 | 14.settlement-payment | 1 | ✅ |
| pending_reconcile → reconcile-jobs | 15.reconcile-job | 1 | ✅ |
| 管理端 UI 登录 | ui/admin-login | 1 | ✅ |
| 玩家端 UI 登录进大厅 | ui/front-login-hall | 1 | ✅ |
合计 ~36 个用例覆盖 e2e 关键链路。
## 已知未覆盖(需外部依赖或重构成本高)
- **玩家提现链路**:与 transfer-out 重叠度 90%,增量价值低
- **报表 / settings 实时生效**:表单字段多,断言脆,价值中
## 跑特定 spec
```bash
cd e2e
npx playwright test 05.wallet-transfer.spec.ts --headed
```
## 关键安全设计
- **生产环境零侵入**`AdminCaptchaService::verify``env('LOTTERY_E2E')` 开关,生产 `.env` 留空 → bypass 分支 dead code。
- **E2E 路由不挂载到生产**`E2EServiceProvider::boot``LOTTERY_E2E !== true` 时直接 return`/api/v1/_e2e/*` 在生产完全 404。
- **数据隔离**e2e 库名固定 `lottery_e2e`,与 `lottery` 主库**端口不同**15432 vs 5432
- **migrate:fresh 是库内操作**:脚本注释里明确"只作用于此 docker 库",并对应 AGENTS.md 规定。
- **JWT / Reverb 密钥运行时随机生成**:避免与生产/主站共用 secret。
## 添加新用例
1.`e2e/tests/api/` 新建 `XX.something.spec.ts`
2. 复用 `fixtures.ts``playerLogin` / `adminLogin` / `playerCtx` / `adminCtx`
3. 任何要复用 e2e-only 路由的辅助,往 `E2EServiceProvider` 挂的路由里加,**绝不**往生产路由加
4. 跑:`cd e2e && npx playwright test 05.new.spec.ts`
## 排障
- **API 启动失败**`tail -n 100 e2e/logs/serve.log` / `queue.log` / `reverb.log`
- **PG/Redis 起不来**`docker compose -f e2e/docker-compose.yml logs`
- **测试卡住**:脚本的 `cleanup` 钩子 Ctrl+C 会停 artisan/queue/reverb
- **player 登录 401**`curl -X POST http://127.0.0.1:8000/api/v1/_e2e/reset-player` 重置玩家
## CI 集成(参考)
```yaml
# .github/workflows/e2e.yml
- name: e2e
run: ./e2e/scripts/run.sh
- uses: actions/upload-artifact@v4
if: failure()
with:
name: e2e-artifacts
path: e2e/artifacts/
```