End-to-end testing
Test the sending parts of your app without flooding your quota.
Real sends count against your quota, are limited to 10 requests per second per key, and touch your reputation. Most of your test suite should never reach usend.
Unit and integration tests: fake the client
Put sending behind a small interface in your code and replace it in tests.
// mailer.ts
export interface Mailer { send(to: string, subject: string, html: string): Promise<string> }
export class UsendMailer implements Mailer {
constructor(private usend: import('@usend/node').Usend) {}
async send(to: string, subject: string, html: string) {
const { data, error } = await this.usend.emails.send({ from: 'Acme <[email protected]>', to: [to], subject, html });
if (error) throw new Error(error.message);
return data!.id;
}
}
// in tests
export class FakeMailer implements Mailer {
sent: { to: string; subject: string; html: string }[] = [];
async send(to: string, subject: string, html: string) { this.sent.push({ to, subject, html }); return 'fake-id'; }
}Assert on FakeMailer.sent: recipient, subject, links in the body. It is fast, free and deterministic.
Or stub HTTP: point the SDK at a local mock server with new Usend(key, { baseUrl: 'http://localhost:4010' }) (Python: Usend(key, base_url=...); both read USEND_BASE_URL).
Staging smoke tests
A handful of real sends are still valuable to prove credentials, the domain and DNS:
- Use a staging domain and a separate API key.
- Send to mailboxes you own: Testing addresses.
- Send one or two emails per deploy, not per test.
- Use an idempotency key per test run so a retried CI job never sends twice.
Checking delivery
Do not scrape the inbox when the API can tell you.
# status after a send
curl https://api.usend.et/emails/$EMAIL_ID -H "Authorization: Bearer $USEND_API_KEY"
# { ..., "last_event": "delivered" }Poll GET /emails/{id} until last_event is delivered (or a failure), with a timeout. Or let a webhook deliver events to a test endpoint.
Webhook tests
Test your handler with recorded payloads and a known secret, so your tests can sign them and exercise verification. Reject an unsigned payload in a test as well. See Verify signatures.
Stay inside the limits
- Mind your plan's daily quota (Free is 100 per day): Account quotas and limits.
- Run suites that send in series, or throttle: more than 10 requests per second per key return
429. - An organization in the sandbox can send only to its verified members; CI inboxes must be among them.