feat: passing hooks int test suite

This commit is contained in:
Jarrod Flesch
2024-02-16 22:27:43 -05:00
parent 1c75ac12e8
commit e597ecfe78
3 changed files with 51 additions and 41 deletions

View File

@@ -1,4 +1,5 @@
import type { Where } from 'payload/types' import type { Where } from 'payload/types'
import type { ParsedQs } from 'qs'
import QueryString from 'qs' import QueryString from 'qs'
@@ -22,13 +23,16 @@ type RequestQuery = {
} }
} }
function generateQueryString(query: RequestQuery['query']): string { function generateQueryString(query: RequestQuery['query'], params: ParsedQs): string {
const { where, limit, page, sort, ...rest } = params || {}
const whereFilter = query?.where || where
return QueryString.stringify( return QueryString.stringify(
{ {
...(query?.where ? { where: query.where } : {}), ...(rest || {}),
limit: query?.limit, ...(whereFilter ? { where: whereFilter } : {}),
page: query?.page, limit: query?.limit || limit || undefined,
sort: query?.sort, page: query?.page || page || undefined,
sort: query?.sort || sort || undefined,
}, },
{ {
addQueryPrefix: true, addQueryPrefix: true,
@@ -61,25 +65,27 @@ export class NextRESTClient {
this._GRAPHQL_POST = createGraphqlPOST(config) this._GRAPHQL_POST = createGraphqlPOST(config)
} }
private generateRequestParts(path: string): { private generateRequestParts(path: ValidPath): {
params?: ParsedQs
slug: string[] slug: string[]
url: string url: string
} { } {
const safePath = path.slice(1) const [slugs, params] = path.slice(1).split('?')
const slug = safePath.split('/') const url = `${this.serverURL}${this.config.routes.api}/${slugs}`
const url = `${this.serverURL}${this.config.routes.api}/${safePath}`
return { return {
url, url,
slug, slug: slugs.split('/'),
params: params ? QueryString.parse(params) : undefined,
} }
} }
async DELETE(path: ValidPath, options: RequestInit & RequestQuery = {}): Promise<Response> { async DELETE(path: ValidPath, options: RequestInit & RequestQuery = {}): Promise<Response> {
const { url, slug } = this.generateRequestParts(path) const { url, slug, params } = this.generateRequestParts(path)
const { query, ...rest } = options || {} const { query, ...rest } = options || {}
const whereQuery = generateQueryString(query) const queryParams = generateQueryString(query, params)
const request = new Request(`${url}${whereQuery}`, { const request = new Request(`${url}${queryParams}`, {
...rest, ...rest,
method: 'DELETE', method: 'DELETE',
headers: { headers: {
@@ -94,11 +100,11 @@ export class NextRESTClient {
path: ValidPath, path: ValidPath,
options: Omit<RequestInit, 'body'> & RequestQuery = {}, options: Omit<RequestInit, 'body'> & RequestQuery = {},
): Promise<Response> { ): Promise<Response> {
const { url, slug } = this.generateRequestParts(path) const { url, slug, params } = this.generateRequestParts(path)
const { query, ...rest } = options || {} const { query, ...rest } = options || {}
const whereQuery = generateQueryString(query) const queryParams = generateQueryString(query, params)
const request = new Request(`${url}${whereQuery}`, { const request = new Request(`${url}${queryParams}`, {
...rest, ...rest,
method: 'GET', method: 'GET',
headers: new Headers({ headers: new Headers({
@@ -125,11 +131,11 @@ export class NextRESTClient {
} }
async PATCH(path: ValidPath, options: RequestInit & RequestQuery): Promise<Response> { async PATCH(path: ValidPath, options: RequestInit & RequestQuery): Promise<Response> {
const { url, slug } = this.generateRequestParts(path) const { url, slug, params } = this.generateRequestParts(path)
const { query, ...rest } = options const { query, ...rest } = options
const whereQuery = generateQueryString(query) const queryParams = generateQueryString(query, params)
const request = new Request(`${url}${whereQuery}`, { const request = new Request(`${url}${queryParams}`, {
...rest, ...rest,
method: 'PATCH', method: 'PATCH',
headers: new Headers({ headers: new Headers({
@@ -141,9 +147,10 @@ export class NextRESTClient {
} }
async POST(path: ValidPath, options: RequestInit = {}): Promise<Response> { async POST(path: ValidPath, options: RequestInit = {}): Promise<Response> {
const { url, slug } = this.generateRequestParts(path) const { url, slug, params } = this.generateRequestParts(path)
const queryParams = generateQueryString({}, params)
const request = new Request(url, { const request = new Request(`${url}${queryParams}`, {
...options, ...options,
method: 'POST', method: 'POST',
headers: new Headers({ headers: new Headers({

View File

@@ -13,20 +13,20 @@ const ContextHooks: CollectionConfig = {
}, },
hooks: { hooks: {
beforeOperation: [ beforeOperation: [
async ({ context, args }) => { ({ context, args }) => {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
const req: PayloadRequest = args.req const req: PayloadRequest = args.req
if (!req.query || !Object.keys(req.query).length) { if (req.searchParams.size === 0) {
return args return args
} }
Object.keys(req.query).forEach((key) => { req.searchParams.forEach((value, key) => {
if (key.startsWith('context_')) { if (key.startsWith('context_')) {
// Strip 'context_' from key, add it to context object and remove it from query params // Strip 'context_' from key, add it to context object and remove it from query params
const newKey = key.substring('context_'.length) const newKey = key.substring('context_'.length)
context[newKey] = req.query[key] context[newKey] = value
delete req.query[key] req.searchParams.delete(key)
} }
}) })

View File

@@ -1,9 +1,11 @@
import type { Payload } from '../../packages/payload/src'
import type { NestedAfterReadHook } from './payload-types' import type { NestedAfterReadHook } from './payload-types'
import payload from '../../packages/payload/src' import { getPayload } from '../../packages/payload/src'
import { AuthenticationError } from '../../packages/payload/src/errors' import { AuthenticationError } from '../../packages/payload/src/errors'
import { devUser, regularUser } from '../credentials' import { devUser, regularUser } from '../credentials'
import { initPayloadTest } from '../helpers/configHelpers' import { NextRESTClient } from '../helpers/NextRESTClient'
import { startMemoryDB } from '../startMemoryDB'
import { afterOperationSlug } from './collections/AfterOperation' import { afterOperationSlug } from './collections/AfterOperation'
import { chainingHooksSlug } from './collections/ChainingHooks' import { chainingHooksSlug } from './collections/ChainingHooks'
import { contextHooksSlug } from './collections/ContextHooks' import { contextHooksSlug } from './collections/ContextHooks'
@@ -16,15 +18,17 @@ import {
import { relationsSlug } from './collections/Relations' import { relationsSlug } from './collections/Relations'
import { transformSlug } from './collections/Transform' import { transformSlug } from './collections/Transform'
import { hooksUsersSlug } from './collections/Users' import { hooksUsersSlug } from './collections/Users'
import { HooksConfig } from './config' import configPromise, { HooksConfig } from './config'
import { dataHooksGlobalSlug } from './globals/Data' import { dataHooksGlobalSlug } from './globals/Data'
let apiUrl let restClient: NextRESTClient
let payload: Payload
describe('Hooks', () => { describe('Hooks', () => {
beforeAll(async () => { beforeAll(async () => {
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } }) const config = await startMemoryDB(configPromise)
apiUrl = `${serverURL}/api` payload = await getPayload({ config })
restClient = new NextRESTClient(payload.config)
}) })
afterAll(async () => { afterAll(async () => {
@@ -268,18 +272,17 @@ describe('Hooks', () => {
context_secretValue: 'data from rest API', context_secretValue: 'data from rest API',
}) })
// send context as query params. It will be parsed by the beforeOperation hook // send context as query params. It will be parsed by the beforeOperation hook
const response = await fetch(`${apiUrl}/${contextHooksSlug}?${params.toString()}`, { const { doc } = await restClient
body: JSON.stringify({ .POST(`/${contextHooksSlug}?${params.toString()}`, {
value: 'wrongvalue', body: JSON.stringify({
}), value: 'wrongvalue',
method: 'post', }),
}) })
.then((res) => res.json())
const document = (await response.json()).doc
const retrievedDoc = await payload.findByID({ const retrievedDoc = await payload.findByID({
collection: contextHooksSlug, collection: contextHooksSlug,
id: document.id, id: doc.id,
}) })
expect(retrievedDoc.value).toEqual('data from rest API') expect(retrievedDoc.value).toEqual('data from rest API')