![]() Test plan: - All existing tests pass flag=none [skip-eslint] Change-Id: I36c1a2f47004185f8f02f4155b838c877ee495e3 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/302256 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> Reviewed-by: Ed Schiebel <eschiebel@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> QA-Review: Aaron Shafovaloff <ashafovaloff@instructure.com> |
||
---|---|---|
.. | ||
__tests__ | ||
README.md | ||
index.js | ||
package.json |
README.md
Basic Usage
This will allow you to mock data for a graphql query (or mutation) that semantically matches the data types for canvas's graphql API. For example, if you queried for some data that should return a not null integer, this will return data for that field that contains a random integer, or if a field is an enum, it will randomly pick one of the enum values. This is a wrapper around the apollo mocking library (https://www.apollographql.com/docs/graphql-tools/mocking/)
async function example() {
const query = gql`
query ExampleQuery {
course(id: "1") {
name
state
}
}
`
const result = await mockGraphqlQuery(query)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"course": {
"name": "Hello World",
"state": "created"
}
}
}
Overriding return data
You can modify the returned data of your query by using the overrides
argument
in mockGraphqlQuery.
async function example() {
const query = gql`
query ExampleQuery {
course(id: "1") {
course_name: name
state
}
}
`
const overrides = [{
Course: {
name: 'Course 1',
state: 'available'
}
}]
const result = await mockGraphqlQuery(query, overrides)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"course": {
"course_name": "Course 1",
"state": "available"
}
}
}
It is important to note that overrides work on the graphql type. Notice that the
above overrides was for Course
, instead of course
like in the query. This is
because Course
is the actual graphql typename for that object. Similarly, when
overriding an aliased field like course_name
, we still apply the override to
to the graphql name for that field, in this case name
.
You can find the graphql typenames by looking at the Documentation Explorer
tab on the /graphiql
page, or by looking at the schema.graphql
file.
Because we are overriding the graphql types, any overrides we provide are going to be used anywhere that type shows up in the given query. This is very helpful for being able to mock data deep in a query without having to go through each individual node to get there. For example:
async function example() {
const query = gql`
query MyQuery {
assignment(id: "1") {
discussion {
modules {
name
}
}
modules {
name
}
}
}
`
const overrides = [{
Module: {name: 'Test Module'}
}]
const result = await mockGraphqlQuery(query, overrides)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"assignment": {
"discussion": {
"modules": [
{"name": "Test Module"},
{"name": "Test Module"}
]
},
"modules": [
{"name": "Test Module"},
{"name": "Test Module"}
]
}
}
}
If you only want to mock data for a single type instead of everywhere it shows up in the graphql query, you can do so by mocking the parent that contains the data. For example:
async function example() {
const query = gql`
query MyQuery {
assignment(id: "1") {
discussion {
modules {
name
}
}
modules {
name
}
}
}
`
const overrides = [{
Module: {name: 'Test Module 1'}
Discussion: {
modules: [{name: "Test Module 2"}]
}
}]
const result = await mockGraphqlQuery(query, overrides)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"assignment": {
"discussion": {
"modules": [
{"name": "Test Module 2"}
]
},
"modules": [
{"name": "Test Module 1"},
{"name": "Test Module 1"}
]
}
}
}
Overriding lists of data
By default, any list type returns a list with two mocked elements in it. We can customize this by passing in our own list of overrides for a specific field, where we can control the number of elements in the list and the specific overrides for each individual element:
async function example() {
const query = gql`
query ExampleQuery {
course(id: "1") {
assignmentsConnection {
nodes {
_id
name
}
}
}
}
`
// We are saying that these overrides should have a list of three items, one
// with no specific overrides, one with the _id overridden, and one with the
// _id and name overwritten.
const overrides = {
Assignment: {
nodes: [
{},
{_id: '1'},
{_id: '2', name: 'Test Assignment'}
]
}
}
const result = await mockGraphqlQuery(query)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"course": {
"assignmentsConnection": {
"nodes": [
{"_id": "1532", "name": "Hello World"},
{"_id": "1", "name": "Hello World"},
{"_id": "2", "name": "Test Assignment"}
]
}
}
}
}
Mocking results of interfaces
When querying an interface that could return different data types (for example
the node
and legacyNode
interfaces), you will need to be explicity about what
type of data you want back from the mocked query. This is done by adding a
__typename
override to the interface:
async function example() {
const query = gql`
query MyQuery {
node(id: "abc123") {
... on User {
name
}
}
}
`
const overrides = [{
Node: {__typename: 'User'}
}]
const result = await mockGraphqlQuery(query, overrides)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"node": {
"name": "Hello World"
}
}
}
Passing in variables
You can also pass in variables to your query via the third argument to mockGraphqlQuery. For example:
const query = gql`
query TestQuery($assignmentID: ID!) {
assignment(id: $assignmentID) {
name
}
}
`
const variables = {assignmentID: '1'}
const result = await mockGraphqlQuery(query, [], variables)
console.log(JSON.stringify(result, null, 2))
{
"data": {
"assignment": {
"name": "Hello World"
}
}
}
Mocking apollo queries ()
Here is an example of using mockGraphqlQuery in conjunction with Apollo's
MockedProvider
. This can be tweaked to the needs of your specific test:
import {createCache} from '@canvas/apollo'
import mockGraphqlQuery from 'graphql-query-mock'
const ASSIGNMENT_QUERY = gql`
query AssignmentQuery($assignmentID: ID!) {
assignment(id: $assignmentID) {
name
}
}
`
async function makeMocks() {
const variables = {assignmentID: '1'}
const overrides = {Assignment: {name: 'foobarbaz'}}
const result = await mockGraphqlQuery(ASSIGNMENT_QUERY, overrides, variables)
return [
{
request: {
query: ASSIGNMENT_QUERY,
variables
},
result
}
]
}
it('does a thing', async () => {
const mocks = await makeMocks()
const {getByText} = render(
<MockedProvider mocks={mocks} cache={createCache()}>
<AssignmentQueryComponent />
</MockedProvider>
)
// Rest of unit test
})
Using functions as mocks resolvers
Instead of setting values for overrides, you can pass in a function instead:
const overrides = {
User: () => ({
_id: () => Math.floor(Math.random() * 10)
})
}
const result = await mockGraphqlQuery(query, overrides)