Skip to content

Commit 5854ef1

Browse files
authored
Merge pull request #5286 from yn-misaki/fix_backtrace_error
Fix GraphQL backtrace handling for inline fragments
2 parents e4f3bf3 + 4d485e1 commit 5854ef1

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

lib/graphql/backtrace/table.rb

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,30 +78,53 @@ def rows
7878
end
7979
end
8080

81-
8281
object = result.graphql_application_value.object.inspect
83-
ast_node = result.graphql_selections.find { |s| s.alias == last_part || s.name == last_part }
84-
field_defn = query.get_field(result.graphql_result_type, ast_node.name)
85-
args = query.arguments_for(ast_node, field_defn).to_h
86-
field_path = field_defn.path
87-
if ast_node.alias
88-
field_path += " as #{ast_node.alias}"
82+
ast_node = nil
83+
result.graphql_selections.each do |s|
84+
found_ast_node = find_ast_node(s, last_part)
85+
if found_ast_node
86+
ast_node = found_ast_node
87+
break
88+
end
8989
end
9090

91-
rows << [
92-
ast_node.position.join(":"),
93-
field_path,
94-
"#{object}",
95-
args.inspect,
96-
inspect_result(@override_value)
97-
]
91+
if ast_node
92+
field_defn = query.get_field(result.graphql_result_type, ast_node.name)
93+
args = query.arguments_for(ast_node, field_defn).to_h
94+
field_path = field_defn.path
95+
if ast_node.alias
96+
field_path += " as #{ast_node.alias}"
97+
end
98+
99+
rows << [
100+
ast_node.position.join(":"),
101+
field_path,
102+
"#{object}",
103+
args.inspect,
104+
inspect_result(@override_value)
105+
]
106+
end
98107

99108
rows << HEADERS
100109
rows.reverse!
101110
rows
102111
end
103112
end
104113

114+
def find_ast_node(node, last_part)
115+
return nil unless node
116+
return node if node.respond_to?(:alias) && node.respond_to?(:name) && (node.alias == last_part || node.name == last_part)
117+
return nil unless node.respond_to?(:selections)
118+
return nil if node.selections.nil? || node.selections.empty?
119+
120+
node.selections.each do |child|
121+
child_ast_node = find_ast_node(child, last_part)
122+
return child_ast_node if child_ast_node
123+
end
124+
125+
nil
126+
end
127+
105128
# @return [String]
106129
def render_table(rows)
107130
max = Array.new(HEADERS.length, MIN_COL_WIDTH)

spec/graphql/backtrace_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,43 @@ def execute_multiplex(multiplex:)
159159
assert_includes err.message, "more lines"
160160
end
161161

162+
it "annotates crashes from user code when using inline fragments" do
163+
err = assert_raises(GraphQL::Backtrace::TracedError) {
164+
backtrace_schema.execute <<-GRAPHQL, root_value: "Root"
165+
query($msg: String = \"Boom\") {
166+
field1 {
167+
... on Thing {
168+
boomError: raiseField(message: $msg)
169+
}
170+
}
171+
}
172+
GRAPHQL
173+
}
174+
175+
# GraphQL backtrace is present
176+
expected_graphql_backtrace = [
177+
"4:15: Thing.raiseField as boomError",
178+
"2:11: Query.field1",
179+
"1:9: query",
180+
]
181+
assert_equal expected_graphql_backtrace, err.graphql_backtrace
182+
183+
hash_inspect = { message: "Boom" }.inspect
184+
# The message includes the GraphQL context
185+
rendered_table = [
186+
'Loc | Field | Object | ' + "Arguments".ljust(hash_inspect.size) + ' | Result',
187+
'4:15 | Thing.raiseField as boomError | :something | ' + hash_inspect + ' | #<RuntimeError: This is broken: Boom>',
188+
'2:11 | Query.field1 | "Root" | ' + "{}".ljust(hash_inspect.size) + ' | {}',
189+
'1:9 | query | "Root" | ' + {"msg" => "Boom"}.inspect.ljust(hash_inspect.size) + ' | {field1: {...}}',
190+
].join("\n")
191+
192+
assert_includes err.message, "\n" + rendered_table
193+
# The message includes the original error message
194+
assert_includes err.message, "This is broken: Boom"
195+
assert_includes err.message, "spec/graphql/backtrace_spec.rb:49", "It includes the original backtrace"
196+
assert_includes err.message, "more lines"
197+
end
198+
162199
it "annotates errors from Query#result" do
163200
query_str = "query StrField { field2 { strField } __typename }"
164201
context = { backtrace: true }

0 commit comments

Comments
 (0)