chore: more passing int suites

This commit is contained in:
Jarrod Flesch
2024-02-16 15:09:51 -05:00
parent 504892ddb9
commit 28c4046300
9 changed files with 215 additions and 113 deletions

View File

@@ -7,6 +7,7 @@ import { APIError, Forbidden } from 'payload/errors'
import { RouteError } from '../../../RouteError' import { RouteError } from '../../../RouteError'
import { createPayloadRequest } from '../../../../../utilities/createPayloadRequest' import { createPayloadRequest } from '../../../../../utilities/createPayloadRequest'
import httpStatus from 'http-status' import httpStatus from 'http-status'
import { endpointsAreDisabled } from '../../../checkEndpoints'
async function checkFileAccess({ async function checkFileAccess({
req, req,
@@ -18,6 +19,9 @@ async function checkFileAccess({
collection: Collection collection: Collection
}) { }) {
const { config } = collection const { config } = collection
const disableEndpoints = endpointsAreDisabled({ request: req, endpoints: config.endpoints })
if (disableEndpoints) return disableEndpoints
const accessResult = await executeAccess({ isReadingStaticFile: true, req }, config.access.read) const accessResult = await executeAccess({ isReadingStaticFile: true, req }, config.access.read)
if (typeof accessResult === 'object') { if (typeof accessResult === 'object') {

View File

@@ -0,0 +1,21 @@
import httpStatus from 'http-status'
import { CollectionConfig, GlobalConfig } from 'payload/types'
export const endpointsAreDisabled = ({
request,
endpoints,
}: {
request: Partial<Request>
endpoints: unknown[] | false
}) => {
if (!endpoints) {
return Response.json(
{
message: `Cannot ${request.method.toUpperCase()} ${request.url}`,
},
{
status: httpStatus.NOT_IMPLEMENTED,
},
)
}
}

View File

@@ -11,6 +11,9 @@ import {
GlobalRouteHandlerWithID, GlobalRouteHandlerWithID,
} from './types' } from './types'
import { RouteError } from './RouteError'
import { endpointsAreDisabled } from './checkEndpoints'
import { me } from './auth/me' import { me } from './auth/me'
import { init } from './auth/init' import { init } from './auth/init'
import { login } from './auth/login' import { login } from './auth/login'
@@ -41,7 +44,6 @@ import { docAccess as docAccessGlobal } from './globals/docAccess'
import { findVersions as findVersionsGlobal } from './globals/findVersions' import { findVersions as findVersionsGlobal } from './globals/findVersions'
import { restoreVersion as restoreVersionGlobal } from './globals/restoreVersion' import { restoreVersion as restoreVersionGlobal } from './globals/restoreVersion'
import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID' import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID'
import { RouteError } from './RouteError'
const endpoints = { const endpoints = {
root: { root: {
@@ -161,13 +163,25 @@ export const GET =
}, },
}) })
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: req.payload.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
collection = req.payload.collections?.[slug1] collection = req.payload.collections?.[slug1]
if (collection) { if (collection) {
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: collection.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1, entitySlug: slug1,
payloadRequest: req, payloadRequest: req,
endpoints: collection.config?.endpoints || [], endpoints: collection.config.endpoints,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
@@ -202,10 +216,17 @@ export const GET =
} }
} else if (slug1 === 'globals') { } else if (slug1 === 'globals') {
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2) const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: globalConfig.endpoints,
})
if (disableEndpoints) return disableEndpoints
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
entitySlug: `${slug1}/${slug2}`, entitySlug: `${slug1}/${slug2}`,
payloadRequest: req, payloadRequest: req,
endpoints: globalConfig?.endpoints || [], endpoints: globalConfig.endpoints,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
@@ -276,11 +297,23 @@ export const POST =
}) })
collection = req.payload.collections?.[slug1] collection = req.payload.collections?.[slug1]
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: req.payload.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
if (collection) { if (collection) {
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: collection.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1, entitySlug: slug1,
payloadRequest: req, payloadRequest: req,
endpoints: collection.config?.endpoints || [], endpoints: collection.config.endpoints,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
@@ -318,6 +351,18 @@ export const POST =
} }
} else if (slug1 === 'globals' && slug2) { } else if (slug1 === 'globals' && slug2) {
const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2) const globalConfig = req.payload.config.globals.find((global) => global.slug === slug2)
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: globalConfig.endpoints,
})
if (disableEndpoints) return disableEndpoints
const customEndpointResponse = await handleCustomEndpoints({
entitySlug: `${slug1}/${slug2}`,
payloadRequest: req,
endpoints: globalConfig.endpoints,
})
if (customEndpointResponse) return customEndpointResponse
switch (slug.length) { switch (slug.length) {
case 2: case 2:
@@ -387,11 +432,23 @@ export const DELETE =
}) })
collection = req.payload.collections?.[slug1] collection = req.payload.collections?.[slug1]
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: req.payload.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
if (collection) { if (collection) {
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: collection.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1, entitySlug: slug1,
payloadRequest: req, payloadRequest: req,
endpoints: collection.config?.endpoints || [], endpoints: collection.config.endpoints,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse
@@ -444,11 +501,23 @@ export const PATCH =
}) })
collection = req.payload.collections?.[slug1] collection = req.payload.collections?.[slug1]
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: req.payload.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
if (collection) { if (collection) {
const disableEndpoints = endpointsAreDisabled({
request,
endpoints: collection.config.endpoints,
})
if (disableEndpoints) return disableEndpoints
const customEndpointResponse = await handleCustomEndpoints({ const customEndpointResponse = await handleCustomEndpoints({
entitySlug: slug1, entitySlug: slug1,
payloadRequest: req, payloadRequest: req,
endpoints: collection.config?.endpoints || [], endpoints: collection.config.endpoints,
}) })
if (customEndpointResponse) return customEndpointResponse if (customEndpointResponse) return customEndpointResponse

View File

@@ -25,6 +25,7 @@ const databaseAdapters = {
export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<SanitizedConfig> { export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<SanitizedConfig> {
const config: Config = { const config: Config = {
secret: 'TEST_SECRET', secret: 'TEST_SECRET',
// editor: slateEditor({}),
editor: undefined, editor: undefined,
rateLimit: { rateLimit: {
max: 9999999999, max: 9999999999,

View File

@@ -1,11 +1,15 @@
import payload from '../../packages/payload/src' import type { Payload } from '../../packages/payload/src'
import { initPayloadTest } from '../helpers/configHelpers'
require('isomorphic-fetch') import { getPayload } from '../../packages/payload/src'
import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config'
let payload: Payload
describe('Config', () => { describe('Config', () => {
beforeAll(async () => { beforeAll(async () => {
await initPayloadTest({ __dirname, init: { local: true } }) const config = await startMemoryDB(configPromise)
payload = await getPayload({ config })
}) })
describe('payload config', () => { describe('payload config', () => {

View File

@@ -1,16 +1,15 @@
import { GraphQLClient } from 'graphql-request' import { getPayload } from '../../packages/payload/src'
import { NextRESTClient } from '../helpers/NextRESTClient'
import { initPayloadTest } from '../helpers/configHelpers' import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config' import configPromise from './config'
let client: GraphQLClient let restClient: NextRESTClient
describe('Custom GraphQL', () => { describe('Custom GraphQL', () => {
beforeAll(async () => { beforeAll(async () => {
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } }) const config = await startMemoryDB(configPromise)
const config = await configPromise const payload = await getPayload({ config })
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}` restClient = new NextRESTClient(payload.config)
client = new GraphQLClient(url)
}) })
describe('Isolated Transaction ID', () => { describe('Isolated Transaction ID', () => {
@@ -19,11 +18,15 @@ describe('Custom GraphQL', () => {
TransactionID1 TransactionID1
TransactionID2 TransactionID2
}` }`
const response = await client.request(query) const { data } = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query }),
})
.then((res) => res.json())
// either no transactions at all or they are different // either no transactions at all or they are different
expect( expect(
(response.TransactionID2 === null && response.TransactionID1 === null) || (data.TransactionID2 === null && data.TransactionID1 === null) ||
response.TransactionID2 !== response.TransactionID1, data.TransactionID2 !== data.TransactionID1,
).toBe(true) ).toBe(true)
}) })
it('should isolate transaction IDs between mutations in the same request', async () => { it('should isolate transaction IDs between mutations in the same request', async () => {
@@ -31,11 +34,15 @@ describe('Custom GraphQL', () => {
MutateTransactionID1 MutateTransactionID1
MutateTransactionID2 MutateTransactionID2
}` }`
const response = await client.request(query) const { data } = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query }),
})
.then((res) => res.json())
// either no transactions at all or they are different // either no transactions at all or they are different
expect( expect(
(response.MutateTransactionID2 === null && response.MutateTransactionID1 === null) || (data.MutateTransactionID2 === null && data.MutateTransactionID1 === null) ||
response.MutateTransactionID2 !== response.MutateTransactionID1, data.MutateTransactionID2 !== data.MutateTransactionID1,
).toBe(true) ).toBe(true)
}) })
}) })

View File

@@ -1,28 +1,25 @@
import { GraphQLClient } from 'graphql-request' import type { Payload } from '../../packages/payload/src'
import type { TypeWithID } from '../../packages/payload/src/collections/config/types' import type { TypeWithID } from '../../packages/payload/src/collections/config/types'
import type { PayloadRequest } from '../../packages/payload/src/types' import type { PayloadRequest } from '../../packages/payload/src/types'
import payload from '../../packages/payload/src' import { getPayload } from '../../packages/payload/src'
import { commitTransaction } from '../../packages/payload/src/utilities/commitTransaction' import { commitTransaction } from '../../packages/payload/src/utilities/commitTransaction'
import { initTransaction } from '../../packages/payload/src/utilities/initTransaction' import { initTransaction } from '../../packages/payload/src/utilities/initTransaction'
import { devUser } from '../credentials' import { devUser } from '../credentials'
import { initPayloadTest } from '../helpers/configHelpers' import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config'
describe('database', () => { let payload: Payload
let serverURL
let client: GraphQLClient
let token: string
const collection = 'posts'
const title = 'title'
let user: TypeWithID & Record<string, unknown> let user: TypeWithID & Record<string, unknown>
let useTransactions = true let useTransactions = true
const collection = 'posts'
const title = 'title'
describe('database', () => {
beforeAll(async () => { beforeAll(async () => {
const init = await initPayloadTest({ __dirname, init: { local: false } }) const config = await startMemoryDB(configPromise)
serverURL = init.serverURL payload = await getPayload({ config })
const url = `${serverURL}/api/graphql`
client = new GraphQLClient(url)
if (payload.db.name === 'mongoose') { if (payload.db.name === 'mongoose') {
useTransactions = false useTransactions = false
} }
@@ -35,7 +32,6 @@ describe('database', () => {
}, },
}) })
if (loginResult.token) token = loginResult.token
user = loginResult.user user = loginResult.user
}) })

View File

@@ -1,24 +1,21 @@
import { GraphQLClient } from 'graphql-request' import type { Payload } from '../../packages/payload/src'
import payload from '../../packages/payload/src' import { getPayload } from '../../packages/payload/src'
import { devUser } from '../credentials' import { devUser } from '../credentials'
import { initPayloadTest } from '../helpers/configHelpers' import { NextRESTClient } from '../helpers/NextRESTClient'
import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config'
import { postDoc } from './config' import { postDoc } from './config'
describe('dataloader', () => { let restClient: NextRESTClient
let serverURL let payload: Payload
beforeAll(async () => {
const init = await initPayloadTest({ __dirname, init: { local: false } })
serverURL = init.serverURL
})
describe('graphql', () => {
let client: GraphQLClient
let token: string let token: string
describe('dataloader', () => {
beforeAll(async () => { beforeAll(async () => {
const url = `${serverURL}/api/graphql` const config = await startMemoryDB(configPromise)
client = new GraphQLClient(url) payload = await getPayload({ config })
restClient = new NextRESTClient(payload.config)
const loginResult = await payload.login({ const loginResult = await payload.login({
collection: 'users', collection: 'users',
@@ -31,6 +28,7 @@ describe('dataloader', () => {
if (loginResult.token) token = loginResult.token if (loginResult.token) token = loginResult.token
}) })
describe('graphql', () => {
it('should allow querying via graphql', async () => { it('should allow querying via graphql', async () => {
const query = `query { const query = `query {
Posts { Posts {
@@ -43,11 +41,16 @@ describe('dataloader', () => {
} }
}` }`
const response = await client.request(query, null, { const { data } = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query }),
headers: {
Authorization: `JWT ${token}`, Authorization: `JWT ${token}`,
},
}) })
.then((res) => res.json())
const { docs } = response.Posts const { docs } = data.Posts
expect(docs[0].title).toStrictEqual(postDoc.title) expect(docs[0].title).toStrictEqual(postDoc.title)
}) })

View File

@@ -1,5 +1,7 @@
import { initPayloadTest } from '../helpers/configHelpers' import { getPayload } from '../../packages/payload/src'
import { RESTClient } from '../helpers/rest' import { NextRESTClient } from '../helpers/NextRESTClient'
import { startMemoryDB } from '../startMemoryDB'
import configPromise from './config'
import { import {
applicationEndpoint, applicationEndpoint,
collectionSlug, collectionSlug,
@@ -10,90 +12,82 @@ import {
rootEndpoint, rootEndpoint,
} from './shared' } from './shared'
require('isomorphic-fetch') let restClient: NextRESTClient
let client: RESTClient
describe('Endpoints', () => { describe('Endpoints', () => {
beforeAll(async () => { beforeAll(async () => {
const config = await initPayloadTest({ __dirname, init: { local: false } }) const config = await startMemoryDB(configPromise)
const { serverURL } = config await getPayload({ config })
client = new RESTClient(config, { serverURL, defaultSlug: collectionSlug }) restClient = new NextRESTClient(config)
}) })
describe('Collections', () => { describe('Collections', () => {
it('should GET a static endpoint', async () => { it('should GET a static endpoint', async () => {
const { status, data } = await client.endpoint(`/api/${collectionSlug}/say-hello/joe-bloggs`) const response = await restClient.GET(`/${collectionSlug}/say-hello/joe-bloggs`)
expect(status).toBe(200) const data = await response.json()
expect(response.status).toBe(200)
expect(data.message).toStrictEqual('Hey Joey!') expect(data.message).toStrictEqual('Hey Joey!')
}) })
it('should GET an endpoint with a parameter', async () => { it('should GET an endpoint with a parameter', async () => {
const name = 'George' const name = 'George'
const { status, data } = await client.endpoint(`/api/${collectionSlug}/say-hello/${name}`) const response = await restClient.GET(`/${collectionSlug}/say-hello/${name}`)
expect(status).toBe(200) const data = await response.json()
expect(response.status).toBe(200)
expect(data.message).toStrictEqual(`Hello ${name}!`) expect(data.message).toStrictEqual(`Hello ${name}!`)
}) })
it('should POST an endpoint with data', async () => { it('should POST an endpoint with data', async () => {
const params = { name: 'George', age: 29 } const params = { name: 'George', age: 29 }
const { status, data } = await client.endpoint( const response = await restClient.POST(`/${collectionSlug}/whoami`, {
`/api/${collectionSlug}/whoami`, body: JSON.stringify(params),
'post', })
params, const data = await response.json()
) expect(response.status).toBe(200)
expect(status).toBe(200)
expect(data.name).toStrictEqual(params.name) expect(data.name).toStrictEqual(params.name)
expect(data.age).toStrictEqual(params.age) expect(data.age).toStrictEqual(params.age)
}) })
it('should disable built-in endpoints when false', async () => { it('should disable built-in endpoints when false', async () => {
let result const response = await restClient.GET(`/${noEndpointsCollectionSlug}`)
try { expect(response.status).toBe(501)
result = await client.endpoint(`/api/${noEndpointsCollectionSlug}`, 'get')
} catch (err: unknown) {
result = err
}
expect(result instanceof Error).toBe(true)
}) })
}) })
describe('Globals', () => { describe('Globals', () => {
it('should call custom endpoint', async () => { it('should call custom endpoint', async () => {
const params = { globals: 'response' } const params = { globals: 'response' }
const { status, data } = await client.endpoint( const response = await restClient.POST(`/globals/${globalSlug}/${globalEndpoint}`, {
`/api/globals/${globalSlug}/${globalEndpoint}`, body: JSON.stringify(params),
'post', })
params, const data = await response.json()
)
expect(status).toBe(200) expect(response.status).toBe(200)
expect(params).toMatchObject(data) expect(params).toMatchObject(data)
}) })
it('should disable built-in endpoints when false', async () => { it('should disable built-in endpoints when false', async () => {
let result const response = await restClient.GET(`/globals/${noEndpointsGlobalSlug}`)
try { expect(response.status).toBe(501)
result = await client.endpoint(`/api/globals/${noEndpointsGlobalSlug}`, 'get')
} catch (err: unknown) {
result = err
}
expect(result instanceof Error).toBe(true)
}) })
}) })
describe('API', () => { describe('API', () => {
it('should call custom endpoint', async () => { it('should call custom endpoint', async () => {
const params = { app: 'response' } const params = { app: 'response' }
const { status, data } = await client.endpoint(`/api/${applicationEndpoint}`, 'post', params) const response = await restClient.POST(`/${applicationEndpoint}`, {
body: JSON.stringify(params),
})
const data = await response.json()
expect(status).toBe(200) expect(response.status).toBe(200)
expect(params).toMatchObject(data) expect(params).toMatchObject(data)
}) })
it('should have i18n on req', async () => { it('should have i18n on req', async () => {
const { status, data } = await client.endpoint(`/api/${applicationEndpoint}/i18n`, 'get') const response = await restClient.GET(`/${applicationEndpoint}/i18n`)
const data = await response.json()
expect(status).toBe(200) expect(response.status).toBe(200)
expect(data.message).toStrictEqual('Back to Dashboard') expect(data.message).toStrictEqual('Back to Dashboard')
}) })
}) })
@@ -101,9 +95,12 @@ describe('Endpoints', () => {
describe('Root', () => { describe('Root', () => {
it('should call custom root endpoint', async () => { it('should call custom root endpoint', async () => {
const params = { root: 'response' } const params = { root: 'response' }
const { status, data } = await client.endpoint(`/${rootEndpoint}`, 'post', params) const response = await restClient.POST(`/${rootEndpoint}`, {
body: JSON.stringify(params),
})
const data = await response.json()
expect(status).toBe(200) expect(response.status).toBe(200)
expect(params).toMatchObject(data) expect(params).toMatchObject(data)
}) })
}) })