Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to stub with webmock #69

Open
brentgreeff opened this issue Nov 27, 2019 · 12 comments
Open

How to stub with webmock #69

brentgreeff opened this issue Nov 27, 2019 · 12 comments

Comments

@brentgreeff
Copy link

brentgreeff commented Nov 27, 2019

This is more my ignorance than an issue.

I am currently using graphql-client but graphlient's block syntax and info on testing make me want to switch over, but I am still not sure how to test my code.

I have a deployed GraphQL server. I can run a query in Postman and get a JSON response.
I copied that response into a string.
I want to consume that endpoint in my rspec test but I want to use the canned JSON response I copied.

stub_request(:post, "http://user:[email protected]")
  .to_return(status: 200, body: canned_body, headers: {})

def canned_body
  '{ "data": {"some": "json"} }'
end

This errors:

Schema = GraphQL::Client.load_schema(HTTP)
KeyError: key not found: "data"
from /Users/bgreeff/.rvm/gems/ruby-2.6.1/gems/graphql-1.9.6/lib/graphql/schema/loader.rb:16:in `fetch'

One issue is that my stub runs after Schema = GraphQL::Client.load_schema(HTTP)
This seems like a design flaw, making my test improbable.

I see your example

stub_request(:post, url).to_return(
      status: 200,
      body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
    )

I am guessing this is because there are actually 2 requests to the server, 1 to load the schema, but I have no idea how this works.

Can you provide a little more info on how I should construct my test please.

@brentgreeff
Copy link
Author

I bit the bullet & installed graphlient, and it seems my first stub is insufficient.

WebMock::NetConnectNotAllowedError:
       Real HTTP connections are disabled. Unregistered request: POST http://example.com/ with body '{"query":"query IntrospectionQuery {\n  __schema 

it does seem that my new non-static code:

      client = Graphlient::Client.new('http://user:[email protected]')
      response = client.query(my_query, { published: true })
  • Does in-fact produce an IntrospectionQuery.

The headers contain:

headers: {
       	  'Accept'=>'*/*',
       	  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
       	  'Authorization'=>'Basic dXNlcjpwYXNzd29yZA==',
       	  'Content-Type'=>'application/json',
       	  'User-Agent'=>'Faraday v0.15.4'
           }).

I am using http basic, but the request made by faraday doesnt have the auth in the url.

If I add:

      stub_request(:post, 'http://example.com').to_return(
        status: 200,
        body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json
      )

NameError:
       uninitialized constant DummySchema

Where do I get this DummySchema or am I being a dummy?

@yuki24
Copy link
Collaborator

yuki24 commented Nov 27, 2019

It's probably the case that the client is trying to load the GraphQL schema over network, rather than from the file system. Try setting the schema_path on client creation:

Client.new(url, schema_path: 'config/your_graphql_schema.json')

@brentgreeff
Copy link
Author

I tried to dump the schema:

url = "http://user:[email protected]/graphql"
[7] pry(main)> client = Graphlient::Client.new(url, schema_path: 'config/your_graphql_schema.json')

=> #<Graphlient::Client:0x00007fa82c2c3388
 @options={:schema_path=>"config/your_graphql_schema.json"},
 @url="http://user:[email protected]/graphql">
[8] pry(main)> client.schema.dump!

Graphlient::Errors::FaradayServerError: 785: unexpected token at 'Temporary Redirect'
from /Users/bgreeff/.rvm/gems/ruby-2.6.1/gems/graphlient-0.3.7/lib/graphlient/adapters/http/faraday_adapter.rb:21:in `rescue in execute'
Caused by Faraday::ParsingError: 785: unexpected token at 'Temporary Redirect'
from /Users/bgreeff/.rvm/gems/ruby-2.6.1/gems/json-2.2.0/lib/json/common.rb:156:in `parse'
Caused by Faraday::ParsingError: 785: unexpected token at 'Temporary Redirect'
from /Users/bgreeff/.rvm/gems/ruby-2.6.1/gems/json-2.2.0/lib/json/common.rb:156:in `parse'
Caused by JSON::ParserError: 785: unexpected token at 'Temporary Redirect'
from /Users/bgreeff/.rvm/gems/ruby-2.6.1/gems/json-2.2.0/lib/json/common.rb:156:in `parse'

@yuki24
Copy link
Collaborator

yuki24 commented Nov 27, 2019

The url needs to be a real URL otherwise the client can't download a schema. Or did you replace it with an example URL to post it here?

@brentgreeff
Copy link
Author

brentgreeff commented Nov 27, 2019

Yea I replaced it with an example, but I had http instead of httpS. - This now works a dream. Thanks very much for the help.

I am still a bit confused about schemas.

I guess the old graphql-client code is loading the schema at class load time, - and will refresh the schema on a server restart / deploy etc.

Now I have written the schema to disk, it will need to be manually refreshed. I might need to add a rake task for this. I don't have enough experience to know the trade-offs yet.

Are these schema requests actually necessary? - people are going to ask questions in standup.

@brentgreeff
Copy link
Author

Good place to start I guess - https://graphql.org/learn/introspection/

@brentgreeff
Copy link
Author

This endpoint is going to be under very light load, - my gut feel is that I would prefer to somehow just bypass/ ignore this introspection query in my rspec, and have the introspection just run every time on production (ie not be cached).

@yuki24
Copy link
Collaborator

yuki24 commented Nov 27, 2019

Are these schema requests actually necessary?

The schema is the key concept of GraphQL that makes developers productive by adding editor suggestions, early type checks, etc. If you are not using GraphQL schema, introspection query, etc in development you are actually dropping the whole point of GraphQL.

On the other hand, in production, loading a schema is not strictly necessary (assuming you test it with the schema in development and test) since all the client does is to just make a POST call. However, making it possible would require changing how graphql-client operates internally and it might not be that beneficial since all it saves is a few seconds that only happens once.

Whether or not to download a schema or load it from the disk it all up to you, but at least you can't disable it due to how graphql-client works.

@brentgreeff
Copy link
Author

I see. thanks for the info. - I guess I need to read the graphlient code to see if I can get the schema to load at class load (statically), but somehow stub this request in tests (so its ignored). -Although introspection is great for /graphiql its not useful as-far-as I can see on production.

At this point though I am not sure under what circumstance we will need to refresh a stale schema on disk, might be a non-issue.

@dblock
Copy link
Collaborator

dblock commented Nov 29, 2019

Where do I get this DummySchema

In this project we have both client and server, but for a client app I think we need a better example.

Generally, I think you want to refresh the schema every time it changes. Which you obviously don't control, but hopefully the server doesn't change the schema nilly willy. I recommend doing the same thing in production and development, either have a task that refreshes the schema locally and commits it, then loads, or always load dynamically.

@brentgreeff Would you be so kind to contribute to the README on the testing side for the next person?

@brentgreeff
Copy link
Author

@dblock - sorry just noticed this now.

Would you be so kind to contribute to the README on the testing side for the next person?

Yes, I will take a look.

@brentgreeff
Copy link
Author

@dblock - Sorry I have not come back earlier, but I no longer have the work laptop I did the work on. I am a bit vague on the details now. I will try come back to this when I touch graphQL again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants