chore(examples/testing): builds testing example (#3443)
This commit is contained in:
5
examples/testing/.env.example
Normal file
5
examples/testing/.env.example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
PORT=3000
|
||||||
|
MONGO_URL=mongodb://127.0.0.1/your-project-name
|
||||||
|
PAYLOAD_SECRET_KEY=alwifhjoq284jgo5w34jgo43f3
|
||||||
|
PAYLOAD_CONFIG_PATH=src/payload.config.ts
|
||||||
|
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
|
||||||
142
examples/testing/README.md
Normal file
142
examples/testing/README.md
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
# Payload Testing Example
|
||||||
|
|
||||||
|
This example demonstrates how to get started with testing Payload using [Jest](https://jestjs.io/). You can clone this down and use it as a starting point for your own Payload projects, or you can follow the steps below to add testing to your existing Payload project.
|
||||||
|
|
||||||
|
## Add testing to your existing Payload project
|
||||||
|
|
||||||
|
1. Initial setup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# install dependencies
|
||||||
|
yarn add --dev jest mongodb-memory-server @swc/jest @swc/core isomorphic-fetch @types/jest
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# create a .env file
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
2. This example uses the following folder structure:
|
||||||
|
```
|
||||||
|
root
|
||||||
|
└─ /src
|
||||||
|
└─ payload.config.ts
|
||||||
|
└─ /tests
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Add test credentials to your project. Create a file at `src/tests/credentials.ts` with the following contents:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export default {
|
||||||
|
email: 'test@test.com',
|
||||||
|
password: 'test',
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Add the global setup file to your project. This file will be run before any tests are run. It will start a MongoDB server and create a Payload instance for you to use in your tests. Create a file at `src/tests/globalSetup.ts` with the following contents:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import payload from 'payload';
|
||||||
|
import express from 'express';
|
||||||
|
import testCredentials from './credentials';
|
||||||
|
|
||||||
|
require('dotenv').config({
|
||||||
|
path: resolve(__dirname, '../../.env'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const globalSetup = async () => {
|
||||||
|
await payload.init({
|
||||||
|
secret: process.env.PAYLOAD_SECRET_KEY,
|
||||||
|
mongoURL: process.env.MONGO_URL,
|
||||||
|
express: app,
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(process.env.PORT, async () => {
|
||||||
|
console.log(`Express is now listening for incoming connections on port ${process.env.PORT}.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await fetch(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/users/first-register`, {
|
||||||
|
body: JSON.stringify({
|
||||||
|
email: testCredentials.email,
|
||||||
|
password: testCredentials.password,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!data.user || !data.user.token) {
|
||||||
|
throw new Error('Failed to register first user');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default globalSetup;
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Add a `jest.config.ts` file to the root of your project:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
module.exports = {
|
||||||
|
verbose: true,
|
||||||
|
globalSetup: '<rootDir>/src/tests/globalSetup.ts',
|
||||||
|
roots: ['<rootDir>/src/'],
|
||||||
|
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(t|j)sx?$': [
|
||||||
|
'@swc/jest',
|
||||||
|
{
|
||||||
|
jsc: {
|
||||||
|
target: 'es2021',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Write your first test. Create a file at `src/tests/login.spec.ts` with the following contents:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { User } from '../payload-types';
|
||||||
|
import testCredentials from './credentials';
|
||||||
|
|
||||||
|
describe('Users', () => {
|
||||||
|
it('should allow a user to log in', async () => {
|
||||||
|
const result: {
|
||||||
|
token: string
|
||||||
|
user: User
|
||||||
|
} = await fetch(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/users/login`, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
email: testCredentials.email,
|
||||||
|
password: testCredentials.password,
|
||||||
|
}),
|
||||||
|
}).then((res) => res.json());
|
||||||
|
|
||||||
|
expect(result.token).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Add a script to run tests via the command line. Add the following to your `package.json` scripts:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"scripts": {
|
||||||
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest --forceExit --detectOpenHandles"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
8. Run your tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
16
examples/testing/jest.config.ts
Normal file
16
examples/testing/jest.config.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module.exports = {
|
||||||
|
verbose: true,
|
||||||
|
globalSetup: '<rootDir>/src/tests/globalSetup.ts',
|
||||||
|
roots: ['<rootDir>/src/'],
|
||||||
|
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(t|j)sx?$': [
|
||||||
|
'@swc/jest',
|
||||||
|
{
|
||||||
|
jsc: {
|
||||||
|
target: 'es2021',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
6
examples/testing/nodemon.json
Normal file
6
examples/testing/nodemon.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"watch": [
|
||||||
|
"./src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exec": "ts-node ./src/server.ts"
|
||||||
|
}
|
||||||
32
examples/testing/package.json
Normal file
32
examples/testing/package.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "jest-payload",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"get-tsconfig": "^4.7.0",
|
||||||
|
"payload": "^1.15.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@swc/core": "^1.3.84",
|
||||||
|
"@swc/jest": "^0.2.29",
|
||||||
|
"@types/jest": "^29.5.4",
|
||||||
|
"isomorphic-fetch": "^3.0.0",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"mongodb-memory-server": "^8.15.1",
|
||||||
|
"nodemon": "^3.0.1",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"typescript": "^5.2.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"generate:types": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
|
||||||
|
"dev": "nodemon",
|
||||||
|
"build:payload": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build",
|
||||||
|
"build:server": "tsc",
|
||||||
|
"build": "yarn build:server && yarn build:payload",
|
||||||
|
"serve": "PAYLOAD_CONFIG_PATH=dist/payload.config.js NODE_ENV=production node dist/server.js",
|
||||||
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest --forceExit --detectOpenHandles"
|
||||||
|
}
|
||||||
|
}
|
||||||
35
examples/testing/src/payload-types.ts
Normal file
35
examples/testing/src/payload-types.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* This file was automatically generated by Payload.
|
||||||
|
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||||
|
* and re-run `payload generate:types` to regenerate this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
collections: {
|
||||||
|
posts: Post
|
||||||
|
users: User
|
||||||
|
}
|
||||||
|
globals: {}
|
||||||
|
}
|
||||||
|
export interface Post {
|
||||||
|
id: string
|
||||||
|
title?: string
|
||||||
|
author?: string | User
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
export interface User {
|
||||||
|
id: string
|
||||||
|
updatedAt: string
|
||||||
|
createdAt: string
|
||||||
|
email: string
|
||||||
|
resetPasswordToken?: string
|
||||||
|
resetPasswordExpiration?: string
|
||||||
|
salt?: string
|
||||||
|
hash?: string
|
||||||
|
loginAttempts?: number
|
||||||
|
lockUntil?: string
|
||||||
|
password?: string
|
||||||
|
}
|
||||||
33
examples/testing/src/payload.config.ts
Normal file
33
examples/testing/src/payload.config.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import dotenv from 'dotenv'
|
||||||
|
import { buildConfig } from 'payload/config'
|
||||||
|
|
||||||
|
dotenv.config({
|
||||||
|
path: path.resolve(__dirname, '../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default buildConfig({
|
||||||
|
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
|
||||||
|
typescript: {
|
||||||
|
outputFile: path.resolve(__dirname, 'payload-types.ts'),
|
||||||
|
},
|
||||||
|
collections: [
|
||||||
|
{
|
||||||
|
slug: 'posts',
|
||||||
|
admin: {
|
||||||
|
useAsTitle: 'title',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'author',
|
||||||
|
type: 'relationship',
|
||||||
|
relationTo: 'users',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
24
examples/testing/src/server.ts
Normal file
24
examples/testing/src/server.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import express from 'express'
|
||||||
|
import payload from 'payload'
|
||||||
|
|
||||||
|
// Use `dotenv` to import your `.env` file automatically
|
||||||
|
require('dotenv').config({
|
||||||
|
path: path.resolve(__dirname, '../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
async function start() {
|
||||||
|
await payload.init({
|
||||||
|
secret: process.env.PAYLOAD_SECRET_KEY,
|
||||||
|
mongoURL: process.env.MONGO_URL,
|
||||||
|
express: app,
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(process.env.PORT, async () => {
|
||||||
|
console.log(`Express is now listening for incoming connections on port ${process.env.PORT}.`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
start()
|
||||||
4
examples/testing/src/tests/credentials.ts
Normal file
4
examples/testing/src/tests/credentials.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
email: 'test@test.com',
|
||||||
|
password: 'test',
|
||||||
|
}
|
||||||
44
examples/testing/src/tests/globalSetup.ts
Normal file
44
examples/testing/src/tests/globalSetup.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { resolve } from 'path'
|
||||||
|
import payload from 'payload'
|
||||||
|
import express from 'express'
|
||||||
|
import testCredentials from './credentials'
|
||||||
|
|
||||||
|
require('dotenv').config({
|
||||||
|
path: resolve(__dirname, '../../.env'),
|
||||||
|
})
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
const globalSetup = async () => {
|
||||||
|
await payload.init({
|
||||||
|
secret: process.env.PAYLOAD_SECRET_KEY,
|
||||||
|
mongoURL: process.env.MONGO_URL,
|
||||||
|
express: app,
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(process.env.PORT, async () => {
|
||||||
|
console.log(`Express is now listening for incoming connections on port ${process.env.PORT}.`)
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/users/first-register`,
|
||||||
|
{
|
||||||
|
body: JSON.stringify({
|
||||||
|
email: testCredentials.email,
|
||||||
|
password: testCredentials.password,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const data = await response.json()
|
||||||
|
|
||||||
|
if (!data.user || !data.user.token) {
|
||||||
|
throw new Error('Failed to register first user')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default globalSetup
|
||||||
22
examples/testing/src/tests/login.spec.ts
Normal file
22
examples/testing/src/tests/login.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { User } from '../payload-types'
|
||||||
|
import testCredentials from './credentials'
|
||||||
|
|
||||||
|
describe('Users', () => {
|
||||||
|
it('should allow a user to log in', async () => {
|
||||||
|
const result: {
|
||||||
|
token: string
|
||||||
|
user: User
|
||||||
|
} = await fetch(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/api/users/login`, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
email: testCredentials.email,
|
||||||
|
password: testCredentials.password,
|
||||||
|
}),
|
||||||
|
}).then((res) => res.json())
|
||||||
|
|
||||||
|
expect(result.token).toBeDefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
27
examples/testing/tsconfig.json
Normal file
27
examples/testing/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"outDir": "./dist",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"ts-node": {
|
||||||
|
"transpileOnly": true
|
||||||
|
}
|
||||||
|
}
|
||||||
8667
examples/testing/yarn.lock
Normal file
8667
examples/testing/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ module.exports = {
|
|||||||
'<rootDir>/packages/payload/src/bundlers/mocks/fileMock.js',
|
'<rootDir>/packages/payload/src/bundlers/mocks/fileMock.js',
|
||||||
},
|
},
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: ['**/packages/payload/src/**/*.spec.ts', '**/test/**/*int.spec.ts'],
|
testMatch: ['<rootDir>/packages/payload/src/**/*.spec.ts', '<rootDir>/test/**/*int.spec.ts'],
|
||||||
testTimeout: 90000,
|
testTimeout: 90000,
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.(t|j)sx?$': ['@swc/jest'],
|
'^.+\\.(t|j)sx?$': ['@swc/jest'],
|
||||||
|
|||||||
Reference in New Issue
Block a user