Randomize Your End-to-End Tests: How to Generate Input Data for TestCafe

User input can be truly unpredictable, so it’s important to use a wide sample of random input data when testing web forms. In this article, we’ll take a look at three Node libraries that generate data: nanoid, faker, and generate-password. We’ll see how TestCafe can leverage their features to help you improve your test coverage.

The farfurix/generating-input-data git repo contains the custom demo page and the test examples created specifically for this article. Clone the repository to follow along.

The Basics (nanoid)

This example page contains a text input field. We can use the t.typeText method to populate it:

import { Selector } from 'testcafe';

fixture `Random Input Data: example 1`
    .page('https://devexpress.github.io/testcafe/example/');

test('Generate a random name', async t => {
    await t
        .typeText('#developer-name', 'Developer Name');
});

Nanoid generates random strings when you call the nanoid() method. We can call this method to randomize our input data.

Import the nanoid module in the beginning of the file:

import { nanoid } from 'nanoid';

Declare a constant with a randomly generated name:

const randomDeveloperName = 'testuser_' + nanoid();

Replace the 'Developer Name' string with the constant we just declared:

await t
    .typeText('#developer-name', randomDeveloperName);

Now every time you run the test, the input value will be unique.

Input validation (faker, generate-password)

Imagine a more complicated scenario: testing a sign-up form’s ability to validate user passwords. We need to make sure that the password chosen by the user contains:

  • At least eight symbols
  • At least one digit
  • A lowercase letter
  • An uppercase letter.

First, we’re going to need a valid email address to serve as our username. Faker — a Node.js library that specializes in generating realistic-looking data, such as home addresses, business details, and emails — can help us. Import the library and call the faker.internet.email() method to create a valid email address.

import faker from 'faker';

const validEmail = faker.internet.email();

The generate-password library will give us the passwords we need. We can set password requirements by passing arguments to the generate method of the generator object. Let’s import the library:

import generator from 'generate-password';

We’re ready to create an array of random, yet valid, passwords. The faker library will, once again, prove itself useful — this time, it will help us determine the password length.

let validPasswords = [];

for (let i = 0; i < 5; i++) {
    let newRandomPassword = generator.generate({
        length: faker.random.number({ 'min': 10, 'max': 20 }), // 10-20 characters long
        numbers: true,
        uppercase: true,
        lowercase: true,
        strict: true
    });

    validPasswords.push(newRandomPassword);
};

It’s just as easy to generate invalid credentials. Let’s use the generateMultiple method to generate invalid passwords of varying length:

// These passwords are too short
const shortPasswords = generator.generateMultiple(5, {
    length: 7,
    numbers: true,
    strict: true
});

// These passwords lack uppercase characters
const passwordsWithoutUppercase = generator.generateMultiple(5, {
    length: 8,
    numbers: true,
    uppercase: false,
    strict: true
});

// These passwords lack lowercase characters
const passwordsWithoutLowercase = generator.generateMultiple(5, {
    length: 8,
    numbers: true,
    lowercase: false,
    strict: true
});

// These passwords lack digits
const passwordsWithoutDigits = generator.generateMultiple(5, {
    length: 8,
    strict: true
});

const invalidPasswords = shortPasswords.concat(passwordsWithoutUppercase, passwordsWithoutLowercase, passwordsWithoutDigits);

Now that we have our fake credentials, we can test the web form.

The first test will feed the form valid passwords. To do this, let’s iterate over the validPasswords array and enter the data it contains into the form. A confirmation of the password’s validity should appear every time we click the #submit button.

test('Successful password validation', async t => {
    for (const validPassword of validPasswords) {
        await t
            .typeText('#email', validEmail, { replace:true })
            .typeText('#password', validPassword, { replace: true })
            .click('#submit')
            .expect(Selector('#password-status').value).eql('Valid password with a length of ' + validPassword.length);
    };
});

The second test will iterate over the invalidPasswords array. The main difference between this test and the previous is the content of the password status message. The message should read: “Invalid password”.

test('Invalid password warning', async t => {
    for (const invalidPassword of invalidPasswords) {
        await t
            .typeText('#email', validEmail, { replace: true })
            .typeText('#password', invalidPassword, { replace: true })
            .click(submit)
            .expect(Selector('#password-status').value).eql('Invalid password');
    }
});

The farfurix/generating-input-data git repo contains full versions of the examples above, as well as a demo page to run these tests against.

As we just demonstrated, it’s easy to use third-party data generators in conjunction with TestCafe to randomize your tests’ user input. Just remember: not all data generators are created equal. Select one based on your website’s unique needs.

Related Topics: