HOW TO TEST

How to Test Notifications.

Core Features A complete testing guide for notification systems: trigger conditions, email/SMS/push/in-app delivery, content accuracy, personalisation, deep links, timing, retry logic, duplicate prevention, user preferences, unsubscribe, locale handling, and failure auditing.

12
scenarios
8
test cases
13 min
read
intermediate3–5 hours (full suite); 1 hour (smoke pass covering trigger, delivery, content, and unsubscribe) testingQA engineersSDETsAutomation engineers

Notifications are the application's primary channel for reaching users after they leave the UI. A bug here silently fails the user: a missed order confirmation, a duplicate alert flooding an inbox, a deep link navigating to the wrong screen, or a unsubscribe link that does not work. This guide covers the full notification surface: trigger conditions for each notification type, multi-channel delivery (email, SMS, push, in-app), content and personalisation accuracy, deep links, timing and scheduling, retry and idempotency, duplicate prevention, user preference enforcement, unsubscribe and opt-out, locale and timezone handling, failure modes, and audit trails. All test cases are written for a Cypress/Playwright engineer with access to a test inbox API.

Risks

Notification sent despite user opting out

If preference or unsubscribe state is checked at creation time rather than delivery time — or if the check is applied to only one channel — a user who has opted out can still receive notifications via another channel.

Duplicate notifications from retry without idempotency

If a delivery failure triggers a retry and the notification system does not track which deliveries have already succeeded, users receive multiple copies of the same notification on retry.

Deep links navigating to the wrong content

A push notification's deep link pointing to entity ID 'order-123' opens the correct screen in development but navigates to a different entity or a 404 in production due to environment-specific ID schemes or missing route handlers.

Notification content exposes another user's data

Template rendering bugs where the recipient's token is not correctly scoped can include another user's name, order details, or account information in the notification — a serious privacy breach.

Time-sensitive notifications arriving late or not at all

Password-reset links, two-factor codes, and order-update notifications have short validity windows. Delivery delays caused by queue backlogs, rate limiting by the email provider, or webhook failures render them useless.

Failed notifications silently dropped — no retry or alert

If the notification service does not implement retry logic or alerting on delivery failure, critical messages (order confirmations, security alerts) are silently lost with no visibility to the team or the user.

Unsubscribe links broken or bypassed

An unsubscribe link that returns a 404, a generic error, or that does not update the user's preference record leaves users unable to opt out and exposes the product to legal liability under CAN-SPAM and GDPR.

Test Scenarios

Correct trigger conditions fire the notification

CriticalfunctionalFully automated

Perform the triggering action (e.g. place an order, reset a password, share a file) and assert the notification is sent. Assert no notification fires for non-trigger actions.

Email notification is delivered to the correct recipient

CriticalfunctionalFully automated

Trigger a notification and poll the test inbox. Assert the email arrives within the defined SLA (e.g. 60 s), is addressed to the triggering user's email only, and not to any other address.

Notification content matches the trigger context

CriticalfunctionalFully automated

Assert the notification body contains the correct personalised data: user name, order ID, amount, entity name — not placeholder text, wrong user data, or missing fields.

Deep link in notification navigates to the correct entity

HighfunctionalFully automated

Click the CTA link in the notification. Assert it opens the correct screen/page with the correct entity (e.g. order detail for the specific order that triggered the notification, not a generic page).

One trigger produces exactly one notification per channel

CriticalfunctionalFully automated

Perform a triggering action once. Assert exactly one email, one push, and one in-app notification is created. Assert retrying the API trigger (with the same idempotency key) does not create a second notification.

Failed delivery is retried and eventually succeeds

HighnegativeFully automated

Simulate a transient delivery failure (mock the email/SMS provider to return 503 on the first attempt). Assert the notification system retries within the documented backoff window and delivers on retry.

Notification is not sent when the user has disabled that type

CriticalfunctionalFully automated

