[Playwright] Tips

发布时间 2023-08-22 15:02:57作者: Zhentiw

Run playwright

A basic playwright code example:

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

test("Math works", () => {
    expect(1+2).toBe(2);
});

// Only run one test suit
test.only('Page demo', async ({page}) => {
    await page.goto("gttps://google.com");
    
    const searchInput = page.locator('input[title=Search]');
    await searchInput.type('Hello World');
    await searchInput.press('Enter');

    ...
})

If you run npx playwright test tests/basics.spec.ts --project=chromium --reporter=list --headed

It will 

  • only run basics.spec.ts file
  • use chrome browser by `--project=chromium`
  • open browser as well by `--headed`

 

It will generates report as well, to see the report:

npx playwright show-report

This is useful command, you can download the artifacts from github CI, then run the command, it will open playwright UI which you can access all kinds of information such as network, console, Before / after snapshot;

 

You can also run playwright in debug mode, so that you can go through each line of code one by one

npx playwright test --debug

 

You can also use playwright to auto generate testing code for you:

npx playwright codegen -o tests/demo.spec.ts

It open browser, you can performan testing actions, the testing code will be auto generated.

 

You can enable screenshot:

use: {
 ..
 screenshot: 'only-on-failure',
 video: 'on-first-retry' | 'retain-on-failure'
}

 

Expect

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

test.beforeEach(async ({ page }) => {
  await page.goto('http://localhost:3000');
});

test.describe('App', () => {

  test('Logo is visible', async ({ page }) => {
    const logo = page.locator('img[alt=logo]');
    await expect(logo).toBeVisible();
  });

  test('Link should be valid', async ({ page }) => {
    const link = page.locator('a', { hasText: 'Learn React' });
    await expect(link).toBeVisible();
    await expect(link).toHaveAttribute('href', 'https://reactjs.org');
  });
});
  • page.locator('a', {hasText: 'Learn React'}) // hasText is useful helper method
  • toBeVisible()

 

Visual Regression Testing

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

test.beforeEach(async ({ page }) => {
  await page.goto('http://localhost:3000');
});

test('Button Base', async ({ page }) => {
  expect(await page.screenshot()).toMatchSnapshot('button-base.png');
});

 

Add threshold to config:

// playwright.config.ts

{
...
toMatchSnapshot: { threshold: 0.2 },
...
}

 

Update snapshot, run:

npx playwright test --update-snapshots

 

Selector

Page:

import type { NextPage } from 'next';

const Home: NextPage = () => {
  return (
    <div style={{ padding: '10px' }}>
      <button data-test="submit" className='primary' type='submit'>Submit</button> <button className='secondary' type='reset'>Reset</button>
    </div>
  );
}

export default Home;

Test:

import { test } from '@playwright/test';

test.beforeEach(async ({ page }) => {
  await page.goto('http://localhost:3000');
});

test('selectors', async ({ page }) => {
  /** CSS Selector */
  await page.locator('button.primary').click();

  /** Explicit CSS Selector */
  await page.locator('css=button.primary').click();

  /** Text Selector */
  await page.locator('text=submit').click();

  /** Chain Selectors */
  await page.locator('button >> text=Submit').click();

  /** nth */
  await page.locator('button >> nth=0').click();

  /** data-test */
  await page.locator('data-test=submit').click();
});

 

Page Object Model Pattern

This is the code which doesn't use page object model pattern:

 

As you can see, it is not so easy to understand the code.

 

Create a page model:

// TodoPage.ts
import { expect, Locator, Page } from '@playwright/test';

export class TodoPage {
  readonly newTodoInput: Locator;
  readonly todoLabels: Locator;

  constructor(readonly page: Page) {
    this.newTodoInput = page.locator('.new-todo');
    this.todoLabels = page.locator('.view label');
  }

  async goto() {
    await this.page.goto('https://demo.playwright.dev/todomvc');
  }

  async addTodo(todo: string) {
    await this.newTodoInput.fill(todo);
    await this.newTodoInput.press('Enter');
  }

  async expectTodos(todos: string[]) {
    await expect(this.todoLabels).toHaveText(todos);
  }
}

Testing code

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

test.beforeEach(async ({ page }) => {
  await new TodoPage(page).goto();
});

test('should allow me to add todo items', async ({ page }) => {
  const todoPage = new TodoPage(page);

  // Create a todo
  await todoPage.addTodo('buy some cheese');

  // Make sure the list has the todo item
  await todoPage.expectTodos(['buy some cheese']);

  // Create 2nd todo.
  await todoPage.addTodo('feed the cat');

  // Make sure the list now has two todo items.
  await todoPage.expectTodos([
    'buy some cheese',
    'feed the cat',
  ]);
});

 

Playwright Test Fixtures, Browser Context and Page

test('demo fixtures', async ({page, browser, browserName, context}) => {})

Use those variable, you can get more information.

 

Playwright Library for Browser Automation

import playwright from 'playwright';

async function main() {
  /** Launch browser */
  const browser = await playwright.chromium.launch({ headless: false });

  /** Create a context, session */
  const context = await browser.newContext();

  /** Create a page, a new tab */
  const page = await context.newPage();

  /** Carry out actions */
  await page.goto('https://google.com');
  await page.locator('[title="Search"]').fill('Microsoft Playwright');
  await page.locator('[title="Search"]').press('Enter');
  await page.locator('#result-stats').waitFor({ state: 'visible' });
  await page.screenshot({ path: './screenshots/page.png' });

  /** Close the browser */
  await browser.close();
}

main();