Testing User Sign-Up and Email Confirmation

A tutorial on testing email dependant actions using MailSlurp test email accounts. Intercept inbound emails in tests and extract confirmation codes to test user sign-up and email verification.

Background

Email is a key component of most modern applications. It identifies users, let’s them sign-up and login, reset passwords and confirm their accounts. Email is important but, strangely, testing processes that rely on email end-to-end can be difficult.

Email testing APIs

MailSlurp is free to use test email account API that was built to solve this problem. It let’s developers create test email accounts on demand in apps and tests, or using a visual dashboard.

An example project

In this post we’ll use a free MailSlurp account to test a typical user sign-up process end-to-end. To do that we will create test email accounts dynamically during each test and use them to sign up for an example website. The MailSlurp Playground will act as our dummy application: a free WebApp that simulates various modern OAuth2 processes.

Testing user sign-up

Here is what we’ll need to verify in our test

  • User can load our application
  • User can sign-up using a generated email address
  • User receives a confirmation code via email
  • User can enter confirmation code and confirm account
  • Lastly, user can login and see a welcome screen.

These steps are common for many applications and may reflect a user sign-up process in your own system.

What does our app look like?

The Playground App is hosted at https://playground.mailslurp.com and is a simple React Application that looks like this:

test-user-signup.

Anyone can sign-up or login to the site. The application was designed with automated testing in mind and simply displays a happy dog upon successful login.

Testing with MailSlurp

To write an automated test for our sign-up process we need a framework. Any framework will do but we will use Webdriver.io (which is similar to Selenium), Javascript and the official MailSlurp package on NPM.

MailSlurp has a REST API and official packages in Java, PHP, Python, Ruby, C# and more.

Project setup

Let’s start by creating a new folder and a few files.

mkdir signup && cd $_

Assuming we have NodeJS installed let’s add MailSlurp as a dependency via npm.

echo '{}' > package.json
npm install --save mailslurp-client

Note: MailSlurp is free for personal use but you will need an API Key. Get one by signing-up.

Add a test framework

Next let’s add Webdriver to our project. Webdriver goes by the alias wdio and splits itself up across several packages. We’ll add those now.

npm install --save @wdio/cli @wdio/local-runner @wdio/mocha-framework @wdio/selenium-standalone-service

For wdio to run inside a web browser we need to make one available to it. Here we will use Chrome.

npm install --save chromedriver wdio-chromedriver-service

Configure Webdriver

Next we need to configure wdio using a wdio.conf.js file in the root of our project. This will tell Webdriver where to look for tests and what browser to use. We want out instance to load the Playground app (see baseUrl) and look for tests in a test folder:

const config = {
  runner: 'local',
  path: '/',
  specs: ['test/*.test.js'],
  exclude: [],
  maxInstances: 10,
  capabilities: [
    {
      maxInstances: 5,
      browserName: 'chrome'
    }
  ],
  logLevel: 'info',
  bail: 0,
  baseUrl: 'https://playground.mailslurp.com',
  waitforTimeout: 30000,
  connectionRetryTimeout: 90000,
  connectionRetryCount: 3,
  framework: 'mocha',
  services: ['chromedriver'],
  reporters: ['spec'],
  mochaOpts: {
    ui: 'bdd',
    timeout: 60000
  }
};

exports.config = config;

Add a test command

Lastly, we need a way to run out tests one we have written them. For this we can extend the package.json scripts property to call wdio. Here’s what our package.json file looks like altogether:

{
  "scripts": {
    "test": "wdio wdio.conf.js"
  },
  "dependencies": {
    "@wdio/cli": "^5.13.2",
    "@wdio/local-runner": "^5.13.2",
    "@wdio/mocha-framework": "^5.13.2",
    "@wdio/selenium-standalone-service": "^5.13.2",
    "@wdio/spec-reporter": "^5.13.2",
    "chromedriver": "^78.0.1",
    "mailslurp-client": "^6.5.0",
    "wdio-chromedriver-service": "^5.0.2"
  }
}

Now when we run npm test Webdriver will execute any files ending with .test.js in the test directory. Speaking of which, let’s write some!

Writing a test

Wdio is configured to find tests in a test durectory so let’s create that and add a test to it.

mkdir test
touch test/sign-up.test.js

Defining test requirements

Before we write our test logic let’s review what we want to achieve. We want to test that our app (the Playground) has a functioning user sign-up feature (a critical component of any application). For this we will need to perform the following actions:

  • Sign up as a new user
  • Confirm the users account
  • Login and see a doggy welcome

Special needs (why we use a email testing API)

Most of these steps are pretty standard for end-to-end testing but sign-up and confirmation are special:

  • Sign up will require a unique email address each time we run the test
  • Confirmation will require that we fetch and extract a confirmation code sent to our user’s email address

Luckily, MailSlurp helps with all that.

With MailSlurp we can create test email accounts and then send and receive emails from them from within tests. That will allow us to create new email addresses for each test run (so that they are unique and empty) and receive and extract the confirmation code for use in the email confirmation step!

happy

Generating test email accounts

MailSlurp makes generating dynamic test email accounts on demand easy.

First obtain your API Key and configure a MailSlurp client to use it.

