Testing webhooks

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 example

Let’s see how to use the MailSlurp test webhooks library:

import fetchApi from "isomorphic-fetch";
import {CreateWebhookOptions, MailSlurp} from "mailslurp-client"
import {
    Configuration as TestWebhookConfiguration,
    CreateRulesetOptionsStrategyEnum,
    DefaultApi as TestWebhookApi
} from '@mailslurp/test-webhooks'

jest.setTimeout(60000)
const apiKey = process.env.apiKey;
const mailslurp = new MailSlurp({apiKey, fetchApi})
const testWebhooks = new TestWebhookApi(new TestWebhookConfiguration({basePath: "https://devhooks.mailslurp.com"}))

describe("NEW_EMAIL webhooks", () => {
    test('can create NEW_EMAIL webhook and receive successfully', async () => {
        // create an inbox, webhook, and a test endpoint
        const testEndpoint = await testWebhooks.createEndpoint({})
        const inbox = await mailslurp.createInbox()
        const webhook = await mailslurp.webhookController.createWebhook(inbox.id!, {
            eventName: CreateWebhookOptions.EventNameEnum.NEWEMAIL,
            url: testEndpoint.url
        })
        // can see that endpoint has not received an event
        const endpointHistory = await testWebhooks.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 testWebhooks.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(webhook.id!)
        expect(results.totalElements).toEqual(1)
        const result = await mailslurp.webhookController.getWebhookResult(results.content?.[0]?.id!)
        expect(result.resultType).toEqual('SUCCESS')
        expect(result.responseStatus).toEqual(200)

        await mailslurp.webhookController.deleteWebhook(inbox.id!, webhook.id!)
    })
})

Now what about testing a failed result:

test('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 testWebhooks.createEndpoint({})
    await testWebhooks.addEndpointRuleset({
        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(inbox.id!, {
        eventName: CreateWebhookOptions.EventNameEnum.NEWEMAIL,
        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 testWebhooks.getEndpointHistory({
        endpointId: testEndpoint.id!,
        expectedLength: 1
    })
    expect(endpointHistory.items?.length).toEqual(1)

    // can see webhook results via mailslurp
    const results = await mailslurp.webhookController.getWebhookResults(webhook.id!)
    expect(results.totalElements).toEqual(1)
    const result = await mailslurp.webhookController.getWebhookResult(results.content?.[0]?.id!)
    expect(result.resultType).toEqual('BAD_RESPONSE')
    expect(result.responseStatus).toEqual(401)

    await mailslurp.webhookController.deleteWebhook(inbox.id!, webhook.id!)
})