nexus/tests/definitions.spec.ts

217 lines
6.3 KiB
TypeScript

/// <reference types="jest" />
import { GraphQLEnumType, GraphQLObjectType, printType } from 'graphql'
import type { TypeMap } from 'graphql/type/schema'
import { enumType, extendInputType, extendType, idArg, inputObjectType, makeSchema, objectType } from '../src'
import { list } from '../src/definitions/list'
import { nonNull } from '../src/definitions/nonNull'
import { PostObject, UserObject } from './__helpers'
enum NativeColors {
RED = 'RED',
BLUE = 'BLUE',
GREEN = 'green', // lower case to ensure we grab correct keys
}
enum NativeNumbers {
ONE = 1,
TWO = 2,
THREE = 3,
}
const buildTypes = <T extends TypeMap = any>(types: any) => {
return makeSchema({
types,
outputs: false,
}).getTypeMap() as T
}
describe('enumType', () => {
it('builds an enum', () => {
const PrimaryColors = enumType({
name: 'PrimaryColors',
members: ['RED', 'YELLOW', 'BLUE'],
})
const typeMap = buildTypes<{ PrimaryColors: GraphQLEnumType }>([PrimaryColors])
expect(typeMap.PrimaryColors).toBeInstanceOf(GraphQLEnumType)
expect(typeMap.PrimaryColors.getValues().map((v) => v.value)).toEqual(['RED', 'YELLOW', 'BLUE'])
})
it('builds an enum from a TypeScript enum with string values', () => {
const Colors = enumType({
name: 'Colors',
members: NativeColors,
})
const typeMap = buildTypes<{ Colors: GraphQLEnumType }>([Colors])
expect(typeMap.Colors).toBeInstanceOf(GraphQLEnumType)
expect(typeMap.Colors.getValues()).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: 'RED',
value: 'RED',
}),
expect.objectContaining({
name: 'BLUE',
value: 'BLUE',
}),
expect.objectContaining({
name: 'GREEN',
value: 'green',
}),
])
)
})
it('builds an enum from a TypeScript enum with number values', () => {
const Numbers = enumType({
name: 'Numbers',
members: NativeNumbers,
})
const typeMap = buildTypes<{ Numbers: GraphQLEnumType }>([Numbers])
expect(typeMap.Numbers).toBeInstanceOf(GraphQLEnumType)
expect(typeMap.Numbers.getValues()).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: 'ONE',
value: 1,
}),
expect.objectContaining({
name: 'TWO',
value: 2,
}),
expect.objectContaining({
name: 'THREE',
value: 3,
}),
])
)
})
it('can map internal values', () => {
const Internal = enumType({
name: 'Internal',
members: [
{ name: 'A', value: '--A--' },
{ name: 'B', value: '--B--' },
],
})
const typeMap = buildTypes<{ Internal: GraphQLEnumType }>([Internal])
expect(typeMap.Internal.getValues().map((v) => v.name)).toEqual(['A', 'B'])
expect(typeMap.Internal.getValues().map((v) => v.value)).toEqual(['--A--', '--B--'])
})
it('has object syntax for enum mapping', () => {
const MappedObj = enumType({
name: 'MappedObj',
members: {
a: 1,
b: 2,
},
})
const typeMap = buildTypes<{
MappedObj: GraphQLEnumType
}>([MappedObj])
expect(typeMap.MappedObj.getValues().map((v) => v.name)).toEqual(['a', 'b'])
expect(typeMap.MappedObj.getValues().map((v) => v.value)).toEqual([1, 2])
})
it('throws if the enum has no members', () => {
expect(() => {
const NoMembers = enumType({
name: 'NoMembers',
members: [],
})
const typeMap = buildTypes<{ NoMembers: GraphQLEnumType }>([NoMembers])
expect(typeMap.NoMembers.getValues()).toHaveLength(0)
}).toThrow('must have at least one member')
})
})
describe('objectType', () => {
it('should build an object type', () => {
const Account = objectType({
name: 'Account',
definition(t) {
t.id('id', { description: 'The ID of the account' })
t.string('name', { description: 'Holder of the account' })
t.string('email', {
description: 'The email of the person whos account this is',
})
t.field('nestedList', { type: list(nonNull(list('String'))) })
t.field({ name: 'nestedList2', type: list(nonNull(list('String'))) })
},
})
const typeMap = buildTypes<{ Account: GraphQLObjectType }>([Account])
const fields = typeMap.Account.getFields()
expect(Object.keys(fields).sort()).toEqual(['email', 'id', 'name', 'nestedList', 'nestedList2'])
expect(fields.nestedList.type.toString()).toEqual('[[String]!]')
expect(fields.nestedList2.type.toString()).toEqual('[[String]!]')
})
})
describe('extendType', () => {
it('should allow adding types to the Query type', () => {
const GetUser = extendType({
type: 'Query',
definition(t) {
t.field('user', { type: 'User', args: { id: idArg() } })
t.field({ name: 'user2', type: 'User', args: { id: idArg() } })
},
})
const GetPost = extendType({
type: 'Query',
definition(t) {
t.field('post', { type: PostObject })
t.field({ name: 'post2', type: PostObject })
},
})
expect(
Object.keys(
buildTypes<{ Query: GraphQLObjectType }>([GetUser, GetPost, PostObject, UserObject]).Query.getFields()
)
).toMatchSnapshot()
})
})
describe('inputObjectType', () => {
it('should output lists properly, #33', () => {
const buildTypesMap = buildTypes([
inputObjectType({
name: 'ExtraBasketInput',
definition(t) {
t.string('foo')
},
}),
inputObjectType({
name: 'AddToBasketInput',
definition(t) {
t.list.field('extras', { type: 'ExtraBasketInput' })
t.list.field({ name: 'extras2', type: 'ExtraBasketInput' })
},
}),
])
expect(printType(buildTypesMap.AddToBasketInput)).toMatchSnapshot()
})
})
describe('extendInputType', () => {
it('should allow extending input objects', () => {
const buildTypesMap = buildTypes([
inputObjectType({
name: 'InputTest',
definition(t) {
t.string('hello')
},
}),
extendInputType({
type: 'InputTest',
definition(t) {
t.string('world')
},
}),
])
expect(printType(buildTypesMap.InputTest)).toMatchSnapshot()
})
})