Managing Test Users with a Custom UserPool in a Node.js Playwright-Cucumber Framework

Managing users efficiently during test automation is essential, especially when dealing with role-based access control and multiple user personas. In my custom test automation framework built on Node.js, leveraging Playwright, CucumberJS, and MongoDB, I have implemented a dynamic UserPool to streamline the handling of test users. This approach improves efficiency, scalability, and ensures smooth parallel test execution without conflicts or redundant logins.

In this post, I will explore the technologies involved and how the UserPool works to manage users dynamically in this automation framework.

Technology Stack

Here’s a quick overview of the technologies powering this framework:

1. Node.js

The framework is built with Node.js, a fast, scalable JavaScript runtime commonly used for backend services and automation frameworks. Node.js facilitates seamless interaction with Playwright and MongoDB in a highly asynchronous environment.

2. Playwright

Playwright is a robust browser automation library that supports modern browser engines such as Chromium, Firefox, and WebKit. It is ideal for automating tests involving different user interactions, and it easily handles parallel execution and session management.

3. CucumberJS

The framework uses CucumberJS for writing feature files in a Behavior-Driven Development (BDD) format. Cucumber enables tests to be written in plain English, making them more readable and maintainable, while still allowing powerful test execution.

4. MongoDB

MongoDB serves as the database for storing test user credentials. Its flexibility and document-based structure make it easy to manage various user roles and ensure that credentials can be accessed dynamically by the framework.

What is the UserPool?

The UserPool is a utility within the framework that manages test user credentials dynamically. Instead of hardcoding user credentials for every test, the UserPool retrieves user information from MongoDB and allocates them based on roles (such as “admin”, “user”, “read-only”, etc.). This approach improves test flexibility, reduces the risk of session conflicts, and supports parallel test execution without overlap.

Implementing the UserPool in Node.js

The UserPool is implemented as a Node.js class that interacts with MongoDB to fetch and manage user sessions. Below is the structure of the UserPool class, along with the newly added releaseAllUsers method.

Storing Users in MongoDB

Users are stored in a MongoDB collection as documents. Each user has fields for their username, password, and role, along with an inUse flag to indicate whether the user is currently engaged in a test:

{
  "_id": ObjectId("617c1c8f8c7e1819dcae9b57"),
  "username": "admin@example.com",
  "password": "secureAdminPassword",
  "role": "admin",
  "inUse": false
},
{
  "_id": ObjectId("617c1c8f8c7e1819dcae9b58"),
  "username": "user@example.com",
  "password": "secureUserPassword",
  "role": "user",
  "inUse": false
}

UserPool Class with releaseAllUsers

The following is the implementation of the UserPool class in Node.js, which interacts with MongoDB to retrieve users based on roles and ensure that they are not already in use.

const { MongoClient } = require('mongodb');

class UserPool {
  constructor() {
    this.db = null;
  }

  // Connect to the MongoDB database
  async connect() {
    if (!this.db) {
      const client = new MongoClient(process.env.MONGO_URI);
      await client.connect();
      this.db = client.db(process.env.DB_NAME);
    }
  }

  // Fetch a user based on role
  async getUser(role) {
    await this.connect();
    
    const user = await this.db.collection('users').findOne({ role, inUse: false });
    if (!user) {
      throw new Error(`No available user found with role: ${role}`);
    }
    
    // Mark user as "in use" to avoid conflicts in parallel tests
    await this.db.collection('users').updateOne({ _id: user._id }, { $set: { inUse: true } });

    return {
      username: user.username,
      password: user.password
    };
  }

  // Release all users (set inUse: false for all users)
  async releaseAllUsers() {
    await this.connect();

    await this.db.collection('users').updateMany({}, { $set: { inUse: false } });
    console.log('All users have been released and set to available.');
  }

  // Release a single user (after test execution)
  async releaseUser(username) {
    await this.connect();

    await this.db.collection('users').updateOne({ username }, { $set: { inUse: false } });
    console.log(`User ${username} has been released and set to available.`);
  }
}

module.exports = new UserPool();

Explanation:

  • Given Step: The getUser method fetches the user credentials based on the required role, ensuring the user is not already in use.
  • After Hook: Once the test scenario completes, the releaseUser method is called to release the user and make them available for future tests.

Benefits of Using releaseAllUsers

  1. Test Integrity: Ensuring that all users are released before the tests start helps maintain a clean testing environment, free from leftover sessions or locked users.
  2. Parallel Execution: The use of the inUse flag prevents session conflicts during parallel test execution by ensuring each test has access to a unique user.
  3. Scalability: As the test suite grows, adding more users to the UserPool is simple and requires minimal code changes, allowing for more efficient and scalable test management.

Conclusion

Implementing a dynamic UserPool in a Node.js-based Playwright-Cucumber framework improves the way test users are managed. By utilizing MongoDB for storage and integrating methods like releaseAllUsers in BeforeAll hooks, this solution ensures that tests run smoothly, even in parallel, without conflicts or redundancy.

If you’re working with multiple user roles or parallel test execution, incorporating a UserPool will significantly enhance the stability and scalability of your test framework.

Feel free to share your thoughts or reach out if you have any questions about implementing similar solutions in your projects!


Posted

in

by

Comments

2 responses to “Managing Test Users with a Custom UserPool in a Node.js Playwright-Cucumber Framework”

  1. Seiren Nishimura Avatar

    Hi! Your insights into managing user pools with Node.js are impressive. The dynamic handling of users for test automation is quite efficient. Quick question, how do you ensure the UserPool syncs perfectly with MongoDB during parallel test execution? I came across a blog that also discusses similar topics around JavaScript and automation. You might find it interesting: https://sebbie.pl/tag/javascript/. Thanks for sharing such useful content!

    1. Dragutin Misirača Avatar

      Hi, thanks :). It uses promises, so no worries about it. Also I’m hosting MongoDB on separated host, I can access it from different runners(different ip addresses).
      Sorry for late reply , I’m planning soon to become more active here. Please share if you like it 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *