Skip to content

Commit 1fc6c9c

Browse files
author
Fredrik Teschke
committed
✨ Add Snapshot.ignore(String... jsonPaths) method
1 parent 01755b3 commit 1fc6c9c

File tree

5 files changed

+138
-4
lines changed

5 files changed

+138
-4
lines changed

pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@
8686
<artifactId>slf4j-api</artifactId>
8787
<version>1.7.25</version>
8888
</dependency>
89+
<dependency>
90+
<groupId>com.jayway.jsonpath</groupId>
91+
<artifactId>json-path</artifactId>
92+
<version>2.4.0</version>
93+
</dependency>
8994
</dependencies>
9095

9196
<build>

src/main/java/io/github/jsonSnapshot/Snapshot.java

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package io.github.jsonSnapshot;
22

3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import com.jayway.jsonpath.DocumentContext;
6+
import com.jayway.jsonpath.JsonPath;
7+
import com.jayway.jsonpath.spi.json.GsonJsonProvider;
38
import org.assertj.core.util.diff.DiffUtils;
49
import org.assertj.core.util.diff.Patch;
510

611
import java.lang.reflect.Method;
12+
import java.util.ArrayList;
713
import java.util.Arrays;
814
import java.util.Collection;
15+
import java.util.List;
916
import java.util.Set;
1017
import java.util.function.Function;
18+
import java.util.stream.Collectors;
1119

