Merge branch 'master' into feat/validate-extended-args
This commit is contained in:
@@ -14,10 +14,13 @@ describe('Collections - Local', () => {
|
||||
describe('Create', () => {
|
||||
it('should allow an upload-enabled file to be created and uploaded', async () => {
|
||||
const alt = 'Alt Text Here';
|
||||
const filePath = path.resolve(__dirname, '../../../admin/assets/images/generic-block-image.svg');
|
||||
const filePath = path.resolve(
|
||||
__dirname,
|
||||
'../../../admin/assets/images/generic-block-image.svg',
|
||||
);
|
||||
const { size } = fs.statSync(filePath);
|
||||
|
||||
const result = await payload.create({
|
||||
const result: Media = await payload.create({
|
||||
collection: 'media',
|
||||
data: {
|
||||
alt,
|
||||
@@ -37,7 +40,7 @@ describe('Collections - Local', () => {
|
||||
it('should allow an upload-enabled file to be re-uploaded and alt-text to be changed.', async () => {
|
||||
const newAltText = 'New Alt Text Here';
|
||||
|
||||
const result = await payload.update({
|
||||
const result: Media = await payload.update({
|
||||
collection: 'media',
|
||||
id: createdMediaID,
|
||||
data: {
|
||||
@@ -115,7 +118,9 @@ describe('Collections - Local', () => {
|
||||
showHiddenFields: true,
|
||||
});
|
||||
|
||||
expect(relationshipBWithHiddenNestedField.post[0].demoHiddenField).toStrictEqual(demoHiddenField);
|
||||
expect(relationshipBWithHiddenNestedField.post[0].demoHiddenField).toStrictEqual(
|
||||
demoHiddenField,
|
||||
);
|
||||
});
|
||||
describe('Find', () => {
|
||||
const title = 'local-find';
|
||||
@@ -139,9 +144,11 @@ describe('Collections - Local', () => {
|
||||
{
|
||||
blockType: 'richTextBlock',
|
||||
blockName: 'Test Block Name',
|
||||
content: [{
|
||||
children: [{ text: 'english' }],
|
||||
}],
|
||||
content: [
|
||||
{
|
||||
children: [{ text: 'english' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -185,3 +192,27 @@ describe('Collections - Local', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
interface ImageSize {
|
||||
url?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
mimeType?: string;
|
||||
filesize?: number;
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
interface Media {
|
||||
id?: string;
|
||||
filename?: string;
|
||||
filesize?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
sizes?: {
|
||||
maintainedAspectRatio?: ImageSize;
|
||||
tablet?: ImageSize;
|
||||
mobile?: ImageSize;
|
||||
icon?: ImageSize;
|
||||
};
|
||||
alt: string;
|
||||
}
|
||||
@@ -63,9 +63,11 @@ describe('Collections - REST', () => {
|
||||
{
|
||||
blockType: 'richTextBlock',
|
||||
blockName: 'Test Block Name',
|
||||
content: [{
|
||||
children: [{ text: 'english' }],
|
||||
}],
|
||||
content: [
|
||||
{
|
||||
children: [{ text: 'english' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -106,9 +108,11 @@ describe('Collections - REST', () => {
|
||||
body: JSON.stringify({
|
||||
title: 'newTitle',
|
||||
description: 'original description',
|
||||
richText: [{
|
||||
children: [{ text: 'english' }],
|
||||
}],
|
||||
richText: [
|
||||
{
|
||||
children: [{ text: 'english' }],
|
||||
},
|
||||
],
|
||||
priority: 1,
|
||||
}),
|
||||
headers,
|
||||
@@ -120,9 +124,11 @@ describe('Collections - REST', () => {
|
||||
const { id } = createData.doc;
|
||||
|
||||
const updatedDesc = 'updated description';
|
||||
const updatedRichText = [{
|
||||
children: [{ text: 'english update' }],
|
||||
}];
|
||||
const updatedRichText = [
|
||||
{
|
||||
children: [{ text: 'english update' }],
|
||||
},
|
||||
];
|
||||
const updatedNonLocalizedArray = [
|
||||
{
|
||||
localizedEmbeddedText: 'english',
|
||||
@@ -152,10 +158,12 @@ describe('Collections - REST', () => {
|
||||
expect(data.doc.richText[0].children[0].text).toBe('english update');
|
||||
|
||||
// make certain the stored object is exactly the same as the returned object
|
||||
const stored = await (await fetch(`${url}/api/localized-posts/${id}`, {
|
||||
method: 'get',
|
||||
headers,
|
||||
})).json();
|
||||
const stored = await (
|
||||
await fetch(`${url}/api/localized-posts/${id}`, {
|
||||
method: 'get',
|
||||
headers,
|
||||
})
|
||||
).json();
|
||||
|
||||
expect(data.doc).toMatchObject(stored);
|
||||
});
|
||||
@@ -181,9 +189,11 @@ describe('Collections - REST', () => {
|
||||
{
|
||||
blockType: 'richTextBlock',
|
||||
blockName: 'Test Block Name',
|
||||
content: [{
|
||||
children: [{ text: 'spanish' }],
|
||||
}],
|
||||
content: [
|
||||
{
|
||||
children: [{ text: 'spanish' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -289,14 +299,18 @@ describe('Collections - REST', () => {
|
||||
});
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
const getResponse = await fetch(`${url}/api/localized-posts?where[description][equals]=${desc}`);
|
||||
const getResponse = await fetch(
|
||||
`${url}/api/localized-posts?where[description][equals]=${desc}`,
|
||||
);
|
||||
const data = await getResponse.json();
|
||||
|
||||
expect(getResponse.status).toBe(200);
|
||||
expect(data.docs[0].description).toBe(desc);
|
||||
expect(data.docs).toHaveLength(1);
|
||||
|
||||
const getResponse2 = await fetch(`${url}/api/localized-posts?where[nonLocalizedGroup.text][equals]=sample content`);
|
||||
const getResponse2 = await fetch(
|
||||
`${url}/api/localized-posts?where[nonLocalizedGroup.text][equals]=sample content`,
|
||||
);
|
||||
const data2 = await getResponse2.json();
|
||||
|
||||
expect(getResponse2.status).toBe(200);
|
||||
@@ -330,7 +344,9 @@ describe('Collections - REST', () => {
|
||||
expect(response.status).toBe(201);
|
||||
expect(response2.status).toBe(201);
|
||||
|
||||
const queryResponse = await fetch(`${url}/api/localized-posts?where[or][0][title][equals]=${title1}&where[or][1][title][equals]=${title2}`);
|
||||
const queryResponse = await fetch(
|
||||
`${url}/api/localized-posts?where[or][0][title][equals]=${title1}&where[or][1][title][equals]=${title2}`,
|
||||
);
|
||||
const data = await queryResponse.json();
|
||||
|
||||
expect(queryResponse.status).toBe(200);
|
||||
@@ -365,7 +381,9 @@ describe('Collections - REST', () => {
|
||||
expect(response.status).toBe(201);
|
||||
expect(response2.status).toBe(201);
|
||||
|
||||
const queryResponse = await fetch(`${url}/api/localized-posts?where[or][0][title][equals]=${title1}&where[or][1][title][equals]=nonexistent`);
|
||||
const queryResponse = await fetch(
|
||||
`${url}/api/localized-posts?where[or][0][title][equals]=${title1}&where[or][1][title][equals]=nonexistent`,
|
||||
);
|
||||
const data = await queryResponse.json();
|
||||
|
||||
expect(queryResponse.status).toBe(200);
|
||||
@@ -395,10 +413,12 @@ describe('Collections - REST', () => {
|
||||
|
||||
const additionalRelationshipARes = await fetch(`${url}/api/relationship-a?depth=0`, {
|
||||
body: JSON.stringify({
|
||||
postLocalizedMultiple: [{
|
||||
relationTo: 'localized-posts',
|
||||
value: localizedPostID,
|
||||
}],
|
||||
postLocalizedMultiple: [
|
||||
{
|
||||
relationTo: 'localized-posts',
|
||||
value: localizedPostID,
|
||||
},
|
||||
],
|
||||
}),
|
||||
headers,
|
||||
method: 'post',
|
||||
@@ -410,7 +430,9 @@ describe('Collections - REST', () => {
|
||||
expect(additionalRelationshipARes.status).toBe(201);
|
||||
expect(relationshipAData.doc.post).toBe(relationshipBData.doc.id);
|
||||
|
||||
const queryRes = await fetch(`${url}/api/relationship-a?where[post.title][equals]=${relationshipBTitle}`);
|
||||
const queryRes = await fetch(
|
||||
`${url}/api/relationship-a?where[post.title][equals]=${relationshipBTitle}`,
|
||||
);
|
||||
const data = await queryRes.json();
|
||||
|
||||
expect(data.docs).toHaveLength(1);
|
||||
@@ -427,7 +449,9 @@ describe('Collections - REST', () => {
|
||||
|
||||
expect(res.status).toBe(201);
|
||||
|
||||
const queryRes1 = await fetch(`${url}/api/relationship-a?where[LocalizedPost.title][in]=${localizedPostTitle}`);
|
||||
const queryRes1 = await fetch(
|
||||
`${url}/api/relationship-a?where[LocalizedPost.title][in]=${localizedPostTitle}`,
|
||||
);
|
||||
const data1 = await queryRes1.json();
|
||||
|
||||
expect(data1.docs).toHaveLength(1);
|
||||
@@ -458,7 +482,9 @@ describe('Collections - REST', () => {
|
||||
|
||||
expect(res.status).toBe(201);
|
||||
|
||||
const queryRes = await fetch(`${url}/api/relationship-a?where[postManyRelationships.value][equals]=${relationshipB.doc.id}`);
|
||||
const queryRes = await fetch(
|
||||
`${url}/api/relationship-a?where[postManyRelationships.value][equals]=${relationshipB.doc.id}`,
|
||||
);
|
||||
const data = await queryRes.json();
|
||||
expect(data.docs).toHaveLength(1);
|
||||
});
|
||||
@@ -478,7 +504,9 @@ describe('Collections - REST', () => {
|
||||
|
||||
expect(relationshipB.doc.id).toBeDefined();
|
||||
|
||||
const queryRes = await fetch(`${url}/api/relationship-b?where[nonLocalizedRelationToMany.value][equals]=${localizedPostID}`);
|
||||
const queryRes = await fetch(
|
||||
`${url}/api/relationship-b?where[nonLocalizedRelationToMany.value][equals]=${localizedPostID}`,
|
||||
);
|
||||
const data = await queryRes.json();
|
||||
expect(data.docs).toHaveLength(1);
|
||||
});
|
||||
@@ -540,12 +568,16 @@ describe('Collections - REST', () => {
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const queryRes1 = await fetch(`${url}/api/localized-posts?where[nonLocalizedGroup.text][equals]=${text}`);
|
||||
const queryRes1 = await fetch(
|
||||
`${url}/api/localized-posts?where[nonLocalizedGroup.text][equals]=${text}`,
|
||||
);
|
||||
const data1 = await queryRes1.json();
|
||||
|
||||
expect(data1.docs).toHaveLength(1);
|
||||
|
||||
const queryRes2 = await fetch(`${url}/api/localized-posts?where[localizedGroup.text][equals]=${text}`);
|
||||
const queryRes2 = await fetch(
|
||||
`${url}/api/localized-posts?where[localizedGroup.text][equals]=${text}`,
|
||||
);
|
||||
const data2 = await queryRes2.json();
|
||||
|
||||
expect(queryRes2.status).toBe(200);
|
||||
@@ -600,7 +632,9 @@ describe('Collections - REST', () => {
|
||||
await createPost(null, desc);
|
||||
}
|
||||
|
||||
const getResponse = await fetch(`${url}/api/localized-posts?where[description][equals]=${desc}`);
|
||||
const getResponse = await fetch(
|
||||
`${url}/api/localized-posts?where[description][equals]=${desc}`,
|
||||
);
|
||||
const data = await getResponse.json();
|
||||
|
||||
expect(getResponse.status).toBe(200);
|
||||
@@ -647,7 +681,9 @@ describe('Collections - REST', () => {
|
||||
const id2 = req2data.doc.id;
|
||||
|
||||
// Query on shared desc and sort ascending
|
||||
const getResponse = await fetch(`${url}/api/localized-posts?where[description][equals]=${desc}&sort=title`);
|
||||
const getResponse = await fetch(
|
||||
`${url}/api/localized-posts?where[description][equals]=${desc}&sort=title`,
|
||||
);
|
||||
const data = await getResponse.json();
|
||||
|
||||
expect(getResponse.status).toBe(200);
|
||||
@@ -656,7 +692,9 @@ describe('Collections - REST', () => {
|
||||
expect(data.docs[1].id).toStrictEqual(id2);
|
||||
|
||||
// Query on shared desc and sort descending
|
||||
const getResponseSorted = await fetch(`${url}/api/localized-posts?where[description][equals]=${desc}&sort=-title`);
|
||||
const getResponseSorted = await fetch(
|
||||
`${url}/api/localized-posts?where[description][equals]=${desc}&sort=-title`,
|
||||
);
|
||||
const sortedData = await getResponseSorted.json();
|
||||
|
||||
expect(getResponse.status).toBe(200);
|
||||
@@ -769,7 +807,6 @@ describe('Collections - REST', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
it('should create collections with custom ID', async () => {
|
||||
expect(data.doc.id).toBe(document.id);
|
||||
});
|
||||
@@ -2,10 +2,12 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import FormData from 'form-data';
|
||||
import { GraphQLClient } from 'graphql-request';
|
||||
import { promisify } from 'util';
|
||||
import getConfig from '../../config/load';
|
||||
import fileExists from '../../../tests/api/utils/fileExists';
|
||||
import { email, password } from '../../mongoose/testCredentials';
|
||||
|
||||
const stat = promisify(fs.stat);
|
||||
|
||||
require('isomorphic-fetch');
|
||||
|
||||
const config = getConfig();
|
||||
@@ -59,11 +61,14 @@ describe('Collections - Uploads', () => {
|
||||
describe('create', () => {
|
||||
it('creates', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')));
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: formData,
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
@@ -113,12 +118,15 @@ describe('Collections - Uploads', () => {
|
||||
|
||||
it('creates media without storing a file', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')));
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const response = await fetch(`${api}/unstored-media`, {
|
||||
body: formData,
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
@@ -150,12 +158,15 @@ describe('Collections - Uploads', () => {
|
||||
|
||||
it('creates with same name', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/samename.png')));
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/samename.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const firstResponse = await fetch(`${api}/media`, {
|
||||
body: formData,
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
@@ -163,12 +174,15 @@ describe('Collections - Uploads', () => {
|
||||
expect(firstResponse.status).toBe(201);
|
||||
|
||||
const sameForm = new FormData();
|
||||
sameForm.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/samename.png')));
|
||||
sameForm.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/samename.png')),
|
||||
);
|
||||
sameForm.append('alt', 'test media');
|
||||
sameForm.append('locale', 'en');
|
||||
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: sameForm,
|
||||
body: sameForm as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
@@ -211,15 +225,16 @@ describe('Collections - Uploads', () => {
|
||||
|
||||
it('update', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/update.png')));
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/update.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `JWT ${token}`,
|
||||
},
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
@@ -233,10 +248,8 @@ describe('Collections - Uploads', () => {
|
||||
updateFormData.append('filename', data.doc.filename);
|
||||
updateFormData.append('alt', newAlt);
|
||||
const updateResponse = await fetch(`${api}/media/${data.doc.id}`, {
|
||||
body: updateFormData,
|
||||
headers: {
|
||||
Authorization: `JWT ${token}`,
|
||||
},
|
||||
body: updateFormData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'put',
|
||||
});
|
||||
|
||||
@@ -280,15 +293,16 @@ describe('Collections - Uploads', () => {
|
||||
|
||||
it('delete', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/delete.png')));
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/delete.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const createResponse = await fetch(`${api}/media`, {
|
||||
body: formData,
|
||||
headers: {
|
||||
Authorization: `JWT ${token}`,
|
||||
},
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
@@ -297,9 +311,7 @@ describe('Collections - Uploads', () => {
|
||||
const docId = createData.doc.id;
|
||||
|
||||
const response = await fetch(`${api}/media/${docId}`, {
|
||||
headers: {
|
||||
Authorization: `JWT ${token}`,
|
||||
},
|
||||
headers,
|
||||
method: 'delete',
|
||||
});
|
||||
|
||||
@@ -318,15 +330,20 @@ describe('Collections - Uploads', () => {
|
||||
let image;
|
||||
const alt = 'alt text';
|
||||
beforeAll(async (done) => {
|
||||
client = new GraphQLClient(`${api}${config.routes.graphQL}`, { headers: { Authorization: `JWT ${token}` } });
|
||||
client = new GraphQLClient(`${api}${config.routes.graphQL}`, {
|
||||
headers: { Authorization: `JWT ${token}` },
|
||||
});
|
||||
|
||||
// create media using REST
|
||||
const formData = new FormData();
|
||||
formData.append('file', fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')));
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')),
|
||||
);
|
||||
formData.append('alt', alt);
|
||||
formData.append('locale', 'en');
|
||||
const mediaResponse = await fetch(`${api}/media`, {
|
||||
body: formData,
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
@@ -364,3 +381,12 @@ describe('Collections - Uploads', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function fileExists(fileName: string): Promise<boolean> {
|
||||
try {
|
||||
await stat(fileName);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
import Logger from '../../utilities/logger';
|
||||
import errorHandler from './errorHandler';
|
||||
import { APIError } from '../../errors';
|
||||
|
||||
const logger = Logger();
|
||||
|
||||
const testError = new APIError('test error', 503);
|
||||
|
||||
const mockResponse = () => {
|
||||
const res = {
|
||||
status: jest.fn(),
|
||||
send: jest.fn(),
|
||||
};
|
||||
|
||||
jest.spyOn(res, 'status').mockImplementation()
|
||||
.mockReturnValue(res);
|
||||
|
||||
jest.spyOn(res, 'send').mockImplementation()
|
||||
.mockReturnValue(res);
|
||||
return res;
|
||||
};
|
||||
|
||||
const mockRequest = async () => {
|
||||
const req = {};
|
||||
req.collection = {
|
||||
config: {
|
||||
hooks: {},
|
||||
},
|
||||
};
|
||||
req.collection.config.hooks.afterError = await jest.fn();
|
||||
return req;
|
||||
};
|
||||
|
||||
describe('errorHandler', () => {
|
||||
let res;
|
||||
let req;
|
||||
beforeAll(async (done) => {
|
||||
res = mockResponse();
|
||||
req = await mockRequest();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should send the response with the error', async () => {
|
||||
const handler = errorHandler({ debug: true, hooks: {} }, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(res.send)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.objectContaining({ errors: [{ message: 'test error' }] }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should include stack trace when config debug is on', async () => {
|
||||
const handler = errorHandler({ debug: true, hooks: {} }, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(res.send)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.objectContaining({ stack: expect.any(String) }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not include stack trace when config debug is not set', async () => {
|
||||
const handler = errorHandler({ hooks: {} }, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(res.send)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.not.objectContaining({ stack: expect.any(String) }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not include stack trace when config debug is false', async () => {
|
||||
const handler = errorHandler({ debug: false, hooks: {} }, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(res.send)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.not.objectContaining({ stack: expect.any(String) }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should show the status code when given an error with a code', async () => {
|
||||
const handler = errorHandler({ debug: false, hooks: {} }, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(res.status)
|
||||
.toHaveBeenCalledWith(
|
||||
503,
|
||||
);
|
||||
});
|
||||
|
||||
it('should default to 500 when an error does not have a status code', async () => {
|
||||
const handler = errorHandler({ debug: false, hooks: {} }, logger);
|
||||
testError.status = undefined;
|
||||
await handler(testError, req, res);
|
||||
expect(res.status)
|
||||
.toHaveBeenCalledWith(
|
||||
500,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call payload config afterError hook', async () => {
|
||||
const afterError = jest.fn();
|
||||
const handler = errorHandler({
|
||||
debug: false,
|
||||
hooks: { afterError },
|
||||
}, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(afterError)
|
||||
// eslint-disable-next-line jest/prefer-called-with
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call collection config afterError hook', async () => {
|
||||
const handler = errorHandler({
|
||||
debug: false,
|
||||
hooks: {},
|
||||
}, logger);
|
||||
await handler(testError, req, res);
|
||||
expect(req.collection.config.hooks.afterError)
|
||||
// eslint-disable-next-line jest/prefer-called-with
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
112
src/express/middleware/errorHandler.spec.ts
Normal file
112
src/express/middleware/errorHandler.spec.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { Response } from 'express';
|
||||
import Logger from '../../utilities/logger';
|
||||
import errorHandler from './errorHandler';
|
||||
import { APIError } from '../../errors';
|
||||
import { PayloadRequest } from '../types';
|
||||
import { SanitizedConfig } from '../../config/types';
|
||||
|
||||
const logger = Logger();
|
||||
|
||||
const testError = new APIError('test error', 503);
|
||||
|
||||
describe('errorHandler', () => {
|
||||
const res = generateResponse();
|
||||
const next = jest.fn();
|
||||
const req = generateRequest() as PayloadRequest;
|
||||
|
||||
it('should send the response with the error', async () => {
|
||||
const handler = errorHandler(generateConfig({ debug: true }), logger);
|
||||
await handler(testError, req, res, next);
|
||||
expect(res.send).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ errors: [{ message: 'test error' }] }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should include stack trace when config debug is on', async () => {
|
||||
const handler = errorHandler(generateConfig({ debug: true }), logger);
|
||||
await handler(testError, req, res, next);
|
||||
expect(res.send).toHaveBeenCalledWith(expect.objectContaining({ stack: expect.any(String) }));
|
||||
});
|
||||
|
||||
it('should not include stack trace when config debug is not set', async () => {
|
||||
const handler = errorHandler(generateConfig({ debug: undefined }), logger);
|
||||
await handler(testError, req, res, next);
|
||||
expect(res.send).toHaveBeenCalledWith(
|
||||
expect.not.objectContaining({ stack: expect.any(String) }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not include stack trace when config debug is false', async () => {
|
||||
const handler = errorHandler(generateConfig({ debug: false }), logger);
|
||||
await handler(testError, req, res, next);
|
||||
expect(res.send).toHaveBeenCalledWith(
|
||||
expect.not.objectContaining({ stack: expect.any(String) }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should show the status code when given an error with a code', async () => {
|
||||
const handler = errorHandler(generateConfig(), logger);
|
||||
await handler(testError, req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(503);
|
||||
});
|
||||
|
||||
it('should default to 500 when an error does not have a status code', async () => {
|
||||
const handler = errorHandler(generateConfig(), logger);
|
||||
testError.status = undefined;
|
||||
await handler(testError, req, res, next);
|
||||
expect(res.status).toHaveBeenCalledWith(500);
|
||||
});
|
||||
|
||||
it('should call payload config afterError hook', async () => {
|
||||
const afterError = jest.fn();
|
||||
const handler = errorHandler(
|
||||
generateConfig({
|
||||
hooks: { afterError },
|
||||
}),
|
||||
logger,
|
||||
);
|
||||
await handler(testError, req, res, next);
|
||||
expect(afterError)
|
||||
// eslint-disable-next-line jest/prefer-called-with
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call collection config afterError hook', async () => {
|
||||
const handler = errorHandler(generateConfig(), logger);
|
||||
await handler(testError, req, res, next);
|
||||
expect(req.collection.config.hooks.afterError)
|
||||
// eslint-disable-next-line jest/prefer-called-with
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
function generateResponse() {
|
||||
const res = {
|
||||
status: jest.fn(),
|
||||
send: jest.fn(),
|
||||
};
|
||||
|
||||
jest.spyOn(res, 'status').mockImplementation().mockReturnValue(res);
|
||||
jest.spyOn(res, 'send').mockImplementation().mockReturnValue(res);
|
||||
return res as unknown as Response;
|
||||
}
|
||||
|
||||
function generateRequest(): PayloadRequest {
|
||||
return {
|
||||
collection: {
|
||||
config: {
|
||||
hooks: {
|
||||
afterError: jest.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as PayloadRequest;
|
||||
}
|
||||
|
||||
function generateConfig(overrides?: Partial<SanitizedConfig>): SanitizedConfig {
|
||||
return {
|
||||
debug: false,
|
||||
hooks: { afterError: jest.fn() },
|
||||
...overrides,
|
||||
} as unknown as SanitizedConfig;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ function buildMutationInputType(name: string, fields: Field[], parentName: strin
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
return acc;
|
||||
}, []),
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user