LiveLoad.Scenario.Context (LiveLoad v0.0.1-rc.27)

Copy Markdown View Source

A context struct that is given to every LiveLoad.Scenario.run/3 callback while running a LiveLoad.Scenario. It wraps the LiveLoad.Browser.Context details for the runner and provides a simple API for interacting with the browser.

This module's API is based on Plug.Conn, using the following patterns:

  • A scenario that is :halted? at any point in the scenario will short-circuit and not run any other functions.
  • A scenario that has an :error at any point in the scenario will short-circuit and not run any other functions.
  • Values can be extracted from the page through the available functions and assigned onto the context for future use in the pipeline.

Scenario Context Lifecycle

A LiveLoad.Scenario.Context is created once per user process at the start of the load test, before the scenario's LiveLoad.Scenario.run/3 callback is called for the first time. It wraps the LiveLoad.Browser.Context that was created for that user, and is then passed into LiveLoad.Scenario.run/3 as the first argument on every iteration of the scenario.

The same context is reused across all iterations of a scenario for a given user. This means that any assigns set during one iteration will still be present on the context at the start of the next iteration. If you want to start each iteration with a clean set of assigns, you can call reset_assigns/1 at the start of your LiveLoad.Scenario.run/3 callback.

Halting and Errors

Halting and errors are mutually exclusive:

  • A scenario can be halted by calling the halt/1 function in order to mark the scenario as halted.
  • A scenario will be marked with an error whenever any error, exception, or exit occurs while an operation is running.

The reason for this mutual exclusivity is to preserve the reason for a scenario not completing. Errors are unexpected occurences that may happen for any number of reasons and are marked as such to ensure that any consumers of LiveLoad are able to understand what errors are happening in their application while load testing their sites. However, halting is manually marked and is a decision by the writer of the scenario. Halting can be used to simply short-circuit a scenario should the writer decide that it can be short-circuited at any point during the scenario's run.

As such, when calling halt/1, a scenario will only be marked has halted if no error has occured in the pipeline in order to preserve the reason for the scenario not completing.

Two helper functions, halted?/1 and failed?/1 are provided in order to determine if a scenario failed or was halted manually.

A LiveLoad.Scenario.Context which is halted? or failed? will stop the LiveLoad.Scenario from iterating any further, and no more iterations will occur for this user's process.

Assigns

All functions exposed on the API accept both a raw value and a 1-arity function so that you can get values from the context and its assigns.

For example, if you simple need to click on a button with a specific hard-coded ID, you might write something like this:

click(context, "#submit")

However, if the button may have a dynamic ID, you can pass in a 1-arity function and build the ID based on the assigns:

click(context, &"##{&1.assigns.button_id}")

Summary

Types

A key passed in to the :as option when using functions that extract values from the context.

One of the loading class types that Phoenix adds to elements when events are in-flight on the Phoenix.LiveView.Socket.

A resolvable variable given to operations on the LiveLoad.Scenario.Context.

t()

Functions

Assigns a value to a key in the context.

Blurs an element that matches the given selector on the current page.

Checks a checkbox or radio button element that matches the given selector on the current page.

Extracts whether or not a checkbox or radio button element matching the given selector is checked and assigns it to the :as option on the context's assigns.

Clears an input element that matches the given selector on the current page.

Clears a specific assign on the context.

Clicks an element that matches the given selector on the current page.

Gets a snapshot of the current storage state of the browser context.

Drags from the source element matching the given selector to the target element matching the given selector.

Detects whether or not the current page is a LiveView.

Marks a LiveLoad.Scenario as failed and prevents the scenario from doing any further operations on the context.

Checks to see if the LiveLoad.Scenario.Context failed to complete.

Fills an input element that matches the given selector on the current page with the given value.

Focuses an element that matches the given selector on the current page.

Extracts the element attribute value for an element matching the given selector and assigns it to the :as option on the context's assigns.

Halts a LiveLoad.Scenario by preventing any further operations to take place on the context.

Checks to see if the LiveLoad.Scenario.Context was halted.

Hovers over an element that matches the given selector on the current page.

Extracts the innerHTML value of an element matching the given selector and assigns it to the :as option on the context's assigns.

Extracts the innerText value of an element matching the given selector and assigns it to the :as option on the context's assigns.

Extracts the value of an input, textarea, or select element matching the given selector and assigns it to the :as option on the context's assigns.

Navigates to the given URL.

Extracts the current page's content and assigns it to the :as option on the context's assigns.

Focuses an element that matches the given selector on the current page and activates the given key.

Reloads the current page.

Resets all of the assigns on the context.

Resets the storage state of the current browser context to an empty state.

Restores the storage state of the browser context from a previously stored snapshot.

Selects multiple options on a select element that matches the given selector on the current page.

Selects an option on a select element that matches the given selector on the current page.

Submits a LiveView form by clicking its submit button. Waits for the form to no longer have the phx-submit-loading class applied.

Extracts the textContent value of an element matching the given selector and assigns it to the :as option on the context's assigns.

