This is a micro library to aid with snapshot testing.
The meat of the project is actually in build tool integration - I wanted to have an experience similar to that of Insta with its Cargo integration. Currently only SBT is supported, but Mill support can be added easily, as the project is already structured in a way that favours that.
One of the goals was being able to work with Scala.js and Scala Native - so the Scala.js portion of the runtime includes small Node.js bindings
to the fs
module for filesystem operations.
The runtime is published for 2.12, 2.13, 3 and JVM, JS, Native.
To add the plugin to your SBT build:
-
addSbtPlugin("com.indoorvivants.snapshots" % "sbt-snapshots" % "VERSION")
to yourproject/plugins.sbt
(see VERSION on the badge above) -
In the project where you would like to use snapshot testing, add these settings:
.settings( snapshotsPackageName := "example", snapshotsIntegrations += SnapshotIntegration.MUnit // if using MUnit ) .enablePlugins(SnapshotsPlugin)
Package name is the only required setting, because the plugin will generate a source file that ties build-time filesystem locations with runtime test execution.
The library provides no diffing capabilities, instead delegating that task to the test framework of choice.
SBT tasks:
snapshotsCheck
- interactively accept modified snapshots (if there are any)snapshotsAcceptAll
- accept all modified snapshotssnapshotsDiscardAll
- discard all snapshot changes
SBT settings:
-
snapshotsIntegrations
- list of test framework integrations to generate in test sourcesInstead of providing a separate dependency for each test framework, the plugin generates a single-file integration. This helps avoid the dependency hell of incompatible framework versions. It might seem weird at first, because it is, but I believe it's the only way to stay sane.
-
snapshotsPackageName
- package name to use for generated file -
snapshotsForceOverwrite
- if set totrue
, snapshot assertions won't fail the tests, but instead they will directly overwrite snapshot contents with the new value.It is particularly useful in a setting where you want to only check snapshots on CI, but always update them locally without having to explicitly accept.
Recommended configuration is therefore
snapshotsForceOverwrite := !sys.env.contains("CI")
- or whatever way you can detect that your code is running in CI
You can see what the workflow looks like by
- Modifying the sample test above
- Running
example/test
and observing a failure - Running
example/snapshotsCheck
and accepting a diff - Running
example/test
again and it should succeed - The snapshot file will be changed on disk
Here's the same workflow in video format:
video.mp4
The snapshots runtime will only run under Node.js (or any runtime where require("node:fs")
import can succeed).
To make sure module import is enabled, you should ensure you're using the correct module kind - for example commonJS:
scalaJSLinkerConfig ~= (_.withModuleKind(ModuleKind.CommonJSModule))
The generated MUnit integration will target MUnit 1.0.0 and above, prompted by the changes in the packages for framework's difflib: https://github.com/scalameta/munit/pull/756/files#diff-a09dc8368568b397ac3069018fd17ad22e4f90c5e5cfdc12a4340f9d7c10ac09
All users are advised to migrate to MUnit 1.0.0+. As a consequence, following version bumps occurred:
- Scala Native 0.4 -> 0.5
- Scala.js 1.16
- Scala 2.13.12 -> 2.13.14
Snapshots moved from src/test/resources/snapshots
to src/snapshots
.
This was done because writing to test/resources
re-triggers file watching
when you run ~test
.
You can return old behaviour by manually configuring new setting snapshotsLocation
.
You can automatically move all the snapshots by running snapshotsMigrate 0.0.6