phoenix_integration v0.2.0 PhoenixIntegration.Requests

A set of functions intended to compliment the regular Phoenix.ConnTest utilities of get, post, put, patch, and delete.

Each request function takes a conn and a set of data telling it what to do. Then it requests one or more paths from your phoenix application, transforming the conn each time. The final conn is returned.

All the functions except follow_path and follow_redirect examine the html conntent of the incoming conn to find a link or form to use. In this way, you can both confirm that content exists in rendered pages and take actions as the user would.

This is intended to be used as a (possibly long) chain of piped functions that exercises a set of functionality in your application.

Examples

test "Basic page flow", %{conn: conn} do
  # get the root index page
  get( conn, page_path(conn, :index) )
  # click/follow through the various about pages
  |> follow_link( "About Us" )
  |> follow_link( "Contact" )
  |> follow_link( "Privacy" )
  |> follow_link( "Terms of Service" )
  |> follow_link( "Home" )
  |> assert_response( status: 200, path: page_path(conn, :index) )
end

test "Create new user", %{conn: conn} do
  # get the root index page
  get( conn, page_path(conn, :index) )
  # create the new user
  |> follow_link( "Sign Up" )
  |> follow_form( %{ user: %{
        name: "New User",
        email: "user@example.com",
        password: "test.password",
        confirm_password: "test.password"
      }} )
  |> assert_response(
      status: 200,
      path: page_path(conn, :index),
      html: "New User" )
end

Summary

Functions

Finds a link in conn.resp_body, requests it as if the user had clicked on it, and returns the resulting conn

Calls a function and follows the any redirects in the returned conn. If the function returns anything other than a conn, then the result is ignored and follow_fn will simply return the original conn

Finds a form in conn.resp_body, fills out the fields with the given data, requests the form’s action, follows any redirects and returns the resulting conn

Finds a link in conn.resp_body, requests it as if the user had clicked on it, follows any redirects, and returns the resulting conn

Similar to a standard get/post/put/patch/delete call in a ConnTest except that follow_path follows any redirects returned in the conn’s response header

Given a conn who’s response is a redirect, follow_redirect calls the path indicated by the “location” response header and returns the conn from that call

Finds a form in conn.resp_body, fills out the fields with the given data, requests the form’s action and returns the resulting conn

Functions

click_link(conn, identifer, opts \\ %{})

Finds a link in conn.resp_body, requests it as if the user had clicked on it, and returns the resulting conn.

Parameters

  • conn should be a conn returned from a previous request that rendered some html. The functions are designed to pass the conn from one call into the next via pipes.
  • identifier indicates which link to find in the html. Valid values can be in the following forms:

    • "/some/path" specify the link’s href starting with a "/" character
    • "http://www.example.com/some/uri", specify the href as full uri starting with either "http" or "https"
    • "#element-id" specify the html element id of the link you are looking for. Must start start with the "#" character (same as css id specifier).
    • "Some Text" specify text contained within the link you are looking for.
  • opts A map of additional options

    • :method - method to use when requesting the path. Defaults to "get";

click_link does not follow any redirects returned by the request. This allows you to explicitly check that the redirect is correct. Use follow_redirect to request the location redirected to, or just use follow_link to do it in one call.

If the link is not found in the body, click_link raises an error.

Examples:

# click a link specified by path or uri
get( conn, thing_path(conn, :index) )
|> click_link( page_path(conn, :index) )

# click a link specified by html id with a non-get method
get( conn, thing_path(conn, :index) )
|> click_link( "#link-id", method: :delete )

# click a link containing the given text
get( conn, thing_path(conn, :index) )
|> click_link( "Settings" )

# test a redirect and continue
get( conn, thing_path(conn, :index) )
|> click_link( "something that redirects to new" )
|> assert_response( status: 302, to: think_path(conn, :new) )
|> follow_redirect()
|> assert_response( status: 200, path: think_path(conn, :new) )

Links that don’t use the :get method

When Phoneix.Html renders a link, it usually generates an <a> tag. However, if you specify a method other than :get, then Phoenix generates html looks like a link, but is really a form using the method. This is why you must specify the method used in opts if you used anything other than the standard :get in your link.

# follow a non-get link
click_link( conn, thing_path(conn, :delete), method: :delete )
follow_fn(conn, func, opts \\ %{})

Calls a function and follows the any redirects in the returned conn. If the function returns anything other than a conn, then the result is ignored and follow_fn will simply return the original conn

This gives a way to insert custom assertions, or other setup code without breaking the piped chain of functions.

Parameters

  • conn A conn that has been set up to work in the test environment. Could be the conn originally passed in to the test;
  • func a function in the form of fn(conn) -> end;
  • opts A map of additional options

    • :max_redirects - Maximum number of redirects to follow. Defaults to 5;

Example:

follow_fn( conn, fn(c) ->
    "/some_path/" <> token = c.request_path
    assert token == "valid_token"
  end)
follow_form(conn, fields, opts \\ %{})

Finds a form in conn.resp_body, fills out the fields with the given data, requests the form’s action, follows any redirects and returns the resulting conn.

Similar to submit_form, except that it does follow redirects.