Unchecks a checkbox or radio button element that matches the given selector on the current page.

Updates a value under a specified key in the context.

Extracts whether or not an element matching the given selector is visible and assigns it to the :as option on the context's assigns.

Waits for a LiveView to be fully connected.

Waits for a phx-*-loading attribute to be removed from an element. Useful for waiting for LiveView event handling to complete.

Waits for an element that matches the given selector to appear on the current page.

Types

assigned_as()

@type assigned_as() ::
  atom() | (term() -> atom()) | (term() -> %{required(atom()) => term()})

A key passed in to the :as option when using functions that extract values from the context.

Values that are extracted can be specified to be assigned to the context's assigns via the :as option, which can receive an atom/0, or a 1-arity function which may return either an atom/0 or a map/0 of atom/0 keys to values which will be merged onto the context's assigns.

phoenix_loading_type()

@type phoenix_loading_type() ::
  :click | :submit | :change | :focus | :blur | :keydown | :keyup

One of the loading class types that Phoenix adds to elements when events are in-flight on the Phoenix.LiveView.Socket.

resolvable(value)

@type resolvable(value) :: value | (t() -> value)

A resolvable variable given to operations on the LiveLoad.Scenario.Context.

Can either be a value, or a 1-arity function that receives a LiveLoad.Scenario.Context and returns a value.

t()

@type t() :: %LiveLoad.Scenario.Context{
  assigns: %{optional(atom()) => term()},
  browser_context: LiveLoad.Browser.Context.t(),
  error: LiveLoad.Scenario.Error.t() | nil,
  halted?: boolean(),
  step: non_neg_integer()
}

Functions

assign(context, key, value)

@spec assign(context :: t(), key :: atom(), value :: term()) :: t()

Assigns a value to a key in the context.

The assigns storage is meant to be used to store values in the connection so that other operations in your scenario's pipeline can access them. The assigns storage is a map.

blur(ctx, selector)

@spec blur(context :: t(), selector :: resolvable(String.t())) :: t()

Blurs an element that matches the given selector on the current page.

check(ctx, selector)

@spec check(context :: t(), selector :: resolvable(String.t())) :: t()

Checks a checkbox or radio button element that matches the given selector on the current page.

checked?(ctx, selector, opts \\ [])

@spec checked?(context :: t(), selector :: String.t(), opts :: [{:as, assigned_as()}]) ::
  t()

Extracts whether or not a checkbox or radio button element matching the given selector is checked and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

clear(ctx, selector)

@spec clear(context :: t(), selector :: resolvable(String.t())) :: t()

Clears an input element that matches the given selector on the current page.

clear_assign(context, key)

@spec clear_assign(context :: t(), key :: atom()) :: t()

Clears a specific assign on the context.

After clearing this key will no longer be available and assertive access will cause an exception.

See assign/3 for information about the assigns storage.

click(ctx, selector)

@spec click(context :: t(), selector :: resolvable(String.t())) :: t()

Clicks an element that matches the given selector on the current page.

context_storage_snapshot(ctx, opts \\ [])

@spec context_storage_snapshot(context :: t(), opts :: [{:as, assigned_as()}]) :: t()

Gets a snapshot of the current storage state of the browser context.

This is a serializable storage snapshot that contains the current browser context's cookies, local storage, and session storage.

This type is intentionally left as an ambiguous term, as it is meant to be usable as a storage and restoration mechanism, however it is not guaranteed to be uniform across different browser connections.

Options

  • :as - an atom key to place the storage snapshot under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

drag_and_drop(ctx, source, target)

@spec drag_and_drop(
  context :: t(),
  source :: resolvable(String.t()),
  target :: resolvable(String.t())
) ::
  t()

Drags from the source element matching the given selector to the target element matching the given selector.

ensure_liveview(ctx)

@spec ensure_liveview(context :: t()) :: t()

Detects whether or not the current page is a LiveView.

fail(ctx, reason)

@spec fail(context :: t(), reason :: term()) :: t()

Marks a LiveLoad.Scenario as failed and prevents the scenario from doing any further operations on the context.

If the scenario has already had an error, this results in a No-Op in order to preserve the error.

failed?(context)

(macro)

Checks to see if the LiveLoad.Scenario.Context failed to complete.

Failure occurs when an error occurs while the LiveLoad.Scenario is running.

Allowed in guard tests.

fill(ctx, selector, value)

@spec fill(
  context :: t(),
  selector :: resolvable(String.t()),
  value :: resolvable(String.t())
) :: t()

Fills an input element that matches the given selector on the current page with the given value.

Passing an empty string as the value will clear the input's value.

focus(ctx, selector)

@spec focus(context :: t(), selector :: resolvable(String.t())) :: t()

Focuses an element that matches the given selector on the current page.

get_attribute(ctx, selector, name, opts \\ [])

@spec get_attribute(
  context :: t(),
  selector :: String.t(),
  name :: String.t(),
  opts :: [{:as, assigned_as()}]
) :: t()

Extracts the element attribute value for an element matching the given selector and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

halt(ctx)

