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