最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

typescript - Playwright targeting mobile browser at a test level - Stack Overflow

programmeradmin2浏览0评论

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 = '';

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'],
     },
    ],
});

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/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'],
     },
    ],
});
Share Improve this question edited Mar 17 at 3:11 Carl Bruiners asked Mar 15 at 16:55 Carl BruinersCarl Bruiners 5902 gold badges8 silver badges23 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 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.

发布评论

评论列表(0)

  1. 暂无评论