Skip to content

Commit

Permalink
Switch to using JsonNode rather than JsonElement
Browse files Browse the repository at this point in the history
  • Loading branch information
theramis committed Jan 2, 2024
1 parent 45a8176 commit d40c387
Show file tree
Hide file tree
Showing 19 changed files with 180 additions and 269 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Changelog
All notable changes to the Snapper project.

## [3.0.0-beta] - 2023-01-02
### Behaviour changes in V3 vs V2
- Snapper now uses `System.Text.Json` rather than `Newtonsoft.Json`. This has a few small behavioural changes.
- `GlobalSnapshotSerialiserSettings` and `SnapshotSerialiserSettings` will now be of type `JsonSerializerOptions`, which will require you to reconfigure any custom settings you have set.
- Snapshot may be formatted differently due to differences between `System.Text.Json` and `Newtonsoft.Json`.
- When using a malformed json string, previously an exception would have been thrown. In V3 the value is serialised as a string.
- Support for Arrays and Primitives.
- Previously these would be converted into a JSON object with the property name `AutoGenerated`, now they will be stored as is.

## [2.4.1] - 2023-12-30
### Added
- Introduces the ability to update snapshots via Custom snapshot settings. This solves [Issue #104](https://github.com/theramis/Snapper/issues/104). Thanks to [@ptjhuang](https://github.com/ptjhuang) for the contribution!
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Snapper V2
# Snapper
**Bringing Jest-esque Snapshot testing to C#**

<!-- <p align="center">
Expand Down Expand Up @@ -44,7 +44,7 @@ public void MyTest()
}

