DEV Community

Cover image for Managing multiple pages in Playwright test
Kayode
Kayode

Posted on

Managing multiple pages in Playwright test

I was trying to write a test in Playwright that opens a multiplayer game on multiple tabs. This method can be useful for test multi-type applications like chats application etc.

But in my case in my case, I was testing a visual game on a HTML canvas so all I did was a visual regression test using Applitools.

How I approached the problem

  • I made an array of Playwright page derived from just a single context.
  • From the Playwright pages, I derived an array of Promises which performs the functions configured for each pages so that I can run run the test using:

    await Promise.all(tasks)
    

The way I have my test setup, rather than defining the tests directly, I create modular functions and variables to be able to reuse the functions or variables. This proved useful when working with selectors. For instance:

import { multiplayerMoves, selectors } from "../pages/canva"

// selectors is an object with contains the selectors specific to a page

test("multiplayer", async () => {
    test.setTimeout(90000);
    const tasks = await multiplayerMoves(2, context, eyes);

    await Promise.all(tasks);
  });
});
Enter fullscreen mode Exit fullscreen mode

The multiplayerMoves looked like this

//canva.ts
export const multiplayerMoves = async (
  numOfPages: number,
  context: BrowserContext,
  eyes: Eyes
) => {
  // pre-allocating an initialized array with empty null with the page
  // the Promise.all is necessary because the async callback in Array.map
  // would return a Promise that would resove to what is returned in the callback
  const pages = await Promise.all(
    Array(numOfPages)
      .fill(null)
      .map(async () => {
        const page = await context.newPage();
        return page;
      })
  );

  // mapping through the number of pages and creating a new promise that calls an async IIFE
  const tasks = pages.map(async (page, ind) => {
    return new Promise((resolve, reject) => {
      (async () => {
        try {
          await page.goto("http://localhost:3000");

          // if even, make us of the diagonal movement coordinate on the canva
          if (ind % 2 === 0) {
            await makeMoves(page, 5, null, "diag");
          } else await makeMoves(page, 5, null, "vert");

          // making use of the first page in the pages array to take a snapshot and send to applitools
          // for visual testing
          if (ind === 0) {
            await page.waitForTimeout(10000);
            await eyes.open(page, "color-board", "multiplayer");
            await eyes.check(
              "board",
              Target.region(selectors.gameboard).layout()
            );
            await eyes.close();
          }

          resolve(undefined);
        } catch (err) {
          reject(err);
        }
      })();
    });
  });

  // returns an array of promise
  return tasks;
};
Enter fullscreen mode Exit fullscreen mode

The makeMoves function is that interate with the canva rendered on the pages and make moves on the canva depending on the arguments passed to it.

Conclusion

What can you say about this temporary method. I look forward to your comments and learning from you. 🤗

Discussion (0)