Skip to content

Commit 07ad62b

Browse files
test: Adds editing visitor tests
1 parent 1554f79 commit 07ad62b

File tree

1 file changed

+211
-1
lines changed

1 file changed

+211
-1
lines changed

Tests/GraphQLTests/LanguageTests/VisitorTests.swift

Lines changed: 211 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,217 @@ class VisitorTests: XCTestCase {
9090
}
9191
))
9292
}
93-
93+
94+
func testAllowsEditingANodeBothOnEnterAndOnLeave() throws {
95+
let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true)
96+
97+
var selectionSet: SelectionSet? = nil
98+
99+
let editedASTNode = visit(root: ast, visitor: .init(
100+
enter: { node, key, parent, path, ancestors in
101+
if let node = node as? OperationDefinition {
102+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors)
103+
selectionSet = node.selectionSet
104+
let newName = node.name
105+
.map { Name(loc: $0.loc, value: $0.value + ".enter") } ??
106+
Name(value: "enter")
107+
node.set(value: .node(newName), key: "name")
108+
node.set(value: .node(SelectionSet(selections: [])), key: "selectionSet")
109+
return .node(node)
110+
}
111+
return .continue
112+
},
113+
leave: { node, key, parent, path, ancestors in
114+
if let node = node as? OperationDefinition {
115+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true)
116+
let newName = node.name
117+
.map { Name(loc: $0.loc, value: $0.value + ".leave") } ??
118+
Name(value: "leave")
119+
node.set(value: .node(newName), key: "name")
120+
node.set(value: .node(selectionSet!), key: "selectionSet")
121+
return .node(node)
122+
}
123+
return .continue
124+
}
125+
))
126+
127+
let editedAST = try XCTUnwrap(editedASTNode as? Document)
128+
let operations = try XCTUnwrap(editedAST.definitions as? [OperationDefinition])
129+
XCTAssertEqual(operations.count, 1)
130+
XCTAssertEqual(operations.first?.name?.value, "enter.leave")
131+
let operationSelections = try XCTUnwrap(operations.first?.selectionSet.selections)
132+
XCTAssertEqual(operationSelections.count, 3)
133+
}
134+
135+
func testAllowsEditingTheRootNodeOnEnterAndOnLeave() throws {
136+
let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true)
137+
138+
let editedASTNode = visit(root: ast, visitor: .init(
139+
enter: { node, key, parent, path, ancestors in
140+
if let node = node as? Document {
141+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors)
142+
var newDefinitions = node.definitions
143+
newDefinitions.append(
144+
DirectiveDefinition(
145+
name: .init(value: "enter"),
146+
locations: [.init(value: "root")]
147+
)
148+
)
149+
node.set(
150+
value: .array(newDefinitions),
151+
key: "definitions"
152+
)
153+
return .node(node)
154+
}
155+
return .continue
156+
},
157+
leave: { node, key, parent, path, ancestors in
158+
if let node = node as? Document {
159+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true)
160+
var newDefinitions = node.definitions
161+
newDefinitions.append(
162+
DirectiveDefinition(
163+
name: .init(value: "leave"),
164+
locations: [.init(value: "root")]
165+
)
166+
)
167+
node.set(
168+
value: .array(newDefinitions),
169+
key: "definitions"
170+
)
171+
return .node(node)
172+
}
173+
return .continue
174+
}
175+
))
176+
177+
let editedAST = try XCTUnwrap(editedASTNode as? Document)
178+
XCTAssertEqual(editedAST.definitions.count, 3)
179+
try XCTAssertEqual(
180+
XCTUnwrap(editedAST.definitions[1] as? DirectiveDefinition).name.value,
181+
"enter"
182+
)
183+
try XCTAssertEqual(
184+
XCTUnwrap(editedAST.definitions[2] as? DirectiveDefinition).name.value,
185+
"leave"
186+
)
187+
}
188+
189+
func testAllowsForEditingOnEnter() throws {
190+
let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true)
191+
192+
let editedASTNode = visit(root: ast, visitor: .init(
193+
enter: { node, key, parent, path, ancestors in
194+
if let node = node as? Field {
195+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors)
196+
if node.name.value == "b" {
197+
return .node(nil)
198+
}
199+
}
200+
return .continue
201+
}
202+
))
203+
204+
let editedAST = try XCTUnwrap(editedASTNode as? Document)
205+
let operation = try XCTUnwrap(editedAST.definitions[0] as? OperationDefinition)
206+
XCTAssertEqual(
207+
operation.selectionSet.selections.count,
208+
2 // "b" is ignored
209+
)
210+
211+
let cField = try XCTUnwrap(operation.selectionSet.selections[1] as? Field)
212+
XCTAssertEqual(
213+
cField.selectionSet?.selections.count,
214+
2 // "b" is ignored
215+
)
216+
}
217+
218+
func testAllowsForEditingOnLeave() throws {
219+
let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true)
220+
221+
let editedASTNode = visit(root: ast, visitor: .init(
222+
leave: { node, key, parent, path, ancestors in
223+
if let node = node as? Field {
224+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors)
225+
if node.name.value == "b" {
226+
return .node(nil)
227+
}
228+
}
229+
return .continue
230+
}
231+
))
232+
233+
let editedAST = try XCTUnwrap(editedASTNode as? Document)
234+
let operation = try XCTUnwrap(editedAST.definitions[0] as? OperationDefinition)
235+
XCTAssertEqual(
236+
operation.selectionSet.selections.count,
237+
2 // "b" is removed
238+
)
239+
240+
let cField = try XCTUnwrap(operation.selectionSet.selections[1] as? Field)
241+
XCTAssertEqual(
242+
cField.selectionSet?.selections.count,
243+
2 // "b" is removed
244+
)
245+
}
246+
247+
func testIgnoresSkipReturnedOnLeave() throws {
248+
let ast = try parse(source: "{ a, b, c { a, b, c } }", noLocation: true)
249+
250+
let editedASTNode = visit(root: ast, visitor: .init(
251+
leave: { _, _, _, _, _ in
252+
.skip // graphql-js 'false' is Swift '.skip'
253+
}
254+
))
255+
256+
let editedAST = try XCTUnwrap(editedASTNode as? Document)
257+
let operation = try XCTUnwrap(editedAST.definitions[0] as? OperationDefinition)
258+
XCTAssertEqual(
259+
operation.selectionSet.selections.count,
260+
3 // "b" remains
261+
)
262+
263+
let cField = try XCTUnwrap(operation.selectionSet.selections[2] as? Field)
264+
XCTAssertEqual(
265+
cField.selectionSet?.selections.count,
266+
3 // "b" remains
267+
)
268+
}
269+
270+
func testVisitsEditedNode() throws {
271+
let addedField = Field(
272+
name: Name(value: "__typename")
273+
)
274+
275+
var didVisitAddedField = false
276+
277+
let ast = try parse(source: "{ a { x } }", noLocation: true)
278+
visit(root: ast, visitor: .init(
279+
enter: { node, key, parent, path, ancestors in
280+
checkVisitorFnArgs(ast, node, key, parent, path, ancestors, isEdited: true)
281+
if let node = node as? Field, node.name.value == "a" {
282+
if let selectionSet = node.selectionSet {
283+
var newSelections = selectionSet.selections
284+
newSelections.append(addedField)
285+
286+
let newSelectionSet = selectionSet
287+
newSelectionSet.set(value: .array(newSelections), key: "selections")
288+
289+
let newNode = node
290+
newNode.set(value: .node(newSelectionSet), key: "selectionSet")
291+
return .node(newNode)
292+
}
293+
}
294+
if let node = node as? Field, node.name.value == "__typename" {
295+
didVisitAddedField = true
296+
}
297+
return .continue
298+
}
299+
))
300+
301+
XCTAssert(didVisitAddedField)
302+
}
303+
94304
func testAllowsSkippingASubTree() throws {
95305
struct VisitedElement: Equatable {
96306
let direction: VisitDirection

0 commit comments

Comments
 (0)