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

Add test for handling partial data with error(s) #15

Merged
merged 4 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,70 @@ try {
}
```

## Partial responses

A GraphQL query may respond with partial data accompanied by errors. In this case we will throw an error but the partial data will still be accessible through `error.data`

```js
const graphql = require('@octokit/graphql').defaults({
headers: {
authorization: `token secret123`
}
})
const query = `{
repository(name: "probot", owner: "probot") {
name
ref(qualifiedName: "master") {
target {
... on Commit {
history(first: 25, after: "invalid cursor") {
nodes {
message
}
}
}
}
}
}
}`

try {
const result = await graphql(query)
} catch (error) {
// server responds with
// { 
// "data": { 
// "repository": { 
// "name": "probot", 
// "ref": null 
// } 
// }, 
// "errors": [ 
// { 
// "type": "INVALID_CURSOR_ARGUMENTS", 
// "path": [ 
// "repository", 
// "ref", 
// "target", 
// "history" 
// ], 
// "locations": [ 
// { 
// "line": 7, 
// "column": 11 
// } 
// ], 
// "message": "`invalid cursor` does not appear to be a valid cursor." 
// } 
// ] 
// } 

console.log('Request failed:', error.request) // { query, variables: {}, headers: { authorization: 'token secret123' } }
console.log(error.message) // `invalid cursor` does not appear to be a valid cursor.
console.log(error.data) // { repository: { name: 'probot', ref: null } }
}
```

## Writing tests

You can pass a replacement for [the built-in fetch implementation](https://github.com/bitinn/node-fetch) as `request.fetch` option. For example, using [fetch-mock](http://www.wheresrhys.co.uk/fetch-mock/) works great to write tests
Expand Down
6 changes: 3 additions & 3 deletions lib/graphql.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ function graphql (request, query, options) {

return request(requestOptions)
.then(response => {
if (response.data.data) {
return response.data.data
if (response.data.errors) {
throw new GraphqlError(requestOptions, response)
}

throw new GraphqlError(requestOptions, response)
return response.data.data
})
}
60 changes: 60 additions & 0 deletions test/error-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,64 @@ describe('errors', () => {
expect(error.request.query).to.equal(query)
})
})

it('Should throw an error for a partial response accompanied by errors', () => {
const query = `{
repository(name: "probot", owner: "probot") {
name
ref(qualifiedName: "master") {
target {
... on Commit {
history(first: 25, after: "invalid cursor") {
nodes {
message
}
}
}
}
}
}
}`

const mockResponse = {
data: {
repository: {
name: 'probot',
ref: null
}
},
errors: [
{
type: 'INVALID_CURSOR_ARGUMENTS',
path: ['repository', 'ref', 'target', 'history'],
locations: [
{
line: 7,
column: 11
}
],
message: '`invalid cursor` does not appear to be a valid cursor.'
}
]
}

return graphql(query, {
headers: {
authorization: `token secret123`
},
request: {
fetch: fetchMock.sandbox()
.post('https://api.github.com/graphql', mockResponse)
}
})

.then(result => {
throw new Error('Should not resolve')
}).catch(error => {
expect(error.message).to.equal('`invalid cursor` does not appear to be a valid cursor.')
expect(error.errors).to.deep.equal(mockResponse.errors)
expect(error.request.query).to.equal(query)
expect(error.data).to.deep.equal(mockResponse.data)
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you agree, we could add a .catch() statement similar to the test above, only also check for error.data. Would that be a desired behavior for partial responses?

Suggested change
})
})
.catch(error => {
expect(error.message).to.equal('Field \'bioHtml\' doesn\'t exist on type \'User\'')
expect(error.errors).to.deep.equal(mockResponse.errors)
expect(error.request.query).to.equal(query)
expect(error.data).to.deep.equal(mockResponse.data)
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that would make the most sense!

})
})