chore: passing graphql test suite

This commit is contained in:
Jarrod Flesch
2024-02-16 09:08:37 -05:00
parent 88457d726b
commit 366db1623b
11 changed files with 362 additions and 278 deletions

View File

@@ -12,6 +12,7 @@ import { initI18n } from '@payloadcms/translations'
import { getRequestLanguage } from './getRequestLanguage' import { getRequestLanguage } from './getRequestLanguage'
import { getRequestLocales } from './getRequestLocales' import { getRequestLocales } from './getRequestLocales'
import { getDataAndFile } from './getDataAndFile' import { getDataAndFile } from './getDataAndFile'
import { getDataLoader } from 'payload/utilities'
type Args = { type Args = {
request: Request request: Request
@@ -38,7 +39,8 @@ export const createPayloadRequest = async ({
const urlProperties = new URL(request.url) const urlProperties = new URL(request.url)
const { searchParams, pathname } = urlProperties const { searchParams, pathname } = urlProperties
const isGraphQL = !config.graphQL.disable && pathname === `/api${config.routes.graphQL}` const isGraphQL =
!config.graphQL.disable && pathname === `${config.routes.api}${config.routes.graphQL}`
const { data, file } = await getDataAndFile({ const { data, file } = await getDataAndFile({
request, request,
@@ -96,6 +98,7 @@ export const createPayloadRequest = async ({
} }
const req: PayloadRequest = Object.assign(request, customRequest) const req: PayloadRequest = Object.assign(request, customRequest)
req.payloadDataLoader = getDataLoader(req)
req.user = await getAuthenticatedUser({ req.user = await getAuthenticatedUser({
payload, payload,

View File

@@ -1,34 +1,36 @@
export { getDataLoader } from '../collections/dataloader'
export { default as getDefaultValue } from '../fields/getDefaultValue' export { default as getDefaultValue } from '../fields/getDefaultValue'
export { promise as afterReadPromise } from '../fields/hooks/afterRead/promise' export { promise as afterReadPromise } from '../fields/hooks/afterRead/promise'
export { traverseFields as afterReadTraverseFields } from '../fields/hooks/afterRead/traverseFields' export { traverseFields as afterReadTraverseFields } from '../fields/hooks/afterRead/traverseFields'
export { extractTranslations } from '../translations/extractTranslations' export { extractTranslations } from '../translations/extractTranslations'
export { default as isImage } from '../uploads/isImage' export { default as isImage } from '../uploads/isImage'
export { combineMerge } from '../utilities/combineMerge' export { combineMerge } from '../utilities/combineMerge'
export { export {
configToJSONSchema, configToJSONSchema,
entityToJSONSchema, entityToJSONSchema,
withNullableJSONSchemaType, withNullableJSONSchemaType,
} from '../utilities/configToJSONSchema' } from '../utilities/configToJSONSchema'
export { createArrayFromCommaDelineated } from '../utilities/createArrayFromCommaDelineated'
export { createArrayFromCommaDelineated } from '../utilities/createArrayFromCommaDelineated'
export { deepCopyObject } from '../utilities/deepCopyObject' export { deepCopyObject } from '../utilities/deepCopyObject'
export { deepMerge } from '../utilities/deepMerge' export { deepMerge } from '../utilities/deepMerge'
export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON' export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON'
export { default as flattenTopLevelFields } from '../utilities/flattenTopLevelFields' export { default as flattenTopLevelFields } from '../utilities/flattenTopLevelFields'
export { formatLabels, formatNames, toWords } from '../utilities/formatLabels' export { formatLabels, formatNames, toWords } from '../utilities/formatLabels'
export { getIDType } from '../utilities/getIDType'
export { getIDType } from '../utilities/getIDType'
export { getObjectDotNotation } from '../utilities/getObjectDotNotation' export { getObjectDotNotation } from '../utilities/getObjectDotNotation'
export { default as getUniqueListBy } from '../utilities/getUniqueListBy' export { default as getUniqueListBy } from '../utilities/getUniqueListBy'
export { isNumber } from '../utilities/isNumber' export { isNumber } from '../utilities/isNumber'
export { isValidID } from '../utilities/isValidID' export { isValidID } from '../utilities/isValidID'
export { setsAreEqual } from '../utilities/setsAreEqual' export { setsAreEqual } from '../utilities/setsAreEqual'
export { splitPathByArrayFields } from '../utilities/splitPathByArrayFields' export { splitPathByArrayFields } from '../utilities/splitPathByArrayFields'
export { default as toKebabCase } from '../utilities/toKebabCase' export { default as toKebabCase } from '../utilities/toKebabCase'
export { default as wait } from '../utilities/wait' export { default as wait } from '../utilities/wait'
export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex' export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex'

View File

@@ -66,7 +66,10 @@ export type CustomPayloadRequest<U = any> = {
transactionIDPromise?: Promise<void> transactionIDPromise?: Promise<void>
/** The signed in user */ /** The signed in user */
user: (U & User) | null user: (U & User) | null
} & Pick<URL, 'host' | 'origin' | 'pathname' | 'protocol' | 'searchParams'> } & Pick<
URL,
'hash' | 'host' | 'href' | 'origin' | 'pathname' | 'port' | 'protocol' | 'search' | 'searchParams'
>
export type PayloadRequest<U = any> = Partial<Request> & export type PayloadRequest<U = any> = Partial<Request> &
Required<Pick<Request, 'headers'>> & Required<Pick<Request, 'headers'>> &
CustomPayloadRequest<U> CustomPayloadRequest<U>

View File

@@ -1,9 +1,11 @@
import type { Payload } from '../../packages/payload/src'
import type { PayloadRequest } from '../../packages/payload/src/types' import type { PayloadRequest } from '../../packages/payload/src/types'
import type { Post, RelyOnRequestHeader, Restricted } from './payload-types' import type { Post, RelyOnRequestHeader, Restricted } from './payload-types'
import payload from '../../packages/payload/src' import { getPayload } from '../../packages/payload/src'
import { Forbidden } from '../../packages/payload/src/errors' import { Forbidden } from '../../packages/payload/src/errors'
import { initPayloadTest } from '../helpers/configHelpers' import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config'
import { requestHeaders } from './config' import { requestHeaders } from './config'
import { import {
firstArrayText, firstArrayText,
@@ -17,12 +19,15 @@ import {
slug, slug,
} from './shared' } from './shared'
let payload: Payload
describe('Access Control', () => { describe('Access Control', () => {
let post1: Post let post1: Post
let restricted: Restricted let restricted: Restricted
beforeAll(async () => { beforeAll(async () => {
await initPayloadTest({ __dirname }) const config = await startMemoryDB(configPromise)
payload = await getPayload({ config })
}) })
beforeEach(async () => { beforeEach(async () => {

View File

@@ -1,10 +1,11 @@
import { buildConfigWithDefaults } from '../buildConfigWithDefaults' import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
import { devUser } from '../credentials' import { devUser } from '../credentials'
import { arraySlug } from './shared'
export default buildConfigWithDefaults({ export default buildConfigWithDefaults({
collections: [ collections: [
{ {
slug: 'arrays', slug: arraySlug,
fields: [ fields: [
{ {
name: 'arrayOfFields', name: 'arrayOfFields',

View File

@@ -1,14 +1,16 @@
import payload from '../../packages/payload/src' import type { Payload } from '../../packages/payload/src'
import { initPayloadTest } from '../helpers/configHelpers'
import configPromise from './config'
let collection: string import { getPayload } from '../../packages/payload/src'
import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config'
import { arraySlug } from './shared'
let payload: Payload
describe('array-update', () => { describe('array-update', () => {
beforeAll(async () => { beforeAll(async () => {
const config = await configPromise const config = await startMemoryDB(configPromise)
collection = config.collections[0]?.slug payload = await getPayload({ config })
await initPayloadTest({ __dirname })
}) })
afterAll(async () => { afterAll(async () => {
@@ -21,7 +23,7 @@ describe('array-update', () => {
const originalText = 'some optional text' const originalText = 'some optional text'
const doc = await payload.create({ const doc = await payload.create({
collection, collection: arraySlug,
data: { data: {
arrayOfFields: [ arrayOfFields: [
{ {
@@ -47,7 +49,7 @@ describe('array-update', () => {
const updatedDoc = await payload.update({ const updatedDoc = await payload.update({
id: doc.id, id: doc.id,
collection, collection: arraySlug,
data: { data: {
arrayOfFields: arrayWithExistingValues, arrayOfFields: arrayWithExistingValues,
}, },
@@ -68,7 +70,7 @@ describe('array-update', () => {
} }
const doc = await payload.create({ const doc = await payload.create({
collection, collection: arraySlug,
data: { data: {
arrayOfFields: [ arrayOfFields: [
{ {
@@ -82,7 +84,7 @@ describe('array-update', () => {
const updatedDoc = await payload.update({ const updatedDoc = await payload.update({
id: doc.id, id: doc.id,
collection, collection: arraySlug,
data: { data: {
arrayOfFields: [ arrayOfFields: [
{ {

View File

@@ -0,0 +1 @@
export const arraySlug = 'arrays'

View File

@@ -71,15 +71,6 @@ describe('Auth', () => {
}) })
describe('REST - admin user', () => { describe('REST - admin user', () => {
beforeAll(async () => {
await restClient.POST(`/${slug}/first-register`, {
body: JSON.stringify({
email,
password,
}),
})
})
it('should prevent registering a new first user', async () => { it('should prevent registering a new first user', async () => {
const response = await restClient.POST(`/${slug}/first-register`, { const response = await restClient.POST(`/${slug}/first-register`, {
body: JSON.stringify({ body: JSON.stringify({

View File

@@ -286,6 +286,7 @@ export default buildConfigWithDefaults({
}, },
}, },
{ {
slug: 'payload-api-test-ones',
access: { access: {
read: () => true, read: () => true,
}, },
@@ -298,9 +299,9 @@ export default buildConfigWithDefaults({
type: 'text', type: 'text',
}, },
], ],
slug: 'payload-api-test-ones',
}, },
{ {
slug: 'payload-api-test-twos',
access: { access: {
read: () => true, read: () => true,
}, },
@@ -318,7 +319,6 @@ export default buildConfigWithDefaults({
type: 'relationship', type: 'relationship',
}, },
], ],
slug: 'payload-api-test-twos',
}, },
{ {
access: { access: {
@@ -328,7 +328,7 @@ export default buildConfigWithDefaults({
{ {
name: 'contentType', name: 'contentType',
hooks: { hooks: {
afterRead: [({ req }) => req.headers?.['content-type']], afterRead: [({ req }) => req.headers?.get('content-type')],
}, },
type: 'text', type: 'text',
}, },
@@ -483,7 +483,7 @@ export default buildConfigWithDefaults({
data: {}, data: {},
}) })
await payload.create({ const t = await payload.create({
collection: 'payload-api-test-twos', collection: 'payload-api-test-twos',
data: { data: {
relation: payloadAPITest1.id, relation: payloadAPITest1.id,

View File

@@ -1,34 +1,35 @@
import { GraphQLClient } from 'graphql-request' import type { Payload } from '../../packages/payload/src'
import type { Post } from './payload-types' import type { Post } from './payload-types'
import payload from '../../packages/payload/src' import { getPayload } from '../../packages/payload/src'
import { mapAsync } from '../../packages/payload/src/utilities/mapAsync' import { mapAsync } from '../../packages/payload/src/utilities/mapAsync'
import { initPayloadTest } from '../helpers/configHelpers' import { NextRESTClient } from '../helpers/NextRESTClient'
import { idToString } from '../helpers/idToString' import { idToString } from '../helpers/idToString'
import { startMemoryDB } from '../startMemoryDB'
import configPromise, { errorOnHookSlug, pointSlug, relationSlug, slug } from './config' import configPromise, { errorOnHookSlug, pointSlug, relationSlug, slug } from './config'
const title = 'title' const title = 'title'
let client: GraphQLClient let restClient: NextRESTClient
let payload: Payload
describe('collections-graphql', () => { describe('collections-graphql', () => {
beforeAll(async () => { beforeAll(async () => {
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } }) const config = await startMemoryDB(configPromise)
const config = await configPromise payload = await getPayload({ config })
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}` restClient = new NextRESTClient(payload.config)
client = new GraphQLClient(url)
// TODO: reenable when we migrate back to mongoose v6
// Wait for indexes to be created, // Wait for indexes to be created,
// as we need them to query by point // as we need them to query by point
if (payload.db.name === 'mongoose') { // if (payload.db.name === 'mongoose') {
await new Promise((resolve, reject) => { // await new Promise((resolve, reject) => {
payload.db?.collections?.point?.ensureIndexes(function (err) { // payload.db?.collections?.point?.ensureIndexes(function (err) {
if (err) reject(err) // if (err) reject(err)
resolve(true) // resolve(true)
}) // })
}) // })
} // }
}) })
afterAll(async () => { afterAll(async () => {
@@ -53,8 +54,11 @@ describe('collections-graphql', () => {
title title
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const doc: Post = response.createPost .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const doc: Post = data.createPost
expect(doc).toMatchObject({ title }) expect(doc).toMatchObject({ title })
expect(doc.id).toBeDefined() expect(doc.id).toBeDefined()
@@ -67,8 +71,16 @@ describe('collections-graphql', () => {
title title
} }
}` }`
const response = (await client.request(query, { title })) as any const { data } = await restClient
const doc: Post = response.createPost .GRAPHQL_POST({
body: JSON.stringify({
query,
variables: { title },
}),
})
.then((res) => res.json())
const doc: Post = data.createPost
expect(doc).toMatchObject({ title }) expect(doc).toMatchObject({ title })
expect(doc.id).toBeDefined() expect(doc.id).toBeDefined()
@@ -81,8 +93,10 @@ describe('collections-graphql', () => {
title title
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const doc: Post = response.Post .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const doc: Post = data.Post
expect(doc).toMatchObject({ id: existingDoc.id, title }) expect(doc).toMatchObject({ id: existingDoc.id, title })
}) })
@@ -96,8 +110,10 @@ describe('collections-graphql', () => {
} }
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: existingDoc.id })) expect(docs).toContainEqual(expect.objectContaining({ id: existingDoc.id }))
}) })
@@ -120,8 +136,10 @@ describe('collections-graphql', () => {
title title
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { postIDs, posts, singlePost } = response .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { postIDs, posts, singlePost } = data
expect(postIDs.docs).toBeDefined() expect(postIDs.docs).toBeDefined()
expect(posts.docs).toBeDefined() expect(posts.docs).toBeDefined()
expect(singlePost.id).toBeDefined() expect(singlePost.id).toBeDefined()
@@ -167,12 +185,12 @@ describe('collections-graphql', () => {
} }
}` }`
client.requestConfig.errorPolicy = 'all' const { data } = await restClient
const response = await client.request(query) .GRAPHQL_POST({ body: JSON.stringify({ query }) })
client.requestConfig.errorPolicy = 'none' .then((res) => res.json())
const createdResult = await payload.findByID({ const createdResult = await payload.findByID({
id: response.createPost.id, id: data.createPost.id,
collection: slug, collection: slug,
}) })
const updateFirstResult = await payload.findByID({ const updateFirstResult = await payload.findByID({
@@ -184,11 +202,11 @@ describe('collections-graphql', () => {
collection: errorOnHookSlug, collection: errorOnHookSlug,
}) })
expect(response?.createPost.id).toBeDefined() expect(data?.createPost.id).toBeDefined()
expect(response?.updateFirst).toBeNull() expect(data?.updateFirst).toBeNull()
expect(response?.updateSecond).toBeNull() expect(data?.updateSecond).toBeNull()
expect(createdResult).toMatchObject(response.createPost) expect(createdResult).toMatchObject(data.createPost)
expect(updateFirstResult).toMatchObject(first) expect(updateFirstResult).toMatchObject(first)
expect(updateSecondResult).toStrictEqual(second) expect(updateSecondResult).toStrictEqual(second)
}) })
@@ -198,6 +216,7 @@ describe('collections-graphql', () => {
query { query {
PayloadApiTestTwos { PayloadApiTestTwos {
docs { docs {
id
payloadAPI payloadAPI
relation { relation {
payloadAPI payloadAPI
@@ -206,9 +225,10 @@ describe('collections-graphql', () => {
} }
} }
` `
const { data } = await restClient
const response = await client.request(query) .GRAPHQL_POST({ body: JSON.stringify({ query }) })
const res = response.PayloadApiTestTwos .then((res) => res.json())
const res = data.PayloadApiTestTwos
expect(res.docs[0].relation.payloadAPI).toStrictEqual('GraphQL') expect(res.docs[0].relation.payloadAPI).toStrictEqual('GraphQL')
}) })
@@ -221,8 +241,10 @@ describe('collections-graphql', () => {
} }
} }
}` }`
const response = await client.request(query) const { data } = await restClient
expect(response.ContentTypes?.docs[0]?.contentType).toEqual('application/json') .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
expect(data.ContentTypes?.docs[0]?.contentType).toEqual('application/json')
}) })
it('should update existing', async () => { it('should update existing', async () => {
@@ -234,8 +256,10 @@ describe('collections-graphql', () => {
title title
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const doc: Post = response.updatePost .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const doc: Post = data.updatePost
expect(doc).toMatchObject({ id: existingDoc.id, title: updatedTitle }) expect(doc).toMatchObject({ id: existingDoc.id, title: updatedTitle })
}) })
@@ -247,8 +271,14 @@ describe('collections-graphql', () => {
title title
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const doc: Post = response.deletePost .GRAPHQL_POST({
body: JSON.stringify({
query,
}),
})
.then((res) => res.json())
const doc: Post = data.deletePost
expect(doc).toMatchObject({ id: existingDoc.id }) expect(doc).toMatchObject({ id: existingDoc.id })
}) })
@@ -266,32 +296,35 @@ describe('collections-graphql', () => {
it('equals', async () => { it('equals', async () => {
const query = `query { const query = `query {
Posts(where:{title: {equals:"${post1.title}"}}) { Posts(where:{title: {equals:"${post1.title}"}}) {
docs { docs {
id id
title title
}
} }
} }`
}` const { data } = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
const response = await client.request(query) .then((res) => res.json())
const { docs } = response.Posts const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: post1.id, title: post1.title })) expect(docs).toContainEqual(expect.objectContaining({ id: post1.id, title: post1.title }))
}) })
it('not_equals', async () => { it('not_equals', async () => {
const query = `query { const query = `query {
Posts(where:{title: {not_equals:"${post1.title}"}}) { Posts(where:{title: {not_equals:"${post1.title}"}}) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
const docsWithWhereTitleNotEqualPostTitle = docs.filter( const docsWithWhereTitleNotEqualPostTitle = docs.filter(
(post) => post.title === post1.title, (post) => post.title === post1.title,
) )
@@ -302,32 +335,36 @@ describe('collections-graphql', () => {
it('like', async () => { it('like', async () => {
const postWithWords = await createPost({ title: 'the quick brown fox' }) const postWithWords = await createPost({ title: 'the quick brown fox' })
const query = `query { const query = `query {
Posts(where:{title: {like:"${postWithWords.title?.split(' ')[1]}"}}) { Posts(where:{title: {like:"${postWithWords.title?.split(' ')[1]}"}}) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs[0]).toMatchObject({ id: postWithWords.id, title: postWithWords.title }) expect(docs[0]).toMatchObject({ id: postWithWords.id, title: postWithWords.title })
}) })
it('contains', async () => { it('contains', async () => {
const query = `query { const query = `query {
Posts(where:{title: {contains:"${post1.title?.slice(0, 4)}"}}) { Posts(where:{title: {contains:"${post1.title?.slice(0, 4)}"}}) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: post1.id, title: post1.title })) expect(docs).toContainEqual(expect.objectContaining({ id: post1.id, title: post1.title }))
expect(docs).toContainEqual(expect.objectContaining({ id: post2.id, title: post2.title })) expect(docs).toContainEqual(expect.objectContaining({ id: post2.id, title: post2.title }))
@@ -336,16 +373,18 @@ describe('collections-graphql', () => {
it('exists - true', async () => { it('exists - true', async () => {
const withDescription = await createPost({ description: 'description' }) const withDescription = await createPost({ description: 'description' })
const query = `query { const query = `query {
Posts(where:{description: {exists:true}}) { Posts(where:{description: {exists:true}}) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual( expect(docs).toContainEqual(
expect.objectContaining({ id: withDescription.id, title: withDescription.title }), expect.objectContaining({ id: withDescription.id, title: withDescription.title }),
@@ -355,16 +394,17 @@ describe('collections-graphql', () => {
it('exists - false', async () => { it('exists - false', async () => {
const withDescription = await createPost({ description: 'description' }) const withDescription = await createPost({ description: 'description' })
const query = `query { const query = `query {
Posts(where:{description: {exists:false}}) { Posts(where:{description: {exists:false}}) {
docs { docs {
id id
title title
}
} }
} }`
}` const { data } = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
const response = await client.request(query) .then((res) => res.json())
const { docs } = response.Posts const { docs } = data.Posts
expect(docs).not.toContainEqual(expect.objectContaining({ id: withDescription.id })) expect(docs).not.toContainEqual(expect.objectContaining({ id: withDescription.id }))
expect(docs).toContainEqual(expect.objectContaining({ id: post1.id })) expect(docs).toContainEqual(expect.objectContaining({ id: post1.id }))
@@ -381,32 +421,34 @@ describe('collections-graphql', () => {
it('greater_than', async () => { it('greater_than', async () => {
const query = `query { const query = `query {
Posts(where:{number: {greater_than:1}}) { Posts(where:{number: {greater_than:1}}) {
docs { docs {
id id
title title
number number
}
} }
} }`
}` const { data } = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
const response = await client.request(query) .then((res) => res.json())
const { docs } = response.Posts const { docs } = data.Posts
expect(docs.map(({ id }) => id)).toContain(numPost2.id) expect(docs.map(({ id }) => id)).toContain(numPost2.id)
}) })
it('greater_than_equal', async () => { it('greater_than_equal', async () => {
const query = `query { const query = `query {
Posts(where:{number: {greater_than_equal:1}}) { Posts(where:{number: {greater_than_equal:1}}) {
docs { docs {
id id
title title
}
} }
} }`
}` const { data } = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
const response = await client.request(query) .then((res) => res.json())
const { docs } = response.Posts const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: numPost1.id })) expect(docs).toContainEqual(expect.objectContaining({ id: numPost1.id }))
expect(docs).toContainEqual(expect.objectContaining({ id: numPost2.id })) expect(docs).toContainEqual(expect.objectContaining({ id: numPost2.id }))
@@ -414,32 +456,36 @@ describe('collections-graphql', () => {
it('less_than', async () => { it('less_than', async () => {
const query = `query { const query = `query {
Posts(where:{number: {less_than:2}}) { Posts(where:{number: {less_than:2}}) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: numPost1.id })) expect(docs).toContainEqual(expect.objectContaining({ id: numPost1.id }))
}) })
it('less_than_equal', async () => { it('less_than_equal', async () => {
const query = `query { const query = `query {
Posts(where:{number: {less_than_equal:2}}) { Posts(where:{number: {less_than_equal:2}}) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: numPost1.id })) expect(docs).toContainEqual(expect.objectContaining({ id: numPost1.id }))
expect(docs).toContainEqual(expect.objectContaining({ id: numPost2.id })) expect(docs).toContainEqual(expect.objectContaining({ id: numPost2.id }))
@@ -448,18 +494,20 @@ describe('collections-graphql', () => {
it('or', async () => { it('or', async () => {
const query = `query { const query = `query {
Posts( Posts(
where: {OR: [{ title: { equals: "${post1.title}" } }, { title: { equals: "${post2.title}" } }] where: {OR: [{ title: { equals: "${post1.title}" } }, { title: { equals: "${post2.title}" } }]
}) { }) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: post1.id })) expect(docs).toContainEqual(expect.objectContaining({ id: post1.id }))
expect(docs).toContainEqual(expect.objectContaining({ id: post2.id })) expect(docs).toContainEqual(expect.objectContaining({ id: post2.id }))
@@ -467,18 +515,20 @@ describe('collections-graphql', () => {
it('or - 1 result', async () => { it('or - 1 result', async () => {
const query = `query { const query = `query {
Posts( Posts(
where: {OR: [{ title: { equals: "${post1.title}" } }, { title: { equals: "nope" } }] where: {OR: [{ title: { equals: "${post1.title}" } }, { title: { equals: "nope" } }]
}) { }) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: post1.id })) expect(docs).toContainEqual(expect.objectContaining({ id: post1.id }))
expect(docs).not.toContainEqual(expect.objectContaining({ id: post2.id })) expect(docs).not.toContainEqual(expect.objectContaining({ id: post2.id }))
@@ -488,22 +538,24 @@ describe('collections-graphql', () => {
const specialPost = await createPost({ description: 'special-123123' }) const specialPost = await createPost({ description: 'special-123123' })
const query = `query { const query = `query {
Posts( Posts(
where: { where: {
AND: [ AND: [
{ title: { equals: "${specialPost.title}" } } { title: { equals: "${specialPost.title}" } }
{ description: { equals: "${specialPost.description}" } } { description: { equals: "${specialPost.description}" } }
] ]
}) { }) {
docs { docs {
id id
title title
}
} }
} }`
}`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual(expect.objectContaining({ id: specialPost.id })) expect(docs).toContainEqual(expect.objectContaining({ id: specialPost.id }))
}) })
@@ -530,8 +582,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(nearQuery) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query: nearQuery }) })
.then((res) => res.json())
const { docs } = data.Points
expect(docs).toHaveLength(1) expect(docs).toHaveLength(1)
}) })
@@ -553,8 +607,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(nearQuery) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query: nearQuery }) })
.then((res) => res.json())
const { docs } = data.Points
expect(docs).toHaveLength(0) expect(docs).toHaveLength(0)
}) })
@@ -591,8 +647,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(nearQuery) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query: nearQuery }) })
.then((res) => res.json())
const { docs } = data.Points
let previous = 0 let previous = 0
docs.forEach(({ point: coordinates }) => { docs.forEach(({ point: coordinates }) => {
@@ -632,8 +690,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Points
expect(docs).toHaveLength(1) expect(docs).toHaveLength(1)
expect(docs[0].point).toEqual([10, 20]) expect(docs[0].point).toEqual([10, 20])
@@ -659,8 +719,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Points
expect(docs).toHaveLength(0) expect(docs).toHaveLength(0)
}) })
@@ -695,8 +757,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Points
expect(docs).toHaveLength(1) expect(docs).toHaveLength(1)
expect(docs[0].point).toEqual([10, 20]) expect(docs[0].point).toEqual([10, 20])
@@ -722,8 +786,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Points .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Points
expect(docs).toHaveLength(0) expect(docs).toHaveLength(0)
}) })
@@ -746,8 +812,10 @@ describe('collections-graphql', () => {
} }
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs).toContainEqual( expect(docs).toContainEqual(
expect.objectContaining({ expect.objectContaining({
@@ -773,8 +841,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs, totalDocs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs, totalDocs } = data.Posts
expect(totalDocs).toStrictEqual(1) expect(totalDocs).toStrictEqual(1)
expect(docs[0].relationToCustomID.id).toStrictEqual(1) expect(docs[0].relationToCustomID.id).toStrictEqual(1)
@@ -814,8 +884,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs[0].relationField).toBeFalsy() expect(docs[0].relationField).toBeFalsy()
}) })
@@ -854,8 +926,10 @@ describe('collections-graphql', () => {
} }
}` }`
const response = await client.request(query) const { data } = await restClient
const { docs } = response.Posts .GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const { docs } = data.Posts
expect(docs[0].relationHasManyField).toHaveLength(0) expect(docs[0].relationHasManyField).toHaveLength(0)
}) })
@@ -864,9 +938,6 @@ describe('collections-graphql', () => {
describe('Error Handler', () => { describe('Error Handler', () => {
it('should return have an array of errors when making a bad request', async () => { it('should return have an array of errors when making a bad request', async () => {
let error
// language=graphQL
const query = `query { const query = `query {
Posts(where: { title: { exists: true }}) { Posts(where: { title: { exists: true }}) {
docs { docs {
@@ -874,16 +945,16 @@ describe('collections-graphql', () => {
} }
} }
}` }`
await client.request(query).catch((err) => { const { errors } = await restClient
error = err .GRAPHQL_POST({
}) body: JSON.stringify({ query }),
expect(Array.isArray(error.response.errors)).toBe(true) })
expect(typeof error.response.errors[0].message).toBe('string') .then((res) => res.json())
expect(Array.isArray(errors)).toBe(true)
expect(typeof errors[0].message).toBe('string')
}) })
it('should return have an array of errors when failing to pass validation', async () => { it('should return have an array of errors when failing to pass validation', async () => {
let error
// language=graphQL
const query = `mutation { const query = `mutation {
createPost(data: {min: 1}) { createPost(data: {min: 1}) {
id id
@@ -893,17 +964,17 @@ describe('collections-graphql', () => {
} }
}` }`
await client.request(query).catch((err) => { const { errors } = await restClient
error = err .GRAPHQL_POST({
}) body: JSON.stringify({ query }),
expect(Array.isArray(error.response.errors)).toBe(true) })
expect(error.response.errors[0].message).toEqual('The following field is invalid: min') .then((res) => res.json())
expect(typeof error.response.errors[0].locations).toBeDefined() expect(Array.isArray(errors)).toBe(true)
expect(errors[0].message).toEqual('The following field is invalid: min')
expect(typeof errors[0].locations).toBeDefined()
}) })
it('should return have an array of errors when failing multiple mutations', async () => { it('should return have an array of errors when failing multiple mutations', async () => {
let error
// language=graphQL
const query = `mutation createTest { const query = `mutation createTest {
test1:createUser(data: { email: "test@test.com", password: "test" }) { test1:createUser(data: { email: "test@test.com", password: "test" }) {
email email
@@ -922,36 +993,36 @@ describe('collections-graphql', () => {
} }
}` }`
await client.request(query).catch((err) => { const { errors } = await restClient
error = err .GRAPHQL_POST({
}) body: JSON.stringify({ query }),
})
.then((res) => res.json())
expect(Array.isArray(error.response.errors)).toBe(true) expect(Array.isArray(errors)).toBe(true)
expect(Array.isArray(error.response.errors[0].locations)).toEqual(true) expect(Array.isArray(errors[0].locations)).toEqual(true)
expect(error.response.errors[0].message).toEqual('The following field is invalid: password') expect(errors[0].message).toEqual('The following field is invalid: password')
expect(error.response.errors[0].path[0]).toEqual('test2') expect(errors[0].path[0]).toEqual('test2')
expect(error.response.errors[0].extensions.name).toEqual('ValidationError') expect(errors[0].extensions.name).toEqual('ValidationError')
expect(error.response.errors[0].extensions.data[0].message).toEqual('No password was given') expect(errors[0].extensions.data[0].message).toEqual('No password was given')
expect(error.response.errors[0].extensions.data[0].field).toEqual('password') expect(errors[0].extensions.data[0].field).toEqual('password')
expect(Array.isArray(error.response.errors[1].locations)).toEqual(true) expect(Array.isArray(errors[1].locations)).toEqual(true)
expect(error.response.errors[1].message).toEqual('The following field is invalid: email') expect(errors[1].message).toEqual('The following field is invalid: email')
expect(error.response.errors[1].path[0]).toEqual('test3') expect(errors[1].path[0]).toEqual('test3')
expect(error.response.errors[1].extensions.name).toEqual('ValidationError') expect(errors[1].extensions.name).toEqual('ValidationError')
expect(error.response.errors[1].extensions.data[0].message).toEqual( expect(errors[1].extensions.data[0].message).toEqual(
'A user with the given email is already registered', 'A user with the given email is already registered',
) )
expect(error.response.errors[1].extensions.data[0].field).toEqual('email') expect(errors[1].extensions.data[0].field).toEqual('email')
expect(Array.isArray(error.response.errors[2].locations)).toEqual(true) expect(Array.isArray(errors[2].locations)).toEqual(true)
expect(error.response.errors[2].message).toEqual('The following field is invalid: email') expect(errors[2].message).toEqual('The following field is invalid: email')
expect(error.response.errors[2].path[0]).toEqual('test4') expect(errors[2].path[0]).toEqual('test4')
expect(error.response.errors[2].extensions.name).toEqual('ValidationError') expect(errors[2].extensions.name).toEqual('ValidationError')
expect(error.response.errors[2].extensions.data[0].message).toEqual( expect(errors[2].extensions.data[0].message).toEqual('Please enter a valid email address.')
'Please enter a valid email address.', expect(errors[2].extensions.data[0].field).toEqual('email')
)
expect(error.response.errors[2].extensions.data[0].field).toEqual('email')
}) })
it('should return the minimum allowed information about internal errors', async () => { it('should return the minimum allowed information about internal errors', async () => {
@@ -963,16 +1034,18 @@ describe('collections-graphql', () => {
} }
}` }`
await client.request(query).catch((err) => { const { errors } = await restClient
error = err .GRAPHQL_POST({
}) body: JSON.stringify({ query }),
})
.then((res) => res.json())
expect(Array.isArray(error.response.errors)).toBe(true) expect(Array.isArray(errors)).toBe(true)
expect(Array.isArray(error.response.errors[0].locations)).toEqual(true) expect(Array.isArray(errors[0].locations)).toEqual(true)
expect(error.response.errors[0].message).toEqual('Something went wrong.') expect(errors[0].message).toEqual('Something went wrong.')
expect(error.response.errors[0].path[0]).toEqual('QueryWithInternalError') expect(errors[0].path[0]).toEqual('QueryWithInternalError')
expect(error.response.errors[0].extensions.statusCode).toEqual(500) expect(errors[0].extensions.statusCode).toEqual(500)
expect(error.response.errors[0].extensions.name).toEqual('Error') expect(errors[0].extensions.name).toEqual('Error')
}) })
}) })
}) })

View File

@@ -61,14 +61,17 @@ export class NextRESTClient {
} }
async GRAPHQL_POST(options: RequestInit): Promise<Response> { async GRAPHQL_POST(options: RequestInit): Promise<Response> {
const request = new Request(`${this.serverURL}${this.config.routes.graphQL}`, { const request = new Request(
...options, `${this.serverURL}${this.config.routes.api}${this.config.routes.graphQL}`,
method: 'POST', {
headers: new Headers({ ...options,
'Content-Type': 'application/json', method: 'POST',
...(options?.headers || {}), headers: new Headers({
}), 'Content-Type': 'application/json',
}) ...(options?.headers || {}),
}),
},
)
return this._GRAPHQL_POST(request) return this._GRAPHQL_POST(request)
} }