[CLAUDE] Tests: Chunk L4 — Update K7 Approver F2 tests cho L1 semantic refactor (advance pointer NOT terminate)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m7s

Run #196 CI FAIL: K7 tests assume Phase=DaDuyet (Plan K K2 original semantic).
L1 (`f3db9e6`) refactor Service ApproveV2Async F2 branch sang advance pointer
tới NV cuối (Phase giữ ChoDuyet) — bro UAT correction.

Em main quên update K7 tests cùng L1 commit → test_infra FAIL → CI block deploy.
L2 (`10ddc87`) + L3 (`f212f04`) inherit failure → bundle hash unchanged prod
(admin/user vẫn CRsX6cFo/X7qb4Zl4 K11 baseline) → L1+L2+L3 KHÔNG deploy.

Fix 2 test assertions match new L1 semantic:
1. ApproveV2_SkipToFinal_AdminTickFlag_AdvancesToLastSlot (rename từ _SetsPhaseDaDuyet):
   - Phase.Should().Be(ChoDuyet) — giữ ChoDuyet KHÔNG terminal
   - CurrentWorkflowStepIndex.Should().Be(1) — lastStepIdx (Bước cuối)
   - CurrentApprovalLevelOrder.Should().Be(2) — lastLevelMaxOrder (Cấp cuối)
   - SlaDeadline.Should().NotBeNull — SLA reset 7d cho NV cuối
   - Changelog assertion: "Approver skip thẳng" (text mới)

2. ApproveV2_SkipToFinal_FlagOff_Admin_BypassesFlagCheck:
   - Phase.Should().Be(ChoDuyet)
   - Pointer advance tới (1, 2)
   - Changelog "Approver skip thẳng"

3. ApproveV2_SkipToFinal_FlagOff_NonAdmin_ThrowsConflictException — UNCHANGED
   (ConflictException semantic giống L1 — flag check trước advance).

Verify:
- dotnet test SolutionErp.slnx 104/104 PASS (58 Domain + 46 Infra)
- 3 Approver F2 tests all green

Pattern lesson saved: Service refactor → update test cùng commit (test-before §7
rule). Em main vi phạm UAT mode skip dotnet test mỗi chunk → CI catch retroactive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-15 01:47:17 +07:00
parent f212f04365
commit da30e270c8

View File

