Skip to content
Back to skills

Push Notification Test Author

ASecurity

Build-an-X for push notification tests (push notifications, web push, FCM / APNs push messages) across Web Push (RFC 8030 / VAPID), Apple Push Notification Service (APNs), and Firebase Cloud Messaging (FCM) - covers subscription handshake, payload encryption, badge / sound / click-action assertions, expired-subscription cleanup, silent-vs-alert, and topic-vs-targeted routing; also carries the in-app notification test workflow (WebSocket / SSE / Firebase-listener delivery, read-unread state, m...

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 12, 2026
testingjavascriptpythongojavanodetestingapidocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 12, 2026

npx -y skills add testland/qa --skill push-notification-test-author --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Push Notification Test Author?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Push Notification Test Author
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/testland-push-notification-test-author/badge)](https://www.skillsdirectory.com/skills/testland-push-notification-test-author)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: push-notification-test-author
description: "Build-an-X for push notification tests (push notifications, web push, FCM / APNs push messages) across Web Push (RFC 8030 / VAPID), Apple Push Notification Service (APNs), and Firebase Cloud Messaging (FCM) - covers subscription handshake, payload encryption, badge / sound / click-action assertions, expired-subscription cleanup, silent-vs-alert, and topic-vs-targeted routing; also carries the in-app notification test workflow (WebSocket / SSE / Firebase-listener delivery, read-unread state, multi-session fan-out, offline-then-reconnect) in references/in-app.md. Use when authoring tests for any push or in-app notification flow."
---

# push-notification-test-author

## Overview

Three push platforms dominate:

| Platform | Standard / Provider |
|---|---|
| **Web Push** | IETF 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 the per-platform test approach.

## 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](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, click-action deep links, and FCM topic routing (Steps 5 - 7).
6. Assert production-vs-sandbox environment routing so tests never reach real users (Step 3).
7. Run the per-channel checklist in Step 8 and reconcile against the Anti-patterns table.

## Step 1 - Choose the test isolation level

| Level | Example | Tradeoffs |
|---|---|---|
| Mock the SDK | Patch FCM/APNs/Web-Push library send method | Fast; misses provider-side behavior |
| Sandbox / emulator | APNs sandbox, FCM emulator (limited), web-push test browser | Realistic; slower |
| End-to-end with test devices | Real device farm | Highest 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

Per IETF RFC 8030 (Web Push Protocol): the user-agent subscribes via `pushManager.subscribe()`, the app server sends an encrypted (RFC 8291) + VAPID-signed (RFC 8292) push to the returned endpoint, and the service worker's `push` event calls `self.registration.showNotification()`. Status code `410 Gone` means the subscription is invalid (user revoked or expired); the app must remove it from storage.

Mock `webPush.sendNotification` and assert payload shape plus the 410 cleanup path; add a service-worker harness test that dispatches a synthetic `PushEvent`. Full Node.js + service-worker recipes: [references/platform-test-patterns.md](references/platform-test-patterns.md).

## Step 3 - APNs tests

Apple Push Notification Service has two environments per
[developer.apple.com/documentation/usernotifications][apns-docs]:

[apns-docs]: https://developer.apple.com/documentation/usernotifications

| Environment | Use |
|---|---|
| `api.sandbox.push.apple.com` | Development; uses development APNs certificate |
| `api.push.apple.com` | Production |

Tests typically run against sandbox + use a development APNs
certificate or Auth Key (`.p8` file). Mock `apns_client.send`, assert the `aps` payload shape (alert title / body, sound), and cover the HTTP 410 (`Unregistered`) token-cleanup path. Python recipes: [references/platform-test-patterns.md](references/platform-test-patterns.md).

## Step 4 - FCM tests

Firebase Cloud Messaging supports HTTP v1 API + legacy HTTP API.
Use HTTP v1 for new code (legacy deprecated). Mock `admin.messaging().send`, assert the cross-platform message shape (`token`, `notification`, `data`, `android`, `apns`), and test the `messaging/registration-token-not-registered` cleanup path (same as APNs Step 3). Node.js recipe: [references/platform-test-patterns.md](references/platform-test-patterns.md).

## Step 5 - Silent vs alert push

- **Alert push**: shows a notification UI; user sees + taps.
  Standard pattern.
- **Silent push** (also "background push"): doesn't show UI; wakes
  the app to do background work. Apple imposes throttling on these
  per [apns-docs][apns-docs].

Tests should distinguish the two and assert correct payload:

```javascript
it('uses content-available for background sync', () => {
  const payload = buildSilentSyncPush();
  expect(payload.aps['content-available']).toBe(1);
  expect(payload.aps.alert).toBeUndefined();   // no UI for silent
});
```

## Step 6 - Click-action / deep-link tests

The push payload includes a click-action / URL that opens a
specific app screen. Test that the right deep-link is in the
payload:

```python
def test_order_push_deep_links_to_order_screen():
    payload = build_order_push(order_id=123)
    assert payload["data"]["click_action"] == "/orders/123"
```

End-to-end click-action tests require device automation (Espresso /
XCUITest); cross-ref `appium-testing` (in the qa-mobile plugin).

## Step 7 - Topic vs targeted routing

FCM supports topic subscriptions (broadcast to all subscribers of a
topic) vs targeted (single device token). Tests for topic routing:

```javascript
it('subscribes user to order-updates topic', async () => {
  const subSpy = jest.spyOn(admin.messaging(), 'subscribeToTopic')
    .mockResolvedValue({ successCount: 1, failureCount: 0, errors: [] });

  await subscribeToOrderUpdates('user-device-token', userId);

  expect(subSpy).toHaveBeenCalledWith(['user-device-token'], `user-${userId}`);
});
```

## Step 8 - End-to-end test recipe

For each push channel:

1. ✅ Happy-path send with correct payload shape (Steps 2 - 4)
2. ✅ Invalid-token cleanup on 410 / unregistered response (Steps 2 - 4)
3. ✅ Silent vs alert distinction (Step 5)
4. ✅ Click-action / deep-link assertion (Step 6)
5. ✅ Topic subscription handling (FCM, Step 7)
6. ✅ Production vs sandbox environment routing (Step 3)

## 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](references/platform-test-patterns.md) recipes for APNs / FCM if the app adds those channels.

## Anti-patterns

| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Test only happy path | Miss expired-token cleanup; storage grows; spam to dead devices | Step 2-4 410 / 404 / unregistered tests |
| Hardcode VAPID public key in tests + checked into repo | Key rotation breaks tests | Inject via env var |
| Send to real production APNs in tests | Real users get test push | Sandbox environment (Step 3) |
| Skip silent-vs-alert distinction | Apple throttles silent push; missing flag → notifications dropped | content-available test (Step 5) |
| Skip click-action test | Deep links break silently after refactors | Step 6 |

## 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

- [references/platform-test-patterns.md](references/platform-test-patterns.md) - full Web Push / APNs / FCM test-pattern code
- [references/in-app.md](references/in-app.md) - in-app notification workflow (WebSocket / SSE / Firebase listeners, unread state, fan-out, reconnect); Firebase listener patterns in [references/firebase-listener-tests.md](references/firebase-listener-tests.md)
- IETF RFC 8030 - Web Push Protocol
- IETF RFC 8291 - Message Encryption for Web Push
- IETF RFC 8292 - VAPID for Web Push
- [apns-docs][apns-docs] - Apple Push Notification Service
- firebase.google.com/docs/cloud-messaging - Firebase Cloud Messaging
- web.dev/explore/notifications - Push API + Notifications API
- npmjs.com/package/web-push - Node.js web-push library
- pypi.org/project/apns2 - Python APNs HTTP/2 library
- `mailpit-testing` (email flows in its references),
  `sms-test-author` - sister channels
- `appium-testing`,
  `xcuitest-suite`,
  `espresso-suite` - device-side click-action verification

Files in this skill

  • .tessl-plugin/plugin.json780 B
  • SKILL.md9.9 KB
  • references/firebase-listener-tests.md3.9 KB
  • references/in-app.md14.4 KB
  • references/platform-test-patterns.md4.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.