Skip to content

Instantly share code, notes, and snippets.

@ali-ehmed
Last active March 14, 2022 15:39
Show Gist options
  • Select an option

  • Save ali-ehmed/3db3558c164e8cace7937c01c01c9571 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown
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