12. Testing
12.1 Standalone Library Tests
Shumoul.Saas.WhatsAppIntegration/Tests — xUnit, 29 test cases across 4 files:
| File | Cases | Covers |
|---|---|---|
WhatsAppWebhookParserTests.cs | 9 | Text/media/status message parsing; the ProfileName regression suite: single contact/message, multi-contact matching by wa_id, no matching contact, no contacts array at all |
WhatsAppSignatureValidatorTests.cs | 7 | Valid signature, invalid signature, missing header, malformed header, missing AppSecret, case-insensitive sha256= prefix |
WhatsAppCloudApiClientRequestConstructionTests.cs | 8 | Text send and template send HTTP request shape (URL, headers, JSON body) |
WhatsAppCloudApiClientMediaTests.cs | 5 | GetMediaMetaAsync happy path / missing-token short-circuit / HTTP-error path; DownloadMediaBytesAsync happy path and metadata-failure short-circuit |
Run with dotnet test from the repository root.
12.2 ERP Tests
Shumoul.Application.Tests/HelpersTests/WhatsAppPhoneHelperTests.cs — 13 test cases, [Theory]-driven,
covering the single consolidated phone normalizer (WhatsAppPhoneHelper.TryNormalizePhone):
- 6 accepted formats: already-normalized
966XXXXXXXXX, local0XXXXXXXXX, bare 9-digit5XXXXXXXX, leading+, embedded spaces, embedded dashes. - 7 rejected inputs:
null, empty, whitespace, non-numeric, too-short, and two wrong-length variants.
No dedicated ERP-side test exists for TenantWhatsAppSender's send path itself — its behavior is fully
delegated to WhatsAppCloudApiClient, already covered on the library side (§12.1); an ERP-side HTTP-mocking
test for the same client would duplicate rather than add coverage.
12.3 Webhook Parser Tests
See §12.1's WhatsAppWebhookParserTests.cs row. The most important regression to be aware of when modifying
this parser: the original test payload never included wa_id on its contact object, because the old (buggy)
code never checked it — the test was corrected to include wa_id and assert the populated ProfileName,
turning a "passes accidentally" test into a real regression guard.
12.4 Signature Tests
See §12.1's WhatsAppSignatureValidatorTests.cs row. Tests construct a real HMAC-SHA256 digest over a known
body/secret pair and assert both the positive (IsValid: true) and negative (IsValid: false, with
Reason populated) cases.
12.5 Phone Normalization Tests
See §12.2. This is the one piece of WhatsApp-related business logic tested in the ERP repository rather than
the standalone library, consistent with WhatsAppPhoneHelper living in Shumoul.Application.Helpers by
design (see ADR-001).
12.6 How QA Should Test Using Postman
- Authenticate against the tenant's auth endpoint to obtain a JWT; set
Authorization: Bearer {token}as a Postman collection-level header. - Verify configuration first —
GET api/v1/Communication/Diagnostics/WhatsAppandGET api/v1/Communication/Healthreveal whether credentials are configured before attempting any send. - Test connectivity without sending a message —
POST api/v1/Communication/Test/WhatsAppperforms a business-account lookup only; safe to run repeatedly. - Test a real template send to a controlled test number —
POST api/v1/WhatsApp/SendTestTemplate(uses the platform's own number) orPOST api/v1/Communication/Send/WhatsApp(uses the tenant's own number, requiresWhatsAppOperationalSettings.EnableSending). - Preview before sending —
POST api/v1/Communication/Previewshows the resolved template/body without dispatching, useful for validating template parameter mapping before a real send. - Simulate an inbound webhook —
POST api/v1/notifications/webhookwith a payload matching §8.5 and a correctly-computedX-Hub-Signature-256header (compute HMAC-SHA256 of the exact request body bytes using the configuredAppSecret; a Postman pre-request script can compute this if the secret is available in a QA-only environment). Note this endpoint requires no JWT — only the signature. - Run the full WhatsApp smoke test —
POST api/v1/Communication/SmokeTest/WhatsAppagainst a test phone number; inspect thesteps[]array in the response for the first failing step rather than only the top-levelpassedflag.
Never point step 4 or step 7 at a real customer's phone number, and never run them against a production tenant unless the intent is genuinely to send that customer a message.