```
The test above is now asserting the `myUser` object with a snapshot stored on disk. Snapper helps you create this snapshot at the beginnging (see [Quick Start](docs/pages/quickstart.md)).
The test above is now asserting the `myUser` object with a snapshot stored on disk. Snapper helps you create this snapshot at the beginning (see [Quick Start](docs/pages/quickstart.md)).

This is the basis of snapshot testing. The idea being a baseline is first generated (in this case a json file which is our snapshot) and then everytime the test runs the output is compared to the snapshot. If the snapshot and the output from the tests don't match the test fails!

Expand Down
2 changes: 1 addition & 1 deletion project/Snapper/Json/JsonDiffGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static string GetDiffMessage(JsonSnapshot currentSnapshot, JsonSnapshot n
var newSnapshotJObject = newSnapshot.Value;

var dmp = new diff_match_patch();
var a = dmp.diff_linesToChars(JsonElementHelper.ToString(currentSnapshotJObject), JsonElementHelper.ToString(newSnapshotJObject));
var a = dmp.diff_linesToChars(JsonNodeHelper.ToString(currentSnapshotJObject), JsonNodeHelper.ToString(newSnapshotJObject));
var lineText1 = (string) a[0];
var lineText2 = (string) a[1];
var lineArray = (List<string>) a[2];
Expand Down
97 changes: 0 additions & 97 deletions project/Snapper/Json/JsonElementHelper.cs

This file was deleted.

51 changes: 51 additions & 0 deletions project/Snapper/Json/JsonNodeHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace Snapper.Json;

internal static class JsonNodeHelper
{
public static JsonNode ParseFromString(string jsonString, SnapshotSettings snapshotSettings)
{
return JsonSerializer.Deserialize<JsonNode>(jsonString, CreateSerialiserSettings(snapshotSettings))
?? throw new InvalidOperationException();
}

public static JsonNode FromObject(object? obj, SnapshotSettings snapshotSettings)
{
if (obj is JsonNode node)
return node;

return JsonSerializer.SerializeToNode(obj, CreateSerialiserSettings(snapshotSettings))
?? throw new InvalidOperationException();
}

public static string ToString(JsonNode json, SnapshotSettings? snapshotSettings = null)
{
return JsonSerializer.Serialize(json, CreateSerialiserSettings(snapshotSettings ?? SnapshotSettings.New()));
}

public static bool JsonEquals(JsonNode x, JsonNode y)
=> JsonNode.DeepEquals(x, y);

private static JsonSerializerOptions CreateSerialiserSettings(SnapshotSettings snapshotSettings)
{
var serializerSettings = new JsonSerializerOptions
{
WriteIndented = true
};

SnapshotSettings.GlobalSnapshotSerialiserSettings?.Invoke(serializerSettings);
snapshotSettings.SnapshotSerialiserSettings?.Invoke(serializerSettings);

return serializerSettings;
}

public static bool TryGetValue(this JsonNode node, string propertyName, out JsonNode value)
{
var prop = node[propertyName];
value = prop ?? new JsonObject();
return prop != null;
}
}
6 changes: 3 additions & 3 deletions project/Snapper/Json/JsonSnapshot.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Snapper.Core;

namespace Snapper.Json;

internal record JsonSnapshot(SnapshotId Id, JsonElement Value)
internal record JsonSnapshot(SnapshotId Id, JsonNode Value)
{
public bool CompareValues(JsonSnapshot other)
{
return JsonElementHelper.JsonEquals(Value, other.Value);
return JsonNodeHelper.JsonEquals(Value, other.Value);
}
}

4 changes: 2 additions & 2 deletions project/Snapper/Json/JsonSnapshotInMemoryStore.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Snapper.Core;

namespace Snapper.Json;

internal class JsonSnapshotInMemoryStore : ISnapshotStore
{
private readonly JsonElement _snapshot;
private readonly JsonNode _snapshot;

public JsonSnapshotInMemoryStore(JsonSnapshotSanitiser jsonSnapshotSanitiser, object snapshot)
{
Expand Down
11 changes: 5 additions & 6 deletions project/Snapper/Json/JsonSnapshotSanitiser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Text.Json;
using Snapper.Exceptions;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace Snapper.Json;

Expand All @@ -13,19 +12,19 @@ public JsonSnapshotSanitiser(SnapshotSettings snapshotSettings)
_snapshotSettings = snapshotSettings;
}

public JsonElement SanitiseSnapshot(object snapshot)
public JsonNode SanitiseSnapshot(object snapshot)
{
if (snapshot is string stringSnapshot)
{
try
{
return JsonElementHelper.ParseFromString(stringSnapshot, _snapshotSettings);
return JsonNodeHelper.ParseFromString(stringSnapshot, _snapshotSettings);
}
catch (JsonException e)
{
}
}

return JsonElementHelper.FromObject(snapshot, _snapshotSettings);
return JsonNodeHelper.FromObject(snapshot, _snapshotSettings);
}
}
18 changes: 8 additions & 10 deletions project/Snapper/Json/JsonSnapshotStore.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.IO;
using System.Text.Json;
using System.Text.Json.Nodes;
using Snapper.Core;

Expand All @@ -19,19 +18,18 @@ public JsonSnapshotStore(SnapshotSettings snapshotSettings)
if (!File.Exists(snapshotId.FilePath))
return null;

var fullSnapshot = JsonElementHelper.ParseFromString(File.ReadAllText(snapshotId.FilePath),
var fullSnapshot = JsonNodeHelper.ParseFromString(File.ReadAllText(snapshotId.FilePath),
_snapshotSettings);

if (snapshotId.PrimaryId == null && snapshotId.SecondaryId == null)
return new JsonSnapshot(snapshotId, fullSnapshot);

if (snapshotId.PrimaryId != null &&
fullSnapshot.TryGetProperty(snapshotId.PrimaryId, out var partialSnapshot))
fullSnapshot.TryGetValue(snapshotId.PrimaryId, out var partialSnapshot))
{
if (snapshotId.SecondaryId != null)
{
if (partialSnapshot is var partialSnapshotJObject &&
partialSnapshotJObject.TryGetProperty(snapshotId.SecondaryId, out partialSnapshot))
if (partialSnapshot.TryGetValue(snapshotId.SecondaryId, out partialSnapshot))
{
return new JsonSnapshot(snapshotId, partialSnapshot);
}
Expand All @@ -50,28 +48,28 @@ public void StoreSnapshot(JsonSnapshot newSnapshot)
if (newSnapshot.Id.PrimaryId == null && newSnapshot.Id.SecondaryId == null)
{
var newSnapshotToWrite = newSnapshot.Value;
File.WriteAllText(newSnapshot.Id.FilePath, JsonElementHelper.ToString(newSnapshotToWrite, _snapshotSettings));
File.WriteAllText(newSnapshot.Id.FilePath, JsonNodeHelper.ToString(newSnapshotToWrite, _snapshotSettings));
}
else
{
var rawSnapshotContent = GetRawSnapshotContent(newSnapshot.Id.FilePath);
var newSnapshotToWrite = rawSnapshotContent == null
? new JsonObject()
: JsonElementHelper.ParseNodeFromString(rawSnapshotContent, _snapshotSettings)!;
: JsonNodeHelper.ParseFromString(rawSnapshotContent, _snapshotSettings)!;

if (newSnapshot.Id.PrimaryId != null && newSnapshot.Id.SecondaryId == null)
{
newSnapshotToWrite[newSnapshot.Id.PrimaryId] = JsonObject.Create(newSnapshot.Value);
newSnapshotToWrite[newSnapshot.Id.PrimaryId] = newSnapshot.Value;
}
else if (newSnapshot.Id.PrimaryId != null && newSnapshot.Id.SecondaryId != null)
{
var firstLevel = newSnapshotToWrite[newSnapshot.Id.PrimaryId];
if (firstLevel == null)
newSnapshotToWrite[newSnapshot.Id.PrimaryId] = new JsonObject();

newSnapshotToWrite[newSnapshot.Id.PrimaryId]![newSnapshot.Id.SecondaryId] = JsonObject.Create(newSnapshot.Value);
newSnapshotToWrite[newSnapshot.Id.PrimaryId]![newSnapshot.Id.SecondaryId] = newSnapshot.Value;
}
File.WriteAllText(newSnapshot.Id.FilePath, JsonElementHelper.ToString(newSnapshotToWrite, _snapshotSettings));
File.WriteAllText(newSnapshot.Id.FilePath, JsonNodeHelper.ToString(newSnapshotToWrite, _snapshotSettings));
}
}

Expand Down
2 changes: 1 addition & 1 deletion project/Snapper/Snapper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ See Project Site for more details</Description>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="System.Text.Json" Version="7.0.3" />
<PackageReference Include="System.Text.Json" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Text.Json;
using System.Text.Json.Nodes;
using FluentAssertions;
using Moq;
using Snapper.Core;
Expand All @@ -10,7 +11,7 @@ namespace Snapper.Internals.Tests.Core;

public class SnapperCoreTests
{
private readonly JsonElement _obj = JsonSerializer.SerializeToElement(new {value = 1});
private readonly JsonNode _obj = JsonSerializer.SerializeToNode(new {value = 1});
private readonly SnapperCore _snapperCore;
private readonly Mock<ISnapshotStore> _store;
private readonly Mock<ISnapshotUpdateDecider> _updateDecider;
Expand Down Expand Up @@ -56,7 +57,7 @@ public void SnapshotDoesNotMatch_ResultStatusIs_SnapshotsDoNotMatch()
_store.Setup(a => a.GetSnapshot(It.IsAny<SnapshotId>())).Returns(MakeJsonSnapshot(_obj));
_updateDecider.Setup(a => a.ShouldUpdateSnapshot()).Returns(false);

var newObj = JsonSerializer.SerializeToElement(new {value = 2});
var newObj = JsonSerializer.SerializeToNode(new {value = 2});
var result = _snapperCore.Snap(MakeJsonSnapshot(newObj));

result.Status.Should().Be(SnapResultStatus.SnapshotsDoNotMatch);
Expand All @@ -70,7 +71,7 @@ public void SnapshotDoesNotMatch_ShouldUpdate_ResultStatusIs_SnapshotUpdated()
_store.Setup(a => a.GetSnapshot(It.IsAny<SnapshotId>())).Returns(MakeJsonSnapshot(_obj));
_updateDecider.Setup(a => a.ShouldUpdateSnapshot()).Returns(true);

var newObj = JsonSerializer.SerializeToElement(new {value = 2});
var newObj = JsonSerializer.SerializeToNode(new {value = 2});
var result = _snapperCore.Snap(MakeJsonSnapshot(newObj));

_store.Verify(a => a.StoreSnapshot(It.IsAny<JsonSnapshot>()), Times.Once);
Expand Down Expand Up @@ -125,6 +126,6 @@ public void SnapshotDoesNotExist_And_IsCiEnv_ResultStatusIs_SnapshotDoesNotExist
Environment.SetEnvironmentVariable("CI", null, EnvironmentVariableTarget.Process);
}

private static JsonSnapshot MakeJsonSnapshot(JsonElement obj)
private static JsonSnapshot MakeJsonSnapshot(JsonNode obj)
=> new JsonSnapshot(new SnapshotId("", "", ""), obj);
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ private static string DiffMaker(Action<StringBuilder> addLinesFunc)
}

private JsonSnapshot MakeJsonSnapshot(object val)
=> new JsonSnapshot(DummySnapshotId(), JsonSerializer.SerializeToElement(val));
=> new JsonSnapshot(DummySnapshotId(), JsonSerializer.SerializeToNode(val));

private static SnapshotId DummySnapshotId()
=> new SnapshotId("dir", "filename", "testname");
Expand Down
Loading

0 comments on commit d40c387

Please sign in to comment.