Skip to content

Instantly share code, notes, and snippets.

@ali-ehmed
Last active March 14, 2022 15:39
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ali-ehmed/3db3558c164e8cace7937c01c01c9571 to your computer and use it in GitHub Desktop.
Save ali-ehmed/3db3558c164e8cace7937c01c01c9571 to your computer and use it in GitHub Desktop.
RSpec - Stub Graphql Client Adapter
require 'graphql/client'
require 'graphql/client/http'
module PlatformGraphqlClient
# Configure GraphQL endpoint using the basic HTTP network adapter.
HTTP = GraphQL::Client::HTTP.new('http://localhost:3001/api/graphql') do
# def headers(context)
# # Optionally set any HTTP headers
# { "Access-Token": "user-access-token" }
# end
end
begin
# Fetch latest schema on init, this will make a network request
SCHEMA = GraphQL::Client.load_schema(HTTP)
# However, it's smart to dump this to a JSON file and load from disk
#
# Run it from a script or rake task
# GraphQL::Client.dump_schema(CoreGraphql::HTTP, "path/to/schema.json")
#
# SCHEMA = GraphQL::Client.load_schema("path/to/schema.json")
#
CLIENT = GraphQL::Client.new(schema: SCHEMA, execute: HTTP)
rescue Errno::ECONNREFUSED
raise 'Graphql could not load schema. The Host URL is invalid/empty.'
end
end
# Stubbed Adapter for Graphqal Client object
class StubGraphqlClientAdapter
def self.execute(document: _, operation_name: _, variables: _, context: _)
custom_response = StubGraphqlCustomResponseGenerator.instance.notify_observers(operation_name)
StubGraphqlCustomResponseGenerator.instance.changed(true) if StubGraphqlCustomResponseGenerator.instance.count_observers > 0
return custom_response if custom_response
case operation_name
when 'ValidateUserEmailQuery'
{ data: { validateUserExistence: false } }.with_indifferent_access
when 'CreateUserQuery'
{ data: { createUser: variables } }.with_indifferent_access
else
{ data: {} }
end
end
end
### CUSTOM STUBBED RESPONSE DURING TEST CASES ###
# If you want to generate a custom response in your specifc RSpec spec for a Graphql Query/Mutation you can use StubGraphqlCustomResponseGenerator in RSpec before hooks, which is singleton btw, and set custom mocked responses.
# All it does is allow you to subscribe multiple observers (which are objects of StubGraphqlCustomResponse) and inside `StubGraphqlCustomResponse.execute`
# it publishes those observers. You can add multiple observers at time, they'll be published sequentially everytime #execute is called.
#
# Usage Examples
#
# before do
# StubGraphqlCustomResponseGenerator.instance.add_response(
# StubGraphqlCustomResponse.new('validateUserExistence', { data: { validateUserExistence: true } }.with_indifferent_access })
# )
# StubGraphqlCustomResponseGenerator.instance.add_response(
# StubGraphqlCustomResponse.new('CreateUserQuery', { { errors: [ { message: "can't be blank ", extensions: { code: "USER_INPUT_ERROR", attribute: "password" } }] }.with_indifferent_access })
# )
# end
#
# it 'should see errors from third party' do
# # Your test definition of a method that will hit Graphql api....
# end
#
class StubGraphqlCustomResponseGenerator
include Singleton
include Observable
def add_observer(observer)
super(observer)
changed(true)
end
alias_method :add_response, :add_observer
def notify_observers(*arg)
if defined? @observer_state and @observer_state
if defined? @observer_peers
@observer_state = false
# Always return executed response from StubGraphqlCustomResponse#update and reject nils
@observer_peers.map do |k, v|
k.send(v, *arg)
end.compact.first
end
end
end
alias_method :collect_response, :notify_observers
end
class StubGraphqlCustomResponse
def initialize(key, response)
@key = key
@response = response
end
def update(operation_name)
if @key == operation_name
StubGraphqlCustomResponseGenerator.instance.delete_observer(self)
@response
end
end
end
## Finally set `StubGraphqlClientAdapter`
#
# Reset your default Adapter (GraphQL::Client::HTTP) object in your initializer (I've set inside HTTP constant) with the `StubGraphqlClientAdapter`
PlatformGraphqlClient.remove_const('HTTP')
PlatformGraphqlClient.const_set('HTTP', StubGraphqlClientAdapter)
# OR
# Reset your default Client object in your initializer (I've set inside CLIENT constant) with a new Client object that can use
# the same (default) scehema but for execution, it should use `StubGraphqlClientAdapter` class instead of GraphQL::Client::HTTP.
PlatformGraphqlClient.remove_const('CLIENT')
PlatformGraphqlClient.const_set('CLIENT', GraphQL::Client.new(schema: PlatformGraphqlClient::SCHEMA, execute: StubGraphqlClientAdapter))
@ali-ehmed
Copy link
Author

Place above file in your spec directory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment