Files
huangjingfen/pro_v3.5.1_副本/tests/hjf/SmokeTest.php
apple 434aa8c69d feat(fsgx): 完成全部24项开发任务 Phase1-7
Phase1 后端核心:
- 新增 fsgx_v1.sql 迁移脚本(is_queue_goods/frozen_points/available_points/no_assess)
- SystemConfigServices 返佣设置扩展(周期人数/分档比例/范围/时机)
- StoreOrderCreateServices 周期循环佣金计算
- StoreOrderTakeServices 佣金发放后同步冻结积分
- StoreProductServices/StoreProduct 保存 is_queue_goods

Phase2 后端接口:
- GET /api/hjf/brokerage/progress 佣金周期进度
- GET /api/hjf/assets/overview 资产总览
- HjfPointsServices 每日 frozen_points 0.4‰ 释放定时任务
- PUT /adminapi/hjf/member/{uid}/no_assess 不考核接口
- GET /adminapi/hjf/points/release_log 积分日志接口

Phase3 前端清理:
- hjfCustom.js 路由精简(仅保留 points/log)
- hjfQueue.js/hjfMember.js API 清理/重定向至 CRMEB 原生接口
- pages.json 公排→推荐佣金/佣金记录/佣金规则

Phase4-5 前端改造:
- queue/status.vue 推荐佣金进度页整体重写
- 商品详情/订单确认/支付结果页文案与逻辑改造
- 个人中心/资产页/引导页/规则页文案改造
- HjfQueueProgress/HjfRefundNotice/HjfAssetCard 组件改造
- 推广中心嵌入佣金进度摘要
- hjfMockData.js 全量更新(公排字段→佣金字段)

Phase6 Admin 增强:
- 用户列表新增 frozen_points/available_points 列及不考核操作按钮
- hjfPoints.js USE_MOCK=false 对接真实积分日志接口

Phase7 配置文档:
- docs/fsgx-phase7-config-checklist.md 后台配置与全链路验收清单

Made-with: Cursor
2026-03-23 22:32:19 +08:00

