ExUnit.Formatter — ExUnit v1.16.3

Search documentation of ExUnit

# View Source ExUnit.Formatter (ExUnit v1.16.3)

Helper functions for formatting and the formatting protocols.

Formatters are `GenServer`s 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

formatter_callback()

A function that this module calls to format various things.

formatter_callback_diff_key()

Key passed to a formatter callback to format a diff.

formatter_callback_info_key()

Key passed to a formatter callback to format information.

id()
test()
times_us()

The times spent on several parts of the test suite.

width()

Width for formatting.

## Functions

format_assertion_diff(assert_error, padding_size, width, formatter)

Formats `ExUnit.AssertionError` diff.

format_filters(filters, type)

Formats filters used to constrain cases to be run.

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

Receives a test module and formats its failure.

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

Receives a test and formats its failures.

format_times(times)

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`.

Link to this type

# id()

View Source

    @type id() :: term()

Link to this type

# test()

View Source

    @type test() :: ExUnit.Test.t()

Link to this type

# times_us()

View Source

    @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"

Link to this function

# format_times(times)

View Source

    @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)"