@pntr/testkit
v0.2.1
Published
Deterministic email and webhook assertions for Playwright, Cypress, and CI
Maintainers
Readme
@pntr/testkit
Deterministic email and webhook assertions for Playwright, Cypress, and CI.
- TestKit overview and examples
- PNTR documentation
- Create the test hostname and API token
- Plans and CI limits
- npm package · source and issues
Install
npm install --save-dev @pntr/testkitIn the PNTR dashboard,
create or select a hostname, enable the inbox or request capture, and create a
token under MCP integration > API token. Store the token as PNTR_TOKEN.
Use synthetic test accounts and test-mode webhook payloads only.
Pass the full hostname shown in the dashboard, such as
testbox.pntr.dev. This is the supported input for application test code.
Wait for an email
import { PntrTestKit, createRecipient, extractOtp } from "@pntr/testkit";
const pntr = new PntrTestKit({ token: process.env.PNTR_TOKEN! });
const emailDomain = "testbox.pntr.dev";
const recipient = createRecipient(emailDomain, {
prefix: "signup",
});
const startedAt = new Date();
// Submit `recipient` through the application under test here.
const message = await pntr.waitForEmail(
emailDomain,
{
recipient,
subject: "Verification code",
since: startedAt,
timeoutSeconds: 20,
}
);
const otp = extractOtp(message);Wait for a webhook
const startedAt = new Date();
// Trigger the test-mode provider event here.
const request = await pntr.waitForWebhook(
"hooks.pntr.dev",
{
method: "POST",
path: "/stripe",
headerName: "stripe-signature",
bodyContains: "payment_intent.succeeded",
since: startedAt,
timeoutSeconds: 20,
}
);
if (request.body_truncated) {
throw new Error("Expected the complete webhook body");
}The server performs the waiting and filtering. The test runner does not need to download and scan the entire inbox or request history every second.
Keep a privacy-safe CI report
Use the WithReport methods when a CI run needs durable, linkable evidence:
const emailMatch = await pntr.waitForEmailWithReport(emailDomain, {
recipient,
subject: "Verification code",
since: startedAt,
});
const webhookMatch = await pntr.waitForWebhookWithReport("hooks.pntr.dev", {
method: "POST",
path: "/stripe",
since: startedAt,
});
console.log(`Email report: ${emailMatch.report.url}`);
console.log(`Webhook report: ${webhookMatch.report.url}`);The ordinary waitForEmail() and waitForWebhook() methods remain available
when a run does not need a durable report.
Report links open an owner-only PNTR page and require the owning account to be signed in. Reports retain only safe summary metadata: PNTR does not copy email addresses, subjects, message bodies, webhook paths, queries, headers, source IPs, or payloads into the report. Reports follow the account's current retention tier (48 hours on Free, 90 days on Premium).
An unexpired report can be fetched later with the same account token:
const report = await pntr.getReport(emailMatch.report.id);For GitHub Actions, write a compact, content-free report to the Step Summary:
import { appendFile } from "node:fs/promises";
import { formatReportMarkdown } from "@pntr/testkit";
if (process.env.GITHUB_STEP_SUMMARY) {
await appendFile(
process.env.GITHUB_STEP_SUMMARY,
formatReportMarkdown(emailMatch.report),
);
}See the complete Playwright workflow for unique recipients, exact-message waits, and CI setup.