Disable a notification type in user preferences (e.g. marketing emails off). Trigger the notification. Assert the notification is NOT delivered via that channel. Assert other channels are unaffected if only one was disabled.

Unsubscribe link correctly opts the user out

CriticalfunctionalFully automated

Click the unsubscribe link in an email. Assert the page confirms the opt-out and the user's preference is updated in the database. Assert no further emails of that type are sent after opt-out.

Notification is sent in the user's configured language

HighfunctionalFully automated

Set a user's locale to French (fr). Trigger a notification. Assert the email subject, body, and CTA button are in French. Assert no English text appears in localised sections.

Scheduled notification is sent at the correct time in the user's timezone

HighfunctionalFully automated

For a notification scheduled at a specific time (e.g. daily digest at 9 AM), set the user's timezone to UTC+5:30. Assert the notification is delivered at 9 AM IST, not 9 AM UTC.

Failed notification delivery is recorded in the audit log

HighfunctionalFully automated

Force a permanent delivery failure (invalid email address, disabled push token). Assert the failure is recorded in the notification log with: timestamp, channel, error code, and recipient.

In-app notification appears in real time without page refresh

HighfunctionalFully automated

While a user is authenticated and the app is open, trigger a notification from another session or API. Assert the in-app notification badge/count updates and the notification appears in the bell menu without requiring a page refresh.

Detailed Test Cases

Preconditions

  • Test user with email test-notif@example.com
  • Test inbox API accessible (Mailhog, Mailtrap)
  • Order placement API available

Steps

  1. 1.POST /api/orders to create a new order for the test user
  2. 2.Record the returned orderId
  3. 3.Poll test inbox for an email to test-notif@example.com (timeout 60 s)
  4. 4.Assert email arrives within 60 s
  5. 5.Assert email subject contains the order reference
  6. 6.Assert email body contains: user's first name, orderId, item list, total amount
  7. 7.Assert email body does NOT contain placeholder tokens like {{firstName}} or [ORDER_ID]
  8. 8.Assert the CTA link leads to /orders/{orderId} (not /orders/{someOtherId})

Expected result

Email arrives within 60 s with correct personalised content and a working order deep link.

Test data

  • Recipient: test-notif@example.com
  • Order ID: from POST /api/orders response

Edge Cases

Notification triggered for an account that was deleted between trigger and delivery

If a user deletes their account after an event fires but before the notification is delivered, the system should silently discard the notification and not log an error about a missing user.

User changes their email address between trigger and delivery

If an email notification is queued and the user updates their email while it is in the queue, the delivery should go to the new email address, not the old one — or use a snapshot of the email at enqueue time (document which behaviour is intended).

Notification triggered millions of times by a runaway job

A background job bug causes the same notification event to fire 10,000 times in a minute. The system should have rate limiting per user+event-type to prevent inbox flooding even if the upstream trigger misfires.

In-app notification count badge not updated after read

The unread-notification badge should decrement when the user opens the notification. If it stays at the stale count, users ignore the badge as unreliable.

Notification sent to a push token that has been invalidated

Push tokens expire when a user reinstalls the app, changes devices, or revokes permission. The push provider returns a 'token not registered' error that the system must handle by removing the stale token from the database.

Notification with a time-expired deep link

A push notification linking to a time-limited promotion arrives after the promotion has ended. The link should navigate to a graceful 'offer expired' page, not a 404.

Notification preferences set to off but a transactional email is still sent

Marketing preferences should not suppress transactional notifications (receipts, password resets). The preference system must distinguish between marketing and transactional channels.

Timezone stored as a name rather than an offset — DST transition

