CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

testland/push-notification-test-author

Use when push or in-app notifications need tests: Web Push with VAPID, Apple APNs and Firebase FCM subscription, payload encryption, badge, sound and click actions, expired subscriptions, silent vs alert pushes and topic routing, plus in-app delivery over WebSocket or SSE with read state.

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files
name:
push-notification-test-author
description:
Use when push or in-app notifications need tests: Web Push with VAPID, Apple APNs and Firebase FCM subscription, payload encryption, badge, sound and click actions, expired subscriptions, silent vs alert pushes and topic routing, plus in-app delivery over WebSocket or SSE with read state.

push-notification-test-author

Overview

Three push platforms dominate:

PlatformStandard / Provider
Web PushIETF RFC 8030 + VAPID (RFC 8292)
APNs (iOS / iPadOS / macOS)Apple proprietary HTTP/2
FCM (Android + cross-platform)Google Firebase

Each platform has distinct test patterns; Step 1 picks the isolation level and Steps 2-4 cover each platform.

When to use

  • The repo sends push notifications via any of the three platforms.
  • A regression suite needs to verify push payload shape, click actions, badge counts.
  • Compliance review needs evidence that revoked subscriptions are cleaned up.
  • The team integrates with FCM / APNs / Web Push directly (not via OneSignal-style abstractions).

How to use

  1. Identify which push platform(s) the app targets - Web Push, APNs, FCM, or a mix (Overview).
  2. Pick the isolation level; default to mocking the SDK send method (Step 1).
  3. Author the happy-path payload-shape test for each channel (Steps 2 - 4, references/platform-test-patterns.md).
  4. Add the invalid-token cleanup test for the 410 / unregistered path (Steps 2 - 4).
  5. Cover silent-vs-alert, deep links, and FCM topic routing (Step 5).
  6. Assert sandbox-only APNs endpoints so tests never reach real users (Step 3).
  7. Sabotage-check each test (Step 6), then run the Step 7 checklist.

Step 1 - Choose the test isolation level

LevelExampleTradeoffs
Mock the SDKPatch FCM/APNs/Web-Push library send methodFast; misses provider-side behavior
Sandbox / emulatorAPNs sandbox, FCM emulator (limited), web-push test browserRealistic; slower
End-to-end with test devicesReal device farmHighest fidelity; expensive + flaky

Default: mock the SDK - fast, deterministic, covers payload-shape + error-path logic which is most of what regressions hit. Use sandbox/emulator when verifying provider-side behavior (encryption, rate-limit, real 410 handling); use real device farms only for grouped-notification / channel UX work.

Step 2 - Web Push tests

Mock webPush.sendNotification, assert the payload, and test that a 410 Gone from the push service deletes the stored subscription (RFC 8030 §6.2 - the subscription has expired or been revoked). Add a service-worker test that dispatches a synthetic PushEvent and asserts showNotification gets the right title and body. Recipes: references/platform-test-patterns.md.

Step 3 - APNs tests

Mock the APNs client, assert the aps payload, and test that a 410 with reason Unregistered removes the device token (sending requests to APNs). Assert the client is built for api.sandbox.push.apple.com in every test and CI configuration; api.push.apple.com reaches real users.

Step 4 - FCM tests

Use the HTTP v1 API: the legacy HTTP and XMPP APIs were deprecated on 20 June 2023 and their shutdown began on 22 July 2024 (FCM migration guide). Mock admin.messaging().send, assert the message (token or topic, notification, data, android, apns), and test that messaging/registration-token-not-registered removes the token.

Step 5 - Payload variants: silent, deep link, topic

Code for each is in the "Payload variants" section of references/platform-test-patterns.md. What each test must assert:

