Cover image for End-to-End Testing with TestCafe Book Excerpt: User Roles

End-to-End Testing with TestCafe Book Excerpt: User Roles

dennmart profile image Dennis Martinez Originally published at dev-tester.com on ・7 min read

This article is an excerpt from one of the chapters of my upcoming book, End-to-End Testing with TestCafe. If you're interested in learning more about the book, visit https://testingwithtestcafe.com.

In the previous chapter, you learned how to use hooks for setting up your tests before they begin and cleaning up after they run. It helps keep repeated functionality in a single place and out of your test scenarios. Hooks can also help with test organization, guiding you on how to effectively set fixtures by grouping tests with similar setup and teardown steps together. These steps go a long way to support the maintainability of your test suite.

However, using hooks has the limitation that the functionality you define in them works only for a single test or group of tests under a fixture. In most cases, this is acceptable behavior. For instance, if you use test hooks for pre-populating data or cleaning up after a set of tests, these steps most likely only need to occur where you define your hooks, not across the entire test suite. You rarely would need to do the same initial setup for other tests.

But there are some scenarios that you need to do in multiple areas of your test suite, like logging in a user. Going through the login process using hooks is ineffective and inconvenient. As your test suite grows, you'll create many test fixtures and separate files. If most of your tests need to have a logged-in user, you'll find yourself writing and repeatedly performing the same steps across multiple files.

You can take advantage of JavaScript's modular approach to structuring code and create a separate module that performs the login actions across your test suite. But your tests will repeat the same steps every time you need to log in a user to the application under test. Over time, these repeated actions add a considerable amount of time for your test suite to run entirely.

How can you avoid all that wasted time logging users in and out of your app? Fortunately, TestCafe has a built-in mechanism to handle authentication in most web applications, called roles. You can use roles to encapsulate how your application deals with authentication, similar to using test hooks. However, roles provide much more functionality to manage user authentication, as you'll see in this chapter.

Why use roles in TestCafe?

Most modern web applications require a user to log in before accessing other sections of the app. As you've seen in the tests you've written for the Feed section on TeamYap, you need to log in before performing any actions on that page, since it's not accessible to everyone visiting the site. The steps required to authenticate the user in those tests are in a test hook, which occurs before running the fixture scenarios.

Once your test suite expands and you begin writing more tests for different scenarios, you'll quickly see how inefficient it is to use test hooks for authenticating users. For instance, many web apps restrict logged-in users from accessing different areas of the site, like administration sections. Another example is ensuring users can only see certain elements when they're logged in, like a menu for deleting an item that belongs to them and preventing them from deleting someone else's data.

If your application has any role-based functionality like this, you'll want to write a few tests to ensure different user accounts can only access the information they're allowed to manage. If you have to log in as many different users throughout your tests, you'll find yourself repeating the login process repeatedly. Your test suite will get littered with duplicate code, and your tests will slow down significantly as you log users in and out of the system on multiple occasions.

That's where TestCafe's roles come into play. Using roles, you can avoid all of these problems while improving the speed of your tests and having more maintainable code. Here are some of the main benefits that TestCafe's roles mechanism brings to your test suite.

Log in once, stay logged in throughout your tests

When you create a role, you need to specify the necessary steps to log in. Once you log in a user successfully using roles, TestCafe saves your browser's cookies and storage data, containing the information it needs to determine that a user has access to the app. Later, if you reuse the role in another test - whether in the same fixture or not - TestCafe automatically uses the saved data to bypass the login steps.

Automatically return to the same spot in your test

After logging in to an account using roles, TestCafe automatically returns to the page your test was when you used the role. If you used the role inside of a beforeEach or before test hook, TestCafe redirects the test to the page defined in the fixture. This functionality speeds up your test runs since you won't have to redirect to another page after logging in. By default, this functionality occurs automatically, but you can optionally bypass it if you don't need to redirect.

Handle multiple user accounts with ease

Chances are you need to deal with multiple users to validate different scenarios. You can set up different user accounts using roles and quickly switch between them with a single command. TestCafe separates the browser's cookies and storage data for each role, so you no longer have to log out of an account to use a different account during test runs.


There's one caveat to using roles in TestCafe. Your application must store the sessions for logged-in users in a browser cookie or through the Web Storage API. If the application doesn't use either of these interfaces to keep track of a user's session, you might not be able to use TestCafe's roles mechanism in your tests.

If you don't know how the application under test handles authentication, speak with one of the developers of the application you're testing for more details.

Setting up roles

TestCafe uses a convenient and familiar way to set up roles to use throughout your test suite. The framework provides a Role constructor that allows you to build and initialize a role. You can import the module in any JavaScript file in your test suite to gain access to the Role constructor:

import { Role } from "testcafe";

The Role constructor requires two parameters when setting it up. The first argument is a string containing the URL of the login page for your application. When you use a role in your test, TestCafe will navigate to this URL and begin the login process. You don't need to navigate to the login page beforehand, as the roles mechanism automatically handles it.

The second parameter is an asynchronous anonymous function containing the code needed to log in the user. Like the async functions in test hooks and when creating test cases, this function gives you access to TestCafe's testing API through the test controller object. Inside the function, you can define the steps to log in a user in the same way you have done for your existing tests.

Role sets up an object that you can use inside your tests when you need to authenticate as a specific user. You can store this object in a constant and access it whenever you need it. In the example below, we're setting up a user constant containing the role object:

import { Role } from "testcafe";

const user = Role("https://example.com/login", async t => {
  await t.
    .typeText("#username", "test-account")
    .typeText("#password", "account-password")

You can set up roles in any test file. However, to get the most out of this mechanism, it's best to create a separate helper file containing your roles and import them as needed. You'll see how to do this later in this chapter.

Using roles in your tests

After you set up a role using the Role constructor, you can use the object to switch between roles at any point in your tests quickly. To use a role, use the t.useRole function provided by TestCafe's test controller object. Because test hooks and test cases have access to the test controller object, you can switch roles inside these functions at any time.


You can't use t.useRole when building your role using the Role constructor. It's the only place where you have access to TestCafe's test controller that you can't use this function.

When you use a role for the first time in a test run with t.useRole, TestCafe will navigate to the specified URL in the Role constructor and perform the steps defined in the constructor's function. If the login process is successful, TestCafe keeps the browser's storage and cookies and redirects the test back to where you called the t.useRole function. If you used t.useRole in a test hook as the first action, your test loads the fixture URL after performing the login steps in the role.

Using a role the first time in a test run works the same as if you defined the steps in your test or a test hook. But the next time you use the role in the same test run, TestCafe will not perform the steps to log the user in again. Instead, it reloads the page where you called t.useRole (or loads the fixture URL if you called it in a test hook) with the session data restored. Your tests will now pick up from where the role switch left off with the authenticated user, sparing you from going through the login process every time you use the role in subsequent tests. This behavior is what makes roles more efficient to use throughout your test suite.

End-to-End Testing with TestCafe

If you found this article useful and want to know when the End-to-End Testing with TestCafe book is available, visit https://testingwithtestcafe.com and sign up to the mailing list. You'll receive the first three chapters of the book for free. You'll also receive exclusive updates and be among the first to know when the book is available for purchase for a discount.

Posted on by:

dennmart profile

Dennis Martinez


I'm a Puerto Rican software engineer working remotely from Osaka, Japan. These days I'm mostly interested in all things testing.


markdown guide