Testing webhook responses
Webhook pub/sub messaging allows the processing of inbound messages at scale. Testing your webhook handler is important for end-to-end integrations.
MailSlurp allows the creation of email webhooks that forward emails, attachments, and new contacts directly to your server URL via HTTP/S POST. When a server responds with a 200 or 201 within 30 seconds the webhook is marked as successfully processed. If not the webhook is marked as unsuccessful and is put into a queue to be retried again every few minutes until successfully processed.
How can we test this process
Manual endpoint testing
We could use a tool like ngrok to create HTTP endpoints that redirect to a local server we are running.
Automated endpoint testing
For automated testing we can use MailSlurp @mailslurp/test-webhooks
library to setup real http endpoints that can respond with a set of responses we configure. This means we can simulate functional or non-functional webhooks and see how MailSlurp handles each.
Test webhook example
Let's see how to use the MailSlurp test webhooks library:
import fetchApi from 'isomorphic-fetch';
import { CreateWebhookOptionsEventNameEnum, MailSlurp } from 'mailslurp-client';
import {
Configuration as TestWebhookConfiguration,
CreateRulesetOptionsStrategyEnum,
EndpointControllerApi,
} from '@mailslurp/test-webhooks';
jest.setTimeout(60000);
const apiKey = process.env.API_KEY!!;
const mailslurp = new MailSlurp({ apiKey, fetchApi });
const devhooksEndpointController = new EndpointControllerApi(
new TestWebhookConfiguration({
basePath: 'http://api.infrahooks.com',
fetchApi,
})
);
describe.skip('NEW_EMAIL webhooks', () => {
test('can create NEW_EMAIL webhook and receive successfully', async () => {
// create an inbox, webhook, and a test endpoint
const testEndpoint = await devhooksEndpointController.createEndpoint({});
const inbox = await mailslurp.createInbox();
const webhook = await mailslurp.webhookController.createWebhook({
createWebhookOptions: {
eventName: CreateWebhookOptionsEventNameEnum.NEW_EMAIL,
url: testEndpoint.url,
},
inboxId: inbox.id!,
});
// can see that endpoint has not received an event
const endpointHistory = await devhooksEndpointController.getEndpointHistory(
{
endpointId: testEndpoint.id!,
}
);
expect(endpointHistory.items?.length).toEqual(0);
// send email to inbox
await mailslurp.sendEmail(inbox.id!, {
to: [inbox.emailAddress!],
subject: 'email1',
});
// can fetch the email directly
const email = await mailslurp.waitForLatestEmail(inbox.id!, 60000, true);
expect(email.subject).toEqual('email1');
// endpoint receives the payload (note the expected length to wait for)
const endpointHistory2 =
await devhooksEndpointController.getEndpointHistory({
endpointId: testEndpoint.id!,
expectedLength: 1,
});
expect(endpointHistory2.items?.length).toEqual(1);
// assert correct payload was sent to endpoint
const payload = JSON.parse(endpointHistory2.items?.[0]?.request?.body!);
expect(payload.webhookId).toEqual(webhook.id);
expect(payload.eventName).toEqual('NEW_EMAIL');
expect(payload.inboxId).toEqual(inbox.id);
expect(payload.emailId).toEqual(email.id);
expect(payload.to).toEqual([inbox.emailAddress]);
expect(payload.from).toEqual(inbox.emailAddress);
expect(payload.subject).toEqual('email1');
// can see webhook results via mailslurp
const results = await mailslurp.webhookController.getWebhookResults({
webhookId: webhook.id!,
});
expect(results.totalElements).toEqual(1);
const result = await mailslurp.webhookController.getWebhookResult({
webhookResultId: results.content?.[0]?.id!,
});
expect(result.resultType).toEqual('SUCCESS');
expect(result.responseStatus).toEqual(200);
await mailslurp.webhookController.deleteWebhook({
inboxId: inbox.id!,
webhookId: webhook.id!,
});
});
});
Testing failed webhooks
Now what about testing a failed result:
test.skip('can create NEW_EMAIL webhook and see failed results when endpoint fails to accept payload', async () => {
// create a test endpoint that always returns a 401 error
const testEndpoint = await devhooksEndpointController.createEndpoint({});
await devhooksEndpointController.createEndpointRuleset({
endpointId: testEndpoint.id!,
createRulesetOptions: {
strategy: CreateRulesetOptionsStrategyEnum.SINGULAR,
responses: [
{
statusCode: 401,
},
],
},
});
// create inbox and webhook
const inbox = await mailslurp.createInbox();
const webhook = await mailslurp.webhookController.createWebhook({
inboxId: inbox.id!,
createWebhookOptions: {
eventName: CreateWebhookOptionsEventNameEnum.NEW_EMAIL,
url: testEndpoint.url,
},
});
// send email to inbox
await mailslurp.sendEmail(inbox.id!, {
to: [inbox.emailAddress!],
subject: 'email2',
});
// wait for endpoint to receive payload
const endpointHistory = await devhooksEndpointController.getEndpointHistory({
endpointId: testEndpoint.id!,
expectedLength: 1,
});
expect(endpointHistory.items?.length).toEqual(1);
// can see webhook results via mailslurp
const results = await mailslurp.webhookController.getWebhookResults({
webhookId: webhook.id!,
});
expect(results.totalElements).toEqual(1);
const result = await mailslurp.webhookController.getWebhookResult({
webhookResultId: results.content?.[0]?.id!,
});
expect(result.resultType).toEqual('BAD_RESPONSE');
expect(result.responseStatus).toEqual(401);
await mailslurp.webhookController.deleteWebhook({
inboxId: inbox.id!,
webhookId: webhook.id!,
});
});