5.2 KiB
title, tags, created
| title | tags | created | ||||
|---|---|---|---|---|---|---|
| Notification Assertion Procedure |
|
2026-06-06 |
Notification Assertion Procedure
Every E2E business step must verify notifications. A test step is incomplete until notification persistence and, where practical, real-time delivery are validated.
Related docs:
Principle
For each state-changing action, assert notifications for the expected recipients. If the product currently does not emit a notification for that action, the E2E must record a notification coverage gap. Silent missing notifications should not be treated as a pass.
Notification Channels To Check
| Channel | Required? | How |
|---|---|---|
| Persistence | Always | GET /api/notifications, GET /api/notifications/unread-count |
| Socket push | Required when runner has sockets enabled | Listen for new-notification on user-<userId> |
| Badge count sync | Required for read/mark-read steps | unread-count-update socket event or count endpoint |
| Email/push | Not required today | Planned digest/push work is not implemented |
Baseline Before a Scenario
For every actor:
- Authenticate.
- Read unread count:
GET /api/notifications/unread-count - Read latest notifications:
GET /api/notifications?page=1&limit=5 - Store:
baselineUnreadCount;- latest notification id;
- timestamp.
Do this before creating purchase requests or offers so later assertions can distinguish new notifications from old ones.
Per-Step Assertion Algorithm
After each action:
- Identify expected recipients.
- Poll each recipient's notifications for up to the notification SLA window.
- Assert at least one new notification matching the action.
- Assert unread count increased by the expected number, unless the notification is intentionally auto-read.
- Assert
actionUrlorrelatedIdpoints to the correct request/payment/offer where the notification type supports it. - If socket instrumentation is active, assert the same notification arrived via
new-notification. - Record
notificationLatencyMs = notification.createdAt - actionCompletedAtor runner-observed first-seen time.
Suggested polling:
| Target | Value |
|---|---|
| poll interval | 500 ms |
| timeout | 10 s for local/dev API notifications |
| hard failure threshold | 30 s |
Expected Marketplace Notifications
| Action | Expected recipients | Expected category/type |
|---|---|---|
| Buyer creates request | eligible sellers | purchase_request / new request or opportunity |
| Seller submits offer | buyer | offer / new offer |
| Buyer accepts offer | selected seller | offer / accepted |
| Buyer accepts offer | non-selected sellers | offer / rejected or no-longer-selected, when implemented |
| Payment intent created | buyer | payment / pending or started, when implemented |
| Scanner confirms payment | buyer, selected seller | payment / confirmed or funded |
| Seller marks delivery | buyer | delivery / delivery submitted |
| Buyer confirms delivery | selected seller | delivery / delivery confirmed |
| Dispute raised | buyer, seller, admin/mediator | delivery/payment/system dispute hold, when implemented |
| Release/refund | buyer, seller | payment / release or refund |
Known current gaps from existing docs:
pending_paymentandseller_paidstatus changes are not covered byNotificationService.notifyRequestStatusChanged.- Dispute service notification emits are TODO stubs in the dashboard dispute path.
These known gaps should still be reported by the E2E runner as gaps, not ignored.
Evidence Format
For each step, append a notification assertion record:
{
"step": "seller_offer_created",
"recipient": "buyer",
"recipientUserId": "<id>",
"expected": true,
"observed": true,
"latencyMs": 742,
"unreadBefore": 3,
"unreadAfter": 4,
"notificationId": "<id>",
"category": "offer",
"actionUrl": "/dashboard/request/<requestId>",
"socketObserved": true,
"gap": null
}
For a known gap:
{
"step": "payment_intent_created",
"recipient": "buyer",
"expected": true,
"observed": false,
"gap": "No notification emitted for pending_payment status",
"linkedDoc": "Notification Flow#Purchase request status coverage gap"
}
Pass/Fail Rules
| Condition | Result |
|---|---|
| Expected notification appears within SLA | pass |
| Expected notification appears after SLA but before hard timeout | warning |
| Expected notification never appears and no approved gap exists | fail |
| Notification appears for wrong user | fail |
| Notification exists but has wrong request/payment/offer id | fail |
| Socket missing but persistence exists | warning unless socket coverage is the target |
| Unread count inconsistent with persisted notification | fail |
Performance Metrics
Notification metrics must be included in concurrency profiles:
- notification persistence latency p50/p95/p99;
- socket delivery latency p50/p95/p99;
- notification failures by action and recipient;
- unread count mismatch rate;
- duplicate notification rate;
- Mongo notification insert error rate.