@ -325,12 +325,15 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests
} }
[Fact] [Fact]
public async Task ApproveV2_SkipToFinal_AdminTickFlag_SetsPhaseDaDuyet() public async Task ApproveV2_SkipToFinal_AdminTickFlag_AdvancesToLastSlot()
{ {
// Happy path: workflow 2 Step × 2 Level. Slot Cấp 1 Bước 1 admin tick // Happy path (L1 S23 t2 semantic refactor): workflow 2 Step × 2 Level.
// AllowApproverSkipToFinal=true. Actor = userA (Cấp 1 Bước 1 approver, // Slot Cấp 1 Bước 1 admin tick AllowApproverSkipToFinal=true. Actor = userA
// non-admin role). PE pin workflow + Phase=ChoDuyet + pointer init Step 0 Cấp 1. // (Cấp 1 Bước 1 approver, non-admin role). PE pin workflow + Phase=ChoDuyet
// → Phase=DaDuyet, pointer cleared, opinion + PEA + Changelog logged. // + pointer init Step 0 Cấp 1.
// → Phase GIỮ ChoDuyet, pointer advance tới last Step (idx=1) + last Level
// (Order=2), opinion + PEA + Changelog logged. NV cuối vẫn cần ký thật để
// tiến DaDuyet (KHÔNG auto-approve terminal — S23 t2 fix bro UAT).
var (svc, fix, db, _) = CreateService(); var (svc, fix, db, _) = CreateService();
using (fix) using (fix)
{ {
@ -372,10 +375,10 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests
skipToFinal: true, skipToFinal: true,
ct: CancellationToken.None); ct: CancellationToken.None);
pe.Phase.Should().Be(PurchaseEvaluationPhase.DaDuyet, "Skip → terminal trực tiếp"); pe.Phase.Should().Be(PurchaseEvaluationPhase.ChoDuyet, "L1 S23 t2: skip advance pointer, NV cuối duyệt thật để DaDuyet");
pe.CurrentWorkflowStepIndex.Should().BeNull("Pointer cleared khi terminal"); pe.CurrentWorkflowStepIndex.Should().Be(1, "Pointer advance tới lastStepIdx (Bước cuối)");
pe.CurrentApprovalLevelOrder.Should().BeNull("Pointer cleared khi terminal"); pe.CurrentApprovalLevelOrder.Should().Be(2, "Pointer advance tới lastLevelMaxOrder (Cấp cuối Bước cuối)");
pe.SlaDeadline.Should().BeNull("SLA cleared khi terminal"); pe.SlaDeadline.Should().NotBeNull("SLA reset 7d cho NV cuối nhận lại");
// 1 PEL opinion UPSERT cho slot Cấp 1 Bước 1 trước skip // 1 PEL opinion UPSERT cho slot Cấp 1 Bước 1 trước skip
var opinions = await db.PurchaseEvaluationLevelOpinions var opinions = await db.PurchaseEvaluationLevelOpinions
@ -391,11 +394,11 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests
approvals[0].ApproverUserId.Should().Be(userA.Id); approvals[0].ApproverUserId.Should().Be(userA.Id);
approvals[0].Decision.Should().Be(ApprovalDecision.Approve); approvals[0].Decision.Should().Be(ApprovalDecision.Approve);
// Changelog entry với context note chứa "Approver duyệt thẳng Cấp cuối" // Changelog entry với context note chứa "Approver skip thẳng" + "Bước/Cấp"
var changelogs = await db.PurchaseEvaluationChangelogs var changelogs = await db.PurchaseEvaluationChangelogs
.Where(c => c.PurchaseEvaluationId == pe.Id).ToListAsync(); .Where(c => c.PurchaseEvaluationId == pe.Id).ToListAsync();
changelogs.Should().Contain(c => c.ContextNote != null changelogs.Should().Contain(c => c.ContextNote != null
&& c.ContextNote.Contains("Approver duyệt thẳng Cấp cuối")); && c.ContextNote.Contains("Approver skip thẳng"));
} }
} }
@ -463,9 +466,11 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests
[Fact] [Fact]
public async Task ApproveV2_SkipToFinal_FlagOff_Admin_BypassesFlagCheck() public async Task ApproveV2_SkipToFinal_FlagOff_Admin_BypassesFlagCheck()
{ {
// Admin bypass: workflow same nhưng AllowApproverSkipToFinal=false cho slot Cấp 1 Bước 1. // Admin bypass (L1 S23 t2 semantic): workflow same nhưng AllowApproverSkipToFinal=false
// Actor = adminUser (actorRoles contains "Admin"), trong slot Cấp 1 Bước 1. // cho slot Cấp 1 Bước 1. Actor = adminUser (actorRoles contains "Admin"), trong slot.
// → DaDuyet (admin bypass flag), pointer cleared, opinion logged, Changelog "Approver duyệt thẳng Cấp cuối". // → Phase GIỮ ChoDuyet, pointer advance tới last slot (idx=1, Order=2),
// opinion logged, Changelog "Approver skip thẳng". Admin bypass flag check
// — NV cuối vẫn cần ký thật để DaDuyet.
var (svc, fix, db, _) = CreateService(); var (svc, fix, db, _) = CreateService();
using (fix) using (fix)
{ {
@ -507,20 +512,20 @@ public class PurchaseEvaluationWorkflowServiceReturnModeTests
skipToFinal: true, skipToFinal: true,
ct: CancellationToken.None); ct: CancellationToken.None);
pe.Phase.Should().Be(PurchaseEvaluationPhase.DaDuyet, "Admin bypass flag → terminal"); pe.Phase.Should().Be(PurchaseEvaluationPhase.ChoDuyet, "L1 S23 t2: skip advance pointer, NV cuối duyệt thật");
pe.CurrentWorkflowStepIndex.Should().BeNull("Pointer cleared"); pe.CurrentWorkflowStepIndex.Should().Be(1, "Pointer advance tới lastStepIdx");
pe.CurrentApprovalLevelOrder.Should().BeNull("Pointer cleared"); pe.CurrentApprovalLevelOrder.Should().Be(2, "Pointer advance tới lastLevelMaxOrder");
// Opinion logged (UPSERT trước skip) // Opinion logged (UPSERT trước skip)
var opinions = await db.PurchaseEvaluationLevelOpinions var opinions = await db.PurchaseEvaluationLevelOpinions
.Where(o => o.PurchaseEvaluationId == pe.Id).ToListAsync(); .Where(o => o.PurchaseEvaluationId == pe.Id).ToListAsync();
opinions.Should().HaveCount(1); opinions.Should().HaveCount(1);
// Changelog entry với "Approver duyệt thẳng Cấp cuối" // Changelog entry với "Approver skip thẳng"
var changelogs = await db.PurchaseEvaluationChangelogs var changelogs = await db.PurchaseEvaluationChangelogs
.Where(c => c.PurchaseEvaluationId == pe.Id).ToListAsync(); .Where(c => c.PurchaseEvaluationId == pe.Id).ToListAsync();
changelogs.Should().Contain(c => c.ContextNote != null changelogs.Should().Contain(c => c.ContextNote != null
&& c.ContextNote.Contains("Approver duyệt thẳng Cấp cuối")); && c.ContextNote.Contains("Approver skip thẳng"));
} }
} }