View Source Pages

CI Hex pm API docs License

An Elixir implementation of the Page Object pattern for interacting with websites. This library can be used to facilitate testing of Phoenix controllers and LiveView pages in the context of ExUnit, and may be used as the basis of other drivers.

Note: prior to the release of 1.0.0, minor releases of this library may include breaking changes. While new, this library is undergoing rapid development. A goal is to reach a stable API and a 1.0.0 release as soon as possible.

See the API reference for more info, specifically the docs for the Pages module.

installation

Installation

def deps do
  [
    {:pages, "~> 0.13", only: :test}
  ]
end

Configure your endpoint in config/test.exs:

config :pages, :phoenix_endpoint, Web.Endpoint

usage

Usage

The typical usage is to create a module for each page of your web app, with functions for each action that a user can take on that page, and then to call those functions in a test. Note that in this example, Web and Test are top-level modules in the app that's being tested.

defmodule Web.HomeLiveTest do
  use Test.ConnCase, async: true
  
  test "has login button", %{conn: conn} do
    conn
    |> Pages.new()
    |> Test.Pages.HomePage.assert_here()
    |> Test.Pages.HomePage.click_login_link()
    |> Test.Pages.LoginPage.assert_here()
  end
end

Here is the definition of the HomePage module that's used in the test above. This test uses assert_eq/3 from the Moar library, and find/2 & attr/2 from the HtmlQuery library.

defmodule Test.Pages.HomePage do
  import Moar.Assertions
  alias HtmlQuery, as: Hq

  @spec assert_here(Pages.Driver.t()) :: Pages.Driver.t()
  def assert_here(%Pages.Driver.LiveView{} = page) do
    page
    |> Hq.find("[data-page]")
    |> Hq.attr("data-page")
    |> assert_eq("home", returning: page)
  end

  @spec click_login_link(Pages.Driver.t()) :: Pages.Driver.t()
  def click_login_link(page),
    do: page |> Pages.click("Log In", test_role: "login-link")

  @spec visit(Pages.Driver.t()) :: Pages.Driver.t()
  def visit(page),
    do: page |> Pages.visit("/")
end

A page module that you define can work with either a controller-based page or a LiveView-based page, and a test can test workflows that use both controllers and LiveViews.

under-the-hood

Under the hood

This library uses functions from Phoenix.ConnTest and from Phoenix.LiveViewTest to simulate a user clicking around and therefore can't test any Javascript functionality. To fix this, a driver for browser-based testing via Wallaby or Playwright Elixir would be needed, but one does not yet exist. The upside is that Pages-based tests are extremely fast.