pnpm add mercurius-integration-testing
# or
yarn add mercurius-integration-testing
# or
npm install mercurius-integration-testing
- query, mutation & subscription support.
- DocumentNode and string support
- TypeScript support
- Support for graphql-typed-document-node, therefore, support for GraphQL Code Generator
- batchQueries support.
- headers management.
- cookies management.
// app.ts | app.js
import Fastify from 'fastify'
import Mercurius from 'mercurius'
import schema from './schema'
import { buildContext } from './buildContext'
export const app = Fastify()
app.register(Mercurius, {
schema,
resolvers: {},
context: buildContext,
allowBatchedQueries: true,
})
// integration.test.js | integration.test.ts
import { createMercuriusTestClient } from 'mercurius-integration-testing'
import { app } from '../app'
// ...
const testClient = createMercuriusTestClient(app)
expect(testClient.query('query { helloWorld }')).resolves.toEqual({
data: {
helloWorld: 'helloWorld',
},
})
Create a testing client instance, you should give it the fastify instance in which Mercurius was already registered, and optionally, some options
const client = createMercuriusTestClient(app, {
/**
* Optional, specify headers to be added to every request in the client
*/
headers: {
authorization: 'hello-world',
},
/**
* Optional, by default it points to /graphql
*/
url: '/graphql',
/**
* Optional, specify cookies to be added to every request in the client
*/
cookies: {
authorization: 'hello-world',
},
})
.query
and.mutate
are basically the same function, but for readability, both exists
// You can give it a simple string
const queryResponse = await client.query(`
query {
helloWorld
}
`)
// Data returned from the API
queryResponse.data
// Possible array of errors from the API
queryResponse.errors
// You can also call `mutate`
// to improve readability for mutations
const mutationResponse = await client.mutate(`
mutation {
helloWorld
}
`)
// You can also give them `DocumentNode`s
// from `graphql-tag` or equivalents
await client.query(gql`
query {
helloWorld
}
`)
// You can give variables in the second parameter options
await client.query(
`
query($foo: String!) {
hello(foo: $foo)
}
`,
{
variables: {
foo: 'bar',
},
}
)
await client.query(
`
query example {
helloExample
}
`,
{
// You can specify operation name if the queries
// are named
operationName: 'helloExample',
// Query specific headers
// These are going to be "merged" with the client set headers
headers: {
hello: 'world',
},
// Query specific cookies
// These are going to be "merged" with the client set headers
cookies: {
foo: 'bar',
},
}
)
You can change the default client headers whenever
client.setHeaders({
authorization: 'other-header',
})
You can change the default client cookies whenever
client.setCookies({
authorization: 'other-cookie',
})
If allowBatchedQueries
is set in the Mercurius registration, you can call some queries together
const batchedResponse = await client.batchQueries(
[
{
query: `
query {
helloWorld
}
`,
},
{
query: `
query($name: String!) {
user(name: $name) {
email
}
}
`,
variables: {
name: 'bob',
},
// operationName: "you-can-specify-it-here-if-needed"
},
],
// Optional
{
// Optional request specific cookies
cookies: {
foo: 'bar',
},
// Optional request specific headers
headers: {
foo: 'bar',
},
}
)
batchedResponse ===
[
{ data: { helloWorld: 'foo' } },
{ data: { user: { email: '[email protected]' } } },
]
If you are not already calling
.listen(PORT)
somewhere, it will automatically call it, assigning a random available port, this means you will have to manually call.close()
somewhere
.subscribe
returns a promise that resolves when the subscription connection is made
headers
&cookies
are applied the same as in.query
and.mutate
const subscription = await client.subscribe({
query: `
subscription {
notificationAdded {
id
message
}
}
`,
onData(response) {
// response.errors => array of graphql errors or undefined
response ==
{ data: { notificationAdded: { id: 1, message: 'hello world' } } }
},
// Optional
variables: { foo: 'bar' },
// Optional
operationName: 'name_if_is_named_query',
// Optional, initialization payload, usually for authorization
initPayload: { authorization: '<token>' },
// Optional, subscription specific cookies
cookies: {
authorization: '<token>',
},
// Optional, subscription specific headers
headers: {
authorization: '<token>',
},
})
// You can manually call the unsubscribe
subscription.unsubscribe()
// You will need to manually close the fastify instance somewhere
app.close()
const dataResponse = await client.query<{
helloWorld: string
}>(`
query {
helloWorld
}
`)
// string
dataResponse.data.helloWorld
const variablesResponse = await client.query<
{
user: {
email: string
}
},
{
name: string
}
>(
`
query($name: String!) {
user(name: $name) {
email
}
}
`,
{
variables: {
name: 'bob',
},
}
)
// string
variablesResponse.data.user.email
await client.subscribe<
{
helloWorld: string
},
{
foo: string
}
>({
query: `
subscription($foo: String!) {
helloWorld(foo: $foo)
}
`,
variables: {
// Error, Type 'number' is not assignable to type 'string'.
foo: 123,
},
onData(response) {
// string
response.data.helloWorld
},
})
MIT