View Source ExUnit.Formatter (ExUnit v1.16.2)

Helper functions for formatting and the formatting protocols.

Formatters are GenServers specified during ExUnit configuration that receive a series of events as casts.

The following events are possible:

  • {:suite_started, opts} - the suite has started with the specified options to the runner.

  • {:suite_finished, times_us} - the suite has finished. Returns several measurements in microseconds for running the suite. See t:times_us for more information.

  • {:module_started, test_module} - a test module has started. See ExUnit.TestModule for details.

  • {:module_finished, test_module} - a test module has finished. See ExUnit.TestModule for details.

  • {:test_started, test} - a test has started. See ExUnit.Test for details.

  • {:test_finished, test} - a test has finished. See ExUnit.Test for details.

  • {:sigquit, [test | test_module]} - the VM is going to shutdown. It receives the test cases (or test module in case of setup_all) still running.

The formatter will also receive the following events but they are deprecated and should be ignored:

  • {:case_started, test_module} - a test module has started. See ExUnit.TestModule for details.

  • {:case_finished, test_module} - a test module has finished. See ExUnit.TestModule for details.

The full ExUnit configuration is passed as the argument to GenServer.init/1 callback when the formatters are started. If you need to do runtime configuration of a formatter, you can add any configuration needed by using ExUnit.configure/1 or ExUnit.start/1, and this will then be included in the options passed to the GenServer.init/1 callback.

Summary

Types

A function that this module calls to format various things.

Key passed to a formatter callback to format a diff.

Key passed to a formatter callback to format information.

The times spent on several parts of the test suite.

Width for formatting.

Functions

Formats filters used to constrain cases to be run.

Receives a test module and formats its failure.

Receives a test and formats its failures.

Formats time taken running the test suite.

Types

Link to this type

formatter_callback()

View Source (since 1.16.0)
@type formatter_callback() ::
  (:diff_enabled?, boolean() -> boolean())
  | (formatter_callback_diff_key(), Inspect.Algebra.t() -> Inspect.Algebra.t())
  | (formatter_callback_info_key(), String.t() -> String.t())

A function that this module calls to format various things.

You can pass this functions to various functions in this module, and use it to customize the formatting of the output. For example, ExUnit's CLI formatter uses this callback to colorize output.

Keys

The possible keys are:

  • :diff_enabled? - whether diffing is enabled. It receives a boolean indicating whether diffing is enabled by default and returns a boolean indicating whether diffing should be enabled for the current test.

  • :diff_delete and :diff_delete_whitespace - Should format a diff deletion, with or without whitespace respectively.

  • :diff_insert and :diff_insert_whitespace - Should format a diff insertion, with or without whitespace respectively.

  • :extra_info - Should format extra information, such as the "code: " label that precedes code to show.

  • :error_info - Should format error information.

  • :test_module_info - Should format test module information. The message returned when this key is passed precedes messages such as "failure on setup_all callback [...]".

  • :test_info - Should format test information.

  • :location_info - Should format test location information.

  • :stacktrace_info - Should format stacktrace information.

  • :blame_diff - Should format a string of code.

Examples

For example, to format errors as red strings and everything else as is, you could define a formatter callback function like this:

formatter_callback = fn
  :error_info, msg -> [:red, msg, :reset] |> IO.ANSI.format() |> IO.iodata_to_binary()
  _key, value -> value
end
Link to this type

formatter_callback_diff_key()

View Source (since 1.16.0)
@type formatter_callback_diff_key() ::
  :diff_delete
  | :diff_delete_whitespace
  | :diff_insert
  | :diff_insert_whitespace

Key passed to a formatter callback to format a diff.

See formatter_callback/0.

Link to this type

formatter_callback_info_key()

View Source (since 1.16.0)
@type formatter_callback_info_key() ::
  :extra_info
  | :error_info
  | :test_module_info
  | :test_info
  | :location_info
  | :stacktrace_info
  | :blame_diff

Key passed to a formatter callback to format information.

See formatter_callback/0.

