1

I have a spec file that has a test:

test.describe('mobile', () => {
  test.beforeEach(async ({ page }) => {
     await page.goto(url);
   });
   test('Mobile check - (Optimal on desktop / tablet) only shown on smaller screens (i.e mobile breakpoint)', async ({ page })=>{
    await page.goto(url);
    await expect(page.getByText('(Optimal on desktop / tablet)')).toBeVisible();
   });
 });

I have in the playwright config setup 2 mobile browsers to test iPhone and Android emulation:

/* Test against mobile viewports. */
 {
  name: 'Mobile Chrome',
  grep: /mobile/,
   use: { ...devices['Pixel 5'] },
},
 {
   name: 'Mobile Safari',
   grep: /mobile/,
   use: { ...devices['iPhone 14 Pro'] },
 },

When I run this, it runs the tests in the desktop browser, not the mobile window. I've seen examples of setting the viewport on a per test basis, but not the emulator itself.

I'd like to be able to have 1 specs file describing both mobile and desktop emulation, rather than separate by device type.

Can I set the target emulator on per test basis?

I don't want to have to run with filters; rather I run the tests, they execute individually against a targeted browser/s.

Edit

test.spec.ts

    import { test, expect, devices } from '@playwright/test';

test.use({ storageState: 'playwright/.auth.json' });
const url = 'https://test.com/custom-library';

test.describe('desktop', () => {
  test('Hide No Data (shown twice) on radar whilst awaiting an input', async ({ page, isMobile }) => {
    test.skip(isMobile)
    await page.goto(url);
    const buttonsCount = await page.getByText('No Data').count();
    expect(buttonsCount).toBe(0);
  });

  test('Desktop check - (Optimal on desktop / tablet) only shown on smaller screens (i.e mobile breakpoint)', async ({ page, isMobile }) => {
    test.skip(isMobile)
    await page.goto(url);
    const buttonsCount = await page.getByText('(Optimal on desktop / tablet)').count();
    expect(buttonsCount).toBe(0);
  });
});

test.describe('mobile', () => {
    test('Mobile check - (Optimal on desktop / tablet) only shown on smaller screens (i.e mobile breakpoint)', async ({ page, isMobile })=>{
      console.log(!isMobile);
      test.skip(!isMobile)
      await page.goto(url);
      await expect(page.getByText('(Optimal on desktop / tablet)')).toBeVisible();
    });
});

My playwright.config.ts file is:

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    trace: 'on-first-retry',
  },

  projects: [
    { 
      name: 'setup', 
      testMatch: /.*\.setup\.ts/
    },
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'], storageState: './playwright/.auth.json' },
      dependencies: ['setup'],
    },

    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'], storageState: './playwright/.auth.json' },
      dependencies: ['setup'],
    },

    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'], storageState: './playwright/.auth.json' },
      dependencies: ['setup'],
    },

    /* Test against mobile viewports. */
     {
      name: 'Mobile Chrome',
      use: { ...devices['Pixel 5'], storageState: './playwright/.auth.json' },
      dependencies: ['setup'],
    },
     {
       name: 'Mobile Safari',
       use: { ...devices['iPhone 14 Pro'], storageState: './playwright/.auth.json' },
       dependencies: ['setup'],
     },
    ],
});
0

1 Answer 1

1

Your approach looks basically OK, with some improvements available. For starters, here's your code as a fully working, reproducible example.

With grep

playwright.config.js:

import {defineConfig, devices} from "@playwright/test"; // ^1.51.0

export default defineConfig({
  projects: [
    {
      name: "Mobile Chrome",
      grep: /mobile/,
      use: {...devices["Pixel 5"]},
    },
    {
      name: "Mobile Safari",
      grep: /mobile/,
      use: {...devices["iPhone 14 Pro"]},
    },
  ],
});

example.test.js:

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

