DEV Community

Željko Šević
Željko Šević

Posted on • Originally published at sevic.dev

Browser automation with Playwright

Playwright is a headless browser library for automating browser tasks. Here's the list of some of the features:

  • Turn off headless mode
  import { chromium } from 'playwright';

  const browser = await chromium.launch({
    headless: false
    // ...
  });
Enter fullscreen mode Exit fullscreen mode
  • Resize the viewport to the window size
  const context = await browser.newContext({
    viewport: null
  });
  const page = await context.newPage();
Enter fullscreen mode Exit fullscreen mode
  • Emulate screen how it's shown to the user via the emulateMedia method
  await page.emulateMedia({ media: 'screen' });
Enter fullscreen mode Exit fullscreen mode
  • Save the page as a PDF file with a specified path, format, scale factor, and page range
  await page.pdf({
    path: 'path.pdf',
    format: 'A3',
    scale: 1,
    pageRanges: '1-2',
    printBackground: true
  });
Enter fullscreen mode Exit fullscreen mode
  • Use preexisting user's credentials to skip logging in to some websites. The user data directory is a parent of the Profile Path value from the chrome://version page. Use launchPersistentContext instead of launch + newContext.
  import { chromium } from 'playwright';

  const context = await chromium.launchPersistentContext(
    'C:\\Users\\<USERNAME>\\AppData\\Local\\Google\\Chrome\\User Data',
    { headless: false }
  );
  const page = context.pages()[0] ?? (await context.newPage());
Enter fullscreen mode Exit fullscreen mode
  • Use Chrome instance instead of Chromium via the channel option. Close Chrome before running the script if the profile is in use.
  import { chromium } from 'playwright';

  const browser = await chromium.launch({
    channel: 'chrome'
    // ...
  });
Enter fullscreen mode Exit fullscreen mode
  • Switch to the selected tab
  await page.bringToFront();
Enter fullscreen mode Exit fullscreen mode
  • Get value based on evaluation in the browser page
  const shouldPaginate = await page.evaluate(
    ([param1, param2]) => {
      // ...
    },
    [param1, param2]
  );
Enter fullscreen mode Exit fullscreen mode
  • Get HTML content from the specific element
  const html = await page.locator('.field--text').evaluate(
    (element) => element.outerHTML
  );
Enter fullscreen mode Exit fullscreen mode
  • Wait for a specific selector to be loaded. You can also provide a timeout in milliseconds
  await page.waitForSelector('.success', { timeout: 5000 });
Enter fullscreen mode Exit fullscreen mode
  • Manipulate with a specific element and click on some of the elements
  await page.locator('#header').evaluate(async (headerElement) => {
    // ...
    headerElement
      .querySelectorAll('svg')
      .item(13)
      .parentNode.click();
  });
Enter fullscreen mode Exit fullscreen mode
  • Extend execution timeout for slow evaluate callbacks
  page.setDefaultTimeout(0);
  // or per action:
  await page.locator('#header').evaluate(async (headerElement) => {
    // ...
  }, { timeout: 0 });
Enter fullscreen mode Exit fullscreen mode
  • Manipulate with multiple elements
  await page.locator('.some-class').evaluateAll(async (elements) => {
    // ...
  });
Enter fullscreen mode Exit fullscreen mode
  • Wait for navigation (e.g., form submitting) to be done
  await page.waitForLoadState('networkidle', { timeout: 0 });
Enter fullscreen mode Exit fullscreen mode

Or wait for navigation triggered by a click:

  await Promise.all([
    page.waitForNavigation({ waitUntil: 'networkidle', timeout: 0 }),
    page.click('button[type="submit"]')
  ]);
Enter fullscreen mode Exit fullscreen mode
  • Trigger hover event on some of the elements
  await page.locator('#header').hover();
Enter fullscreen mode Exit fullscreen mode

Or dispatch a custom event in the page:

  await page.locator('#header').evaluate((headerElement) => {
    const hoverEvent = new MouseEvent('mouseover', {
      view: window,
      bubbles: true,
      cancelable: true
    });

    headerElement.dispatchEvent(hoverEvent);
  });
Enter fullscreen mode Exit fullscreen mode
  • Expose a function in the browser and use it in evaluate / evaluateAll callbacks (e.g., simulate typing using the window.type function)
  await page.exposeFunction('type', async (selector, text, options) => {
    await page.locator(selector).type(text, options);
  });

  await page.locator('.some-class').evaluateAll(async (elements) => {
    // ...
    await window.type(selector, text, { delay: 0 });
  });
Enter fullscreen mode Exit fullscreen mode
  • Press the Enter button after typing the input field value
  await page.locator(selector).fill(text);
  await page.locator(selector).press('Enter');
Enter fullscreen mode Exit fullscreen mode
  • Open a file chooser and select file for upload
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.locator(selector).click();
  const fileChooser = await fileChooserPromise;

  const filePath = `C:/Users/<USERNAME>/Downloads/test.jpeg`; // use "/" instead of "\" in file path
  await fileChooser.setFiles(filePath);
Enter fullscreen mode Exit fullscreen mode
  • Remove the value from the input field before typing the new one
  await page.locator(selector).fill(text);
Enter fullscreen mode Exit fullscreen mode

Or select all and replace:

  await page.locator(selector).click({ clickCount: 3 });
  await page.locator(selector).type(text, options);
Enter fullscreen mode Exit fullscreen mode
  • Pass a variable into evaluate / evaluateAll callbacks via extra arguments
  await page.locator('#element').evaluate(
    async (element, customVariable) => {
      // ...
    },
    customVariable
  );
Enter fullscreen mode Exit fullscreen mode
  • Mock response for the specific request
  await page.route(REDIRECTION_URL, async (route) => {
    await route.fulfill({
      contentType: 'text/html',
      status: 304,
      body: '<body></body>'
    });
  });
Enter fullscreen mode Exit fullscreen mode
  • Intercept page redirections (via route) and open them in new tabs rather than following them in the same tab
  await page.route(REDIRECTION_URL, async (route) => {
    const url = route.request().url();

    await route.fulfill({
      contentType: 'text/html',
      status: 304,
      body: '<body></body>'
    });

    const newPage = await context.newPage();
    await newPage.goto(url, { waitUntil: 'domcontentloaded', timeout: 0 });
    // ...
    await newPage.close();
  });
Enter fullscreen mode Exit fullscreen mode
  • Intercept page response
  page.on('response', async (response) => {
    if (response.url() === RESPONSE_URL) {
      if (response.status() === 200) {
        // ...
      }
      // ...
    }
  });
Enter fullscreen mode Exit fullscreen mode

Top comments (0)