defmodule Excessibility do import Phoenix.ConnTest, only: [html_response: 2] alias Plug.Conn use Wallaby.DSL alias Wallaby.Session @output_path Application.compile_env( :excessibility, :excessibility_output_path, "test/excessibility" ) @snapshots_path "#{@output_path}/html_snapshots" @moduledoc """ Documentation for `Excessibility`. """ @doc """ Using the Excessibility macro will require the file for you. ## Examples use Excessibility """ defmacro __using__(_opts) do quote do require Excessibility end end @doc """ The here function is the meat of the package. Calling htis macro will produce an HTML snapshot of any conn or Wallaby session that you pass to it. These can be used later to run pa11y against..It will return the conn or session that was passed in so that you can include it in a pipeline. ## Examples iex> Excessibility.html_snapshot(conn_or_session) conn_or_session """ defmacro html_snapshot(conn_or_session) do quote do Excessibility.html_snapshot(unquote(conn_or_session), __ENV__, __MODULE__) end end def html_snapshot(conn_or_session, env, module) do filename = get_filename(env, module) get_html(conn_or_session) |> write_html(filename) conn_or_session end defp get_html(%Element{} = _conn_or_session) do raise ArgumentError, message: ~s""" html_snapshot/1 cannot be called with an %Element{} Instead you can try something like: find(element, fn el -> el |> click_the_thing() |> assert_the_stuff() end) |> Excessibility.html_snapshot() """ end defp get_html(%Conn{} = conn) do html_response(conn, 200) |> Floki.parse_document!() |> Floki.raw_html(pretty: true) end defp get_html(%Session{} = session) do Wallaby.Browser.page_source(session) end defp write_html(html, filename) do html = html |> relativize_asset_paths() File.mkdir_p("#{@snapshots_path}") Path.join([File.cwd!(), "#{@snapshots_path}", filename]) |> File.write(html, [:write]) end defp get_filename(env, module) do "#{module |> get_module_name()}_#{env.line}.html" |> String.replace(" ", "_") end defp get_module_name(module) do module |> Atom.to_string() |> String.downcase() |> String.splitter(".") |> Enum.take(-1) end defp relativize_asset_paths(html) do html |> String.replace("\"/assets/js/", "\"./assets/js/") |> String.replace("\"/assets/css/", "\"./assets/css/") end end