327 lines
12 KiB
PHP
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.
<?php
declare(strict_types=1);
namespace tests\hjf;
use PHPUnit\Framework\TestCase;
/**
* P4 联调冒烟测试SmokeTest
*
* 使用说明:
* 1. 确保 Phase 2 数据库迁移已执行eb_queue_pool / eb_points_release_log 等表已创建)
* 2. 确保后端服务已启动ThinkPHP 8 + Swoole 或 PHP-FPM
* 3. 设置环境变量:
* HJF_API_BASE=http://127.0.0.1:8080/api
* HJF_ADMIN_BASE=http://127.0.0.1:8080/adminapi
* HJF_TOKEN=<有效用户Token>
* HJF_ADMIN_TOKEN=<有效管理员Token>
* 4. 运行:./vendor/bin/phpunit tests/hjf/SmokeTest.php
*
* 覆盖场景:
* P4-02 UniApp 冒烟:登录后访问公排/资产/积分/会员接口
* P4-03 Admin 冒烟:公排订单列表 / 配置保存 / 会员等级 / 积分日志
* P4-05 定时任务验证:手动调用积分释放 command验证 release_log 有新记录
*
* Class SmokeTest
* @package tests\hjf
*/
class SmokeTest extends TestCase
{
private string $apiBase;
private string $adminBase;
private string $token;
private string $adminToken;
protected function setUp(): void
{
$this->apiBase = rtrim(getenv('HJF_API_BASE') ?: 'http://127.0.0.1:8080/api', '/');
$this->adminBase = rtrim(getenv('HJF_ADMIN_BASE') ?: 'http://127.0.0.1:8080/adminapi', '/');
$this->token = getenv('HJF_TOKEN') ?: '';
$this->adminToken = getenv('HJF_ADMIN_TOKEN') ?: '';
}
// -----------------------------------------------------------------------
// 辅助方法
// -----------------------------------------------------------------------
/**
* 发送 GET 请求,返回解析后的响应体数组
*/
private function get(string $url, string $token = ''): array
{
$headers = ['Content-Type: application/json'];
if ($token) {
$headers[] = "Authorization: Bearer {$token}";
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode((string)$body, true) ?: [];
$data['__http_code'] = $http;
return $data;
}
/**
* 发送 POST 请求,返回解析后的响应体数组
*/
private function post(string $url, array $payload, string $token = ''): array
{
$headers = ['Content-Type: application/json'];
if ($token) {
$headers[] = "Authorization: Bearer {$token}";
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode((string)$body, true) ?: [];
$data['__http_code'] = $http;
return $data;
}
// -----------------------------------------------------------------------
// P4-02 UniApp 冒烟测试
// -----------------------------------------------------------------------
/**
* @test
* P4-02-A: 公排状态接口可访问,返回 200 且包含 total_orders/my_orders/progress 字段
*/
public function testUniAppQueueStatus(): void
{
if (!$this->token) {
$this->markTestSkipped('HJF_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->apiBase}/hjf/queue/status", $this->token);
$this->assertEquals(200, $res['__http_code'], '公排状态接口 HTTP 200');
$this->assertArrayHasKey('data', $res, '响应包含 data 字段');
$data = $res['data'];
$this->assertArrayHasKey('total_orders', $data, 'data 包含 total_orders');
$this->assertArrayHasKey('my_orders', $data, 'data 包含 my_orders');
$this->assertArrayHasKey('progress', $data, 'data 包含 progress');
}
/**
* @test
* P4-02-B: 公排历史接口可访问,返回分页格式
*/
public function testUniAppQueueHistory(): void
{
if (!$this->token) {
$this->markTestSkipped('HJF_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->apiBase}/hjf/queue/history?page=1&limit=10", $this->token);
$this->assertEquals(200, $res['__http_code'], '公排历史接口 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('list', $data, 'data 包含 list');
$this->assertArrayHasKey('count', $data, 'data 包含 count');
}
/**
* @test
* P4-02-C: 资产总览接口,返回余额+积分字段
*/
public function testUniAppAssetsOverview(): void
{
if (!$this->token) {
$this->markTestSkipped('HJF_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->apiBase}/hjf/assets/overview", $this->token);
$this->assertEquals(200, $res['__http_code'], '资产总览接口 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('now_money', $data, 'data 包含 now_money');
$this->assertArrayHasKey('frozen_points', $data, 'data 包含 frozen_points');
$this->assertArrayHasKey('available_points', $data, 'data 包含 available_points');
}
/**
* @test
* P4-02-D: 积分明细接口,返回分页列表
*/
public function testUniAppPointsDetail(): void
{
if (!$this->token) {
$this->markTestSkipped('HJF_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->apiBase}/hjf/points/detail?page=1&limit=10", $this->token);
$this->assertEquals(200, $res['__http_code'], '积分明细接口 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('list', $data, 'data 包含 list');
$this->assertArrayHasKey('count', $data, 'data 包含 count');
}
/**
* @test
* P4-02-E: 会员信息接口,返回 member_level 字段
*/
public function testUniAppMemberInfo(): void
{
if (!$this->token) {
$this->markTestSkipped('HJF_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->apiBase}/hjf/member/info", $this->token);
$this->assertEquals(200, $res['__http_code'], '会员信息接口 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('member_level', $data, 'data 包含 member_level');
$this->assertContains(
(int)($data['member_level'] ?? -1),
[0, 1, 2, 3, 4],
'member_level 取值 0~4'
);
}
// -----------------------------------------------------------------------
// P4-03 Admin 冒烟测试
// -----------------------------------------------------------------------
/**
* @test
* P4-03-A: Admin 公排订单列表接口,返回分页数据
*/
public function testAdminQueueOrderList(): void
{
if (!$this->adminToken) {
$this->markTestSkipped('HJF_ADMIN_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->adminBase}/hjf/queue/order?page=1&limit=10", $this->adminToken);
$this->assertEquals(200, $res['__http_code'], 'Admin 公排订单列表 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('list', $data, 'data 包含 list');
$this->assertArrayHasKey('count', $data, 'data 包含 count');
}
/**
* @test
* P4-03-B: Admin 公排配置读取,返回 hjf_trigger_multiple 等关键字段
*/
public function testAdminQueueConfigGet(): void
{
if (!$this->adminToken) {
$this->markTestSkipped('HJF_ADMIN_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->adminBase}/hjf/queue/config", $this->adminToken);
$this->assertEquals(200, $res['__http_code'], 'Admin 公排配置 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('hjf_trigger_multiple', $data, 'data 包含 hjf_trigger_multiple');
}
/**
* @test
* P4-03-C: Admin 公排配置保存(写回原值,不改变业务数据)
*/
public function testAdminQueueConfigSave(): void
{
if (!$this->adminToken) {
$this->markTestSkipped('HJF_ADMIN_TOKEN 未设置,跳过');
}
// 先读取当前配置
$getRes = $this->get("{$this->adminBase}/hjf/queue/config", $this->adminToken);
$current = $getRes['data'] ?? ['hjf_trigger_multiple' => 4, 'hjf_release_rate' => 4];
// 写回原值
$saveRes = $this->post("{$this->adminBase}/hjf/queue/config", $current, $this->adminToken);
$this->assertEquals(200, $saveRes['__http_code'], 'Admin 公排配置保存 HTTP 200');
}
/**
* @test
* P4-03-D: Admin 会员列表接口,返回分页数据含 member_level 列
*/
public function testAdminMemberList(): void
{
if (!$this->adminToken) {
$this->markTestSkipped('HJF_ADMIN_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->adminBase}/hjf/member/list?page=1&limit=10", $this->adminToken);
$this->assertEquals(200, $res['__http_code'], 'Admin 会员列表 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('list', $data, 'data 包含 list');
$this->assertArrayHasKey('count', $data, 'data 包含 count');
// 若有记录,验证字段完整性
if (!empty($data['list'])) {
$first = $data['list'][0];
$this->assertArrayHasKey('member_level', $first, 'list[0] 包含 member_level');
$this->assertArrayHasKey('direct_order_count', $first, 'list[0] 包含 direct_order_count');
$this->assertArrayHasKey('umbrella_order_count', $first, 'list[0] 包含 umbrella_order_count');
}
}
/**
* @test
* P4-03-E: Admin 积分释放日志接口,返回分页数据
*/
public function testAdminPointsReleaseLog(): void
{
if (!$this->adminToken) {
$this->markTestSkipped('HJF_ADMIN_TOKEN 未设置,跳过');
}
$res = $this->get("{$this->adminBase}/hjf/points/release-log?page=1&limit=10", $this->adminToken);
$this->assertEquals(200, $res['__http_code'], 'Admin 积分释放日志 HTTP 200');
$data = $res['data'] ?? [];
$this->assertArrayHasKey('list', $data, 'data 包含 list');
$this->assertArrayHasKey('count', $data, 'data 包含 count');
}
// -----------------------------------------------------------------------
// P4-05 定时任务验证(积分每日释放)
// -----------------------------------------------------------------------
/**
* @test
* P4-05: 手动触发 Artisan/Think 积分释放命令后release_log 有新记录
*
* 验证方式:
* 1. 记录触发前的日志总数
* 2. 调用 Admin 接口触发(或本地 CLIphp think hjf:release-points
* 3. 等待队列消费最多10秒
* 4. 再次查询日志总数,新增量 >= 1
*/
public function testDailyPointsReleaseCreatesLogs(): void
{
if (!$this->adminToken) {
$this->markTestSkipped('HJF_ADMIN_TOKEN 未设置,跳过');
}
// 触发前的日志总数
$before = $this->get("{$this->adminBase}/hjf/points/release-log?page=1&limit=1", $this->adminToken);
$countBefore = (int)($before['data']['count'] ?? 0);
// 触发定时任务(通过 CLI实际测试时需在后端服务器执行
// 此处记录预期行为:执行后 count 应增加
// 若在 CI 环境中可替换为shell_exec('php think hjf:release-points');
// 由于无法在 PHPUnit 内部确保队列消费完成,此测试标记为 skipped 并记录说明
$this->markTestIncomplete(
"P4-05 定时任务测试需在后端服务器手动执行:\n" .
" php think hjf:release-points\n" .
"执行后再运行本测试检验 release_log count 从 {$countBefore} 增加。\n" .
"若 frozen_points 为0的用户较多释放量可能为0属正常行为"
);
}
}