Managing multiple pages in Playwright test
Tags: playwright, javascript, testing, qa
Published: 2022-03-10 07:21:30

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](https://applitools.com/). 

### 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:
    
    ```jsx
    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:

```jsx
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);
  });
});
```

The `multiplayerMoves` looked like this

```jsx
//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;
};
```

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. 🤗