npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ranger-testing/inbox-relay

v0.0.16

Published

`@ranger-testing/inbox-relay` is a wrapper around the Ranger API which allows tests to receive messages and make assertions on their content, including One-Time-Passowords (OTP), Magic Auth Links or Confirm Email Links, and transactional messages.

Readme

Ranger Inbox Relay Client

@ranger-testing/inbox-relay is a wrapper around the Ranger API which allows tests to receive messages and make assertions on their content, including One-Time-Passowords (OTP), Magic Auth Links or Confirm Email Links, and transactional messages.

The client library is the only way tests can interact with inboxes.

Table of Contents

Getting Started

For working locally:

npm install @ranger-testing/inbox-relay

Concepts

Permanent Inboxes

Permanent Inboxes are managed through the Debug Tool, and should be created to correspond with a Permanent Test User within a third party system. These inboxes are best used for tests which do not involve the creation and disposal of new user accounts.

It is not possible to create or delete a Permanent Inbox during a test.

Temporary Inboxes

Temporary Inboxes are created during a test, or during the beforeAll for an entire suite of tests. They are automatically cleaned-up after a configurable expiration period.

Temporary Inboxes are created with InboxRelayClient.createTemporaryInbox().

Locking an Inbox and Reading Messages

  • An inbox must be locked before messages can be received.
  • This guarantees that messages from parallel tests do not conflict.
  • All locks have a (configurable) expiration, so that an inbox cannot remain locked indefinitely due to errors.

When you need to use an inbox, you must first request a lock with InboxRelayClient.lockInbox(). This method retries and waits for a lock until one is available. If the inbox is not already locked, this is immediate. Otherwise, the method waits until the previous lock is released, up to a configured timeout.

Once your lock is successful, you can perform actions that will cause emails to be sent to the inbox. Once you are finished, you can await and retrieve all messages delivered to the inbox since your lock began. Messages are retrieved with InboxRelayClient.unlockAndReadMessages().

The inbox lock is automatically released after you retrive messages. It is not possible to retrieve messages that were received before you locked the inbox, or after you unlock it. You cannot unlock the same inbox twice without locking it again.

If you need to retrieve messages more than once (because later test steps depend on message content), you must lock the inbox more than once.

Considerations

  • Locking prevents an entire class of test-flake issues, especially when we are reusing a single Test User for multiple tests.
  • In most cases, email should not take very long, and tests will not spend much time waiting.
  • Multiple inboxes can be used to spend less time waiting for locks. There is no downside to creating multiple test users with dedicated inboxes if a use case calls for it.
  • Because of this, Inboxes do not need to be unique per-test.

Use Case Examples

Magic Link Auth: Permanent Inbox

Customer has asked Ranger to test Magic Link login with an existing user account.

  1. Ranger creates a Permanent Inbox for [email protected] using the Debug Tool.
  2. Ranger or Customer creates the Test User in the Customer environment using that email address.
  3. Ranger tests can assert proper magic-link login behavior:
import { InboxRelayClient } from '@ranger-testing/inbox-relay'

const API_TOKEN = process.env.API_TOKEN
const PERMANENT_INBOX = '[email protected]'
const inboxes = new InboxRelayClient({ apiToken: API_TOKEN })

export async function run(page: Page) {
  // >>> Request a lock for the (already-existing) permanent inbox:
  await inboxes.lockInbox({ address: PERMANENT_INBOX })

  // >>> Next, perform the steps that send the magic-link auth email:
  const usernameInput = page.getByRole('textbox', { name: 'Username' })
  await usernameInput.fill(PERMANENT_INBOX)

  const loginButton = page.getByRole('button', { name: 'Log In' })
  await loginButton.click()

  // >>> Unlock the inbox and retrieve the message:
  const message = (await inboxes.unlockAndReadMessages())[0]

  // >>> Expect that the magic link works:
  await page.goto(message.magicLink)
  expect(page.locator('button[aria-label="Profile Menu"]')).toContainText('Ranger Test User')
}

Transactional Emails: Permanent Inbox

Customer has asked Ranger to test transactional Task Notification Emails, which are sent when a task is assigned, completed, and reviewed.

  1. Ranger creates a Permanent Inbox for [email protected] using the Debug Tool.
  2. Ranger or Customer creates a test user in the Customer environment using that email adddress.
  3. Ranger tests can assert proper transactional email behavior:
import { InboxRelayClient } from '@ranger-testing/inbox-relay'

const API_TOKEN = process.env.API_TOKEN
const PERMANENT_INBOX = '[email protected]'
const inboxes = new InboxRelayClient({ apiToken: API_TOKEN })

export async function run(page: Page) {
  // >>> Request a lock for the (already-existing) permanent inbox:
  await inboxes.lockInbox({ address: PERMANENT_INBOX })

  // >>> Next, perform the steps that send one or more emails:
  const assigneeDropdown = page.getByRole('combobox', { name: 'Assignee' })
  await assigneeDropdown.selectOption(PERMANENT_INBOX)

  const assignButton = page.getByRole('button', { name: 'Assign' })
  await assignButton.click()

  // >>> Unlock the inbox and retrieve messages:
  const message = (await inboxes.unlockAndReadMessages())[0]

  // >>> Expect the message to contain the right content:
  expect(message.content).toMatch(/You were assigned task "\w*?"/)

  // >>> Optionally assert on the number of attachments
  expect(message.attachmentCount).toBeGreaterThan(0)
}

