Playwright - Cleaner Promise Chains

05/01/2021, Sat
Categories: #testing

Fluent API

As with many JavaScript libraries, asynchronous operations are dealt with using promises, and the commonly preferred way of structuring promises flows entails the use of async / await.

From the Playwright documentation

const { webkit } = require('playwright');

(async () => {
  const browser = await webkit.launch();
  const page = await browser.newPage();
  await page.goto('http://whatsmyuseragent.org/');
  await page.screenshot({ path: `example.png` });
  await browser.close();
})();

Every page operation will require the use of an await since each yields a promise. However, this simple example shows the extra effort needed to tame async control flow by having to prepend each operation with an await. This is a bit noisy and detracts from the true intent of the tests steps.

With the help of this library, playwright-jest, it is possible to clean up an async await block in playwright to use only one await per block.

Modified example from the "playwright-fluent" documentation

import { PlaywrightFluent, userDownloadsDirectory } from 'playwright-fluent';
const p = new PlaywrightFluent();

await p
    .withBrowser('firefox')
    .withOptions({ headless: false })
    .withCursor()
    .recordPageErrors()
    .recordFailedRequests()
    .recordDownloadsTo(userDownloadsDirectory)
    .emulateDevice('iPhone 6 landscape')
    .navigateTo('https://reactstrap.github.io/components/form/')
    .click('#exampleEmail')
    .typeText('foo.bar@baz.com')

// Use the playwright api for taking a screenshot
const page = p.currentPage()

await page
    .screenshot({ path: `example.png` })

// Peform more browser actions
await p
    .pressKey('Tab')
    .expectThatSelector('#examplePassword')
    .hasFocus()
    .typeText("don't tell!")
    .pressKey('Tab')

// Take another screenshot
await page
    .screenshot({ path: `another-example.png` })

// Close the browser window
p.currentBrowser().close();

The original "playwright" object is needed for certain methods calls that are not implemented in "playwright-fluent" such as the screenshotting to file functionality, but the consecutive promise chains grouped together with "playwright-fluent" still provide greater clarity.