const MailSlurp = require('mailslurp-client').default;
const apiKey = process.env.API_KEY;
const mailslurp = new MailSlurp({ apiKey });

Then to create a new randomized test email address invoke the createInbox function.

const { 
  emailAddress, 
  id 
} = await mailslurp.createInbox();

You can specify an address by passing the emailAddress parameter and using a custom domain you own. Unspecified email addresses will be randomly assigned under the @mailslurp.com domain.

Testing user sign-up with disposable email addresses

Now that we know how to create email addresses on demand with MailSlurp we can write a test that loads the Playground, creates an email account and then uses it to sign-up.

Here’s the first step for our test:

const assert = require('assert');

describe('sign up page', () => {
  it('can load playground app', async () => {
    await browser.url('/');
    await browser.setWindowSize(1200, 1200);
  });
});

The above loads the Playground - that’s it. Next we need to navigate to the sign-up form by clicking a link. Then we assert that we are in the right location. We add the following to the same test:

it('can load the sign-up section', async () => {
  await $('[data-test="sign-in-create-account-link"]')
    .then(e => e.click())
  await $('.sign-up-header-section')
    .then(e => e.getText())
    .then(text => assert.strictEqual(text, 'Testable Sign Up Form'));
});

Let’s test this now to see if it works as we expect.

API_KEY=your-mailslurp-api-key npm run test

We should see Chrome launch, the sign-up page load and the test complete with successful output:

[chrome  linux #0-0] Running: chrome on linux
[chrome  linux #0-0]
[chrome  linux #0-0] sign up page
[chrome  linux #0-0]    ✓ can load playground app
[chrome  linux #0-0]    ✓ can load the sign-up section
[chrome  linux #0-0]
[chrome  linux #0-0] 2 passing (607ms)


Spec Files:	 1 passed, 1 total (100% completed) in 00:00:01 

If your Chromedriver complains you may need to install a version that matches the version of Chrome on your computer.

Signing up

Ok, it works. Now for the fun stuff. Let’s sign up a new user.

let inbox;
let password = 'test-password';

it('can sign-up with test email account', async () => {
  // create a new email address for the test run
  inbox = await mailslurp.createInbox();

  // fill out and submit the new user form
  await $('[name="email"]')
    .then(e => e.setValue(inbox.emailAddress));
  await $('[name="password"]')
    .then(e => e.setValue(password));
  await $('[data-test="sign-up-create-account-button"]')
    .then(e => e.click());
});

Running that test should fill out a form like below:

test-sign-up

Capturing email confirmation code in tests

So we have successfully signed up a user using the test email address we created. Now we should see a confirmation page that asks us to enter a code that has been emailed to the address that we used.

confirmation

MailSlurp allows use to receive emails in tests!

To enter the confirmation code let’s fetch the expected email using MailSlurp, extract the code, and enter it into the form:

it('can fetch confirmation code', async () => {
  // fetch the email from mailslurp
  const email = await mailslurp.waitForLatestEmail(inbox.id)

  // verify that it contains the code
  assert.strictEqual(/verification code is/.test(email.body), true);

  // extract the confirmation code
  code = /([0-9]{6})$/.exec(email.body)[1]
});

it('can enter confirmation code and confirm user', async () => {
  await $('[name="code"]')
    .then(e => e.setValue(code));
  await $('[data-test="confirm-sign-up-confirm-button"]')
    .then(e => e.click());
});

Voila, the test passes, the user is confirmed and we see the sign-in screen. The most important parts of the test above are the lines that fetch the confirmation email and extract the code. The email that is sent looks like this:

welcome

To receive the email in our test we use the waitForLatestEmail method and pass the id of the inbox that we created during that test run. This will return the first email in the inbox or wait for one to be received.

To extract the verification code we use a regex that matches 6 digits and apply that to the email body.

code = /([0-9]{6})$/.exec(email.body)[1]

Logging in with confirmed account

Lastly, let’s test that the confirmed user can sign-in and see a welcome screen. The welcome screen looks a bit like this:

welcome

Here is the code to login in a verify the happy dog is present:

it('can log in with confirmed account', async () => {
  // assert we see the sign in form
  await $('[data-test="sign-in-header-section"]')
    .then(e => e.getText())
    .then(text => assert.strictEqual(text, 'Sign in to your account'));

  // fill out username (email) and password
  await $('[name="username"]')
    .then(e => e.setValue(inbox.emailAddress));
  await $('[name="password"]')
    .then(e => e.setValue(password));
 
  // submit
  await $('[data-test="sign-in-sign-in-button"]')
    .then(e => e.click());
});

it('shows the successful greeting', async () => {
  await $('[data-test="greetings-nav-bar"]')
    .then(e => e.getText())
    .then(text => assert.strictEqual(/Hello/.test(text), true));
});

In summary

This post demonstrating how you can truly end-to-end test email related processes like user sign-up, email confirmation, and login. It used Webdriver to run the tests but the only required aspect is an email API provider like MailSlurp. MailSlurp is free for personal use and will let you and your team test every crucial aspect of your app. Give it a go today!

Code samples

As always full code samples for this post are available on GitHub.