Files
payload/test/graphql/int.spec.ts
Sasha 3fb81ef43b fix(graphql): nextPage and prevPage are non nullable even though they can be null sometimes (#12201)
This PR introduced https://github.com/payloadcms/payload/pull/11952
improvement for graphql schema with making fields of the `Paginated<T>`
interface non-nullable.

However, there are a few special ones - `nextPage` and `prevPage`. They
can be `null` when:
The result returned 0 docs.
The result returned `x` docs, but in the DB we don't have `x+1` doc.
Thus, `nextPage` will be `null`. The result will have `nextPage: null`.
Finally, when we query 1st page, `prevPage` is `null` as well.

<img width="873" alt="image"
src="https://github.com/user-attachments/assets/04d04b13-ac26-4fc1-b421-b5f86efc9b65"
/>
2025-05-05 09:12:44 -04:00

154 lines
3.5 KiB
TypeScript

import type { Payload } from 'payload'
import path from 'path'
import { fileURLToPath } from 'url'
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
import { idToString } from '../helpers/idToString.js'
import { initPayloadInt } from '../helpers/initPayloadInt.js'
let payload: Payload
let restClient: NextRESTClient
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
describe('graphql', () => {
beforeAll(async () => {
;({ payload, restClient } = await initPayloadInt(dirname))
})
afterAll(async () => {
if (typeof payload.db.destroy === 'function') {
await payload.db.destroy()
}
})
describe('graphql', () => {
it('should not be able to query introspection', async () => {
const query = `query {
__schema {
queryType {
name
}
}
}`
const response = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query }),
})
.then((res) => res.json())
expect(response.errors[0].message).toMatch(
'GraphQL introspection is not allowed, but the query contained __schema or __type',
)
})
it('should respect maxComplexity', async () => {
const post = await payload.create({
collection: 'posts',
data: {
title: 'example post',
},
})
await payload.update({
collection: 'posts',
id: post.id,
data: {
relationToSelf: post.id,
},
})
const query = `query {
Post(id: ${idToString(post.id, payload)}) {
title
relationToSelf {
id
}
}
}`
const response = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query }),
})
.then((res) => res.json())
expect(response.errors[0].message).toMatch(
'The query exceeds the maximum complexity of 800. Actual complexity is 804',
)
})
it('should sanitize hyphenated field names to snake case', async () => {
const post = await payload.create({
collection: 'posts',
data: {
title: 'example post',
'hyphenated-name': 'example-hyphenated-name',
},
})
const query = `query {
Post(id: ${idToString(post.id, payload)}) {
title
hyphenated_name
}
}`
const { data } = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
const res = data.Post
expect(res.hyphenated_name).toStrictEqual('example-hyphenated-name')
})
it('should not error because of non nullable fields', async () => {
await payload.delete({ collection: 'posts', where: {} })
// this is an array if any errors
const res_1 = await restClient
.GRAPHQL_POST({
body: JSON.stringify({
query: `
query {
Posts {
docs {
title
}
prevPage
}
}
`,
}),
})
.then((res) => res.json())
expect(res_1.errors).toBeFalsy()
await payload.create({
collection: 'posts',
data: { title: 'any-title' },
})
const res_2 = await restClient
.GRAPHQL_POST({
body: JSON.stringify({
query: `
query {
Posts(limit: 1) {
docs {
title
}
}
}
`,
}),
})
.then((res) => res.json())
expect(res_2.errors).toBeFalsy()
})
})
})