@spec halt(context :: t()) :: t()

Halts a LiveLoad.Scenario by preventing any further operations to take place on the context.

If the scenario has already had an error, this results in a No-Op and the context will not be marked as halted in order to preserve the error.

halted?(context)

(macro)

Checks to see if the LiveLoad.Scenario.Context was halted.

Halting occurs when the halt/1 function is called on the context directly.

Allowed in guard tests.

hover(ctx, selector)

@spec hover(context :: t(), selector :: resolvable(String.t())) :: t()

Hovers over an element that matches the given selector on the current page.

inner_html(ctx, selector, opts \\ [])

@spec inner_html(
  context :: t(),
  selector :: String.t(),
  opts :: [{:as, assigned_as()}]
) :: t()

Extracts the innerHTML value of an element matching the given selector and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

inner_text(ctx, selector, opts \\ [])

@spec inner_text(
  context :: t(),
  selector :: String.t(),
  opts :: [{:as, assigned_as()}]
) :: t()

Extracts the innerText value of an element matching the given selector and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

input_value(ctx, selector, opts \\ [])

@spec input_value(
  context :: t(),
  selector :: String.t(),
  opts :: [{:as, assigned_as()}]
) :: t()

Extracts the value of an input, textarea, or select element matching the given selector and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

page_content(ctx, opts \\ [])

@spec page_content(context :: t(), opts :: [{:as, assigned_as()}]) :: t()

Extracts the current page's content and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

press(ctx, selector, key)

@spec press(
  context :: t(),
  selector :: resolvable(String.t()),
  key :: resolvable(String.t())
) :: t()

Focuses an element that matches the given selector on the current page and activates the given key.

reload(ctx)

@spec reload(context :: t()) :: t()

Reloads the current page.

reset_assigns(context)

@spec reset_assigns(context :: t()) :: t()

Resets all of the assigns on the context.

During a LiveLoad.Scenario, the scenario will loop and run many iterations per user process. The LiveLoad.Scenario.Context is maintained across the loops, so that you can use assigns from a previous loop in order to take new actions on the previous data.

See assign/3 for information about the assigns storage.

reset_context_storage(ctx)

@spec reset_context_storage(context :: t()) :: t()

Resets the storage state of the current browser context to an empty state.

This will clear all cookies, local storage and session storage of the browser context.

restore_context_storage(ctx, snapshot)

@spec restore_context_storage(context :: t(), snapshot :: resolvable(term())) :: t()

Restores the storage state of the browser context from a previously stored snapshot.

select_multiple_options(ctx, selector, values)

@spec select_multiple_options(
  context :: t(),
  selector :: resolvable(String.t()),
  values :: resolvable([String.t()])
) :: t()

Selects multiple options on a select element that matches the given selector on the current page.

select_option(ctx, selector, value)

@spec select_option(
  context :: t(),
  selector :: resolvable(String.t()),
  value :: resolvable(String.t())
) ::
  t()

Selects an option on a select element that matches the given selector on the current page.

submit_form(ctx, form_selector)

@spec submit_form(context :: t(), form_selector :: resolvable(String.t())) :: t()

Submits a LiveView form by clicking its submit button. Waits for the form to no longer have the phx-submit-loading class applied.

text_content(ctx, selector, opts \\ [])

@spec text_content(
  context :: t(),
  selector :: String.t(),
  opts :: [{:as, assigned_as()}]
) :: t()

Extracts the textContent value of an element matching the given selector and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

uncheck(ctx, selector)

@spec uncheck(context :: t(), selector :: resolvable(String.t())) :: t()

Unchecks a checkbox or radio button element that matches the given selector on the current page.

update_assign!(context, key, update_fn)

@spec update_assign!(context :: t(), key :: atom(), (term() -> term())) :: t()

Updates a value under a specified key in the context.

Raises a KeyError exception if the specified key does not exist on the assigns.

See assign/3 for information about the assigns storage.

visible?(ctx, selector, opts \\ [])

@spec visible?(context :: t(), selector :: String.t(), opts :: [{:as, assigned_as()}]) ::
  t()

Extracts whether or not an element matching the given selector is visible and assigns it to the :as option on the context's assigns.

Options

  • :as - an atom key to place the page content under on the context's assigns. Alternatively, you can pass a 1-arity function which will be run with the returned value. The function must return either an atom, which will be used as the key, or a map of new assigns values that will be merged into the current assigns on the context.

wait_for_liveview(ctx)

@spec wait_for_liveview(context :: t()) :: t()

Waits for a LiveView to be fully connected.

wait_for_phx_loading_completion(ctx, type, selector)

@spec wait_for_phx_loading_completion(
  context :: t(),
  type :: phoenix_loading_type(),
  selector :: resolvable(String.t())
) :: t()

Waits for a phx-*-loading attribute to be removed from an element. Useful for waiting for LiveView event handling to complete.

wait_for_selector(ctx, selector)

@spec wait_for_selector(context :: t(), selector :: resolvable(String.t())) :: t()

Waits for an element that matches the given selector to appear on the current page.