VariantAssert
Silent (background) push, APNsaps holds only content-available: 1 (no alert, sound, badge); request headers apns-push-type: background and apns-priority: 5. The system may throttle or drop these, so the app must not depend on every one arriving (background updates)
Alert pushalert title and body present; apns-push-type: alert
Deep linkThe payload's link / data route points at the exact screen (/orders/123), built from the entity id, not a constant
FCM topicSubscribe call uses the topic name the sender publishes to; a send to that topic uses topic, not token

Opening the deep link on a device needs device automation (appium-testing, espresso-suite, xcuitest-suite).

Step 6 - Check the suite catches regressions

Before calling the suite done, prove each test can fail:

  1. Comment out the token / subscription delete in the cleanup handler: the 410 / Unregistered / registration-token-not-registered tests must go red. Restore it.
  2. Change the deep-link builder to a constant route: the deep-link test must go red.
  3. Add alert to the silent payload: the silent-push test must go red.
  4. grep -rn "api.push.apple.com" tests/ config/test*: no hits.

A test that stays green through its own sabotage is not testing the path; fix the assertion (usually it asserts on the mock call instead of the stored state) and repeat.

Step 7 - Per-channel checklist

For each channel the app uses:

  1. Happy-path send with correct payload (Steps 2-4)
  2. Invalid-token cleanup asserted on stored state (Steps 2-4)
  3. Silent vs alert payload and headers (Step 5)
  4. Deep link (Step 5)
  5. Topic routing (FCM, Step 5)
  6. Sandbox-only endpoints in tests (Step 3)
  7. Each test seen failing once (Step 6)

Worked example

An e-commerce app sends a Web Push "order shipped" notification and must clean up revoked subscriptions.

  1. Platform: Web Push only (Overview). Isolation: mock webPush.sendNotification (Step 1 default).
  2. Happy path: a test drives pushOrderUpdate(sub, { orderId: 123, status: 'shipped' }) and asserts sendNotification was called with a payload string containing "orderId":123. The mock returns { statusCode: 201 }; the assertion passes.
  3. Revocation: a second test mocks sendNotification to reject with { statusCode: 410 }. After pushOrderUpdate runs, the test asserts the subscription row is gone from storage (Subscription.findOne(...) returns null), proving the 410 cleanup path per RFC 8030.
  4. Service-worker side: dispatch a synthetic PushEvent whose data.json() returns the order payload; assert self.registration.showNotification was called with body shipped.
  5. Result: three passing tests - payload shape, 410 cleanup, and SW render - cover the whole Web Push channel. Repeat the references/platform-test-patterns.md recipes for APNs / FCM if the app adds those channels.

Anti-patterns

Anti-patternWhy it failsFix
Test only happy pathMiss expired-token cleanup; storage grows; spam to dead devicesStep 2-4 410 / 404 / unregistered tests
Hardcode VAPID public key in tests + checked into repoKey rotation breaks testsInject via env var
Send to real production APNs in testsReal users get test pushSandbox environment (Step 3)
Silent payload with alert or without apns-push-type: background / apns-priority: 5Not delivered as a background updateStep 5
Skip deep-link testDeep links break silently after refactorsStep 5
Cleanup test asserts only that the mock was calledPasses when the delete is goneAssert stored state; sabotage check (Step 6)
FCM legacy server key / fcm.googleapis.com/fcm/sendLegacy API shut down from July 2024HTTP v1 (Step 4)

Limitations

  • This is a build-an-X workflow. Tests use the application's chosen push library + mocks at the SDK boundary.
  • APNs sandbox has rate limits; high-volume CI may need to mock vs real sandbox.
  • FCM emulator coverage is limited; many provider-side behaviors require real FCM (sandbox / dev project).
  • Push-notification UX (e.g., grouped notifications, notification channels on Android) requires device-side testing (Espresso / XCUITest); see qa-mobile plugins.
  • iOS notification permissions UI flow is OS-managed; tests cover app-side request + handle response.

References

Workspace
testland
Visibility
Public
Created
Last updated
Source
GitHub Actions
Repository
https://github.com/testland/qaVerified
Badge
testland/push-notification-test-author badge