Sign Up Flow: Temporary Inbox

Customer has asked Ranger to test their new-user signup flow. The user should receive an a confirm-email link email as well as a welcome email.

This test case requires us to create a temporary inbox before completing the signup flow:

import { InboxRelayClient } from '@ranger-testing/inbox-relay'

const API_TOKEN = process.env.API_TOKEN
const inboxes = new InboxRelayClient({ apiToken: API_TOKEN })

export async function run(page: Page) {
  // >>> Create and lock the temporary inbox:
  const { address } = await inboxes.createTemporaryInbox()
  await inboxes.lockInbox({ address })

  // >>> Next, sign up the new user:
  const newUserEmailInput = page.getByRole('textbox', { name: 'Email Address' })
  await newUserEmailInput.fill(TEMPORARY_INBOX)

  const submitButton = page.getByRole('button', { name: 'Sign Up' })
  await submitButton.click()

  // >>> Unlock the inbox and retrieve messages:
  const messages = await inboxes.unlockAndReadMessages({
    // We are expecting both a welcome email and a confirm-email link
    expectedMessages: 2
  })
  // Find the message which contains a confirm link
  const confirmEmail = messages.find((message) => !!message.magicLink)

  // >>> Expect the confirm-email link to work
  await page.goto(confirmEmail.magicLink)
  expect(page.getByTestId('success-callout')).toContainText('confirmed successfully')
}

InboxMessage Contents

export interface InboxMessage {
  /** The sender of the message. */
  sender: string | null
  /** The subject of the message. */
  subject: string | null
  /** The body of the message. */
  content: string | null
  /** Some HTML emails include a `text/plain` alternative. If so, it is provided here. */
  contentText: string | null
  /** The instant the message was received. */
  receivedTimestamp: Date
  /** An alphanumeric one-time-password, if one was found. */
  otp: string | null
  /** Any links that were found in the body of the message. */
  links: string[]
  /** Our best guess as to which link is a magic link, if one is found. */
  magicLink: string | null
  /** Number of attachments in the message. */
  attachmentCount: number
}

PDF Attachment Processing: Temporary Inbox

Customer has asked Ranger to test that invoice PDFs are properly generated and emailed to users after purchase completion.

This test case demonstrates downloading and parsing PDF attachments:

import { InboxRelayClient } from '@ranger-testing/inbox-relay'
import pdf from 'pdf-parse'

const API_TOKEN = process.env.API_TOKEN
const inboxes = new InboxRelayClient({ apiToken: API_TOKEN })

export async function run(page: Page) {
  // >>> Create and lock the temporary inbox:
  const { address } = await inboxes.createTemporaryInbox()
  await inboxes.lockInbox({ address })

  // >>> Complete a purchase that generates an invoice email:
  const emailInput = page.getByRole('textbox', { name: 'Email' })
  await emailInput.fill(address)

  const purchaseButton = page.getByRole('button', { name: 'Complete Purchase' })
  await purchaseButton.click()

  // >>> Unlock the inbox and retrieve messages with attachments:
  const messages = await inboxes.unlockAndReadMessages({
    includeAttachments: true
  })

  // >>> Download and parse the PDF attachment:
  const pdfAttachment = messages
        .flatMap((msg) => msg.attachments)
        .find((att) => att?.name.endsWith('.pdf'));
  expect(pdfAttachment).toBeTruthy();
  
  const buffer = Buffer.from(pdfAttachment.contentBase64, 'base64');
  const pdfData = await pdf(buffer);
  
  // >>> Assert on PDF content:
  expect(pdfData.text).toContain('Invoice #')
  expect(pdfData.text).toContain('Total Amount: $')
  expect(pdfData.text).toContain(address) // Customer email should be in invoice
}

SMS OTP Verification: Phone Number

Customer has asked Ranger to test SMS OTP verification for two-factor authentication.

This test case demonstrates using findAndLockPhoneNumber to automatically find and lock an available phone number for receiving SMS messages:

import { InboxRelayClient } from '@ranger-testing/inbox-relay'

const API_TOKEN = process.env.API_TOKEN
const inboxes = new InboxRelayClient({ apiToken: API_TOKEN })

export async function run(page: Page) {
  // >>> Find and lock an available phone number:
  const { address: phoneNumber } = await inboxes.findAndLockPhoneNumber()

  // >>> Enter the phone number in the 2FA setup form:
  const phoneInput = page.getByRole('textbox', { name: 'Phone Number' })
  await phoneInput.fill(phoneNumber)

  const sendCodeButton = page.getByRole('button', { name: 'Send Code' })
  await sendCodeButton.click()

  // >>> Unlock the phone number and retrieve the SMS message:
  const message = (await inboxes.unlockAndReadMessages())[0]

  // >>> Extract the OTP and complete verification:
  const otpInput = page.getByRole('textbox', { name: 'Verification Code' })
  await otpInput.fill(message.otp!)

  const verifyButton = page.getByRole('button', { name: 'Verify' })
  await verifyButton.click()

  // >>> Expect successful verification:
  expect(page.getByTestId('success-message')).toContainText('Phone verified successfully')
}