14. Postman Testing Guide
This chapter describes the manual/Postman test sequence used to validate the feature end-to-end during development (Phases 1.3–1.6). Use it for local/dev verification — never against a production tenant or database.
14.1 Collection variables
Set these as Postman collection/environment variables:
| Variable | Example | Notes |
|---|---|---|
mtapi_base | https://localhost:7156 | Shumoul.MultiTenancyApi.Host |
backend_base | https://localhost:5001 | Shumoul.Api |
jwt | (obtained from a real login response) | Use the app's real login endpoint against a dev tenant — do not hand-craft tokens against anything but a local dev environment |
internal_key | (from your local OnboardingApplyBridgeSettings:InternalApiKey / InternalServiceAuthSettings:OnboardingApplyApiKey) | Only needed for directly testing the internal bridge; never share this value |
session_id | (captured from the answers response) |
14.2 Golden-path sequence
- Login against
Shumoul.Api's normal login endpoint with a real dev tenant admin account. Save the returned token to{{jwt}}. GET {{mtapi_base}}/api/v1/onboarding/statuswithAuthorization: Bearer {{jwt}}— expectisRequired: true,status: "NotStarted".GET {{mtapi_base}}/api/v1/onboarding/survey?lang=ar— confirm steps/questions come back; note the required question keys.POST {{mtapi_base}}/api/v1/onboarding/answerswith a body covering at least the required questions, e.g.:Save the returned session id to{ "answers": { "activityType": "RestaurantCafe", "hasPos": true, "usesVat": true } }{{session_id}}.POST {{mtapi_base}}/api/v1/onboarding/recommendation— confirmsettingsPatchincludes the groups you expect for the answers given (e.g.CashierAppsSettings,TaxSettings).POST {{mtapi_base}}/api/v1/onboarding/applywith{ "sessionId": "{{session_id}}", "acceptAll": true }— expectsucceeded: true.GET {{mtapi_base}}/api/v1/onboarding/statusagain — confirmstatus: "Applied"andappliedProfileCodeis populated.- Verify in the database (dev only) — confirm the touched
AppSettingsrows in the tenant's own database actually changed, and that aTenantOnboardingApplyLogsrow exists withAppliedBymatching your test user.
14.3 Negative test checklist
| Test | Request | Expected |
|---|---|---|
| No token | GET status with no Authorization header | 401 |
| Invalid token | GET status with a garbage/expired Authorization header | 401 |
| Non-admin token | POST answers / recommendation / apply / skip with a valid token for a user without the Admin role | 403 |
| Cross-tenant | POST apply with a valid token for a different tenant, targeting a sessionId that belongs to another tenant | 403, "Session does not belong to the current tenant." (or an earlier gate rejecting first, depending on the other tenant's subscription state) |
| Double apply | POST apply again on an already-Applied session | 200, succeeded: false, "already been applied" |
| Apply before recommendation | POST apply on a session still at InProgress | 200, succeeded: false, "must be generated before it can be applied" |
14.4 Internal bridge negative tests (dev only, direct to Shumoul.Api)
| Test | Request | Expected |
|---|---|---|
| Missing internal key | POST {{backend_base}}/api/internal/onboarding/apply-settings-patch with no X-Shumoul-Internal-Key | 401 |
| Wrong internal key | Same, with an incorrect key value | 403 |
| Tenant mismatch | Same, with a TenantId header that doesn't match the request body's tenantId | 502, "Tenant could not be resolved.", and no AppSettings row changes |
| CacheSettings in patch | A patch containing a CacheSettings group | ignoredGroups includes it, a warning explains why, no crash |
| Guid property in patch | A patch setting a Guid-typed property like WarehouseId | Ignored with a warning; sibling valid properties in the same group still apply |
14.5 What not to test manually
Do not attempt to hand-craft a JWT against a staging or production environment's signing key. Hand-crafted tokens (matching the exact claim shape in Chapter 9) are a development-only technique for exercising specific role/tenant combinations quickly when a matching real user doesn't exist yet — always prefer a real login response in any shared environment.
