diff --git a/tests/Feature/AdminPlatformBatchShowPageFallbackCountsShouldRenderWithoutLastResultTest.php b/tests/Feature/AdminPlatformBatchShowPageFallbackCountsShouldRenderWithoutLastResultTest.php new file mode 100644 index 0000000..fe10b90 --- /dev/null +++ b/tests/Feature/AdminPlatformBatchShowPageFallbackCountsShouldRenderWithoutLastResultTest.php @@ -0,0 +1,106 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_show_page_should_render_fallback_counts_without_last_result(): void + { + $this->loginAsPlatformAdmin(); + + $merchant = Merchant::query()->firstOrFail(); + $plan = Plan::query()->create([ + 'code' => 'plan_batch_show_fallback_counts_0001', + 'name' => '批次页 fallback 粗统计测试套餐', + 'billing_cycle' => 'monthly', + 'price' => 10, + 'list_price' => 10, + 'status' => 'active', + 'sort' => 10, + 'published_at' => now(), + ]); + + $runId = 'BAS_FALLBACK_COUNTS_0001'; + + PlatformOrder::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'order_no' => 'PO_BATCH_FALLBACK_A', + 'order_type' => 'new_purchase', + 'status' => 'activated', + 'payment_status' => 'paid', + 'plan_name' => $plan->name, + 'billing_cycle' => $plan->billing_cycle, + 'period_months' => 1, + 'quantity' => 1, + 'payable_amount' => 10, + 'paid_amount' => 10, + 'placed_at' => now()->subMinutes(10), + 'paid_at' => now()->subMinutes(9), + 'activated_at' => now()->subMinutes(8), + 'meta' => [ + 'batch_activation' => [ + 'run_id' => $runId, + ], + 'subscription_activation_error' => [ + 'message' => '模拟失败:同步异常', + 'at' => now()->toDateTimeString(), + 'admin_id' => 1, + ], + ], + ]); + + PlatformOrder::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'order_no' => 'PO_BATCH_FALLBACK_B', + 'order_type' => 'new_purchase', + 'status' => 'activated', + 'payment_status' => 'paid', + 'plan_name' => $plan->name, + 'billing_cycle' => $plan->billing_cycle, + 'period_months' => 1, + 'quantity' => 1, + 'payable_amount' => 10, + 'paid_amount' => 10, + 'placed_at' => now()->subMinutes(7), + 'paid_at' => now()->subMinutes(6), + 'activated_at' => now()->subMinutes(5), + 'meta' => [ + 'batch_activation' => [ + 'run_id' => $runId, + ], + ], + ]); + + $html = $this->get('/admin/platform-batches/show?type=bas&run_id=' . $runId) + ->assertOk() + ->getContent(); + + $this->assertStringContainsString('本批次尚未生成 last_result 汇总', $html); + $this->assertStringContainsString('data-role="batch-matched-link"', $html); + $this->assertStringContainsString('>2<', $html); + $this->assertStringContainsString('data-role="batch-failed-count-link"', $html); + $this->assertStringContainsString('>1<', $html); + $this->assertStringContainsString('失败占比:', $html); + $this->assertStringContainsString('50%', $html); + } +} diff --git a/tests/Feature/AdminPlatformBatchShowPageShouldRenderErrorWhenParamsMissingTest.php b/tests/Feature/AdminPlatformBatchShowPageShouldRenderErrorWhenParamsMissingTest.php new file mode 100644 index 0000000..733ec7f --- /dev/null +++ b/tests/Feature/AdminPlatformBatchShowPageShouldRenderErrorWhenParamsMissingTest.php @@ -0,0 +1,35 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_show_page_should_render_error_when_type_or_run_id_missing(): void + { + $this->loginAsPlatformAdmin(); + + $html = $this->get('/admin/platform-batches/show?type=bas') + ->assertOk() + ->getContent(); + + $this->assertStringContainsString('参数不完整:请提供 type(bas/bmpa)与 run_id。', $html); + $this->assertStringContainsString('href="/admin/platform-orders"', $html); + $this->assertStringNotContainsString('data-action="copy-run-id"', $html); + $this->assertStringNotContainsString('data-role="batch-spot-check-link"', $html); + } +} diff --git a/tests/Feature/AdminPlatformBatchShowPageTopReasonTooLongShouldNotRenderGovernanceLinkTest.php b/tests/Feature/AdminPlatformBatchShowPageTopReasonTooLongShouldNotRenderGovernanceLinkTest.php new file mode 100644 index 0000000..925c1e2 --- /dev/null +++ b/tests/Feature/AdminPlatformBatchShowPageTopReasonTooLongShouldNotRenderGovernanceLinkTest.php @@ -0,0 +1,127 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_show_page_should_not_render_top_reason_governance_link_when_reason_too_long(): void + { + $this->loginAsPlatformAdmin(); + + $merchant = Merchant::query()->firstOrFail(); + $plan = Plan::query()->create([ + 'code' => 'plan_batch_show_long_reason_0001', + 'name' => '批次页长原因护栏测试套餐', + 'billing_cycle' => 'monthly', + 'price' => 10, + 'list_price' => 10, + 'status' => 'active', + 'sort' => 10, + 'published_at' => now(), + ]); + + $longReasonBas = str_repeat('B', 260); + $longReasonBmpa = str_repeat('P', 260); + + PlatformOrder::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'order_no' => 'PO_BATCH_SHOW_LONG_REASON_BAS_0001', + 'order_type' => 'new_purchase', + 'status' => 'activated', + 'payment_status' => 'paid', + 'plan_name' => $plan->name, + 'billing_cycle' => $plan->billing_cycle, + 'period_months' => 1, + 'quantity' => 1, + 'payable_amount' => 10, + 'paid_amount' => 10, + 'placed_at' => now()->subMinutes(10), + 'paid_at' => now()->subMinutes(9), + 'activated_at' => now()->subMinutes(8), + 'meta' => [ + 'batch_activation' => [ + 'run_id' => 'BAS_LONG_REASON_0001', + 'last_result' => [ + 'run_id' => 'BAS_LONG_REASON_0001', + 'success' => 1, + 'failed' => 1, + 'matched' => 2, + 'processed' => 2, + 'top_reasons' => [ + ['reason' => $longReasonBas, 'count' => 1], + ], + 'at' => now()->toDateTimeString(), + ], + ], + ], + ]); + + PlatformOrder::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'order_no' => 'PO_BATCH_SHOW_LONG_REASON_BMPA_0001', + 'order_type' => 'new_purchase', + 'status' => 'activated', + 'payment_status' => 'paid', + 'plan_name' => $plan->name, + 'billing_cycle' => $plan->billing_cycle, + 'period_months' => 1, + 'quantity' => 1, + 'payable_amount' => 10, + 'paid_amount' => 10, + 'placed_at' => now()->subMinutes(7), + 'paid_at' => now()->subMinutes(6), + 'activated_at' => now()->subMinutes(5), + 'meta' => [ + 'batch_mark_paid_and_activate' => [ + 'run_id' => 'BMPA_LONG_REASON_0001', + 'last_result' => [ + 'run_id' => 'BMPA_LONG_REASON_0001', + 'success' => 1, + 'failed' => 1, + 'matched' => 2, + 'processed' => 2, + 'top_reasons' => [ + ['reason' => $longReasonBmpa, 'count' => 1], + ], + 'at' => now()->toDateTimeString(), + ], + ], + ], + ]); + + $basHtml = $this->get('/admin/platform-batches/show?type=bas&run_id=BAS_LONG_REASON_0001') + ->assertOk() + ->getContent(); + $bmpaHtml = $this->get('/admin/platform-batches/show?type=bmpa&run_id=BMPA_LONG_REASON_0001') + ->assertOk() + ->getContent(); + + $this->assertStringNotContainsString('sync_error_keyword=', $basHtml); + $this->assertStringContainsString('原因过长,请复制到列表页筛选框', $basHtml); + $this->assertStringNotContainsString('data-role="batch-top-reason-link"', $basHtml); + + $this->assertStringNotContainsString('bmpa_error_keyword=', $bmpaHtml); + $this->assertStringContainsString('原因过长,请复制到列表页筛选框', $bmpaHtml); + $this->assertStringNotContainsString('data-role="batch-top-reason-link"', $bmpaHtml); + } +} diff --git a/tests/Feature/AdminPlatformBatchShowPageUnsafeBackShouldBeDroppedTest.php b/tests/Feature/AdminPlatformBatchShowPageUnsafeBackShouldBeDroppedTest.php new file mode 100644 index 0000000..4aadd66 --- /dev/null +++ b/tests/Feature/AdminPlatformBatchShowPageUnsafeBackShouldBeDroppedTest.php @@ -0,0 +1,88 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_batch_show_page_should_drop_unsafe_back_from_return_and_governance_links(): void + { + $this->loginAsPlatformAdmin(); + + $merchant = Merchant::query()->firstOrFail(); + $plan = Plan::query()->create([ + 'code' => 'plan_batch_show_unsafe_back_0001', + 'name' => '批次页 unsafe back 护栏测试套餐', + 'billing_cycle' => 'monthly', + 'price' => 10, + 'list_price' => 10, + 'status' => 'active', + 'sort' => 10, + 'published_at' => now(), + ]); + + $runId = 'BAS_UNSAFE_BACK_0001'; + + PlatformOrder::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'order_no' => 'PO_BATCH_SHOW_UNSAFE_BACK_0001', + 'order_type' => 'new_purchase', + 'status' => 'activated', + 'payment_status' => 'paid', + 'plan_name' => $plan->name, + 'billing_cycle' => $plan->billing_cycle, + 'period_months' => 1, + 'quantity' => 1, + 'payable_amount' => 10, + 'paid_amount' => 10, + 'placed_at' => now()->subMinutes(10), + 'paid_at' => now()->subMinutes(9), + 'activated_at' => now()->subMinutes(8), + 'meta' => [ + 'batch_activation' => [ + 'run_id' => $runId, + 'last_result' => [ + 'run_id' => $runId, + 'success' => 1, + 'failed' => 1, + 'matched' => 2, + 'processed' => 2, + 'top_reasons' => [ + ['reason' => '模拟失败:订阅同步异常', 'count' => 1], + ], + 'at' => now()->toDateTimeString(), + ], + ], + ], + ]); + + $unsafeBack = '/admin/platform-orders?x=1%26back%3D%2Fadmin'; + + $html = $this->get('/admin/platform-batches/show?type=bas&run_id=' . $runId . '&back=' . urlencode($unsafeBack)) + ->assertOk() + ->getContent(); + + $this->assertStringContainsString('href="/admin/platform-orders"', $html); + $this->assertStringNotContainsString('back=' . urlencode($unsafeBack), $html); + $this->assertStringContainsString('batch_activation_run_id=' . $runId, $html); + $this->assertStringNotContainsString('batch_activation_run_id=' . $runId . '&back=', $html); + } +}