Skip to content

Instantly share code, notes, and snippets.

@BjRo
Last active January 27, 2018 12:26
Show Gist options
  • Save BjRo/db44b99b55c2bf197607090c54c3be21 to your computer and use it in GitHub Desktop.
Save BjRo/db44b99b55c2bf197607090c54c3be21 to your computer and use it in GitHub Desktop.
GraphQL testing in XING One
package com.xing.one.engine
import akka.http.scaladsl.model._
import com.xing.one.GraphqlEngine
import com.xing.one.helpers.EngineSpecification
import com.xing.one.helpers.Matchers._
class BasicInterfaceSpec extends EngineSpecification {
isolated
val engine: GraphqlEngine = createEngine()
"can execute a basic query" >> {
val query =
"""
| query Query {
| viewer {
| xingId {
| id
| firstName
| }
| }
| }
"""
val internalResponse =
"""
| {
| "collection" : [{
| "id" : 1234,
| "correlationId": "1234",
| "firstName" : "John"
| }]
| }
"""
stubRequest("/rest/profiles/xing_ids", internalResponse)
val (statusCode, response) = runQuery(engine, query)
statusCode must be_==(StatusCodes.OK)
response must beJson(
"""
|{
| "data": {
| "viewer" : {
| "xingId" : {
| "id" : "1234",
| "firstName" : "John"
| }
| }
| }
|}
"""
)
}
"can execute a query with optional values" >> {
val query =
"""
| query Query {
| viewer {
| xingId {
| id
| academicTitle
| }
| }
| }
"""
val internalResponse =
"""
| {
| "collection" : [{
| "id" : 1234,
| "correlationId": "1234",
| "academicTitle" : "Prof."
| }]
| }
"""
stubRequest("/rest/profiles/xing_ids", internalResponse)
val (statusCode, response) = runQuery(engine, query)
statusCode must be_==(StatusCodes.OK)
response must beJson(
"""
|{
| "data": {
| "viewer" : {
| "xingId" : {
| "id" : "1234",
| "academicTitle" : "PROF"
| }
| }
| }
|}
"""
)
}
"tolerates absence of optional values" >> {
val query =
"""
| query Query {
| viewer {
| xingId {
| id
| academicTitle
| }
| }
| }
"""
val internalResponse =
"""
| {
| "collection" : [{
| "id" : 1234,
| "correlationId": "1234",
| "academicTitle" : null
| }]
| }
"""
stubRequest("/rest/profiles/xing_ids", internalResponse)
val (statusCode, response) = runQuery(engine, query)
statusCode must be_==(StatusCodes.OK)
response must beJson(
"""
|{
| "data": {
| "viewer" : {
| "xingId" : {
| "id" : "1234",
| "academicTitle" : null
| }
| }
| }
|}
"""
)
}
}
#= viewer_id: 1
#= accept_language: de
query getXINGID($userID: SlugOrID!) {
profileModules(id: $userID) {
xingIdModule {
...XINGIDProfileData
}
}
}
fragment XINGIDProfileData on XingIdModule {
__typename
xingId {
__typename
id
firstName
lastName
displayName
pageName
contactDegree
displayFlag
location {
displayLocation
}
occupations {
category
summary
}
profileQuote
academicTitle
}
layout
}
__INPUT__
#= sample: other
{
"userID": "90"
}
__INPUT__
#= sample: self
{
"userID": "1"
}
@BjRo
Copy link
Author

BjRo commented Jan 27, 2018

I've added samples of both kind of tests. One thing to know about our @graphql project is that it's a proxy over internal REST APIs. That makes it a bit special in some aspects.

So what are we seeing here? The first kind of tests is written in Scala (our solution is build around Sangria) and execute the core engine against a test schema and stubs out the REST backend. This is pretty flexible because we can test whether the basic features work, plug-in middlewares and test them in isolation and very certain capabilities we offer on schema level (our schema is almost exclusively build from SDL with custom directives). And yes, those tests are pretty fast.

The second test is mostly using Ruby, Rspec and some other internal tools. In a nutshell it's a snapshot based testing approach (I can't share the actual snapshot data). The part you're seeing here is the query with some metadata (who's calling what headers are set) and then sample input. For each input there's a checked in snapshot JSON result against which the response is compared against. This kind of test is executed against a dockerized-mini version of our whole product. It executes the whole system and as such is pretty slow. We run it on every merge to master (we work with feature branches), but the integration tests can also be manually triggered from every GH pull request manually.

Let me know if you've got additional questions. And please don't redistribute this :)

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