Fluffy (Fluffy v0.5.2)

Copy Markdown View Source

Pipeable feature testing for Phoenix applications.

Start a session with the Phoenix (:phoenix) or Playwright (:playwright) backend, then compose locators, actions, expectations, and event capture. Import Fluffy.Expect for expectations, or use Fluffy.Assert for ExUnit-style assertions. The Phoenix backend selects its Static (Phoenix.ConnTest) or LiveView (Phoenix.LiveViewTest) driver for each page; the Playwright backend uses the Playwright driver.

Unless a function documents additional entries, action, assertion, reload, and event-wait option lists accept:

  • :timeout (non_neg_integer/0) - Maximum time in milliseconds to wait for the operation. Playwright browser bookkeeping and navigation synchronization use the session timeout separately.

Summary

Lifecycle and navigation

Closes a named Playwright page, or the active page when no name is supplied.

Closes a session and its resources. Returns :ok or {:error, reason}.

Navigates backward in browser history. Does nothing if there is no entry.

Navigates forward in browser history. Does nothing if there is no entry.

Creates and activates a named blank page in the session's browser context.

Returns all current session-local page names.

Reloads the active page's current document and returns the updated session.

Starts an isolated :phoenix or :playwright session.

Makes a named Playwright page the target of subsequent actions and assertions.

Actions

Drags the source locator onto the target locator in the same frame. Requires Playwright.

Hovers over a locator. Requires Playwright.

Presses Enter, Space, or Tab on one strict target.

Types text character by character, emitting keyboard events. Accepts :delay in milliseconds. Requires Playwright.

Selects local paths or in-memory Fluffy.FilePayload values for a file input, or clears its FileList with [].

Submits one form through its native submission path.

Event capture and results

Returns a previously captured dialog without consuming it.

Returns a previously captured download without consuming it.

Returns a previously captured file chooser without consuming it.

Returns a previously captured navigation without consuming it.

Returns a previously captured Fluffy.Page without consuming it.

Returns a previously captured request without consuming it.

Returns a previously captured response without consuming it.

Captures an event caused by action and stores the normalized result under the event's key.

Diagnostics and native access

Groups the operations in fun under a named diagnostic step.

Runs a driver-specific native operation and returns the reconciled session.

Lifecycle and navigation

close_page(session, name \\ nil)

(Playwright only)

Closes a named Playwright page, or the active page when no name is supplied.

When closing the active page, the returned session targets its opener if that page is still open. Otherwise, it targets another remaining page; the selection order is unspecified. Page switching history is not tracked. Closing an inactive page leaves the active page unchanged.

Closing a page does not close pages it opened. Raises ArgumentError when attempting to close the last page in the session.

Raises Fluffy.CapabilityError with the Phoenix backend.

close_session(session)

Closes a session and its resources. Returns :ok or {:error, reason}.

go_back(session, options \\ [])

(Playwright only)

Navigates backward in browser history. Does nothing if there is no entry.

go_forward(session, options \\ [])

(Playwright only)

Navigates forward in browser history. Does nothing if there is no entry.

new_page(session, name)

(Playwright only)

Creates and activates a named blank page in the session's browser context.

page_names(session)

Returns all current session-local page names.

reload(session, options \\ [])

@spec reload(Fluffy.Session.t(), [action_option()]) :: Fluffy.Session.t()

Reloads the active page's current document and returns the updated session.

The Phoenix backend re-dispatches the current URL and selects the Static or LiveView driver for the returned page. The Playwright backend asks the active browser page to reload.

start_session(backend, options \\ [])

@spec start_session(backend(), [session_option()]) :: Fluffy.Session.t()

Starts an isolated :phoenix or :playwright session.

Configure the application endpoint once with config :fluffy, endpoint: MyAppWeb.Endpoint. The session base URL uses the endpoint's active HTTP or HTTPS listener when available and otherwise falls back to MyAppWeb.Endpoint.url(). An explicit :endpoint or :base_url option overrides the application configuration for this session.

Options

switch_page(session, name)

(Playwright only)

Makes a named Playwright page the target of subsequent actions and assertions.

Raises Fluffy.CapabilityError with the Phoenix backend.

visit(session, path)

Actions

blur(session, locator, options \\ [])

check(session, locator, options \\ [])

click(session, locator, options \\ [])

drag_to(session, source, target, options \\ [])

(Playwright only)

Drags the source locator onto the target locator in the same frame. Requires Playwright.

fill(session, locator, value, options \\ [])

focus(session, locator, options \\ [])

hover(session, locator, options \\ [])

(Playwright only)

Hovers over a locator. Requires Playwright.