Parameters

  • conn should be a conn returned from a previous request that rendered some html. The functions are designed to pass the conn from one call into the next via pipes.
  • fields a map of fields and data to be written into the form before submitting it’s action.
  • opts A map of additional options

    • identifier indicates which link to find in the html. Defaults to nil. Valid values can be in the following forms:

      • "/some/path" specify the link’s href starting with a "/" character
      • "http://www.example.com/some/uri", specify the href as full uri starting with either "http" or "https"
      • "#element-id" specify the html element id of the link you are looking for. Must start start with the "#" character (same as css id specifier).
      • "Some Text" specify text contained within the link you are looking for.
    • :method - restricts the forms searched to those whose action uses the given method (such as “post” or “put”). Defaults to nil;
    • :finder - finding string passed to Floki.find. Defaults to "form"

If no opts.identifier is specified, the first form that makes sense is used. Unless you have multiple forms on your page, this often is the most understandable pattern.

If no appropriate form is found, follow_form raises an error.

Example:

  # fill out a form and submit it
  get( conn, thing_path(conn, :edit, thing) )
  |> follow_form( %{ thing: %{
      name: "Updated Name",
      some_count: 42
    }})
  |> assert_response( status: 200, path: thing_path(conn, :show, thing) )
follow_link(conn, indentifer, opts \\ %{})

Finds a link in conn.resp_body, requests it as if the user had clicked on it, follows any redirects, and returns the resulting conn.

Parameters

  • conn should be a conn returned from a previous request that rendered some html. The functions are designed to pass the conn from one call into the next via pipes.
  • identifier indicates which link to find in the html. Valid values can be in the following forms:

    • "/some/path" specify the link’s href starting with a "/" character
    • "http://www.example.com/some/uri", specify the href as full uri starting with either "http" or "https"
    • "#element-id" specify the html element id of the link you are looking for. Must start start with the "#" character (same as css id specifier).
    • "Some Text" specify text contained within the link you are looking for.
  • opts A map of additional options

    • :method - method to use when requesting the path. Defaults to "get";
    • :max_redirects - Maximum number of redirects to follow. Defaults to 5;

This is similar to click_link, except that it follows returned redirects. This is very useful during integration tests as you typically want to emulate what the user is really doing. You will probably use follow_link more than click_link.

If the link is not found in the body, follow_link raises an error.

Example:

  # click through several pages that should point to each other
  get( conn, thing_path(conn, :index) )
  |> follow_link( "#settings" )
  |> follow_link( "Cancel" )
  |> assert_response( path: thing_path(conn, :index) )

Links that don’t use the :get method

When Phoneix.Html renders a link, it usually generates an <a> tag. However, if you specify a method other than :get, then Phoenix generates html looks like a link, but is really a form using the method. This is why you must specify the method used in opts if you used anything other than the standard :get in your link.

# follow a non-get link
follow_link( conn, thing_path(conn, :delete), method: :delete )
follow_path(conn, path, opts \\ %{})

Similar to a standard get/post/put/patch/delete call in a ConnTest except that follow_path follows any redirects returned in the conn’s response header.

Unlike the rest of the functions in this module, follow_path ignores the conn.resp_body and simply uses the given path.

Parameters

  • conn A conn that has been set up to work in the test environment. Could be the conn originally passed in to the test;
  • path A path that works with your router;
  • opts A map of additional options

    • :method - method to use when requesting the path. Defaults to "get";
    • :max_redirects - Maximum number of redirects to follow. Defaults to 5;

Example:

follow_path( conn, thing_path(conn, :index) )
|> assert_response( status: 200, path: think_path(conn, :index) )
follow_redirect(conn, max_redirects \\ 5)

Given a conn who’s response is a redirect, follow_redirect calls the path indicated by the “location” response header and returns the conn from that call.

Parameters

  • conn A conn whose status 302, which is a redirect. The conn’s location header should point to the path being redirected to.
  • max_redirects The maximum number of recirects to follow. Defaults to 5;

Any incoming conn.status other than 302 causes follow_redirect to take no action and return the incoming conn for further processing.

submit_form(conn, fields, opts \\ %{})

Finds a form in conn.resp_body, fills out the fields with the given data, requests the form’s action and returns the resulting conn.

Parameters

  • conn should be a conn returned from a previous request that rendered some html. The functions are designed to pass the conn from one call into the next via pipes.
  • fields a map of fields and data to be written into the form before submitting it’s action.
  • opts A map of additional options

    • identifier indicates which link to find in the html. Defaults to nil. Valid values can be in the following forms:

      • "/some/path" specify the link’s href starting with a "/" character
      • "http://www.example.com/some/uri", specify the href as full uri starting with either "http" or "https"
      • "#element-id" specify the html element id of the link you are looking for. Must start start with the "#" character (same as css id specifier).
      • "Some Text" specify text contained within the link you are looking for.
    • :method - restricts the forms searched to those whose action uses the given method (such as “post” or “put”). Defaults to nil;
    • :finder - finding string passed to Floki.find. Defaults to "form"

If no opts.identifier is specified, the first form that makes sense is used. Unless you have multiple forms on your page, this often is the most understandable pattern.

If no appropriate form is found, submit_form raises an error.

Any redirects are not followed.

Example:

  # fill out a form and submit it
  get( conn, thing_path(conn, :edit, thing) )
  |> submit_form( %{ thing: %{
      name: "Updated Name",
      some_count: 42
    }})
  |> assert_response( status: 302, to: thing_path(conn, :show, thing) )