gleewright

Playwright-powered end-to-end testing for Gleam.

In a Gleam project targeting JavaScript on Node, install both packages and the browser from the directory containing gleam.toml:

gleam add --dev gleewright
npm init -y # only if you don't already have a package.json
npm install --save-dev @playwright/test@^1.63.0
npx playwright install chromium

For a suite in src/, use gleam add gleewright without --dev. On Linux or CI, npx playwright install --with-deps chromium also installs system libraries. Reinstall browsers after upgrading Playwright. Run suites with gleam run -m <module>; no playwright.config.ts is needed. Gleewright uses its own config and runner, not npx playwright test.

This module defines tests and runs them. The other modules drive the browser:

A suite is a module with a main function that calls main:

import gleewright
import gleewright/expect
import gleewright/locator
import gleewright/page
import gleewright/role
import gleewright/step

pub fn main() {
  gleewright.config()
  |> gleewright.base_url("http://localhost:3000")
  |> gleewright.main(tests(), _)
}

fn tests() -> List(gleewright.Test) {
  [
    gleewright.it("signs in", fn(page) {
      use _ <- step.try(page.goto(page, "/login"))
      use _ <- step.try(
        page.get_by_label(page, "Email") |> locator.fill("me@example.com"),
      )
      use _ <- step.try(
        page.get_by_role_named(page, role.Button, "Sign in") |> locator.click,
      )
      expect.page(page) |> expect.to_have_url("/dashboard")
    }),
  ]
}

Run it with gleam run -m <module>. See the README for setup.

Types

How to run tests. Create one with config and adjust it with the builder functions below.

pub opaque type Config

How a single test ended.

pub type Outcome {
  Passed
  Failed(error: error.Error, screenshot: option.Option(String))
  Skipped
}

Constructors

  • Passed

    Every step of the test succeeded.

  • Failed(error: error.Error, screenshot: option.Option(String))

    A step failed. screenshot is the path of a screenshot of the page taken at the time of the failure, if screenshots are enabled.

  • Skipped

    The test was skipped with skip, or another test was focused with only.

The outcome of a test run.

pub type Report {
  Report(results: List(TestResult), duration: Int)
}

Constructors

  • Report(results: List(TestResult), duration: Int)

A test, or a group of tests.

pub opaque type Test

The outcome of a single test. name includes the names of the groups the test is in, separated by ›.

pub type TestResult {
  TestResult(name: String, outcome: Outcome, duration: Int)
}

Constructors

  • TestResult(name: String, outcome: Outcome, duration: Int)

Values

pub fn action_timeout(
  config: Config,
  milliseconds: Int,
) -> Config

How long a single action such as a click or navigation may take, in milliseconds.

pub fn all_passed(report: Report) -> Bool

Whether every test that ran passed.

pub fn base_url(config: Config, url: String) -> Config

The URL relative URLs in page.goto and expect.to_have_url are resolved against, e.g. "http://localhost:3000".

pub fn browser(
  config: Config,
  browser: browser.BrowserType,
) -> Config

Which browser to run the tests in.

pub fn config() -> Config

The default config: headless Chromium, a 1280x720 viewport, 30 second test timeout, 10 second action timeout, and screenshots of failing tests saved to build/gleewright.

pub fn describe(name: String, tests: List(Test)) -> Test

Group tests under a common name.

pub fn filter(config: Config, text: String) -> Config

Only run tests whose full name contains the given text.

pub fn headed(config: Config) -> Config

Show the browser window while tests run.

pub fn it(
  name: String,
  body: fn(page.Page) -> step.Step(Nil),
) -> Test

Define a test. The body gets a fresh page in its own browser context, so cookies and storage never leak between tests. The test passes if the step it returns succeeds.

pub fn main(
  tests: List(Test),
  config: Config,
) -> promise.Promise(Nil)

Run tests from a main function: reads command line flags (see with_flags), runs the tests, prints the results, and exits with a non-zero status if any test failed.

gleam run -m my_app_e2e -- --grep login --headed
pub fn no_screenshots(config: Config) -> Config

Don’t take screenshots of failing tests.

pub fn only(t: Test) -> Test

Focus on a test or group: if any test is focused, only focused tests run.

pub fn quiet(config: Config) -> Config

Don’t print anything while running.

pub fn run(
  tests: List(Test),
  config: Config,
) -> promise.Promise(Result(Report, error.Error))

Run tests one after another, each with a fresh page. Fails only if the browser could not be launched; test failures are recorded in the report.

pub fn screenshot_dir(
  config: Config,
  directory: String,
) -> Config

Where to save screenshots of failing tests.

pub fn skip(t: Test) -> Test

Skip a test or group.

pub fn slow_mo(config: Config, milliseconds: Int) -> Config

Slow every Playwright operation down by the given number of milliseconds, to follow along in a headed browser.

pub fn test_timeout(config: Config, milliseconds: Int) -> Config

How long a whole test may take, in milliseconds.

pub fn viewport(
  config: Config,
  width width: Int,
  height height: Int,
) -> Config

The size of the browser viewport.

pub fn with_flags(
  config: Config,
  flags: List(String),
) -> Result(Config, String)

Apply command line flags to a config:

  • --grep <text> only runs tests whose name contains the text
  • --headed shows the browser window
  • --browser <chromium|firefox|webkit> picks the browser
  • --slow-mo <ms> slows every operation down
✨ Search Document