press(session, locator, key, options \\ [])

Presses Enter, Space, or Tab on one strict target.

On a LiveView page, direct or window phx-keydown/phx-keyup bindings and phx-key filters are dispatched with their browser-shaped key and current value payload before and around the supported structural default action. Plain event names and push-only Phoenix.LiveView.JS bindings are portable; client-side JS commands, custom LiveSocket metadata, modifiers, key repeat, and timing assertions require Playwright.

press(locator, "Enter") means the browser's implicit Enter behavior. Use submit/2 when the intent is simply to submit a form.

press_sequentially(session, locator, text, options \\ [])

(Playwright only)

Types text character by character, emitting keyboard events. Accepts :delay in milliseconds. Requires Playwright.

select_option(session, locator, requested, options \\ [])

@spec select_option(Fluffy.Session.t(), Fluffy.Locator.t(), term(), [action_option()]) ::
  Fluffy.Session.t()

set_input_files(session, locator_or_chooser, selection, options \\ [])

Selects local paths or in-memory Fluffy.FilePayload values for a file input, or clears its FileList with [].

One path or payload selects one file. A non-empty homogeneous list selects files in list order on an input with the multiple attribute. [] clears the current selection. The complete value is validated and snapshotted before the page changes. Static and LiveView drivers carry those snapshots into form submission or the supported managed-upload lifecycle; Playwright uses its native path or payload transport.

The default aggregate selection limit is configured with config :fluffy, file_input_max_bytes: 10_000_000. Override it for one action with :max_bytes. File contents are never included in size or validation errors.

When locator_or_chooser is an atom, it names a chooser previously captured with Fluffy.Event.file_chooser/2. Chooser-key selection is available only in Playwright sessions.

Options

  • :timeout (non_neg_integer/0) - Maximum time in milliseconds to wait for the operation. Playwright browser bookkeeping and navigation synchronization use the session timeout separately.

  • :max_bytes (non_neg_integer/0) - Maximum aggregate size of the selected files in bytes.

submit(session, locator, options \\ [])

Submits one form through its native submission path.

This is a semantic form action, not a synthetic keyboard event. Clicking a particular submit button remains the way to select a submitter and its name/value or override attributes.

Playwright follows browser-native constraint validation. Static and LiveView deliberately bypass it and submit the current structural form state; use Playwright when the test concerns invalid events, validity UI, focus, or browser-blocked submission.

uncheck(session, locator, options \\ [])

Event capture and results

dialog(session, key)

(Playwright only)

Returns a previously captured dialog without consuming it.

download(session, key)

Returns a previously captured download without consuming it.

file_chooser(session, key)

(Playwright only)

Returns a previously captured file chooser without consuming it.

page(session, name)

(Playwright only)
@spec page(Fluffy.Session.t(), term()) :: Fluffy.Page.t()

Returns a previously captured Fluffy.Page without consuming it.

request(session, key)

(Playwright only)

Returns a previously captured request without consuming it.

response(session, key)

(Playwright only)

Returns a previously captured response without consuming it.

wait_for(session, event, action, options \\ [])

Captures an event caused by action and stores the normalized result under the event's key.

The listener is installed before the action runs. The capture timeout starts when arming; events arriving after it expires are ignored. The returned session keeps the captured result so the call remains pipeable.

Diagnostics and native access

step(session, name, fun)

(macro)

Groups the operations in fun under a named diagnostic step.

Playwright sessions with tracing enabled record a nested trace group at the call site's source location. Phoenix sessions and untraced Playwright sessions simply run the callback. The callback must return the updated session, which is also returned by step/3.

unwrap(session, fun)

Runs a driver-specific native operation and returns the reconciled session.

Static callbacks receive the current Plug.Conn and must return an updated Plug.Conn. LiveView callbacks receive the current Phoenix.LiveViewTest.View, and Playwright callbacks receive a Fluffy.Playwright.Handle. Successful LiveView and Playwright callback return values are ignored.

Native operations are not cross-driver compatible. Prefer the shared Fluffy API whenever it covers the behavior under test.

Types

action_option()

@type action_option() :: {:timeout, non_neg_integer()}

backend()

@type backend() :: :phoenix | :playwright

file_input_option()

@type file_input_option() ::
  {:timeout, non_neg_integer()} | {:max_bytes, non_neg_integer()}

session_option()

@type session_option() ::
  {:endpoint, atom()}
  | {:base_url, binary()}
  | {:headers, [{atom() | binary(), binary()}]}
  | {:conn, struct()}
  | {:timeout, pos_integer()}
  | {:browser_context, keyword()}