feat: initial test suite framework (#4929)
This commit is contained in:
3
__mocks__/payload-config.ts
Normal file
3
__mocks__/payload-config.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default typeof process.env.PAYLOAD_CONFIG_PATH === 'string'
|
||||||
|
? require(process.env.PAYLOAD_CONFIG_PATH)
|
||||||
|
: {}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
module.exports = {
|
const customJestConfig = {
|
||||||
globalSetup: './test/jest.setup.ts',
|
globalSetup: './test/jest.setup.ts',
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'\\.(css|scss)$': '<rootDir>/packages/payload/src/bundlers/mocks/emptyModule.js',
|
'\\.(css|scss)$': '<rootDir>/packages/payload/src/bundlers/mocks/emptyModule.js',
|
||||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
||||||
'<rootDir>/packages/payload/src/bundlers/mocks/fileMock.js',
|
'<rootDir>/packages/payload/src/bundlers/mocks/fileMock.js',
|
||||||
|
'payload-config': '<rootDir>/__mocks__/payload-config.ts',
|
||||||
},
|
},
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: ['<rootDir>/packages/payload/src/**/*.spec.ts', '<rootDir>/test/**/*int.spec.ts'],
|
testMatch: ['<rootDir>/packages/payload/src/**/*.spec.ts', '<rootDir>/test/**/*int.spec.ts'],
|
||||||
@@ -13,3 +14,5 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
verbose: true,
|
verbose: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = customJestConfig
|
||||||
|
|||||||
@@ -80,16 +80,18 @@
|
|||||||
"lexical": "0.12.5",
|
"lexical": "0.12.5",
|
||||||
"lint-staged": "^14.0.1",
|
"lint-staged": "^14.0.1",
|
||||||
"minimist": "1.2.8",
|
"minimist": "1.2.8",
|
||||||
"mongodb-memory-server": "8.13.0",
|
"next": "14.1.1-canary.26",
|
||||||
"next": "14.0.2",
|
|
||||||
"node-fetch": "2.6.12",
|
"node-fetch": "2.6.12",
|
||||||
"nodemon": "3.0.2",
|
"nodemon": "3.0.2",
|
||||||
|
"pino": "8.15.0",
|
||||||
|
"pino-pretty": "10.2.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"prompts": "2.4.2",
|
"prompts": "2.4.2",
|
||||||
"qs": "6.11.2",
|
"qs": "6.11.2",
|
||||||
"read-stream": "^2.1.1",
|
"read-stream": "^2.1.1",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"semver": "^7.5.4",
|
"semver": "^7.5.4",
|
||||||
|
"sharp": "0.32.6",
|
||||||
"shelljs": "0.8.5",
|
"shelljs": "0.8.5",
|
||||||
"simple-git": "^3.20.0",
|
"simple-git": "^3.20.0",
|
||||||
"slash": "3.0.0",
|
"slash": "3.0.0",
|
||||||
@@ -102,7 +104,6 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-i18next": "11.18.6",
|
|
||||||
"react-router-dom": "5.3.4"
|
"react-router-dom": "5.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -27,18 +27,17 @@
|
|||||||
"prepublishOnly": "pnpm clean && pnpm build"
|
"prepublishOnly": "pnpm clean && pnpm build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bson-ext": "^4.0.3",
|
||||||
"bson-objectid": "2.0.4",
|
"bson-objectid": "2.0.4",
|
||||||
"deepmerge": "4.3.1",
|
"deepmerge": "4.3.1",
|
||||||
"get-port": "5.1.1",
|
"get-port": "5.1.1",
|
||||||
"mongoose": "6.12.0",
|
"mongoose": "6.12.0",
|
||||||
"mongoose-aggregate-paginate-v2": "1.0.6",
|
|
||||||
"mongoose-paginate-v2": "1.7.22",
|
"mongoose-paginate-v2": "1.7.22",
|
||||||
"prompts": "2.4.2",
|
"prompts": "2.4.2",
|
||||||
"uuid": "9.0.0"
|
"uuid": "9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@payloadcms/eslint-config": "workspace:*",
|
"@payloadcms/eslint-config": "workspace:*",
|
||||||
"@types/mongoose-aggregate-paginate-v2": "1.0.9",
|
|
||||||
"mongodb-memory-server": "8.13.0",
|
"mongodb-memory-server": "8.13.0",
|
||||||
"payload": "workspace:*"
|
"payload": "workspace:*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const connect: Connect = async function connect(this: MongooseAdapter, pa
|
|||||||
useFacet: undefined,
|
useFacet: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'test') {
|
if ([process.env.APP_ENV, process.env.NODE_ENV].includes('test')) {
|
||||||
if (process.env.PAYLOAD_TEST_MONGO_URL) {
|
if (process.env.PAYLOAD_TEST_MONGO_URL) {
|
||||||
urlToConnect = process.env.PAYLOAD_TEST_MONGO_URL
|
urlToConnect = process.env.PAYLOAD_TEST_MONGO_URL
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import type { Init } from 'payload/database'
|
|||||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||||
|
|
||||||
import mongoose from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
import mongooseAggregatePaginate from 'mongoose-aggregate-paginate-v2'
|
|
||||||
import paginate from 'mongoose-paginate-v2'
|
import paginate from 'mongoose-paginate-v2'
|
||||||
import {
|
import {
|
||||||
buildVersionCollectionFields,
|
buildVersionCollectionFields,
|
||||||
@@ -45,10 +44,6 @@ export const init: Init = async function init(this: MongooseAdapter) {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (collection.versions?.drafts) {
|
|
||||||
versionSchema.plugin(mongooseAggregatePaginate)
|
|
||||||
}
|
|
||||||
|
|
||||||
const model = mongoose.model(
|
const model = mongoose.model(
|
||||||
versionModelName,
|
versionModelName,
|
||||||
versionSchema,
|
versionSchema,
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
import type {
|
import type { IndexDefinition, IndexOptions, Model, PaginateModel, SchemaOptions } from 'mongoose'
|
||||||
AggregatePaginateModel,
|
|
||||||
IndexDefinition,
|
|
||||||
IndexOptions,
|
|
||||||
Model,
|
|
||||||
PaginateModel,
|
|
||||||
SchemaOptions,
|
|
||||||
} from 'mongoose'
|
|
||||||
import type { Payload } from 'payload'
|
import type { Payload } from 'payload'
|
||||||
import type { SanitizedConfig } from 'payload/config'
|
import type { SanitizedConfig } from 'payload/config'
|
||||||
import type {
|
import type {
|
||||||
@@ -34,11 +27,7 @@ import type {
|
|||||||
|
|
||||||
import type { BuildQueryArgs } from './queries/buildQuery'
|
import type { BuildQueryArgs } from './queries/buildQuery'
|
||||||
|
|
||||||
export interface CollectionModel
|
export interface CollectionModel extends Model<any>, PaginateModel<any>, PassportLocalModel {
|
||||||
extends Model<any>,
|
|
||||||
PaginateModel<any>,
|
|
||||||
AggregatePaginateModel<any>,
|
|
||||||
PassportLocalModel {
|
|
||||||
/** buildQuery is used to transform payload's where operator into what can be used by mongoose (e.g. id => _id) */
|
/** buildQuery is used to transform payload's where operator into what can be used by mongoose (e.g. id => _id) */
|
||||||
buildQuery: (args: BuildQueryArgs) => Promise<Record<string, unknown>> // TODO: Delete this
|
buildQuery: (args: BuildQueryArgs) => Promise<Record<string, unknown>> // TODO: Delete this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ export const upsertRow = async <T extends TypeWithID>({
|
|||||||
message: req.t('error:valueMustBeUnique'),
|
message: req.t('error:valueMustBeUnique'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
req?.t ?? i18nInit(req.payload.config.i18n).t,
|
req.t,
|
||||||
)
|
)
|
||||||
: error
|
: error
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/dev/mocks.js
Normal file
1
packages/dev/mocks.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const mongooseAdapter = () => ({})
|
||||||
@@ -8,8 +8,6 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
serverComponentsExternalPackages: ['drizzle-kit', 'drizzle-kit/utils', 'pino', 'pino-pretty'],
|
serverComponentsExternalPackages: ['drizzle-kit', 'drizzle-kit/utils', 'pino', 'pino-pretty'],
|
||||||
},
|
},
|
||||||
reactStrictMode: false,
|
|
||||||
// transpilePackages: ['@payloadcms/db-mongodb', 'mongoose'],
|
|
||||||
webpack: (config) => {
|
webpack: (config) => {
|
||||||
return {
|
return {
|
||||||
...config,
|
...config,
|
||||||
@@ -19,15 +17,30 @@ const nextConfig = {
|
|||||||
'drizzle-kit/utils',
|
'drizzle-kit/utils',
|
||||||
'pino',
|
'pino',
|
||||||
'pino-pretty',
|
'pino-pretty',
|
||||||
'mongoose',
|
|
||||||
'sharp',
|
'sharp',
|
||||||
],
|
],
|
||||||
|
ignoreWarnings: [
|
||||||
|
...(config.ignoreWarnings || []),
|
||||||
|
{ module: /node_modules\/mongodb\/lib\/utils\.js/ },
|
||||||
|
{ file: /node_modules\/mongodb\/lib\/utils\.js/ },
|
||||||
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
...config.resolve,
|
...config.resolve,
|
||||||
alias: {
|
alias: {
|
||||||
...config.resolve.alias,
|
...config.resolve.alias,
|
||||||
graphql$: path.resolve(__dirname, '../next/node_modules/graphql/index.js'),
|
graphql$: path.resolve(__dirname, '../next/node_modules/graphql/index.js'),
|
||||||
'graphql-http$': path.resolve(__dirname, '../next/node_modules/graphql-http/index.js'),
|
'graphql-http$': path.resolve(__dirname, '../next/node_modules/graphql-http/index.js'),
|
||||||
|
'payload-config$': path.resolve(process.env.PAYLOAD_CONFIG_PATH),
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
...config.resolve.fallback,
|
||||||
|
'@aws-sdk/credential-providers': false,
|
||||||
|
'@mongodb-js/zstd': false,
|
||||||
|
aws4: false,
|
||||||
|
kerberos: false,
|
||||||
|
'mongodb-client-encryption': false,
|
||||||
|
snappy: false,
|
||||||
|
'supports-color': false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
6
packages/dev/server.js
Normal file
6
packages/dev/server.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const { bootAdminPanel } = require('../../test/helpers/bootAdminPanel.ts')
|
||||||
|
|
||||||
|
bootAdminPanel({
|
||||||
|
appDir: __dirname,
|
||||||
|
port: 3000,
|
||||||
|
})
|
||||||
@@ -36,7 +36,6 @@ export default buildConfig({
|
|||||||
// title: 'Test Page',
|
// title: 'Test Page',
|
||||||
// },
|
// },
|
||||||
// })
|
// })
|
||||||
//
|
|
||||||
// await payload.update({
|
// await payload.update({
|
||||||
// collection: 'pages',
|
// collection: 'pages',
|
||||||
// id: page.id,
|
// id: page.id,
|
||||||
|
|||||||
@@ -17,21 +17,20 @@
|
|||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
"name": "next"
|
"name": "next",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"payload": ["../payload/src"],
|
"payload": ["../payload/src"],
|
||||||
"payload/*": ["../payload/src/exports/*"],
|
"payload/*": ["../payload/src/exports/*"],
|
||||||
"payload-config": ["./src/payload.config.ts"],
|
|
||||||
"@payloadcms/db-mongodb": ["../db-mongodb/src"],
|
"@payloadcms/db-mongodb": ["../db-mongodb/src"],
|
||||||
"@payloadcms/richtext-lexical": ["../richtext-lexical/src"],
|
"@payloadcms/richtext-lexical": ["../richtext-lexical/src"],
|
||||||
"@payloadcms/ui/*": ["../ui/src/exports/*"],
|
"@payloadcms/ui/*": ["../ui/src/exports/*"],
|
||||||
"@payloadcms/translations": ["../translations/src/exports/index.ts"],
|
"@payloadcms/translations": ["../translations/src/exports/index.ts"],
|
||||||
"@payloadcms/translations/client": ["../translations/src/all"],
|
"@payloadcms/translations/client": ["../translations/src/all"],
|
||||||
"@payloadcms/translations/api": ["../translations/src/all"],
|
"@payloadcms/translations/api": ["../translations/src/all"],
|
||||||
"@payloadcms/next/*": ["../next/src/*"]
|
"@payloadcms/next/*": ["../next/src/*"],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
@@ -43,6 +42,6 @@
|
|||||||
{ "path": "../translations" },
|
{ "path": "../translations" },
|
||||||
{ "path": "../db-mongodb" },
|
{ "path": "../db-mongodb" },
|
||||||
{ "path": "../db-postgres" },
|
{ "path": "../db-postgres" },
|
||||||
{ "path": "../richtext-lexical" }
|
{ "path": "../richtext-lexical" },
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,7 @@ import { PayloadRequest } from 'payload/types'
|
|||||||
|
|
||||||
export type Context = {
|
export type Context = {
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
headers: Headers
|
headers: {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"http-status": "1.6.2",
|
"http-status": "1.6.2",
|
||||||
"i18next": "22.5.1",
|
"next": "14.1.1-canary.26",
|
||||||
"next": "^14.0.0",
|
|
||||||
"payload": "^2.0.0"
|
"payload": "^2.0.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -111,8 +111,13 @@ export const POST = (config: Promise<SanitizedConfig>) => async (request: Reques
|
|||||||
validationRules: (request, args, defaultRules) => defaultRules.concat(validationRules(args)),
|
validationRules: (request, args, defaultRules) => defaultRules.concat(validationRules(args)),
|
||||||
})(originalRequest)
|
})(originalRequest)
|
||||||
|
|
||||||
|
const resHeaders = new Headers(apiResponse.headers)
|
||||||
|
for (let key in headers) {
|
||||||
|
resHeaders.append(key, headers[key])
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(apiResponse.body, {
|
return new Response(apiResponse.body, {
|
||||||
status: apiResponse.status,
|
status: apiResponse.status,
|
||||||
headers: new Headers(headers),
|
headers: new Headers(resHeaders),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
||||||
"rootDir": "./src" /* Specify the root folder within your source files. */,
|
"rootDir": "./src" /* Specify the root folder within your source files. */,
|
||||||
"paths": {
|
"paths": {
|
||||||
"payload-config": ["./src/config.ts"],
|
|
||||||
"@payloadcms/graphql": ["../graphql/dist/index.ts"],
|
"@payloadcms/graphql": ["../graphql/dist/index.ts"],
|
||||||
"@payloadcms/ui": ["../ui/src/exports/index.ts"],
|
"@payloadcms/ui": ["../ui/src/exports/index.ts"],
|
||||||
"@payloadcms/translations/*": ["../translations/dist/*"]
|
"@payloadcms/translations/*": ["../translations/dist/*"]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const APIKeyAuthentication =
|
|||||||
async ({ headers, payload }) => {
|
async ({ headers, payload }) => {
|
||||||
const authHeader = headers.get('Authorization')
|
const authHeader = headers.get('Authorization')
|
||||||
|
|
||||||
if (authHeader.startsWith(`${collectionConfig.slug} API-Key `)) {
|
if (authHeader?.startsWith(`${collectionConfig.slug} API-Key `)) {
|
||||||
const apiKey = authHeader.replace(`${collectionConfig.slug} API-Key `, '')
|
const apiKey = authHeader.replace(`${collectionConfig.slug} API-Key `, '')
|
||||||
const apiKeyIndex = crypto.createHmac('sha1', payload.secret).update(apiKey).digest('hex')
|
const apiKeyIndex = crypto.createHmac('sha1', payload.secret).update(apiKey).digest('hex')
|
||||||
|
|
||||||
@@ -38,8 +38,6 @@ export const APIKeyAuthentication =
|
|||||||
collection: collectionConfig.slug,
|
collection: collectionConfig.slug,
|
||||||
depth: collectionConfig.auth.depth,
|
depth: collectionConfig.auth.depth,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
// TODO(JAMES)(REVIEW): had to remove with new pattern
|
|
||||||
// req,
|
|
||||||
where,
|
where,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ export const build = async (): Promise<void> => {
|
|||||||
disableOnInit: true,
|
disableOnInit: true,
|
||||||
local: true,
|
local: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
await payload.config.admin.bundler.build(payload.config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when build.js is launched directly
|
// when build.js is launched directly
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ export type PayloadHandler = ({
|
|||||||
/**
|
/**
|
||||||
* Docs: https://payloadcms.com/docs/rest-api/overview#custom-endpoints
|
* Docs: https://payloadcms.com/docs/rest-api/overview#custom-endpoints
|
||||||
*/
|
*/
|
||||||
export type Endpoint = {
|
export type Endpoint<U = User> = {
|
||||||
/** Extension point to add your custom data. */
|
/** Extension point to add your custom data. */
|
||||||
custom?: Record<string, any>
|
custom?: Record<string, any>
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import { decrypt, encrypt } from './auth/crypto'
|
|||||||
import { APIKeyAuthentication } from './auth/strategies/apiKey'
|
import { APIKeyAuthentication } from './auth/strategies/apiKey'
|
||||||
import { JWTAuthentication } from './auth/strategies/jwt'
|
import { JWTAuthentication } from './auth/strategies/jwt'
|
||||||
import localOperations from './collections/operations/local'
|
import localOperations from './collections/operations/local'
|
||||||
import findConfig from './config/find'
|
|
||||||
import buildEmail from './email/build'
|
import buildEmail from './email/build'
|
||||||
import { defaults as emailDefaults } from './email/defaults'
|
import { defaults as emailDefaults } from './email/defaults'
|
||||||
import sendEmail from './email/sendEmail'
|
import sendEmail from './email/sendEmail'
|
||||||
@@ -311,14 +310,14 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
|
|||||||
this.config = await options.config
|
this.config = await options.config
|
||||||
|
|
||||||
// TODO(JARROD/JAMES): can we keep this?
|
// TODO(JARROD/JAMES): can we keep this?
|
||||||
const configPath = findConfig()
|
// const configPath = findConfig()
|
||||||
this.config = {
|
this.config = {
|
||||||
...this.config,
|
...this.config,
|
||||||
paths: {
|
// paths: {
|
||||||
config: configPath,
|
// config: configPath,
|
||||||
configDir: path.dirname(configPath),
|
// configDir: path.dirname(configPath),
|
||||||
rawConfig: configPath,
|
// rawConfig: configPath,
|
||||||
},
|
// },
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.config.secret) {
|
if (!this.config.secret) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { ElementType } from 'react'
|
import type { ElementType } from 'react'
|
||||||
|
|
||||||
import { Tooltip } from 'payload/components'
|
import { Tooltip } from '@payloadcms/ui'
|
||||||
import React, { useCallback, useState } from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import { useSlate } from 'slate-react'
|
import { useSlate } from 'slate-react'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { ShimmerEffect } from 'payload/components'
|
import { ShimmerEffect } from '@payloadcms/ui'
|
||||||
import React, { Suspense, lazy } from 'react'
|
import React, { Suspense, lazy } from 'react'
|
||||||
|
|
||||||
import type { FieldProps } from '../types'
|
import type { FieldProps } from '../types'
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { RichTextAdapter } from 'payload/types'
|
import type { RichTextAdapter } from 'payload/types'
|
||||||
|
|
||||||
import { withMergedProps, withNullableJSONSchemaType } from 'payload/utilities'
|
import { withMergedProps } from '@payloadcms/ui/utilities'
|
||||||
|
import { withNullableJSONSchemaType } from 'payload/utilities'
|
||||||
|
|
||||||
import type { AdapterArguments } from './types'
|
import type { AdapterArguments } from './types'
|
||||||
|
|
||||||
|
|||||||
@@ -34,3 +34,4 @@ export { useDrawerSlug } from '../elements/Drawer/useDrawerSlug'
|
|||||||
export { default as Popup } from '../elements/Popup'
|
export { default as Popup } from '../elements/Popup'
|
||||||
// export { useThumbnail } from '../elements/Upload'
|
// export { useThumbnail } from '../elements/Upload'
|
||||||
export { Translation } from '../elements/Translation'
|
export { Translation } from '../elements/Translation'
|
||||||
|
export { Tooltip } from '../elements/Tooltip'
|
||||||
|
|||||||
@@ -290,8 +290,7 @@ const Relationship: React.FC<Props> = (props) => {
|
|||||||
await priorRelation
|
await priorRelation
|
||||||
|
|
||||||
const idsToLoad = ids.filter((id) => {
|
const idsToLoad = ids.filter((id) => {
|
||||||
return !options.find(
|
return !options.find((optionGroup) =>
|
||||||
(optionGroup) =>
|
|
||||||
optionGroup?.options?.find(
|
optionGroup?.options?.find(
|
||||||
(option) => option.value === id && option.relationTo === relation,
|
(option) => option.value === id && option.relationTo === relation,
|
||||||
),
|
),
|
||||||
|
|||||||
643
pnpm-lock.yaml
generated
643
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
packages:
|
packages:
|
||||||
# all packages in direct subdirs of packages/
|
# all packages in direct subdirs of packages/
|
||||||
- 'packages/*'
|
- 'packages/*'
|
||||||
|
- 'test/REST_API'
|
||||||
# exclude packages that are inside test directories
|
# exclude packages that are inside test directories
|
||||||
- '!**/test/**'
|
# - '!**/test/**'
|
||||||
|
|||||||
@@ -1,26 +1,34 @@
|
|||||||
import payload from '../../packages/payload/src'
|
import type { Payload } from '../../packages/payload/src'
|
||||||
|
|
||||||
import { devUser } from '../credentials'
|
import { devUser } from '../credentials'
|
||||||
import { initPayloadTest } from '../helpers/configHelpers'
|
import { initPayloadTest } from '../helpers/configHelpers'
|
||||||
import { postsSlug } from './collections/Posts'
|
import { postsSlug } from './collections/Posts'
|
||||||
|
|
||||||
require('isomorphic-fetch')
|
require('isomorphic-fetch')
|
||||||
|
|
||||||
let apiUrl
|
let payload: Payload
|
||||||
|
let apiURL: string
|
||||||
let jwt
|
let jwt
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
}
|
}
|
||||||
const { email, password } = devUser
|
const { email, password } = devUser
|
||||||
|
|
||||||
describe('_Community Tests', () => {
|
describe('_Community Tests', () => {
|
||||||
// --__--__--__--__--__--__--__--__--__
|
// --__--__--__--__--__--__--__--__--__
|
||||||
// Boilerplate test setup/teardown
|
// Boilerplate test setup/teardown
|
||||||
// --__--__--__--__--__--__--__--__--__
|
// --__--__--__--__--__--__--__--__--__
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } })
|
const { payload: payloadClient, serverURL } = await initPayloadTest({
|
||||||
apiUrl = `${serverURL}/api`
|
__dirname,
|
||||||
|
init: { local: false },
|
||||||
|
})
|
||||||
|
|
||||||
const response = await fetch(`${apiUrl}/users/login`, {
|
apiURL = `${serverURL}/api`
|
||||||
|
payload = payloadClient
|
||||||
|
|
||||||
|
const response = await fetch(`${apiURL}/users/login`, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
@@ -56,7 +64,7 @@ describe('_Community Tests', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('rest API example', async () => {
|
it('rest API example', async () => {
|
||||||
const newPost = await fetch(`${apiUrl}/${postsSlug}`, {
|
const newPost = await fetch(`${apiURL}/${postsSlug}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
...headers,
|
...headers,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import type { User } from '../../packages/payload/src/auth'
|
import type { User } from '../../packages/payload/src/auth'
|
||||||
import type { UIField } from '../../packages/payload/src/fields/config/types'
|
import type { UIField } from '../../packages/payload/src/fields/config/types'
|
||||||
|
|
||||||
import { useAuth } from '../../packages/payload/src/admin/components/utilities/Auth'
|
import { useAuth } from '../../packages/ui'
|
||||||
|
|
||||||
export const AuthDebug: React.FC<UIField> = () => {
|
export const AuthDebug: React.FC<UIField> = () => {
|
||||||
const [state, setState] = useState<User | null | undefined>()
|
const [state, setState] = useState<User | null | undefined>()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { GraphQLClient } from 'graphql-request'
|
import { GraphQLClient } from 'graphql-request'
|
||||||
import jwtDecode from 'jwt-decode'
|
import jwtDecode from 'jwt-decode'
|
||||||
|
|
||||||
|
import type { Payload } from '../../packages/payload/src'
|
||||||
import type { User } from '../../packages/payload/src/auth'
|
import type { User } from '../../packages/payload/src/auth'
|
||||||
|
|
||||||
import payload from '../../packages/payload/src'
|
|
||||||
import configPromise from '../collections-graphql/config'
|
import configPromise from '../collections-graphql/config'
|
||||||
import { devUser } from '../credentials'
|
import { devUser } from '../credentials'
|
||||||
import { initPayloadTest } from '../helpers/configHelpers'
|
import { initPayloadTest } from '../helpers/configHelpers'
|
||||||
@@ -13,6 +13,7 @@ require('isomorphic-fetch')
|
|||||||
|
|
||||||
let apiUrl
|
let apiUrl
|
||||||
let client: GraphQLClient
|
let client: GraphQLClient
|
||||||
|
let payload: Payload
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -22,7 +23,11 @@ const { email, password } = devUser
|
|||||||
|
|
||||||
describe('Auth', () => {
|
describe('Auth', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } })
|
const { serverURL, payload: payloadClient } = await initPayloadTest({
|
||||||
|
__dirname,
|
||||||
|
init: { local: false },
|
||||||
|
})
|
||||||
|
payload = payloadClient
|
||||||
apiUrl = `${serverURL}/api`
|
apiUrl = `${serverURL}/api`
|
||||||
const config = await configPromise
|
const config = await configPromise
|
||||||
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}`
|
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}`
|
||||||
@@ -35,6 +40,10 @@ describe('Auth', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules()
|
||||||
|
})
|
||||||
|
|
||||||
describe('GraphQL - admin user', () => {
|
describe('GraphQL - admin user', () => {
|
||||||
let token
|
let token
|
||||||
let user
|
let user
|
||||||
@@ -653,6 +662,14 @@ describe('Auth', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('REST API', () => {
|
||||||
|
it('should respond from route handlers', async () => {
|
||||||
|
const test = await fetch(`${apiUrl}/api/test`)
|
||||||
|
|
||||||
|
expect(test.status).toStrictEqual(200)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('API Key', () => {
|
describe('API Key', () => {
|
||||||
it('should authenticate via the correct API key user', async () => {
|
it('should authenticate via the correct API key user', async () => {
|
||||||
const usersQuery = await payload.find({
|
const usersQuery = await payload.find({
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import path from 'path'
|
|||||||
|
|
||||||
import type { Config, SanitizedConfig } from '../packages/payload/src/config/types'
|
import type { Config, SanitizedConfig } from '../packages/payload/src/config/types'
|
||||||
|
|
||||||
import { viteBundler } from '../packages/bundler-vite/src'
|
|
||||||
import { webpackBundler } from '../packages/bundler-webpack/src'
|
|
||||||
import { mongooseAdapter } from '../packages/db-mongodb/src'
|
import { mongooseAdapter } from '../packages/db-mongodb/src'
|
||||||
import { postgresAdapter } from '../packages/db-postgres/src'
|
import { postgresAdapter } from '../packages/db-postgres/src'
|
||||||
import { buildConfig as buildPayloadConfig } from '../packages/payload/src/config/build'
|
import { buildConfig as buildPayloadConfig } from '../packages/payload/src/config/build'
|
||||||
@@ -11,11 +9,6 @@ import { slateEditor } from '../packages/richtext-slate/src'
|
|||||||
|
|
||||||
// process.env.PAYLOAD_DATABASE = 'postgres'
|
// process.env.PAYLOAD_DATABASE = 'postgres'
|
||||||
|
|
||||||
const bundlerAdapters = {
|
|
||||||
vite: viteBundler(),
|
|
||||||
webpack: webpackBundler(),
|
|
||||||
}
|
|
||||||
|
|
||||||
const databaseAdapters = {
|
const databaseAdapters = {
|
||||||
mongoose: mongooseAdapter({
|
mongoose: mongooseAdapter({
|
||||||
migrationDir: path.resolve(__dirname, '../packages/db-mongodb/migrations'),
|
migrationDir: path.resolve(__dirname, '../packages/db-mongodb/migrations'),
|
||||||
@@ -30,10 +23,9 @@ const databaseAdapters = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<SanitizedConfig> {
|
export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<SanitizedConfig> {
|
||||||
const [name] = process.argv.slice(2)
|
|
||||||
|
|
||||||
const config: Config = {
|
const config: Config = {
|
||||||
editor: slateEditor({}),
|
secret: 'TEST_SECRET',
|
||||||
|
editor: undefined,
|
||||||
rateLimit: {
|
rateLimit: {
|
||||||
max: 9999999999,
|
max: 9999999999,
|
||||||
window: 15 * 60 * 1000, // 15min default,
|
window: 15 * 60 * 1000, // 15min default,
|
||||||
@@ -53,49 +45,6 @@ export function buildConfigWithDefaults(testConfig?: Partial<Config>): Promise<S
|
|||||||
},
|
},
|
||||||
...(config.admin || {}),
|
...(config.admin || {}),
|
||||||
buildPath: path.resolve(__dirname, '../build'),
|
buildPath: path.resolve(__dirname, '../build'),
|
||||||
bundler: bundlerAdapters[process.env.PAYLOAD_BUNDLER || 'webpack'],
|
|
||||||
webpack: (webpackConfig) => {
|
|
||||||
const existingConfig =
|
|
||||||
typeof testConfig?.admin?.webpack === 'function'
|
|
||||||
? testConfig.admin.webpack(webpackConfig)
|
|
||||||
: webpackConfig
|
|
||||||
return {
|
|
||||||
...existingConfig,
|
|
||||||
name,
|
|
||||||
cache: process.env.NODE_ENV === 'test' ? { type: 'memory' } : existingConfig.cache,
|
|
||||||
entry: {
|
|
||||||
main: [
|
|
||||||
`webpack-hot-middleware/client?path=${
|
|
||||||
testConfig?.routes?.admin || '/admin'
|
|
||||||
}/__webpack_hmr`,
|
|
||||||
path.resolve(__dirname, '../packages/payload/src/admin'),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
...existingConfig.resolve,
|
|
||||||
alias: {
|
|
||||||
...existingConfig.resolve?.alias,
|
|
||||||
[path.resolve(__dirname, '../packages/bundler-vite/src/index')]: path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'../packages/bundler-vite/mock.js',
|
|
||||||
),
|
|
||||||
[path.resolve(__dirname, '../packages/bundler-webpack/src/index')]: path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'../packages/bundler-webpack/src/mocks/emptyModule.js',
|
|
||||||
),
|
|
||||||
[path.resolve(__dirname, '../packages/db-mongodb/src/index')]: path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'../packages/db-mongodb/mock.js',
|
|
||||||
),
|
|
||||||
[path.resolve(__dirname, '../packages/db-postgres/src/index')]: path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'../packages/db-postgres/mock.js',
|
|
||||||
),
|
|
||||||
react: path.resolve(__dirname, '../packages/payload/node_modules/react'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.PAYLOAD_DISABLE_ADMIN === 'true') {
|
if (process.env.PAYLOAD_DISABLE_ADMIN === 'true') {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export default buildConfigWithDefaults({
|
|||||||
{
|
{
|
||||||
path: '/send-test-email',
|
path: '/send-test-email',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: async (req, res) => {
|
handler: async ({ req }) => {
|
||||||
await req.payload.sendEmail({
|
await req.payload.sendEmail({
|
||||||
from: 'dev@payloadcms.com',
|
from: 'dev@payloadcms.com',
|
||||||
to: devUser.email,
|
to: devUser.email,
|
||||||
@@ -55,19 +55,15 @@ export default buildConfigWithDefaults({
|
|||||||
// },
|
// },
|
||||||
})
|
})
|
||||||
|
|
||||||
res.status(200).send('Email sent')
|
return Response.json({ message: 'Email sent' })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/internal-error-here',
|
path: '/internal-error-here',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: async (req, res, next) => {
|
handler: () => {
|
||||||
try {
|
|
||||||
// Throwing an internal error with potentially sensitive data
|
// Throwing an internal error with potentially sensitive data
|
||||||
throw new Error('Lost connection to the Pentagon. Secret data: ******')
|
throw new Error('Lost connection to the Pentagon. Secret data: ******')
|
||||||
} catch (err) {
|
|
||||||
next(err)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ export default buildConfigWithDefaults({
|
|||||||
{
|
{
|
||||||
path: '/hello',
|
path: '/hello',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (_, res): void => {
|
handler: () => {
|
||||||
res.json({ message: 'hi' })
|
return Response.json({ message: 'hi' })
|
||||||
},
|
},
|
||||||
custom: { examples: [{ type: 'response', value: { message: 'hi' } }] },
|
custom: { examples: [{ type: 'response', value: { message: 'hi' } }] },
|
||||||
},
|
},
|
||||||
@@ -38,9 +38,9 @@ export default buildConfigWithDefaults({
|
|||||||
{
|
{
|
||||||
path: '/greet',
|
path: '/greet',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (req, res): void => {
|
handler: ({ req }) => {
|
||||||
const { name } = req.query
|
const sp = new URL(req.url).searchParams
|
||||||
res.json({ message: `Hi ${name}!` })
|
return Response.json({ message: `Hi ${sp.get('name')}!` })
|
||||||
},
|
},
|
||||||
custom: { params: [{ in: 'query', name: 'name', type: 'string' }] },
|
custom: { params: [{ in: 'query', name: 'name', type: 'string' }] },
|
||||||
},
|
},
|
||||||
@@ -60,8 +60,8 @@ export default buildConfigWithDefaults({
|
|||||||
path: '/config',
|
path: '/config',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
root: true,
|
root: true,
|
||||||
handler: (req, res): void => {
|
handler: ({ req }) => {
|
||||||
res.json(req.payload.config)
|
return Response.json(req.payload.config)
|
||||||
},
|
},
|
||||||
custom: { description: 'Get the sanitized payload config' },
|
custom: { description: 'Get the sanitized payload config' },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ describe('Config', () => {
|
|||||||
|
|
||||||
it('allows a custom field in collection endpoints', () => {
|
it('allows a custom field in collection endpoints', () => {
|
||||||
const [collection] = payload.config.collections
|
const [collection] = payload.config.collections
|
||||||
const [endpoint] = collection.endpoints
|
const [endpoint] = collection.endpoints || []
|
||||||
|
|
||||||
expect(endpoint.custom).toEqual({
|
expect(endpoint.custom).toEqual({
|
||||||
examples: [{ type: 'response', value: { message: 'hi' } }],
|
examples: [{ type: 'response', value: { message: 'hi' } }],
|
||||||
@@ -52,7 +52,7 @@ describe('Config', () => {
|
|||||||
|
|
||||||
it('allows a custom field in global endpoints', () => {
|
it('allows a custom field in global endpoints', () => {
|
||||||
const [global] = payload.config.globals
|
const [global] = payload.config.globals
|
||||||
const [endpoint] = global.endpoints
|
const [endpoint] = global.endpoints || []
|
||||||
|
|
||||||
expect(endpoint.custom).toEqual({ params: [{ in: 'query', name: 'name', type: 'string' }] })
|
expect(endpoint.custom).toEqual({ params: [{ in: 'query', name: 'name', type: 'string' }] })
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { GraphQLClient } from 'graphql-request'
|
import { GraphQLClient } from 'graphql-request'
|
||||||
|
|
||||||
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/express/types'
|
import type { PayloadRequest } from '../../packages/payload/src/types'
|
||||||
|
|
||||||
import payload from '../../packages/payload/src'
|
import payload from '../../packages/payload/src'
|
||||||
import { commitTransaction } from '../../packages/payload/src/utilities/commitTransaction'
|
import { commitTransaction } from '../../packages/payload/src/utilities/commitTransaction'
|
||||||
|
|||||||
27
test/dev.ts
27
test/dev.ts
@@ -1,11 +1,10 @@
|
|||||||
import * as dotenv from 'dotenv'
|
import * as dotenv from 'dotenv'
|
||||||
import express from 'express'
|
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { v4 as uuid } from 'uuid'
|
|
||||||
|
|
||||||
import payload from '../packages/payload/src'
|
import { getPayload } from '../packages/payload/src'
|
||||||
import { prettySyncLoggerDestination } from '../packages/payload/src/utilities/logger'
|
import { prettySyncLoggerDestination } from '../packages/payload/src/utilities/logger'
|
||||||
|
import { bootAdminPanel } from './helpers/bootAdminPanel'
|
||||||
import { startLivePreviewDemo } from './live-preview/startLivePreviewDemo'
|
import { startLivePreviewDemo } from './live-preview/startLivePreviewDemo'
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
@@ -46,42 +45,30 @@ if (process.argv.includes('--no-auto-login') && process.env.NODE_ENV !== 'produc
|
|||||||
process.env.PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN = 'true'
|
process.env.PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN = 'true'
|
||||||
}
|
}
|
||||||
|
|
||||||
const expressApp = express()
|
|
||||||
|
|
||||||
const startDev = async () => {
|
const startDev = async () => {
|
||||||
await payload.init({
|
const payload = await getPayload({
|
||||||
email: {
|
email: {
|
||||||
fromAddress: 'hello@payloadcms.com',
|
fromAddress: 'hello@payloadcms.com',
|
||||||
fromName: 'Payload',
|
fromName: 'Payload',
|
||||||
logMockCredentials: false,
|
logMockCredentials: false,
|
||||||
},
|
},
|
||||||
express: expressApp,
|
config: require(configPath).default,
|
||||||
secret: uuid(),
|
|
||||||
...prettySyncLogger,
|
...prettySyncLogger,
|
||||||
onInit: async (payload) => {
|
onInit: (payload) => {
|
||||||
payload.logger.info('Payload Dev Server Initialized')
|
payload.logger.info('Payload Dev Server Initialized')
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Redirect root to Admin panel
|
|
||||||
expressApp.get('/', (_, res) => {
|
|
||||||
res.redirect('/admin')
|
|
||||||
})
|
|
||||||
|
|
||||||
const externalRouter = express.Router()
|
|
||||||
|
|
||||||
externalRouter.use(payload.authenticate)
|
|
||||||
|
|
||||||
if (testSuiteDir === 'live-preview') {
|
if (testSuiteDir === 'live-preview') {
|
||||||
await startLivePreviewDemo({
|
await startLivePreviewDemo({
|
||||||
payload,
|
payload,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
expressApp.listen(3000, async () => {
|
await bootAdminPanel({ appDir: path.resolve(__dirname, '../packages/dev') })
|
||||||
|
|
||||||
payload.logger.info(`Admin URL on http://localhost:3000${payload.getAdminURL()}`)
|
payload.logger.info(`Admin URL on http://localhost:3000${payload.getAdminURL()}`)
|
||||||
payload.logger.info(`API URL on http://localhost:3000${payload.getAPIURL()}`)
|
payload.logger.info(`API URL on http://localhost:3000${payload.getAPIURL()}`)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import path from 'path'
|
|
||||||
|
|
||||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
|
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
|
||||||
import { devUser } from '../credentials'
|
import { devUser } from '../credentials'
|
||||||
import { collectionEndpoints } from './endpoints/collections'
|
import { collectionEndpoints } from './endpoints/collections'
|
||||||
@@ -61,20 +59,6 @@ export default buildConfigWithDefaults({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
endpoints,
|
endpoints,
|
||||||
admin: {
|
|
||||||
webpack: (config) => {
|
|
||||||
return {
|
|
||||||
...config,
|
|
||||||
resolve: {
|
|
||||||
...config.resolve,
|
|
||||||
alias: {
|
|
||||||
...config.resolve.alias,
|
|
||||||
express: path.resolve(__dirname, './mocks/emptyModule.js'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onInit: async (payload) => {
|
onInit: async (payload) => {
|
||||||
await payload.create({
|
await payload.create({
|
||||||
collection: 'users',
|
collection: 'users',
|
||||||
|
|||||||
@@ -1,37 +1,34 @@
|
|||||||
import type { Response } from 'express'
|
|
||||||
|
|
||||||
import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
|
import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
|
||||||
import type { PayloadRequest } from '../../../packages/payload/src/express/types'
|
|
||||||
|
|
||||||
export const collectionEndpoints: CollectionConfig['endpoints'] = [
|
export const collectionEndpoints: CollectionConfig['endpoints'] = [
|
||||||
{
|
{
|
||||||
path: '/say-hello/joe-bloggs',
|
path: '/say-hello/joe-bloggs',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: () => {
|
||||||
res.json({ message: 'Hey Joey!' })
|
return Response.json({ message: 'Hey Joey!' })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/say-hello/:group/:name',
|
path: '/say-hello/:group/:name',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ routeParams }) => {
|
||||||
res.json({ message: `Hello ${req.params.name} @ ${req.params.group}` })
|
return Response.json({ message: `Hello ${routeParams.name} @ ${routeParams.group}` })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/say-hello/:name',
|
path: '/say-hello/:name',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ routeParams }) => {
|
||||||
res.json({ message: `Hello ${req.params.name}!` })
|
return Response.json({ message: `Hello ${routeParams.name}!` })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/whoami',
|
path: '/whoami',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ req }) => {
|
||||||
res.json({
|
return Response.json({
|
||||||
name: req.body.name,
|
name: req.data.name,
|
||||||
age: req.body.age,
|
age: req.data.age,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import type { Response } from 'express'
|
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../../packages/payload/src/express/types'
|
|
||||||
import type { GlobalConfig } from '../../../packages/payload/src/globals/config/types'
|
import type { GlobalConfig } from '../../../packages/payload/src/globals/config/types'
|
||||||
|
|
||||||
import { globalEndpoint } from '../shared'
|
import { globalEndpoint } from '../shared'
|
||||||
@@ -9,8 +6,8 @@ export const globalEndpoints: GlobalConfig['endpoints'] = [
|
|||||||
{
|
{
|
||||||
path: `/${globalEndpoint}`,
|
path: `/${globalEndpoint}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ req }) => {
|
||||||
res.json(req.body)
|
return Response.json(req.body)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import type { Response } from 'express'
|
|
||||||
|
|
||||||
import express from 'express'
|
|
||||||
|
|
||||||
import type { Config } from '../../../packages/payload/src/config/types'
|
import type { Config } from '../../../packages/payload/src/config/types'
|
||||||
import type { PayloadRequest } from '../../../packages/payload/src/express/types'
|
|
||||||
|
|
||||||
import { applicationEndpoint, rootEndpoint } from '../shared'
|
import { applicationEndpoint, rootEndpoint } from '../shared'
|
||||||
|
|
||||||
@@ -11,41 +6,38 @@ export const endpoints: Config['endpoints'] = [
|
|||||||
{
|
{
|
||||||
path: `/${applicationEndpoint}`,
|
path: `/${applicationEndpoint}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ req }) => {
|
||||||
res.json(req.body)
|
return Response.json(req.body)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/${applicationEndpoint}`,
|
path: `/${applicationEndpoint}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ req }) => {
|
||||||
res.json({ message: 'Hello, world!' })
|
return Response.json({ message: 'Hello, world!' })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/${applicationEndpoint}/i18n`,
|
path: `/${applicationEndpoint}/i18n`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: ({ req }) => {
|
||||||
res.json({ message: req.t('general:backToDashboard') })
|
return Response.json({ message: req.t('general:backToDashboard') })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/${rootEndpoint}`,
|
path: `/${rootEndpoint}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
root: true,
|
root: true,
|
||||||
handler: (req: PayloadRequest, res: Response): void => {
|
handler: () => {
|
||||||
res.json({ message: 'Hello, world!' })
|
return Response.json({ message: 'Hello, world!' })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/${rootEndpoint}`,
|
path: `/${rootEndpoint}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
root: true,
|
root: true,
|
||||||
handler: [
|
handler: ({ req }) => {
|
||||||
express.json({ type: 'application/json' }),
|
return Response.json(req.body)
|
||||||
(req: PayloadRequest, res: Response): void => {
|
|
||||||
res.json(req.body)
|
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
39
test/helpers/bootAdminPanel.ts
Normal file
39
test/helpers/bootAdminPanel.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { createServer } from 'http'
|
||||||
|
import next from 'next'
|
||||||
|
import { parse } from 'url'
|
||||||
|
|
||||||
|
type args = {
|
||||||
|
appDir: string
|
||||||
|
port?: number
|
||||||
|
}
|
||||||
|
export const bootAdminPanel = async ({ port = 3000, appDir }: args) => {
|
||||||
|
const serverURL = `http://localhost:${port}`
|
||||||
|
const app = next({
|
||||||
|
dev: true,
|
||||||
|
hostname: 'localhost',
|
||||||
|
port,
|
||||||
|
dir: appDir,
|
||||||
|
})
|
||||||
|
|
||||||
|
const handle = app.getRequestHandler()
|
||||||
|
await app.prepare()
|
||||||
|
|
||||||
|
createServer(async (req, res) => {
|
||||||
|
try {
|
||||||
|
const parsedUrl = parse(req.url, true)
|
||||||
|
console.log('Requested path: ', parsedUrl.path)
|
||||||
|
await handle(req, res, parsedUrl)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error occurred handling', req.url, err)
|
||||||
|
res.statusCode = 500
|
||||||
|
res.end('internal server error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.once('error', (err) => {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
.listen(port, () => {
|
||||||
|
console.log(`> Ready on ${serverURL}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
import swcRegister from '@swc/register'
|
|
||||||
import express from 'express'
|
|
||||||
import getPort from 'get-port'
|
import getPort from 'get-port'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import shelljs from 'shelljs'
|
import shelljs from 'shelljs'
|
||||||
import { v4 as uuid } from 'uuid'
|
|
||||||
|
|
||||||
import type { Payload } from '../../packages/payload/src'
|
import type { Payload } from '../../packages/payload/src'
|
||||||
import type { InitOptions } from '../../packages/payload/src/config/types'
|
import type { InitOptions } from '../../packages/payload/src/config/types'
|
||||||
|
|
||||||
import payload from '../../packages/payload/src'
|
import { getPayload } from '../../packages/payload/src'
|
||||||
|
import { bootAdminPanel } from './bootAdminPanel'
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
__dirname: string
|
__dirname: string
|
||||||
@@ -29,42 +27,31 @@ export async function initPayloadE2E(__dirname: string): Promise<InitializedPayl
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function initPayloadTest(options: Options): Promise<InitializedPayload> {
|
export async function initPayloadTest(options: Options): Promise<InitializedPayload> {
|
||||||
const initOptions = {
|
process.env.PAYLOAD_CONFIG_PATH = path.resolve(options.__dirname, './config.ts')
|
||||||
|
|
||||||
|
const initOptions: InitOptions = {
|
||||||
local: true,
|
local: true,
|
||||||
secret: uuid(),
|
config: require(process.env.PAYLOAD_CONFIG_PATH).default,
|
||||||
mongoURL: `mongodb://localhost/${uuid()}`,
|
// loggerOptions: {
|
||||||
|
// enabled: false,
|
||||||
|
// },
|
||||||
...(options.init || {}),
|
...(options.init || {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
process.env.PAYLOAD_DROP_DATABASE = 'true'
|
process.env.PAYLOAD_DROP_DATABASE = 'true'
|
||||||
process.env.NODE_ENV = 'test'
|
process.env.NODE_ENV = 'test'
|
||||||
process.env.PAYLOAD_CONFIG_PATH = path.resolve(options.__dirname, './config.ts')
|
|
||||||
|
|
||||||
if (!initOptions?.local) {
|
const payload = await getPayload(initOptions)
|
||||||
initOptions.express = express()
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - bad @swc/register types
|
|
||||||
swcRegister({
|
|
||||||
sourceMaps: 'inline',
|
|
||||||
jsc: {
|
|
||||||
parser: {
|
|
||||||
syntax: 'typescript',
|
|
||||||
tsx: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
type: 'commonjs',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
await payload.init(initOptions)
|
|
||||||
|
|
||||||
const port = await getPort()
|
const port = await getPort()
|
||||||
if (initOptions.express) {
|
const serverURL = `http://localhost:${port}`
|
||||||
initOptions.express.listen(port)
|
|
||||||
|
if (!initOptions?.local) {
|
||||||
|
process.env.APP_ENV = 'test'
|
||||||
|
process.env.__NEXT_TEST_MODE = 'jest'
|
||||||
|
await bootAdminPanel({ port, appDir: path.resolve(__dirname, '../../packages/dev') })
|
||||||
|
jest.resetModules()
|
||||||
}
|
}
|
||||||
|
|
||||||
return { serverURL: `http://localhost:${port}`, payload }
|
return { serverURL, payload }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import payload 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 { initPayloadTest } from '../helpers/configHelpers'
|
||||||
import { RESTClient } from '../helpers/rest'
|
|
||||||
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'
|
||||||
@@ -17,17 +16,14 @@ 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 configPromise, { HooksConfig } from './config'
|
import { HooksConfig } from './config'
|
||||||
import { dataHooksGlobalSlug } from './globals/Data'
|
import { dataHooksGlobalSlug } from './globals/Data'
|
||||||
|
|
||||||
let client: RESTClient
|
|
||||||
let apiUrl
|
let apiUrl
|
||||||
|
|
||||||
describe('Hooks', () => {
|
describe('Hooks', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } })
|
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } })
|
||||||
const config = await configPromise
|
|
||||||
client = new RESTClient(config, { serverURL, defaultSlug: transformSlug })
|
|
||||||
apiUrl = `${serverURL}/api`
|
apiUrl = `${serverURL}/api`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Payload } from '../../../packages/payload/src'
|
import type { Payload } from '../../../packages/payload/src'
|
||||||
import type { PayloadRequest } from '../../../packages/payload/src/express/types'
|
import type { PayloadRequest } from '../../../packages/payload/src/types'
|
||||||
|
|
||||||
import { formsSlug, pagesSlug } from '../shared'
|
import { formsSlug, pagesSlug } from '../shared'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Payload } from '../../../packages/payload/src'
|
import type { Payload } from '../../../packages/payload/src'
|
||||||
import type { PayloadRequest } from '../../../packages/payload/src/express/types'
|
import type { PayloadRequest } from '../../../packages/payload/src/types'
|
||||||
|
|
||||||
export const seed = async (payload: Payload): Promise<boolean> => {
|
export const seed = async (payload: Payload): Promise<boolean> => {
|
||||||
payload.logger.info('Seeding data...')
|
payload.logger.info('Seeding data...')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import wait from '../../packages/payload/dist/utilities/wait'
|
|
||||||
import payload from '../../packages/payload/src'
|
import payload from '../../packages/payload/src'
|
||||||
|
import wait from '../../packages/payload/src/utilities/wait'
|
||||||
import { initPayloadTest } from '../helpers/configHelpers'
|
import { initPayloadTest } from '../helpers/configHelpers'
|
||||||
|
|
||||||
describe('Search Plugin', () => {
|
describe('Search Plugin', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { randomBytes } from 'crypto'
|
import { randomBytes } from 'crypto'
|
||||||
|
|
||||||
import type { PayloadRequest } from '../../packages/payload/src/express/types'
|
import type { PayloadRequest } from '../../packages/payload/src/types'
|
||||||
import type {
|
import type {
|
||||||
ChainedRelation,
|
ChainedRelation,
|
||||||
CustomIdNumberRelation,
|
CustomIdNumberRelation,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"noEmit": false /* Do not emit outputs. */,
|
"noEmit": false /* Do not emit outputs. */,
|
||||||
"emitDeclarationOnly": true,
|
"emitDeclarationOnly": true,
|
||||||
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
||||||
"rootDir": "../" /* Specify the root folder within your source files. */
|
"rootDir": "../" /* Specify the root folder within your source files. */,
|
||||||
},
|
},
|
||||||
"exclude": ["dist", "build", "node_modules", ".eslintrc.js"],
|
"exclude": ["dist", "build", "node_modules", ".eslintrc.js"],
|
||||||
"include": [
|
"include": [
|
||||||
@@ -14,6 +14,11 @@
|
|||||||
"src/**/*.json",
|
"src/**/*.json",
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
"test/**/*.tsx",
|
"test/**/*.tsx",
|
||||||
"../packages/**/src/**/*.ts"
|
"../packages/**/src/**/*.ts",
|
||||||
]
|
],
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next",
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import path from 'path'
|
|
||||||
|
|
||||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
|
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
|
||||||
import AutosavePosts from './collections/Autosave'
|
import AutosavePosts from './collections/Autosave'
|
||||||
import DisablePublish from './collections/DisablePublish'
|
import DisablePublish from './collections/DisablePublish'
|
||||||
@@ -12,18 +10,6 @@ import DraftGlobal from './globals/Draft'
|
|||||||
import { clearAndSeedEverything } from './seed'
|
import { clearAndSeedEverything } from './seed'
|
||||||
|
|
||||||
export default buildConfigWithDefaults({
|
export default buildConfigWithDefaults({
|
||||||
admin: {
|
|
||||||
webpack: (config) => ({
|
|
||||||
...config,
|
|
||||||
resolve: {
|
|
||||||
...config.resolve,
|
|
||||||
alias: {
|
|
||||||
...config?.resolve?.alias,
|
|
||||||
fs: path.resolve(__dirname, './mocks/emptyModule.js'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
collections: [DisablePublish, Posts, AutosavePosts, DraftPosts, VersionPosts],
|
collections: [DisablePublish, Posts, AutosavePosts, DraftPosts, VersionPosts],
|
||||||
globals: [AutosaveGlobal, DraftGlobal, DisablePublishGlobal],
|
globals: [AutosaveGlobal, DraftGlobal, DisablePublishGlobal],
|
||||||
indexSortableFields: true,
|
indexSortableFields: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user