View Source Exposure

CI Package

Exposure is a simple and leightweight snapshot testing library for Elixir

Installation

This package can be installed by adding :exposure to your list of dependencies in mix.exs:

def deps do
  [
    {:exposure, "~> 1.0.0", only: :test}
  ]
end

Documentation

For additional documentation, see HexDocs.

Usage

Exposure is easy to use and is designed to integrate seamlessly with Elixir's ExUnit module.

Defining Snapshot Tests

Snapshot tests can be defined with the test_snapshot macro. This macro is syntactically similar to the normal test macro and interacts with other ExUnit entities in the same way.

defmodule SampleTest do
  use ExUnit.Case

  import Exposure

  setup_all do
    %{foo: 1, bar: 2}
  end

  describe "Map.put/3" do
    @tag :sample_tag
    test_snapshot "will add a new pair to a map", ctx do
      ctx
      |> Map.put(:baz, 3)
      |> Map.take([:foo, :bar, :baz])
    end
  end
end

Updating Snapshot Files

Once a snapshot test is defined, a snapshot file can be generated by running the test with the EXPOSURE_OVERRIDE flag set to true:

EXPOSURE_OVERRIDE=true mix test test/sample_test.exs:12

Exposure creates a snapshot directory for each test path and a snapshot file for each test. The snapshot directory structure mirrors the test path directory structure. For the example snapshot test above, the command would generate a file at the following location:

test/_snapshots/sample_test/test_map_put_3_will_add_a_new_pair_to_a_map.snap

Projects using Exposure can also leverage the configured :snapshot_test_tag to create a custom alias for generating snapshots:

defmodule MyApp.MixProject do
  use Mix.Project

  def project do
    [
      aliases: ["snapshots.generate": &generate_snapshots/1],
      preferred_cli_env: ["snapshots.generate": :test],
      ...
    ]
  end

  defp generate_snapshots(args) do
    System.put_env("EXPOSURE_OVERRIDE", "true")
    args = ["--only", "snapshot"] ++ args
    Mix.Tasks.Test.run(args)
  end

  ...
end

Running Snapshot Tests

Once a snapshot file has been created, a snapshot test can be run in the same way as a normal test:

mix test test/sample_test.exs:12

Configuration

Exposure has a few few configuration options that can be set in the application config:

# In config/test.exs
config :exposure,
  snapshot_directory: "my_snapshot_dir",
  snapshot_test_tag: :my_test_tag

More specifically, the configuration options are:

  • :snapshot_directory - A binary/0 denoting the name of the snapshot directory. Defaults to _snapshots.

  • :snapshot_test_tag - An atom/0 denoting the tag that Exposure uses to differentiate snapshot tests. Defaults to :snapshot.

Test Paths

Exposure can also be used for projects with non-traditional test paths. For more information on how to configure multiple test paths, see the mix test docs.

In general, Exposure creates a separate snapshot directory for each test path. The only exception is if one test path contains another. In that case, a snapshot directory is only created in the parent path. For example, consider a project with the following configuration:

# In mix.exs
def project do
  [
    test_paths: ["test", "other_test", "other_test/dir"]
  ]
end

Exposure would only create two snapshot directories for the above project:

test/_snapshots
other_test/_snapshots

Exposure requires that all snapshot tests exist within one of the project test paths. In conjunction with the above simplification, this constraint guarantees a consistent snapshot file location for every test.

Other Libraries

The Exposure API is heavily inspired by the Snapshy library. For the vast majority of cases, Snapshy is more than sufficient. The main differences are relatively niche:

  • Exposure has explicit support for additional test paths.

  • Exposure has slightly different naming rules for snapshot files.

  • Exposure requires a snapshot to exist before running a test.

If those differences are unimportant for your project, Snapshy may be a better choice.

Additionally, no discussion of snapshot testing in Elixir would be complete without mentioning the assert_value package. The concept of a snapshot is handled slightly differently in assert_value but the library is robust and mature and definitely worth investigating.