const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="text"></div>
<script>
function updateText() {
  const textElement = document.getElementById("text");
  textElement.textContent =
    window.innerWidth <= 900 ? "mobile" : "desktop";
}
updateText();
window.addEventListener("resize", updateText);
</script>
</body>
</html>`;

test("mobile check", async ({page}) => {
  await page.setContent(html);
  await expect(page.locator("#text")).toHaveText("mobile");
});

test("desktop check", async ({page}) => {
  await page.setContent(html);
  await expect(page.locator("#text")).toHaveText("desktop");
});

Sample run:

% npx playwright test

Running 2 tests using 2 workers

  ✓  1 [Mobile Chrome] › example.test.js:23:5 › mobile check (261ms)
  ✓  2 [Mobile Safari] › example.test.js:23:5 › mobile check (465ms)

  2 passed (930ms)

The first note to mention is that grep applies to the whole test name, including the project name and file name. So if your project name happens to match the grep pattern, every test will run regardless of whether the test is mobile or not!

As such, the preferred approach is to use tags which are less prone to inaccuracies like this.

With tags

playwright.config.js:

import {defineConfig, devices} from "@playwright/test";

export default defineConfig({
  projects: [
    {
      name: "Mobile Chrome",
      grep: /@mobile/,
      use: {...devices["Pixel 5"]},
    },
    {
      name: "Mobile Safari",
      grep: /@mobile/,
      use: {...devices["iPhone 14 Pro"]},
    },
  ],
});

example.test.js:

test("mobile check", {tag: "@mobile"}, async ({page}) => {
  await page.setContent(html);
  await expect(page.locator("#text")).toHaveText("mobile");
});

test("desktop check", {tag: "@desktop"}, async ({page}) => {
  await page.setContent(html);
  await expect(page.locator("#text")).toHaveText("desktop");
});

Output:

% npx playwright test

Running 2 tests using 2 workers

  ✓  1 [Mobile Safari] › example.test.js:23:5 › mobile check @mobile (531ms)
  ✓  2 [Mobile Chrome] › example.test.js:23:5 › mobile check @mobile (290ms)

  2 passed (1.1s)

With isMobile and test.skip()

isMobile and test.skip() are another options:

playwright.config.js

import {defineConfig, devices} from "@playwright/test";

export default defineConfig({
  projects: [
    {
      name: "Mobile Chrome",
      use: {...devices["Pixel 5"]},
    },
    {
      name: "Desktop",
      use: {...devices["Desktop Chrome"]},
    },
  ],
});

example.test.js

test("mobile check", async ({page, isMobile}) => {
  test.skip(!isMobile)
  await page.setContent(html);
  await expect(page.locator("#text")).toHaveText("mobile");
});

test("desktop check", async ({page, isMobile}) => {
  test.skip(isMobile)
  await page.setContent(html);
  await expect(page.locator("#text")).toHaveText("desktop");
});

Output:

% npx playwright test

Running 4 tests using 2 workers

  ✓  1 [Mobile Chrome] › example.test.js:23:5 › mobile check (171ms)
  -  2 [Desktop] › example.test.js:23:5 › mobile check
  ✓  3 [Desktop] › example.test.js:29:5 › desktop check (78ms)
  -  4 [Mobile Chrome] › example.test.js:29:5 › desktop check

  2 skipped
  2 passed (747ms)

You can use any of these methods at a describe block level to create groups of tests if you prefer.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, awesome response. I'm having problems with running mobile tests still, it keeps skipping the ones I'm flagging for mobile testing: test('Mobile check - (Optimal on desktop / tablet) only shown on smaller screens (i.e mobile breakpoint)', async ({ page, isMobile })=>{ console.log(!isMobile); test.skip(!isMobile) await page.goto(url); await expect(page.getByText('(Optimal on desktop / tablet)')).toBeVisible(); }); This skips everytime (tested !isMobile in console log and it returns true, so shouldn't skip)
Glad it was helpful! Not sure I follow the comment though--test.skip(!isMobile) means "skip this test if it's NOT mobile" (i.e. test.skip(!isMobile) is what you want to add on mobile tests). So that seems to be working as expected in my example. Maybe check to make sure that the project device for that test really is a mobile device. I'd probably have to see your tests and config, so you could open a new question, or edit the current one if it doesn't invalidate my answer.
Thanks, I'm using test.skip(!isMobile) for the mobile tests :). My config file has { name: 'Mobile Safari', use: { ...devices['iPhone 14 Pro'], storageState: './playwright/.auth.json' }, dependencies: ['setup'], } If this isn't helpful, I'll edit this question :)
Edited the original question and added in one of the test files and also the config file
Thanks ggorlen, and now I must confess I'm an idiot. For the sake of this I was running it through the UI and hadn't selected in the UI (unlike running it through terminal) the mobile versions of safari and chrome... its working and working fine. Leaving the comment above in place in case someone makes the same mistake.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.