3

How can I use playwright expect to check for one of two exact matches?

Here's my function.

export const assertThirdPartyInternetPath = async (
  page: Page,
  path: string,
) => {
  expect(page.url()).toBe(path);
};

I am using it to test links to wikipedia pages.

await this.assertThirdPartyInternetPath('https://en.wikipedia.org/wiki/Larry_Sanger'

However, some sites like Wikipedia will redirect mobile devices (including playwright devices) to the m subdomain.

So I want to assert that the user is at either https://en.wikipedia.org/wiki/Larry_Sanger or https://en.m.wikipedia.org/wiki/Larry_Sanger. How can I do that?

Note that I want to do an exact match; I know I can use expect(string.toContain(myPattern) but I have various things to match and I want to do exact matches.

Patrick Kenny
  • 4,515
  • 7
  • 47
  • 76

2 Answers2

5

Reversing the comparison as suggested in Jest matcher to match any one of three values is possible, but makes the assertion message and overall flow a bit awkward.

expect([
  "https://en.wikipedia.org/wiki/Larry_Sanger",
  "https://en.m.wikipedia.org/wiki/Larry_Sanger",
]).toContain(page.url());

I'd prefer to use regex because it keeps the assertion in the normal direction:

expect(page.url())
  .toMatch(/^https:\/\/en\.(?:m\.)?wikipedia\.org\/wiki\/Larry_Sanger$/);

The problems are readability and remembering to escape regex characters and add anchors. You could use a normal string and escape it with a bit of extra utility code.

Another option is to write a custom matcher:

import {expect, test} from "@playwright/test"; // ^1.30.0

expect.extend({
  async toBeAnyOf(received, ...possibilities) {
    if (possibilities.includes(received)) {
      return {
        message: () => "passed",
        pass: true,
      };
    }

    return {
      message: () =>
        `failed: '${received}' was not any of ${possibilities}`,
      pass: false,
    };
  },
});

test("is on the normal site", async ({page}) => {
  await page.goto("https://en.wikipedia.org/wiki/Larry_Sanger");
  expect(page.url()).toBeAnyOf(
    "https://en.wikipedia.org/wiki/Larry_Sanger",
    "https://en.m.wikipedia.org/wiki/Larry_Sanger",
  );
});

test("is on the mobile site", async ({page}) => {
  await page.goto("https://en.m.wikipedia.org/wiki/Larry_Sanger");
  expect(page.url()).toBeAnyOf(
    "https://en.wikipedia.org/wiki/Larry_Sanger",
    "https://en.m.wikipedia.org/wiki/Larry_Sanger",
  );
});
ggorlen
  • 44,755
  • 7
  • 76
  • 106
-1

You may use toMatch with a regular expression to exact match either of two strings.

expect(value).toMatch(/^A$|^B$/)
Vishal Aggarwal
  • 1,929
  • 1
  • 13
  • 23
  • Thanks for the answer. This _looks_ simple, but please use OP's input. It has regex special characters that would fail if dropped directly into this pattern. You'll need to escape them as shown in the existing answer. Users unfamiliar with regex may be misled. Once you make this adjustment, I think you'll see that your solution is not that much simpler or different than what's already been proposed. – ggorlen May 18 '23 at 15:08
  • My answer is for more even broader audience who has simple text based strings. I have used this numerous times in simple text based strings successfully where there was no regex involved. – Vishal Aggarwal May 18 '23 at 15:18