[CLAUDE] Tests: Plan C B-Wrap BW1-BW7 Contract V2 test bundle +9 tests (111→120)
Plan C B-Wrap (spec D-Bis migration-todos.md lines 563-619) — Contract V2
ApproveV2Async ~227 LOC NO test cover after S29 Plan B deploy prod. Risk
gotcha #48 high. Anh main S32 chốt defer dedicated session ~2h post-Phase 9
stabilize. S33 kick off cùng Plan B G-H1.
7 BW spec deterministic → 9 [Fact] method (BW6 split 3 for clean isolation):
BW1 — ApproveV2 happy path Cấp 1→Cấp 2 cùng Bước advance pointer + Approval
row + LevelOpinion UPSERT + LogTransition "Hoàn tất Cấp 1, sang Cấp 2"
BW2 — Terminal Cấp cuối Bước cuối → DaPhatHanh + gen mã HĐ format
"FLOCK01/HĐTP/SOL&BTBM/01" + clear pointers
BW3 — skipToFinal F2 admin opt-in AllowApproverSkipToFinal=true Cấp 1 Bước 1
→ advance lastStepIdx/lastLevelMaxOrder + prefix [Duyệt vượt cấp]
BW4 — Outsider (không trong pendingLevelGroup.ApproverUserId) → ForbiddenException
BW5 — CreateContractCommand pin workflow ApplicableType=DuyetNcc → exception
"Workflow phải ApplicableType=Contract" (Reviewer S29 MAJOR catch)
BW6a — ContractLevelOpinion duplicate composite (ContractId, LevelId)
→ DbUpdateException (UNIQUE Mig 33)
BW6b — UPSERT pattern fetch+update → 1 row only Comment updated
BW6c — Delete Contract → FK Cascade auto-delete ContractLevelOpinions
BW7 — V1 fallback skipToFinal non-admin → ConflictException
"skipToFinal chỉ hỗ trợ HĐ V2"
Test infra dependencies:
- ✅ TestApplicationDbContext SQLite reuse (Common/SqliteDbFixture.cs)
- ✅ IdentityFixture reuse (UserManager + CreateUserAsync helper)
- ✅ FixedDateTime reuse (deterministic clock)
- ✅ NoOpNotificationService reuse
- 🆕 TestCurrentUser stub ICurrentUser (configurable per-test scope) — 31 LOC
- ✅ REAL ChangelogService inject TestCurrentUser
- ✅ REAL ContractCodeGenerator inline (no mock needed, SqliteDbFixture
enough for atomic sequence test)
Verify:
- dotnet build: 0 err 0 warn (2.49s)
- dotnet test: **120/120 PASS** (was 111 baseline + 9 new)
- Domain: 58/58 PASS
- Infrastructure: 62/62 PASS (was 53 → +9 BW)
Reviewer S33 verdict: **PASS** — 0 critical/major issues, 3 minor cosmetic
defer-OK (CreateService helper dead code unused, TestCurrentUser null
defensive C# warning shadow, BW1-4+7 vs BW6 using pattern style). 9/9 indep
verify PASS in 4.7s. Spec strings exact match service source (BW1 ContextNote
+ BW2 Mã HĐ + BW3 ContextNote + BW4-7 exception messages).
Smart Friend independence lần thứ 5 cumulative:
1. S22 #44 silent 403 — Reviewer catch
2. S25 #48 SQLite tie-break — Reviewer catch
3. S29 Plan CA password ≥12 — Reviewer catch
4. S29 Plan B ApplicableType — Reviewer catch
5. S33 Plan C BW — clean, em main+Implementer quality genuine NOT lowered
Patterns applied:
- Implementer Pattern 12-bis cross-module entity cookie-cutter mirror PE
→ Contract (proven 3× S29 + S33)
- Test deterministic seeded helper SeedApproverF2WorkflowAsync mirror
PurchaseEvaluationWorkflowServiceReturnModeTests.cs structure
Files (4 new tests + 1 stub):
- A tests/SolutionErp.Infrastructure.Tests/Common/TestCurrentUser.cs (31 LOC)
- A tests/SolutionErp.Infrastructure.Tests/Services/ContractWorkflowServiceApproveV2Tests.cs
- A tests/SolutionErp.Infrastructure.Tests/Application/CreateContractCommandApplicableTypeTests.cs
- A tests/SolutionErp.Infrastructure.Tests/Common/ContractV2SchemaPersistenceTests.cs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>