Storing 'America/New_York' (correct) vs '-05:00' (incorrect — doesn't handle DST). Scheduled notifications should use IANA timezone names and be re-evaluated at send time to correctly account for daylight saving time changes.

Long notification body exceeds SMS character limit

SMS messages over 160 characters are split into multiple parts. If the application does not account for this, the message body is truncated at exactly 160 characters mid-sentence.

Automation Ideas

Test inbox polling for email delivery assertions

Integrate Mailhog or Mailtrap's REST API into the test suite. After triggering a notification, poll the inbox with a timeout and assert the email content — subject, personalisation, deep link — without manual checking.

Tools: playwright, cypress

Mock notification provider for failure and retry tests

Use Mock Service Worker (MSW) or Wiremock to stub the email/SMS provider. Configure it to return 503 on the first call and 200 on the second. Assert the notification log records the retry and the eventual success.

Tools: msw, wiremock, playwright

Idempotency key collision test

Fire the same trigger twice with the same idempotency key via the API. Assert the inbox contains exactly one email. Automatable via parallel API calls + inbox count assertion.

Tools: playwright, postman

Notification preference enforcement matrix

Drive a matrix of {channel, preferenceState, triggerType, expectedDelivery} through the notification trigger endpoint. Assert each combination: opt-out + marketing → 0 emails, opt-in + transactional → 1 email, etc.

Tools: playwright, postman

Localisation completeness check

For each supported locale, trigger all notification types and assert: (1) no {{placeholder}} tokens in the rendered output, (2) subject is non-English for non-English locales, (3) character encoding is correct (no mojibake for CJK or accented characters).

Tools: playwright, cypress

Audit log completeness assertion

After each notification delivery (success or failure), assert the audit log entry contains: notificationId, userId, channel, status, timestamp, and errorCode if failed. Run as a contract test against the audit API.

Tools: playwright, postman

Common Bugs

Email sent to the previous email address after an address change

The notification job captures the user's email at enqueue time and caches it. When the user updates their email before delivery, the job still uses the cached address, which may belong to someone else.

Impact: Sensitive notifications sent to a third party; data leak if the old email is now owned by another person.

Unsubscribe link uses GET and is triggered by email preview

Some email security tools and clients pre-fetch all links in an email to check for malware. An unsubscribe link that opts out on GET (not POST) causes users to be unsubscribed without their knowledge when the email is scanned.

Double delivery on transient webhook failure

When the notification webhook to the email provider times out, the notification service retries — but the first request had already been accepted and queued by the provider. The provider delivers both, and the user receives two identical emails.

In-app notification count does not decrement on read

The unread count is fetched on page load but never updated in real time. After reading all notifications, the badge still shows the old count until the page is refreshed.

Placeholder tokens appear in production emails

Template rendering fails silently when a data field is null. Instead of falling back to a default, the raw template token ({{firstName}}, {{orderTotal}}) is included in the sent email.

Notification preferences UI shows 'off' but backend sends anyway

The preference toggle is a UI-only control that updates a local state variable but fails to POST the change to the API due to a missing error handler. The backend still has the old preference state.

Notification fired for cancelled or rolled-back orders

A notification event is emitted synchronously when the order is created, before the payment confirmation arrives. If payment fails and the order is cancelled, the 'order confirmed' email has already been sent.

SMS truncated at exactly 160 characters mid-word

Long SMS notification bodies are not split intelligently. The application truncates at 160 characters without word boundary detection, breaking messages mid-word.

Useful Tools

Playwright

End-to-end notification flows, inbox polling via API, and in-app notification UI assertions.

Cypress

Notification E2E tests with cy.intercept for stubbing webhook endpoints and testing retry behaviour.

WireMock

Stub email/SMS provider APIs to simulate delivery failures, delays, and rate limits deterministically.

MSW (Mock Service Worker)

Intercept notification provider API calls at the network layer in browser tests to simulate failures.

Postman

Trigger notification events via API, assert audit logs, and test idempotency key behaviour.

Mailtrap

Catch test emails, inspect content and headers, and query deliveries via REST API without real SMTP.

Mockoon

Mock third-party notification providers (email, SMS, push) locally with configurable response scenarios.

Practice this → Try it hands-on in the Buggy Web App.