JSON

C#
using Nullean.Snapshots.Json;

responseBody.Should().MatchJsonSnapshot();
product.Should().MatchJsonSnapshot(AppJsonContext.Default.Product);
product.Should().MatchJsonSnapshot(new JsonSerializerOptions(JsonSerializerDefaults.Web));
responseBody.Should().BeJson("""{ "id": 1, "tags": ["a"] }""");
  1. JSON text
  2. an object, AOT-safe

JSON is stored indented by two spaces, properties in the order they were written, numbers as written and non-ASCII text unescaped. It is compared as a tree:

  • Maps compare by key; order does not matter unless you ask for it.
  • Numbers compare by value: 1, 1.0 and 10e-1 are equal, and integers beyond 2^53 still compare exactly.
  • Arrays keep their order. Items are aligned by their longest common subsequence, so inserting one item reports that item, not everything after it, and a changed field inside an item is reported by its path:
Text
$[0]                     unexpected in actual
$[1].v (actual $[2].v)   expected "b"   actual "B"   (verified.json:1:31)

A property that appears twice in one object is an error, and so is invalid JSON.

C#
var diff = new TreeDiffOptions
{
	MapOrder = MapOrder.Significant,
	StrictNumbers = true,
	NullEqualsMissing = true,                              // "x": null equals no "x"
	IgnorePaths = ["$.meta.generatedAt", "$..id", "$.items[*].etag"],
};
json.Should().MatchJsonSnapshot(diff);
  1. report a different key order
  2. 1 and 1.0 differ

See paths and options.

The overload that takes JsonSerializerOptions serializes with reflection and is marked as such; use the JsonTypeInfo<T> overload with a source-generated context in trimmed or native AOT test projects.

For a short value there is MatchInlineJsonSnapshot, which keeps the expected value in the test as a literal: see inline snapshots.