@type id() :: term()
@type test() :: ExUnit.Test.t()
@type times_us() :: %{
  run: pos_integer(),
  async: pos_integer() | nil,
  load: pos_integer() | nil
}

The times spent on several parts of the test suite.

The following properties can be computed:

sync = run - (async || 0)
total = run + (load || 0)

async is nil when there are no async tests. load is nil when the test suite is running and loading tests concurrently.

Link to this type

width()

View Source (since 1.16.0)
@type width() :: non_neg_integer() | :infinity

Width for formatting.

For example, see format_assertion_diff/4.

Functions

Link to this function

format_assertion_diff(assert_error, padding_size, width, formatter)

View Source
@spec format_assertion_diff(
  ExUnit.AssertionError.t(),
  non_neg_integer(),
  width(),
  formatter_callback()
) :: keyword()

Formats ExUnit.AssertionError diff.

It returns a keyword list with diffing information from the left and right side of the assertion, if any exists.

It expects the assertion error, the padding_size for formatted content, the width (may be :infinity), and the formatter callback function.

Examples

iex> error = assert_raise ExUnit.AssertionError, fn -> assert [1, 2] == [1, 3] end
iex> formatter_cb = fn
...>   :diff_enabled?, _ -> true
...>   _key, value -> value
...> end
iex> keyword = format_assertion_diff(error, 5, 80, formatter_cb)
iex> for {key, val} <- keyword, do: {key, IO.iodata_to_binary(val)}
[left: "[1, 2]", right: "[1, 3]"]
Link to this function

format_filters(filters, type)

View Source
@spec format_filters(
  keyword(),
  atom()
) :: String.t()

Formats filters used to constrain cases to be run.

Examples

iex> format_filters([run: true, slow: false], :include)
"Including tags: [run: true, slow: false]"

iex> format_filters([list: [61, 62, 63]], :exclude)
"Excluding tags: [list: [61, 62, 63]]"
Link to this function

format_test_all_failure(test_module, failures, counter, width, formatter)

View Source
@spec format_test_all_failure(
  ExUnit.TestModule.t(),
  [failure],
  non_neg_integer(),
  width(),
  formatter_callback()
) :: String.t()
when failure: {atom(), term(), Exception.stacktrace()}

Receives a test module and formats its failure.

Examples

iex> failure = {:error, catch_error(raise "oops"), _stacktrace = []}
iex> formatter_cb = fn _key, value -> value end
iex> test_module = %ExUnit.TestModule{name: Hello}
iex> format_test_all_failure(test_module, [failure], 1, 80, formatter_cb)
"  1) Hello: failure on setup_all callback, all tests have been invalidated\n     ** (RuntimeError) oops\n"
Link to this function

format_test_failure(test, failures, counter, width, formatter)

View Source
@spec format_test_failure(
  test(),
  [failure],
  non_neg_integer(),
  width(),
  formatter_callback()
) :: String.t()
when failure: {atom(), term(), Exception.stacktrace()}

Receives a test and formats its failures.

Examples

iex> failure = {:error, catch_error(raise "oops"), _stacktrace = []}
iex> formatter_cb = fn _key, value -> value end
iex> test = %ExUnit.Test{name: :"it works", module: MyTest, tags: %{file: "file.ex", line: 7}}
iex> format_test_failure(test, [failure], 1, 80, formatter_cb)
"  1) it works (MyTest)\n     file.ex:7\n     ** (RuntimeError) oops\n"
@spec format_times(times_us()) :: String.t()

Formats time taken running the test suite.

Examples

iex> format_times(%{run: 10000, async: nil, load: nil})
"Finished in 0.01 seconds (0.00s async, 0.01s sync)"

iex> format_times(%{run: 10000, async: nil, load: 20000})
"Finished in 0.03 seconds (0.02s on load, 0.00s async, 0.01s sync)"

iex> format_times(%{run: 10000, async: nil, load: 200_000})
"Finished in 0.2 seconds (0.2s on load, 0.00s async, 0.01s sync)"

iex> format_times(%{run: 100_000, async: 50000, load: 200_000})
"Finished in 0.3 seconds (0.2s on load, 0.05s async, 0.05s sync)"