1220
public class Snapshot {
1321

@@ -19,6 +27,10 @@ public class Snapshot {
1927

2028
private Function<Object, String> jsonFunction;
2129

30+
private final Gson gsonForIgnoringPaths = new GsonBuilder().create();
31+
32+
private final List<String> pathsToIgnore = new ArrayList<>();
33+
2234
private Object[] current;
2335

2436
Snapshot(SnapshotFile snapshotFile, Class clazz, Method method, Function<Object, String> jsonFunction, Object... current) {
@@ -69,11 +81,38 @@ private String getRawSnapshot(Collection<String> rawSnapshots) {
6981
return null;
7082
}
7183

84+
private Object ignorePaths(Object input) {
85+
DocumentContext context = JsonPath.using(new GsonJsonProvider()).parse(gsonForIgnoringPaths.toJsonTree(input));
86+
this.pathsToIgnore.forEach(path -> context.delete(path));
87+
String root = "$";
88+
return context.read(root);
89+
}
90+
91+
private Object[] getCurrentWithoutIgnoredPaths() {
92+
if (pathsToIgnore.isEmpty() || current == null) {
93+
return current;
94+
}
95+
96+
return Arrays.asList(current).stream()
97+
.map(this::ignorePaths)
98+
.collect(Collectors.toList())
99+
.toArray();
100+
}
101+
72102
private String takeSnapshot() {
73-
return getSnapshotName() + jsonFunction.apply(current);
103+
return getSnapshotName() + jsonFunction.apply(getCurrentWithoutIgnoredPaths());
74104
}
75105

76106
public String getSnapshotName() {
77107
return clazz.getName() + "." + method.getName() + "=";
78108
}
109+
110+
/**
111+
* Ignore fields when comparing object and snapshot.
112+
* @param jsonPathsToIgnore A list of paths to ignore in <a href="https://github.com/json-path/JsonPath">JsonPath</a> syntax.
113+
*/
114+
public Snapshot ignoring(String... jsonPathsToIgnore) {
115+
this.pathsToIgnore.addAll(Arrays.asList(jsonPathsToIgnore));
116+
return this;
117+
}
79118
}

src/test/java/io/github/jsonSnapshot/SnapshotIntegrationTest.java

+24
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,28 @@ public void shouldThrowStackOverflowError() {
7676

7777
expect(fakeObject1).toMatchSnapshot();
7878
}
79+
80+
@Test
81+
public void shouldMatchSnapshotAndIgnoreTopLevelFieldMethod() {
82+
expect(FakeObject.builder().id("anyId6").value(6).name("anyName6").build())
83+
.ignoring("value")
84+
.toMatchSnapshot();
85+
}
86+
87+
@Test
88+
public void shouldMatchSnapshotAndIgnoreSeveralNestedFieldsMethod() {
89+
FakeObject grandChild = FakeObject.builder().id("grandChild7").value(7).build();
90+
FakeObject child = FakeObject.builder().id("child7").value(7).fakeObject(grandChild).build();
91+
expect(FakeObject.builder().id("anyId7").value(7).name("anyName7").fakeObject(child).build())
92+
.ignoring("value", "fakeObject.id", "fakeObject.fakeObject")
93+
.toMatchSnapshot();
94+
}
95+
96+
@Test
97+
public void shouldMatchSnapshotAndIgnoreEverythingMethod() {
98+
FakeObject child = FakeObject.builder().id("child8").value(8).build();
99+
expect(FakeObject.builder().id("anyId8").value(8).name("anyName8").fakeObject(child).build())
100+
.ignoring("$..*")
101+
.toMatchSnapshot();
102+
}
79103
}

src/test/java/io/github/jsonSnapshot/SnapshotIntegrationTest.snap

+24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
io.github.jsonSnapshot.SnapshotIntegrationTest.shouldMatchSnapshotAndIgnoreEverythingMethod=[
2+
{}
3+
]
4+
5+
6+
io.github.jsonSnapshot.SnapshotIntegrationTest.shouldMatchSnapshotAndIgnoreSeveralNestedFieldsMethod=[
7+
{
8+
"id": "anyId7",
9+
"name": "anyName7",
10+
"fakeObject": {
11+
"value": 7
12+
}
13+
}
14+
]
15+
16+
17+
io.github.jsonSnapshot.SnapshotIntegrationTest.shouldMatchSnapshotAndIgnoreTopLevelFieldMethod=[
18+
{
19+
"id": "anyId6",
20+
"name": "anyName6"
21+
}
22+
]
23+
24+
125
io.github.jsonSnapshot.SnapshotIntegrationTest.shouldMatchSnapshotFour=[
226
{
327
"id": "anyId4",

src/test/java/io/github/jsonSnapshot/SnapshotTest.java

+45-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.github.jsonSnapshot;
22

33
import com.google.gson.GsonBuilder;
4+
import com.google.gson.JsonParser;
5+
import com.jayway.jsonpath.PathNotFoundException;
46
import org.junit.After;
57
import org.junit.Before;
68
import org.junit.Test;
@@ -10,6 +12,7 @@
1012
import java.io.IOException;
1113
import java.nio.file.Files;
1214
import java.nio.file.Paths;
15+
import java.util.Collections;
1316
import java.util.TreeSet;
1417
import java.util.stream.Collectors;
1518
import java.util.stream.Stream;
@@ -28,13 +31,17 @@ public class SnapshotTest {
2831

2932
private Snapshot snapshot;
3033

34+
private Snapshot createSnapshot(Object... current) throws NoSuchMethodException {
35+
return new Snapshot(snapshotFile, String.class,
36+
String.class.getDeclaredMethod("toString"),
37+
(object) -> new GsonBuilder().setPrettyPrinting().create().toJson(object),current);
38+
}
39+
3140

3241
@Before
3342
public void setUp() throws NoSuchMethodException, IOException {
3443
snapshotFile = new SnapshotFile(DEFAULT_CONFIG.getFilePath(), "anyFilePath");
35-
snapshot = new Snapshot(snapshotFile, String.class,
36-
String.class.getDeclaredMethod("toString"),
37-
(object) -> new GsonBuilder().setPrettyPrinting().create().toJson(object),"anyObject");
44+
snapshot = createSnapshot("anyObject");
3845
}
3946

4047
@After
@@ -60,4 +67,39 @@ public void shouldMatchSnapshotWithException() {
6067
snapshot.toMatchSnapshot();
6168
}
6269

70+
@Test
71+
public void shouldNotFailOnEmptyIgnoredPathList() {
72+
snapshot.ignoring().toMatchSnapshot();
73+
assertThat(snapshotFile.getRawSnapshots()).isEqualTo(Stream.of(SNAPSHOT).collect(Collectors.toCollection(TreeSet::new)));
74+
}
75+
76+
@Test(expected = PathNotFoundException.class)
77+
public void shouldFailWhenTryingToIgnoreChildOfPrimitiveJsonObject() {
78+
snapshot.ignoring("anyObject_is_a_json_string_and_can_not_have_children").toMatchSnapshot();
79+
}
80+
81+
@Test
82+
public void shouldIgnoreTopLevelAndNestedFields() throws NoSuchMethodException {
83+
Object object = new JsonParser().parse("{\n" +
84+
" \"notIgnored\": \"notIgnored\",\n" +
85+
" \"ignoredInParent\": \"ignored\",\n" +
86+
" \"child\": {\n" +
87+
" \"ignoredInParent\": \"notIgnored\",\n" +
88+
" \"ignoredInChild\": \"ignored\"\n" +
89+
" }\n" +
90+
"}");
91+
Snapshot snapshot = createSnapshot(object);
92+
93+
snapshot.ignoring("ignoredInParent", "child.ignoredInChild").toMatchSnapshot();
94+
String expectedSnapshot = "java.lang.String.toString=[\n" +
95+
" {\n" +
96+
" \"notIgnored\": \"notIgnored\",\n" +
97+
" \"child\": {\n" +
98+
" \"ignoredInParent\": \"notIgnored\"\n" +
99+
" }\n" +
100+
" }\n" +
101+
"]";
102+
assertThat(snapshotFile.getRawSnapshots()).isEqualTo(Collections.singleton(expectedSnapshot));
103+
}
104+
63105
}

0 commit comments

Comments
 (0)