Class: GraphWeaver::Testing::FakeClient

Inherits:
Object
  • Object
show all
Includes:
Selection
Defined in:
lib/graph_weaver/testing/fake_client.rb

Overview

A fake client that fabricates schema-correct responses for whatever query arrives — the zero-setup way to test code built on generated modules:

 fake = GraphWeaver::Testing::FakeClient.new(schema:)
 result = PersonQuery.execute!(id: "1", fake — positionally)
 result.person.name  # => a plausible String, typed and castable

Values are type-correct by construction (real enum values, valid __typename members for unions/interfaces, iso8601 for date scalars), so every fake response casts cleanly through the generated structs. See Values for value fabrication (mode: :faker / :literal).

overrides: pin fields by GraphQL name — schema vocabulary, so keys survive query refactors. "Type.field" beats "field"; values are literals or zero-arg procs. (An override with a wrong-typed value is also the way to simulate a corrupt payload — casting raises GraphWeaver::TypeError.)

 FakeClient.new(schema:, overrides: {
   "Person.name" => "Daniel",
   "email" => -> { "test@example.com" },
 })

Partial failures: fail_at simulates a field-level error with spec-correct null propagation — the field's error lands in the errors array (with its concrete path), the field becomes null, and nulls bubble past non-null positions to the nearest nullable ancestor, just like a real server:

 FakeClient.new(schema:, fail_at: "person.pets.name")
 FakeClient.new(schema:, fail_at: { path: "person.email", message: "hidden", code: "PRIVATE" })

errors: appends verbatim top-level errors alongside the fake data.

Type mismatches: corrupt: names fields ("Type.field") that should arrive wire-corrupted — a wrong-typed value derived from the schema, so casting raises GraphWeaver::TypeError. One spec checks the failure path; every other spec gets working data:

 FakeClient.new(schema:, corrupt: "Person.birthday")

seed: makes a run reproducible (also seeds faker). Per-instance options fall back to GraphWeaver::Testing.config.

Constant Summary collapse

NULL_BUBBLE =

sentinel: a simulated failure bubbling up to the nearest nullable spot

Object.new.freeze

Instance Method Summary collapse

Methods included from Selection

#applies?, #each_field, #load_operation, #operation_root_type

Constructor Details

#initialize(schema:, overrides: {}, seed: nil, mode: nil, list_size: nil, null_chance: nil, errors: nil, fail_at: nil, corrupt: nil) ⇒ FakeClient

Returns a new instance of FakeClient.



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/graph_weaver/testing/fake_client.rb', line 56

def initialize(schema:, overrides: {}, seed: nil, mode: nil, list_size: nil, null_chance: nil,
  errors: nil, fail_at: nil, corrupt: nil)
  config = GraphWeaver::Testing.config
  @schema = schema
  @overrides = config.overrides.merge(overrides)
  @values = GraphWeaver::Testing::Values.new(seed:, mode:)
  @list_size = list_size || config.list_size
  @null_chance = null_chance || config.null_chance
  # NOT Array(): it would explode a bare Hash into key/value pairs
  @extra_errors = wrap(errors).map { |error| normalize_error(error) }
  @fail_at = wrap(fail_at).map { |spec| normalize_fail_spec(spec) }
  @corrupt = wrap(corrupt)
end

Instance Method Details

#execute(query, variables: {}) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/graph_weaver/testing/fake_client.rb', line 70

def execute(query, variables: {})
  operation = load_operation(query)
  root_type = operation_root_type(operation)

  @path = []
  @failures = []
  data = object_value(root_type, operation.selections)
  data = nil if data.equal?(NULL_BUBBLE) # total propagation, like a real server

  response = { "data" => data }
  errors = @failures + @extra_errors
  response["errors"] = errors unless errors.empty?
  response
end