756 lines
20 KiB
TypeScript
756 lines
20 KiB
TypeScript
import {
|
|
execute,
|
|
ExecutionArgs,
|
|
GraphQLError,
|
|
GraphQLFieldResolver,
|
|
parse,
|
|
printSchema,
|
|
printType,
|
|
} from 'graphql'
|
|
import { connectionFromArray } from 'graphql-relay'
|
|
import { arg, connectionPlugin, makeSchema, objectType } from '../../src'
|
|
import { ConnectionFieldConfig, ConnectionPluginConfig } from '../../src/plugins/connectionPlugin'
|
|
|
|
const userNodes: { id: string; name: string }[] = []
|
|
for (let i = 0; i < 10; i++) {
|
|
userNodes.push({ id: `User:${i + 1}`, name: `Test ${i + 1}` })
|
|
}
|
|
|
|
const User = objectType({
|
|
name: 'User',
|
|
definition(t) {
|
|
t.id('id')
|
|
t.string('name')
|
|
},
|
|
})
|
|
|
|
const UsersFieldBody = `
|
|
nodes { id }
|
|
edges {
|
|
cursor
|
|
node { id }
|
|
}
|
|
pageInfo {
|
|
hasNextPage
|
|
hasPreviousPage
|
|
startCursor
|
|
endCursor
|
|
}
|
|
`
|
|
|
|
const UsersLast = parse(`query UsersFieldLast($last: Int!) { users(last: $last) { ${UsersFieldBody} } }`)
|
|
const UsersLastBefore = parse(
|
|
`query UsersFieldLastBefore($last: Int!, $before: String!) { users(last: $last, before: $before) { ${UsersFieldBody} } }`
|
|
)
|
|
const UsersFirst = parse(`query UsersFieldFirst($first: Int!) { users(first: $first) { ${UsersFieldBody} } }`)
|
|
const UsersFirstAfter = parse(
|
|
`query UsersFieldFirstAfter($first: Int!, $after: String!) { users(first: $first, after: $after) { ${UsersFieldBody} } }`
|
|
)
|
|
|
|
const executeOk = async (args: ExecutionArgs) => {
|
|
const result = await execute(args)
|
|
expect(result.errors).toBeUndefined()
|
|
return result
|
|
}
|
|
|
|
const customResolveFn: GraphQLFieldResolver<any, any> = (root: any, args: any) => {
|
|
return connectionFromArray(userNodes, args)
|
|
}
|
|
|
|
const makeTestSchema = (
|
|
pluginConfig: ConnectionPluginConfig = {},
|
|
fieldConfig: Omit<ConnectionFieldConfig<any, any>, 'type'> = {}
|
|
) =>
|
|
makeSchema({
|
|
outputs: false,
|
|
types: [
|
|
User,
|
|
objectType({
|
|
name: 'Query',
|
|
definition(t) {
|
|
// @ts-ignore
|
|
t.connectionField('users', {
|
|
type: User,
|
|
nodes(root: any, args: any, ctx: any, info: any) {
|
|
return userNodes
|
|
},
|
|
...fieldConfig,
|
|
})
|
|
},
|
|
}),
|
|
],
|
|
plugins: [connectionPlugin(pluginConfig)],
|
|
nonNullDefaults: {
|
|
input: false,
|
|
output: false,
|
|
},
|
|
})
|
|
|
|
beforeEach(() => {
|
|
jest.resetAllMocks()
|
|
})
|
|
|
|
describe('defaults', () => {
|
|
it('hasPreviousPage when paginating backwards assumes that node count equal to page size means there is another page to visit backward', async () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
nodes(root, args, ctx) {
|
|
return userNodes.slice(0, 5)
|
|
},
|
|
}
|
|
)
|
|
const result = await executeOk({
|
|
schema,
|
|
document: UsersLastBefore,
|
|
variableValues: {
|
|
last: 5,
|
|
before: 'whatever',
|
|
},
|
|
})
|
|
expect(result.data?.users.pageInfo.hasPreviousPage).toEqual(true)
|
|
})
|
|
it('should provide forward pagination defaults', async () => {
|
|
const schema = makeTestSchema({})
|
|
const nodes = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 1 },
|
|
})
|
|
expect(nodes.data?.users.edges).toEqual([{ cursor: 'Y3Vyc29yOjA=', node: { id: 'User:1' } }])
|
|
expect(Buffer.from(nodes.data?.users.edges[0].cursor, 'base64').toString('utf8')).toEqual('cursor:0')
|
|
})
|
|
})
|
|
|
|
describe('basic behavior', () => {
|
|
it('should adhere to the Relay spec', () => {
|
|
const schema = makeTestSchema({})
|
|
expect(printType(schema.getType('UserConnection')!)).toMatchSnapshot()
|
|
expect(printType(schema.getType('UserEdge')!)).toMatchSnapshot()
|
|
expect(printType(schema.getType('PageInfo')!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('resolves string value', () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
// @ts-ignore
|
|
type: 'User',
|
|
}
|
|
)
|
|
expect(schema.getType('UserConnection')).not.toBeUndefined()
|
|
expect(schema.getType('UserEdge')).not.toBeUndefined()
|
|
expect(schema.getType('PageInfo')).not.toBeUndefined()
|
|
})
|
|
|
|
it('should continue forward pagination from the after index', async () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
nodes(root: any, args: any) {
|
|
expect(args).toEqual({ first: 1, after: '0' })
|
|
return userNodes
|
|
},
|
|
}
|
|
)
|
|
const nodes = await executeOk({
|
|
schema,
|
|
document: UsersFirstAfter,
|
|
variableValues: { first: 1, after: 'Y3Vyc29yOjA=' },
|
|
})
|
|
expect(Buffer.from(nodes.data?.users.edges[0].cursor, 'base64').toString('utf8')).toEqual('cursor:1')
|
|
})
|
|
|
|
it('can paginate backward from a before cursor', async () => {
|
|
const schema = makeTestSchema({
|
|
encodeCursor: (str) => str,
|
|
decodeCursor: (str) => str,
|
|
})
|
|
const first = await executeOk({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 9 },
|
|
})
|
|
expect(first.data?.users.pageInfo).toEqual({
|
|
hasNextPage: true,
|
|
hasPreviousPage: false,
|
|
startCursor: 'cursor:0',
|
|
endCursor: 'cursor:8',
|
|
})
|
|
const lastNodes = await executeOk({
|
|
schema,
|
|
document: UsersLastBefore,
|
|
variableValues: {
|
|
last: 3,
|
|
before: first.data?.users.pageInfo.endCursor,
|
|
},
|
|
})
|
|
expect(lastNodes.data?.users.pageInfo).toEqual({
|
|
startCursor: 'cursor:5',
|
|
endCursor: 'cursor:7',
|
|
hasNextPage: true,
|
|
hasPreviousPage: true,
|
|
})
|
|
})
|
|
|
|
it('can paginate backward without a before with a custom cursorFromNodes', async () => {
|
|
const getTotalCount = async () => Promise.resolve(100)
|
|
const schema = makeTestSchema({
|
|
encodeCursor: (str) => str,
|
|
decodeCursor: (str) => str,
|
|
cursorFromNode: async (node, args, ctx, info, { index, nodes }) => {
|
|
if (args.last && !args.before) {
|
|
const totalCount = await getTotalCount()
|
|
return `cursor:${totalCount - args.last + index + 1}`
|
|
}
|
|
return connectionPlugin.defaultCursorFromNode(node, args, ctx, info, {
|
|
index,
|
|
nodes,
|
|
})
|
|
},
|
|
})
|
|
const lastNodes = await executeOk({
|
|
schema,
|
|
document: UsersLast,
|
|
variableValues: {
|
|
last: 3,
|
|
},
|
|
})
|
|
expect(lastNodes.data?.users.pageInfo).toEqual({
|
|
startCursor: 'cursor:98',
|
|
endCursor: 'cursor:100',
|
|
hasNextPage: false,
|
|
hasPreviousPage: true,
|
|
})
|
|
})
|
|
|
|
it('cannot paginate backward without a before cursor or a custom cursorFromNodes', async () => {
|
|
const schema = makeTestSchema({
|
|
encodeCursor: (str) => str,
|
|
decodeCursor: (str) => str,
|
|
})
|
|
const lastNodes = await execute({
|
|
schema,
|
|
document: UsersLast,
|
|
variableValues: {
|
|
last: 3,
|
|
},
|
|
})
|
|
expect(lastNodes.errors).toEqual([
|
|
new GraphQLError(`Cannot paginate backward without a "before" cursor by default.`),
|
|
])
|
|
})
|
|
|
|
it('should resolve pageInfo with basics', async () => {
|
|
const schema = makeTestSchema({})
|
|
const lastNodes = await executeOk({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 10 },
|
|
})
|
|
expect(lastNodes.data?.users.pageInfo).toEqual({
|
|
endCursor: 'Y3Vyc29yOjk=',
|
|
hasNextPage: false,
|
|
hasPreviousPage: false,
|
|
startCursor: 'Y3Vyc29yOjA=',
|
|
})
|
|
})
|
|
|
|
it('should resolve nodes & edges at the same time', async () => {
|
|
const schema = makeTestSchema({
|
|
includeNodesField: true,
|
|
})
|
|
const lastNodes = await executeOk({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 10 },
|
|
})
|
|
expect(lastNodes.data?.users.nodes).toEqual(lastNodes.data?.users.edges.map((e: any) => e.node))
|
|
})
|
|
|
|
it('can define custom resolve', async () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
nodes: undefined,
|
|
resolve: customResolveFn,
|
|
}
|
|
)
|
|
const lastNodes = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 2 },
|
|
})
|
|
expect(lastNodes).toMatchSnapshot()
|
|
})
|
|
|
|
it('can define custom resolve, which will derive nodes if includeNodesField is true', async () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
includeNodesField: true,
|
|
},
|
|
{
|
|
nodes: undefined,
|
|
resolve: customResolveFn,
|
|
}
|
|
)
|
|
const lastNodes = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 2 },
|
|
})
|
|
expect(lastNodes).toMatchSnapshot()
|
|
})
|
|
|
|
it('can define custom resolve, supplying nodes directly', async () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
includeNodesField: true,
|
|
},
|
|
{
|
|
nodes: undefined,
|
|
resolve: (...args) => {
|
|
const result = customResolveFn(...args)
|
|
return {
|
|
...result,
|
|
nodes: result.edges.map((e: any) => e.node),
|
|
}
|
|
},
|
|
}
|
|
)
|
|
const lastNodes = await executeOk({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 2 },
|
|
})
|
|
expect(lastNodes).toMatchSnapshot()
|
|
})
|
|
|
|
it('default arg validation: throws if no connection are provided', async () => {
|
|
const schema = makeTestSchema({})
|
|
const result = await execute({
|
|
schema,
|
|
document: parse(`{ users { edges { cursor } } }`),
|
|
variableValues: {},
|
|
})
|
|
expect(result).toEqual({
|
|
data: { users: null },
|
|
errors: [new GraphQLError('The Query.users connection field requires a "first" or "last" argument')],
|
|
})
|
|
})
|
|
|
|
it('default arg validation: allows first to be zero', async () => {
|
|
const schema = makeTestSchema({})
|
|
const result = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 0 },
|
|
})
|
|
expect(result).toEqual({
|
|
data: {
|
|
users: {
|
|
edges: [],
|
|
pageInfo: {
|
|
endCursor: null,
|
|
hasNextPage: true,
|
|
hasPreviousPage: false,
|
|
startCursor: null,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
it('default arg validation: allows last to be zero', async () => {
|
|
const schema = makeTestSchema({})
|
|
const result = await execute({
|
|
schema,
|
|
document: UsersLast,
|
|
variableValues: { last: 0 },
|
|
})
|
|
expect(result).toEqual({
|
|
data: {
|
|
users: {
|
|
edges: [],
|
|
pageInfo: {
|
|
endCursor: null,
|
|
hasNextPage: false,
|
|
hasPreviousPage: true,
|
|
startCursor: null,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
it('default arg validation: throws if both first & last are provided', async () => {
|
|
const schema = makeTestSchema({})
|
|
const result = await execute({
|
|
schema,
|
|
document: parse(`{ users(first: 2, last: 1) { edges { cursor } } }`),
|
|
variableValues: {},
|
|
})
|
|
expect(result).toEqual({
|
|
data: { users: null },
|
|
errors: [
|
|
new GraphQLError('The Query.users connection field requires a "first" or "last" argument, not both'),
|
|
],
|
|
})
|
|
})
|
|
|
|
it('default arg validation: throws if first & before are mixed', async () => {
|
|
const schema = makeTestSchema({})
|
|
const result = await execute({
|
|
schema,
|
|
document: parse(`{ users(first: 1, before: "FAKE") { edges { cursor } } }`),
|
|
variableValues: {},
|
|
})
|
|
expect(result).toEqual({
|
|
data: { users: null },
|
|
errors: [
|
|
new GraphQLError('The Query.users connection field does not allow a "before" argument with "first"'),
|
|
],
|
|
})
|
|
})
|
|
|
|
it('default arg validation: throws if last & after are mixed', async () => {
|
|
const schema = makeTestSchema({})
|
|
const result = await execute({
|
|
schema,
|
|
document: parse(`{ users(last: 2, after: "FAKE") { edges { cursor } } }`),
|
|
variableValues: {},
|
|
})
|
|
expect(result).toEqual({
|
|
data: { users: null },
|
|
errors: [
|
|
new GraphQLError('The Query.users connection field does not allow a "last" argument with "after"'),
|
|
],
|
|
})
|
|
})
|
|
|
|
it('returns null and logs an error if the nodes resolve is missing', async () => {
|
|
const consoleError = jest.spyOn(console, 'error').mockImplementation()
|
|
const schema = makeTestSchema(
|
|
{
|
|
includeNodesField: true,
|
|
},
|
|
{
|
|
nodes: undefined,
|
|
}
|
|
)
|
|
const lastNodes = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 2 },
|
|
})
|
|
expect(lastNodes.data?.users).toEqual(null)
|
|
expect(consoleError).toHaveBeenCalledTimes(1)
|
|
expect(consoleError).toHaveBeenLastCalledWith(
|
|
new Error('Nexus Connection Plugin: Missing nodes or resolve property for Query.users')
|
|
)
|
|
})
|
|
|
|
it('returns empty arrays, but warns if the nodes returns null', async () => {
|
|
const consoleWarn = jest.spyOn(console, 'warn').mockImplementation()
|
|
const schema = makeTestSchema(
|
|
{
|
|
includeNodesField: true,
|
|
},
|
|
{
|
|
nodes() {
|
|
return null as any
|
|
},
|
|
}
|
|
)
|
|
const lastNodes = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 2 },
|
|
})
|
|
expect(lastNodes.data?.users).toEqual({
|
|
edges: [],
|
|
nodes: [],
|
|
pageInfo: {
|
|
hasNextPage: false,
|
|
hasPreviousPage: false,
|
|
startCursor: null,
|
|
endCursor: null,
|
|
},
|
|
})
|
|
expect(consoleWarn).toHaveBeenCalledTimes(1)
|
|
expect(consoleWarn).toHaveBeenLastCalledWith(
|
|
'You resolved null/undefined from nodes() at path ["users"], this is likely an error. Return an empty array to suppress this warning.'
|
|
)
|
|
})
|
|
|
|
it('resolves any promises in nodes', async () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
nodes() {
|
|
return userNodes.map((node) => Promise.resolve(node))
|
|
},
|
|
}
|
|
)
|
|
const result = await execute({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 10 },
|
|
})
|
|
expect(result).toMatchSnapshot()
|
|
})
|
|
|
|
it('returns list as length of nodes if result is smaller than requested', async () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
includeNodesField: true,
|
|
},
|
|
{
|
|
nodes() {
|
|
return userNodes
|
|
},
|
|
}
|
|
)
|
|
const result = await executeOk({
|
|
schema,
|
|
document: UsersFirst,
|
|
variableValues: { first: 1000 },
|
|
})
|
|
expect(result.data?.users.nodes.length).toEqual(10)
|
|
})
|
|
})
|
|
|
|
describe('global plugin configuration', () => {
|
|
it('allows disabling forward pagination', () => {
|
|
const schema = makeTestSchema({
|
|
disableForwardPagination: true,
|
|
})
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('allows disabling backward pagination', () => {
|
|
const schema = makeTestSchema({
|
|
disableBackwardPagination: true,
|
|
})
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('allows disabling forward pagination w/ strictArgs:false to make `last` nullable', () => {
|
|
const schema = makeTestSchema({
|
|
disableForwardPagination: true,
|
|
strictArgs: false,
|
|
})
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('allows disabling backward pagination w/ strictArgs: false to make `first` nullable', () => {
|
|
const schema = makeTestSchema({
|
|
disableBackwardPagination: true,
|
|
strictArgs: false,
|
|
})
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('can configure additional fields for the connection globally', () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
extendConnection: {
|
|
totalCount: {
|
|
type: 'Int',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// @ts-ignore
|
|
totalCount: () => 1,
|
|
}
|
|
)
|
|
expect(printType(schema.getType('UserConnection')!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('logs error if the extendConnection resolver is not specified', () => {
|
|
const spy = jest.spyOn(console, 'error').mockImplementation()
|
|
makeTestSchema({
|
|
extendConnection: {
|
|
totalCount: {
|
|
type: 'Int',
|
|
},
|
|
},
|
|
})
|
|
expect(spy.mock.calls[0]).toMatchSnapshot()
|
|
expect(spy).toBeCalledTimes(1)
|
|
})
|
|
|
|
it('logs error if the extendEdge resolver is not specified', () => {
|
|
const spy = jest.spyOn(console, 'error').mockImplementation()
|
|
makeTestSchema({
|
|
extendEdge: {
|
|
totalCount: {
|
|
type: 'Int',
|
|
},
|
|
},
|
|
})
|
|
expect(spy.mock.calls[0]).toMatchSnapshot()
|
|
expect(spy).toBeCalledTimes(1)
|
|
})
|
|
|
|
it('can configure additional fields for the edge globally', () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
extendEdge: {
|
|
createdAt: {
|
|
type: 'String',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// @ts-ignore
|
|
edgeFields: {
|
|
createdAt: () => 'FakeDate',
|
|
},
|
|
}
|
|
)
|
|
expect(printType(schema.getType('UserEdge')!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('can include a "nodes" field, with an array of nodes', () => {
|
|
const schema = makeTestSchema({
|
|
includeNodesField: true,
|
|
})
|
|
expect(schema.getType('UserConnection')!).toMatchSnapshot()
|
|
})
|
|
|
|
it('can define additional args for all connections', () => {
|
|
const schema = makeTestSchema({
|
|
additionalArgs: {
|
|
order: arg({
|
|
type: 'String',
|
|
required: true,
|
|
description: 'This should be included',
|
|
}),
|
|
},
|
|
})
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
})
|
|
|
|
describe('field level configuration', () => {
|
|
it('can configure the connection per-instance', () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
extendConnection(t) {
|
|
t.int('totalCount', { resolve: () => 1 })
|
|
},
|
|
}
|
|
)
|
|
expect(printType(schema.getType('QueryUsers_Connection')!)).toMatchSnapshot()
|
|
expect(schema.getType('QueryUsers_Edge')).toBeUndefined()
|
|
})
|
|
|
|
it('can configure the edge per-instance', () => {
|
|
const schema = makeTestSchema(
|
|
{},
|
|
{
|
|
extendEdge(t) {
|
|
t.string('role', { resolve: () => 'admin' })
|
|
},
|
|
}
|
|
)
|
|
expect(printType(schema.getType('QueryUsers_Connection')!)).toMatchSnapshot()
|
|
expect(printType(schema.getType('QueryUsers_Edge')!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('can modify the behavior of cursorFromNode ', () => {})
|
|
|
|
it('can define additional args for the connection', () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
additionalArgs: {
|
|
order: arg({
|
|
type: 'String',
|
|
required: true,
|
|
description: 'This should be ignored',
|
|
}),
|
|
},
|
|
},
|
|
{
|
|
additionalArgs: {
|
|
filter: arg({
|
|
type: 'String',
|
|
description: 'This should be included',
|
|
}),
|
|
},
|
|
}
|
|
)
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('can inherit the additional args from the main config', () => {
|
|
const schema = makeTestSchema(
|
|
{
|
|
additionalArgs: {
|
|
order: arg({
|
|
type: 'String',
|
|
required: true,
|
|
description: 'This should be included',
|
|
}),
|
|
},
|
|
},
|
|
{
|
|
inheritAdditionalArgs: true,
|
|
additionalArgs: {
|
|
filter: arg({
|
|
type: 'String',
|
|
description: 'This should also be included',
|
|
}),
|
|
},
|
|
}
|
|
)
|
|
expect(printType(schema.getQueryType()!)).toMatchSnapshot()
|
|
})
|
|
|
|
it('can define a schema with multiple plugins, and separate them by typePrefix', () => {
|
|
const schema = makeSchema({
|
|
outputs: false,
|
|
types: [
|
|
objectType({
|
|
name: 'Query',
|
|
definition(t) {
|
|
// @ts-ignore
|
|
t.connectionField('users', {
|
|
type: User,
|
|
nodes(root: any, args: any, ctx: any, info: any) {
|
|
return userNodes
|
|
},
|
|
})
|
|
// @ts-ignore
|
|
t.analyticsConnectionField('userStats', {
|
|
type: User,
|
|
nodes() {
|
|
return userNodes
|
|
},
|
|
})
|
|
},
|
|
}),
|
|
],
|
|
plugins: [
|
|
connectionPlugin({}),
|
|
connectionPlugin({
|
|
typePrefix: 'Analytics',
|
|
nexusFieldName: 'analyticsConnectionField',
|
|
extendConnection: {
|
|
totalCount: { type: 'Int' },
|
|
averageCount: { type: 'Int' },
|
|
},
|
|
}),
|
|
],
|
|
nonNullDefaults: {
|
|
input: false,
|
|
output: false,
|
|
},
|
|
})
|
|
expect(printSchema(schema)).toMatchSnapshot()
|
|
})
|
|
})
|