test: remove all old tests
This commit is contained in:
@@ -2,6 +2,7 @@ module.exports = {
|
|||||||
verbose: true,
|
verbose: true,
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testMatch: [
|
testMatch: [
|
||||||
|
'**/src/**/*.spec.ts',
|
||||||
'**/test/**/*int.spec.ts',
|
'**/test/**/*int.spec.ts',
|
||||||
],
|
],
|
||||||
globalSetup: './test/jest.setup.ts',
|
globalSetup: './test/jest.setup.ts',
|
||||||
|
|||||||
@@ -1,417 +0,0 @@
|
|||||||
/**
|
|
||||||
* @jest-environment node
|
|
||||||
*/
|
|
||||||
import { request, GraphQLClient } from 'graphql-request';
|
|
||||||
import getConfig from '../../../config/load';
|
|
||||||
import { email, password } from '../../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const config = getConfig();
|
|
||||||
|
|
||||||
const url = `${config.serverURL}${config.routes.api}${config.routes.graphQL}`;
|
|
||||||
|
|
||||||
let client = null;
|
|
||||||
let token = null;
|
|
||||||
|
|
||||||
describe('GrahpQL Resolvers', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const query = `
|
|
||||||
mutation {
|
|
||||||
loginAdmin(
|
|
||||||
email: "${email}",
|
|
||||||
password: "${password}"
|
|
||||||
) {
|
|
||||||
token
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await request(url, query);
|
|
||||||
|
|
||||||
token = response.loginAdmin.token;
|
|
||||||
|
|
||||||
client = new GraphQLClient(url, { headers: { Authorization: `JWT ${token}` } });
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Create', () => {
|
|
||||||
it('should allow a localized post to be created', async () => {
|
|
||||||
const title = 'gql create';
|
|
||||||
const description = 'description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: {title: "${title}", description: "${description}", priority: 10}) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
description
|
|
||||||
priority
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const data = response.createLocalizedPost;
|
|
||||||
|
|
||||||
expect(data.title).toBe(title);
|
|
||||||
expect(data.id).toStrictEqual(expect.any(String));
|
|
||||||
// const timestampRegex = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;
|
|
||||||
// expect(data.createdAt).toStrictEqual(expect.stringMatching(timestampRegex));
|
|
||||||
// expect(data.updatedAt).toStrictEqual(expect.stringMatching(timestampRegex));
|
|
||||||
expect(data.createdAt).toStrictEqual(expect.any(String));
|
|
||||||
expect(data.updatedAt).toStrictEqual(expect.any(String));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Read', () => {
|
|
||||||
it('should be able to read localized post', async () => {
|
|
||||||
const title = 'gql read 1';
|
|
||||||
const description = 'description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: {title: "${title}", description: "${description}", priority: 10}) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
description
|
|
||||||
priority
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { id } = response.createLocalizedPost;
|
|
||||||
// language=graphQL
|
|
||||||
const readQuery = `query {
|
|
||||||
LocalizedPost(id: "${id}") {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const readResponse = await client.request(readQuery);
|
|
||||||
const retrievedId = readResponse.LocalizedPost.id;
|
|
||||||
|
|
||||||
expect(retrievedId).toStrictEqual(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query exists - true', async () => {
|
|
||||||
const title = 'gql read 2';
|
|
||||||
const description = 'description';
|
|
||||||
const summary = 'summary';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: {title: "${title}", description: "${description}", summary: "${summary}", priority: 10}) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
description
|
|
||||||
priority
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { id } = response.createLocalizedPost;
|
|
||||||
// language=graphQL
|
|
||||||
const readQuery = `query {
|
|
||||||
LocalizedPosts(where: { summary: { exists: true }}) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
description
|
|
||||||
summary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const readResponse = await client.request(readQuery);
|
|
||||||
const retrievedId = readResponse.LocalizedPosts.docs[0].id;
|
|
||||||
|
|
||||||
expect(readResponse.LocalizedPosts.docs).toHaveLength(1);
|
|
||||||
expect(retrievedId).toStrictEqual(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query exists - false', async () => {
|
|
||||||
const title = 'gql read 3';
|
|
||||||
const description = 'description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: {title: "${title}", description: "${description}", priority: 10}) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
description
|
|
||||||
priority
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { id } = response.createLocalizedPost;
|
|
||||||
// language=graphQL
|
|
||||||
const readQuery = `query {
|
|
||||||
LocalizedPosts(where: { summary: { exists: false }}) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
summary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const readResponse = await client.request(readQuery);
|
|
||||||
const retrievedDoc = readResponse.LocalizedPosts.docs[0];
|
|
||||||
|
|
||||||
expect(readResponse.LocalizedPosts.docs.length).toBeGreaterThan(0);
|
|
||||||
expect(retrievedDoc.id).toStrictEqual(id);
|
|
||||||
expect(retrievedDoc.summary).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Update', () => {
|
|
||||||
it('should allow updating an existing post', async () => {
|
|
||||||
const title = 'gql update';
|
|
||||||
const description = 'description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: { title: "${title}", description: "${description}", priority: 10}) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
description
|
|
||||||
priority
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const createResponse = await client.request(query);
|
|
||||||
|
|
||||||
const createData = createResponse.createLocalizedPost;
|
|
||||||
const { id } = createData;
|
|
||||||
const updatedDesc = 'updated description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const update = `
|
|
||||||
mutation {
|
|
||||||
updateLocalizedPost(id: "${id}" data: {description: "${updatedDesc}"}) {
|
|
||||||
description
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(update);
|
|
||||||
const data = response.updateLocalizedPost;
|
|
||||||
|
|
||||||
expect(data.description).toBe(updatedDesc);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Delete', () => {
|
|
||||||
it('should be able to delete a localized post', async () => {
|
|
||||||
const title = 'gql delete';
|
|
||||||
const description = 'description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: {title: "${title}", description: "${description}", priority: 10}) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
description
|
|
||||||
priority
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { id } = response.createLocalizedPost;
|
|
||||||
// language=graphQL
|
|
||||||
const deleteMutation = `mutation {
|
|
||||||
deleteLocalizedPost(id: "${id}") {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const deleteResponse = await client.request(deleteMutation);
|
|
||||||
const deletedId = deleteResponse.deleteLocalizedPost.id;
|
|
||||||
|
|
||||||
expect(deletedId).toStrictEqual(id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Error Handler', () => {
|
|
||||||
it('should return have an array of errors when making a bad request', async () => {
|
|
||||||
let error;
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `query {
|
|
||||||
LocalizedPosts(where: { summary: { exists: true }}) {
|
|
||||||
docs {
|
|
||||||
badFieldName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
await client.request(query).catch((err) => {
|
|
||||||
error = err;
|
|
||||||
});
|
|
||||||
expect(Array.isArray(error.response.errors)).toBe(true);
|
|
||||||
expect(typeof error.response.errors[0].message).toBe('string');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return have an array of errors when failing to pass validation', async () => {
|
|
||||||
let error;
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createLocalizedPost(data: {priority: 10}) {
|
|
||||||
id
|
|
||||||
priority
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await client.request(query).catch((err) => {
|
|
||||||
error = err;
|
|
||||||
});
|
|
||||||
expect(Array.isArray(error.response.errors)).toBe(true);
|
|
||||||
expect(typeof error.response.errors[0].message).toBe('string');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Custom ID', () => {
|
|
||||||
it('should create', async () => {
|
|
||||||
const id = 10;
|
|
||||||
const query = `mutation {
|
|
||||||
createCustomID(data: {
|
|
||||||
id: ${id},
|
|
||||||
name: "custom"
|
|
||||||
}) {
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const response = await client.request(query);
|
|
||||||
const data = response.createCustomID;
|
|
||||||
expect(data.id).toStrictEqual(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update', async () => {
|
|
||||||
const id = 11;
|
|
||||||
const name = 'custom name';
|
|
||||||
|
|
||||||
const query = `
|
|
||||||
mutation {
|
|
||||||
createCustomID(data: {
|
|
||||||
id: ${id},
|
|
||||||
name: "${name}"
|
|
||||||
}) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await client.request(query);
|
|
||||||
const updatedName = 'updated name';
|
|
||||||
|
|
||||||
const update = `
|
|
||||||
mutation {
|
|
||||||
updateCustomID(id: ${id} data: {name: "${updatedName}"}) {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(update);
|
|
||||||
const data = response.updateCustomID;
|
|
||||||
|
|
||||||
expect(data.name).toStrictEqual(updatedName);
|
|
||||||
expect(data.name).not.toStrictEqual(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query on id', async () => {
|
|
||||||
const id = 15;
|
|
||||||
const name = 'custom name';
|
|
||||||
|
|
||||||
const create = `mutation {
|
|
||||||
createCustomID(data: {
|
|
||||||
id: ${id},
|
|
||||||
name: "${name}"
|
|
||||||
}) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await client.request(create);
|
|
||||||
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
CustomIDs(where: { id: { equals: ${id} } }) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const response = await client.request(query);
|
|
||||||
const [doc] = response.CustomIDs.docs;
|
|
||||||
expect(doc.id).toStrictEqual(id);
|
|
||||||
expect(doc.name).toStrictEqual(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete', async () => {
|
|
||||||
const id = 12;
|
|
||||||
const query = `mutation {
|
|
||||||
createCustomID(data: {
|
|
||||||
id: ${id},
|
|
||||||
name: "delete me"
|
|
||||||
}) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await client.request(query);
|
|
||||||
|
|
||||||
const deleteMutation = `mutation {
|
|
||||||
deleteCustomID(id: ${id}) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const deleteResponse = await client.request(deleteMutation);
|
|
||||||
const deletedId = deleteResponse.deleteCustomID.id;
|
|
||||||
|
|
||||||
expect(deletedId).toStrictEqual(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow relationships', async () => {
|
|
||||||
const id = 13;
|
|
||||||
const query = `mutation {
|
|
||||||
createCustomID(data: {
|
|
||||||
id: ${id},
|
|
||||||
name: "relate me"
|
|
||||||
}) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
await client.request(query);
|
|
||||||
const relation = `mutation {
|
|
||||||
createRelationshipA(data: {
|
|
||||||
customID: [ ${id} ]
|
|
||||||
}) {
|
|
||||||
customID {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const relationResponse = await client.request(relation);
|
|
||||||
const { customID } = relationResponse.createRelationshipA;
|
|
||||||
|
|
||||||
expect(customID).toHaveLength(1);
|
|
||||||
expect(customID).toHaveLength(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import { UploadedFile } from 'express-fileupload';
|
|
||||||
import payload from '../../..';
|
|
||||||
import getFileByPath from '../../../uploads/getFileByPath';
|
|
||||||
|
|
||||||
let createdMediaID;
|
|
||||||
|
|
||||||
payload.init({
|
|
||||||
secret: 'SECRET_KEY',
|
|
||||||
mongoURL: 'mongodb://localhost/payload',
|
|
||||||
local: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
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 { size } = fs.statSync(filePath);
|
|
||||||
|
|
||||||
const result: Media = await payload.create({
|
|
||||||
collection: 'media',
|
|
||||||
data: {
|
|
||||||
alt,
|
|
||||||
},
|
|
||||||
filePath,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.id).toBeDefined();
|
|
||||||
expect(result.alt).toStrictEqual(alt);
|
|
||||||
expect(result.filename).toStrictEqual('generic-block-image.svg');
|
|
||||||
expect(result.filesize).toStrictEqual(size);
|
|
||||||
createdMediaID = result.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow an upload-enabled file to be created from file instead of filepath', async () => {
|
|
||||||
const name = 'upload-local.svg';
|
|
||||||
const alt = 'Alt Text Here';
|
|
||||||
const filePath = path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'../../../admin/assets/images/generic-block-image.svg',
|
|
||||||
);
|
|
||||||
const { size } = fs.statSync(filePath);
|
|
||||||
const file = getFileByPath(filePath);
|
|
||||||
file.name = name;
|
|
||||||
|
|
||||||
const result: Media = await payload.create({
|
|
||||||
collection: 'media',
|
|
||||||
data: {
|
|
||||||
alt,
|
|
||||||
},
|
|
||||||
file,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.id).toBeDefined();
|
|
||||||
expect(result.alt).toStrictEqual(alt);
|
|
||||||
expect(result.filename).toStrictEqual(name);
|
|
||||||
expect(result.filesize).toStrictEqual(size);
|
|
||||||
createdMediaID = result.id;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Update', () => {
|
|
||||||
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: Media = await payload.update({
|
|
||||||
collection: 'media',
|
|
||||||
id: createdMediaID,
|
|
||||||
data: {
|
|
||||||
alt: newAltText,
|
|
||||||
},
|
|
||||||
filePath: path.resolve(__dirname, '../../../admin/assets/images/og-image.png'),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.alt).toStrictEqual(newAltText);
|
|
||||||
expect(result.sizes.mobile.width).toStrictEqual(320);
|
|
||||||
expect(result.width).toStrictEqual(640);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Read with Hidden Fields', () => {
|
|
||||||
it('should allow a document with nested hidden fields to be retrieved with hidden fields shown.', async () => {
|
|
||||||
const demoHiddenField = 'this is going to be hidden';
|
|
||||||
|
|
||||||
const result = await payload.create({
|
|
||||||
collection: 'localized-posts',
|
|
||||||
data: {
|
|
||||||
title: 'this post has a hidden field present',
|
|
||||||
description: 'desc',
|
|
||||||
priority: 1,
|
|
||||||
nonLocalizedGroup: {
|
|
||||||
text: '40w5g534gw34j',
|
|
||||||
},
|
|
||||||
localizedGroup: {
|
|
||||||
text: '34lijgw45ligjw4li5j',
|
|
||||||
demoHiddenField,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.id).toBeDefined();
|
|
||||||
expect(result.localizedGroup).toBeDefined();
|
|
||||||
expect(result.localizedGroup.demoHiddenField).toBeUndefined();
|
|
||||||
|
|
||||||
const withHiddenFields = await payload.findByID({
|
|
||||||
collection: 'localized-posts',
|
|
||||||
id: result.id,
|
|
||||||
showHiddenFields: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(withHiddenFields.localizedGroup.demoHiddenField).toStrictEqual(demoHiddenField);
|
|
||||||
expect(withHiddenFields.id).toStrictEqual(result.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a document with a relationship to a document with hidden fields to read the related document hidden fields', async () => {
|
|
||||||
const demoHiddenField = 'this is going to be hidden';
|
|
||||||
|
|
||||||
const relationshipA = await payload.create({
|
|
||||||
collection: 'relationship-a',
|
|
||||||
data: {
|
|
||||||
demoHiddenField,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(relationshipA.id).toBeDefined();
|
|
||||||
expect(relationshipA.demoHiddenField).toBeUndefined();
|
|
||||||
|
|
||||||
const relationshipB = await payload.create({
|
|
||||||
collection: 'relationship-b',
|
|
||||||
data: {
|
|
||||||
title: 'pretty clever name here',
|
|
||||||
post: [relationshipA.id],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(relationshipB.id).toBeDefined();
|
|
||||||
|
|
||||||
const relationshipBWithHiddenNestedField = await payload.findByID({
|
|
||||||
collection: 'relationship-b',
|
|
||||||
id: relationshipB.id,
|
|
||||||
showHiddenFields: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(relationshipBWithHiddenNestedField.post[0].demoHiddenField).toStrictEqual(
|
|
||||||
demoHiddenField,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
describe('Find', () => {
|
|
||||||
const title = 'local-find';
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const data = {
|
|
||||||
title,
|
|
||||||
description: 'a description',
|
|
||||||
priority: 1,
|
|
||||||
nonLocalizedGroup: {
|
|
||||||
text: 'english',
|
|
||||||
},
|
|
||||||
localizedGroup: {
|
|
||||||
text: 'english',
|
|
||||||
},
|
|
||||||
nonLocalizedArray: [
|
|
||||||
{
|
|
||||||
localizedEmbeddedText: 'english',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
richTextBlocks: [
|
|
||||||
{
|
|
||||||
blockType: 'richTextBlock',
|
|
||||||
blockName: 'Test Block Name',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
children: [{ text: 'english' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await payload.create({
|
|
||||||
collection: 'localized-posts',
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
Array.from(Array(10).keys()).map(async (i) => {
|
|
||||||
const uniqueTitle = `${title}-${i}`;
|
|
||||||
await payload.create({
|
|
||||||
collection: 'localized-posts',
|
|
||||||
data: {
|
|
||||||
...data,
|
|
||||||
title: uniqueTitle,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
it('should find collection with query', async () => {
|
|
||||||
const result = await payload.find({
|
|
||||||
collection: 'localized-posts',
|
|
||||||
where: {
|
|
||||||
title: {
|
|
||||||
equals: title,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const doc = result.docs[0];
|
|
||||||
expect(doc.id).toBeDefined();
|
|
||||||
expect(doc.title).toStrictEqual(title);
|
|
||||||
});
|
|
||||||
it('should allow disable pagination to return all docs', async () => {
|
|
||||||
const result = await payload.find({
|
|
||||||
collection: 'localized-posts',
|
|
||||||
pagination: false,
|
|
||||||
limit: 5, // limit will not be used
|
|
||||||
});
|
|
||||||
expect(result.docs.length).toBeGreaterThan(10);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,892 +0,0 @@
|
|||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = {};
|
|
||||||
|
|
||||||
let localizedPost;
|
|
||||||
let relationshipBID;
|
|
||||||
const localizedPostTitle = 'title';
|
|
||||||
const englishPostDesc = 'english description';
|
|
||||||
const spanishPostDesc = 'spanish description';
|
|
||||||
|
|
||||||
describe('Collections - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Create', () => {
|
|
||||||
let response;
|
|
||||||
let data;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
response = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: localizedPostTitle,
|
|
||||||
description: englishPostDesc,
|
|
||||||
priority: 1,
|
|
||||||
nonLocalizedGroup: {
|
|
||||||
text: 'english',
|
|
||||||
},
|
|
||||||
localizedGroup: {
|
|
||||||
text: 'english',
|
|
||||||
},
|
|
||||||
nonLocalizedArray: [
|
|
||||||
{
|
|
||||||
localizedEmbeddedText: 'english',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
richTextBlocks: [
|
|
||||||
{
|
|
||||||
blockType: 'richTextBlock',
|
|
||||||
blockName: 'Test Block Name',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
children: [{ text: 'english' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
data = await response.json();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a localized post to be created', async () => {
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
expect(data.doc.title).toBeDefined();
|
|
||||||
expect(data.doc.id).toBeDefined();
|
|
||||||
expect(data.doc.nonLocalizedGroup.text).toStrictEqual('english');
|
|
||||||
expect(data.doc.localizedGroup.text).toStrictEqual('english');
|
|
||||||
expect(data.doc.nonLocalizedArray[0].localizedEmbeddedText).toStrictEqual('english');
|
|
||||||
expect(data.doc.richTextBlocks[0].content[0].children[0].text).toStrictEqual('english');
|
|
||||||
|
|
||||||
const timestampRegex = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;
|
|
||||||
expect(data.doc.createdAt).toStrictEqual(expect.stringMatching(timestampRegex));
|
|
||||||
expect(data.doc.updatedAt).toStrictEqual(expect.stringMatching(timestampRegex));
|
|
||||||
|
|
||||||
localizedPost = data.doc;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add id to array items', async () => {
|
|
||||||
expect(data.doc.nonLocalizedArray[0].id).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add id to block items', async () => {
|
|
||||||
expect(data.doc.richTextBlocks[0].id).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Update', () => {
|
|
||||||
it('should allow updating an existing post', async () => {
|
|
||||||
const createResponse = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'newTitle',
|
|
||||||
description: 'original description',
|
|
||||||
richText: [
|
|
||||||
{
|
|
||||||
children: [{ text: 'english' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(createResponse.status).toBe(201);
|
|
||||||
const createData = await createResponse.json();
|
|
||||||
const { id } = createData.doc;
|
|
||||||
|
|
||||||
const updatedDesc = 'updated description';
|
|
||||||
const updatedRichText = [
|
|
||||||
{
|
|
||||||
children: [{ text: 'english update' }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const updatedNonLocalizedArray = [
|
|
||||||
{
|
|
||||||
localizedEmbeddedText: 'english',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
localizedEmbeddedText: 'english update',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const response = await fetch(`${url}/api/localized-posts/${id}`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'newTitle',
|
|
||||||
description: updatedDesc,
|
|
||||||
richText: updatedRichText,
|
|
||||||
nonLocalizedArray: updatedNonLocalizedArray,
|
|
||||||
priority: '',
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.doc.description).toBe(updatedDesc);
|
|
||||||
expect(data.doc.priority).not.toStrictEqual(1);
|
|
||||||
expect(data.doc.nonLocalizedArray).toHaveLength(2);
|
|
||||||
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();
|
|
||||||
|
|
||||||
expect(data.doc).toMatchObject(stored);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a Spanish locale to be added to an existing post', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts/${localizedPost.id}?locale=es`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title in spanish',
|
|
||||||
description: spanishPostDesc,
|
|
||||||
priority: 1,
|
|
||||||
nonLocalizedGroup: {
|
|
||||||
text: 'spanish',
|
|
||||||
},
|
|
||||||
localizedGroup: {
|
|
||||||
text: 'spanish',
|
|
||||||
},
|
|
||||||
nonLocalizedArray: [
|
|
||||||
{
|
|
||||||
id: localizedPost.nonLocalizedArray[0].id,
|
|
||||||
localizedEmbeddedText: 'spanish',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
richTextBlocks: [
|
|
||||||
{
|
|
||||||
id: localizedPost.richTextBlocks[0].id,
|
|
||||||
blockType: 'richTextBlock',
|
|
||||||
blockName: 'Test Block Name',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
children: [{ text: 'spanish' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.doc.description).toBe(spanishPostDesc);
|
|
||||||
expect(data.doc.nonLocalizedGroup.text).toStrictEqual('spanish');
|
|
||||||
expect(data.doc.localizedGroup.text).toStrictEqual('spanish');
|
|
||||||
expect(data.doc.nonLocalizedArray[0].localizedEmbeddedText).toStrictEqual('spanish');
|
|
||||||
expect(data.doc.richTextBlocks[0].content[0].children[0].text).toStrictEqual('spanish');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Read', () => {
|
|
||||||
describe('Localized', () => {
|
|
||||||
it('should allow a localized post to be retrieved in unspecified locale, defaulting to English', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts/${localizedPost.id}`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.description).toBe(englishPostDesc);
|
|
||||||
expect(data.nonLocalizedGroup.text).toStrictEqual('english');
|
|
||||||
expect(data.localizedGroup.text).toStrictEqual('english');
|
|
||||||
expect(data.nonLocalizedArray[0].localizedEmbeddedText).toStrictEqual('english');
|
|
||||||
expect(data.richTextBlocks[0].content[0].children[0].text).toStrictEqual('english');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a localized post to be retrieved in specified English locale', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts/${localizedPost.id}?locale=en`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.description).toBe(englishPostDesc);
|
|
||||||
expect(data.nonLocalizedGroup.text).toStrictEqual('english');
|
|
||||||
expect(data.localizedGroup.text).toStrictEqual('english');
|
|
||||||
expect(data.nonLocalizedArray[0].localizedEmbeddedText).toStrictEqual('english');
|
|
||||||
expect(data.richTextBlocks[0].content[0].children[0].text).toStrictEqual('english');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a localized post to be retrieved in Spanish', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts/${localizedPost.id}?locale=es`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.description).toBe(spanishPostDesc);
|
|
||||||
expect(data.nonLocalizedGroup.text).toStrictEqual('spanish');
|
|
||||||
expect(data.localizedGroup.text).toStrictEqual('spanish');
|
|
||||||
expect(data.nonLocalizedArray[0].localizedEmbeddedText).toStrictEqual('spanish');
|
|
||||||
expect(data.richTextBlocks[0].content[0].children[0].text).toStrictEqual('spanish');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a localized post to be retrieved in all locales', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts/${localizedPost.id}?locale=all`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.description.es).toBe(spanishPostDesc);
|
|
||||||
expect(data.description.en).toBe(englishPostDesc);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by id', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'another title',
|
|
||||||
description: 'description',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
const getResponse = await fetch(`${url}/api/localized-posts/${data.doc.id}`);
|
|
||||||
|
|
||||||
expect(getResponse.status).toBe(200);
|
|
||||||
|
|
||||||
const getData = await getResponse.json();
|
|
||||||
|
|
||||||
expect(getData.id).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying on a field', async () => {
|
|
||||||
const desc = 'query test';
|
|
||||||
const response = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'unique title here',
|
|
||||||
description: desc,
|
|
||||||
priority: 1,
|
|
||||||
nonLocalizedGroup: {
|
|
||||||
text: 'sample content',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
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 data2 = await getResponse2.json();
|
|
||||||
|
|
||||||
expect(getResponse2.status).toBe(200);
|
|
||||||
expect(data2.docs[0].description).toBe(desc);
|
|
||||||
expect(data2.docs).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying with OR', async () => {
|
|
||||||
const title1 = 'Or1';
|
|
||||||
const title2 = 'Or2';
|
|
||||||
const response = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: title1,
|
|
||||||
description: 'desc',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response2 = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: title2,
|
|
||||||
description: 'desc',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
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 data = await queryResponse.json();
|
|
||||||
|
|
||||||
expect(queryResponse.status).toBe(200);
|
|
||||||
expect(data.docs).toHaveLength(2);
|
|
||||||
expect(data.docs).toContainEqual(expect.objectContaining({ title: title1 }));
|
|
||||||
expect(data.docs).toContainEqual(expect.objectContaining({ title: title2 }));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying with OR, 1 result', async () => {
|
|
||||||
const title1 = 'OrNegative1';
|
|
||||||
const title2 = 'OrNegative2';
|
|
||||||
const response = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: title1,
|
|
||||||
description: 'desc',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const response2 = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: title2,
|
|
||||||
description: 'desc',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
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 data = await queryResponse.json();
|
|
||||||
|
|
||||||
expect(queryResponse.status).toBe(200);
|
|
||||||
expect(data.docs).toHaveLength(1);
|
|
||||||
expect(data.docs[0].title).toBe(title1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by a non-localized nested relationship property', async () => {
|
|
||||||
const relationshipBTitle = 'test';
|
|
||||||
const relationshipBRes = await fetch(`${url}/api/relationship-b?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: relationshipBTitle,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const relationshipBData = await relationshipBRes.json();
|
|
||||||
|
|
||||||
const res = await fetch(`${url}/api/relationship-a?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
post: relationshipBData.doc.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const additionalRelationshipARes = await fetch(`${url}/api/relationship-a?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
postLocalizedMultiple: [
|
|
||||||
{
|
|
||||||
relationTo: 'localized-posts',
|
|
||||||
value: localizedPost.id,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const relationshipAData = await res.json();
|
|
||||||
|
|
||||||
expect(res.status).toBe(201);
|
|
||||||
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 data = await queryRes.json();
|
|
||||||
|
|
||||||
expect(data.docs).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by a localized nested relationship property', async () => {
|
|
||||||
const res = await fetch(`${url}/api/relationship-a`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
LocalizedPost: [localizedPost.id],
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(res.status).toBe(201);
|
|
||||||
|
|
||||||
const queryRes1 = await fetch(
|
|
||||||
`${url}/api/relationship-a?where[LocalizedPost.title][in]=${localizedPostTitle}`,
|
|
||||||
);
|
|
||||||
const data1 = await queryRes1.json();
|
|
||||||
|
|
||||||
expect(data1.docs).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by a localized nested relationship with many relationTos', async () => {
|
|
||||||
const relationshipBTitle = 'lawleifjawelifjew';
|
|
||||||
const relationshipB = await fetch(`${url}/api/relationship-b?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: relationshipBTitle,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
}).then((res) => res.json());
|
|
||||||
|
|
||||||
expect(relationshipB.doc.id).toBeDefined();
|
|
||||||
|
|
||||||
const res = await fetch(`${url}/api/relationship-a`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
postManyRelationships: {
|
|
||||||
value: relationshipB.doc.id,
|
|
||||||
relationTo: 'relationship-b',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(res.status).toBe(201);
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by a non-localized relationship with many relationTos', async () => {
|
|
||||||
const relationshipB = await fetch(`${url}/api/relationship-b?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'awefjlaiwejfalweiijfaew',
|
|
||||||
nonLocalizedRelationToMany: {
|
|
||||||
relationTo: 'localized-posts',
|
|
||||||
value: localizedPost.id,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
}).then((res) => res.json());
|
|
||||||
|
|
||||||
expect(relationshipB.doc.id).toBeDefined();
|
|
||||||
relationshipBID = relationshipB.doc.id;
|
|
||||||
|
|
||||||
const queryRes = await fetch(
|
|
||||||
`${url}/api/relationship-b?where[nonLocalizedRelationToMany.value][equals]=${localizedPost.id}`,
|
|
||||||
);
|
|
||||||
const data = await queryRes.json();
|
|
||||||
expect(data.docs).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should propagate locale through populated documents', async () => {
|
|
||||||
const relationshipB = await fetch(`${url}/api/relationship-b/${relationshipBID}?locale=es`, {
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await relationshipB.json();
|
|
||||||
expect(data.nonLocalizedRelationToMany.value.description).toBe(spanishPostDesc);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by a numeric custom ID', async () => {
|
|
||||||
const customID = 1988;
|
|
||||||
|
|
||||||
const customIDResult = await fetch(`${url}/api/custom-id?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: customID,
|
|
||||||
name: 'woohoo',
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
}).then((res) => res.json());
|
|
||||||
|
|
||||||
expect(customIDResult.doc.id).toStrictEqual(customID);
|
|
||||||
|
|
||||||
await fetch(`${url}/api/custom-id?depth=0`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: 2343452,
|
|
||||||
name: 'another post',
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
}).then((res) => res.json());
|
|
||||||
|
|
||||||
const queryRes1 = await fetch(`${url}/api/custom-id?where[id][equals]=${customID}`, {
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
|
|
||||||
const data1 = await queryRes1.json();
|
|
||||||
|
|
||||||
expect(data1.docs).toHaveLength(1);
|
|
||||||
|
|
||||||
const queryByIDRes = await fetch(`${url}/api/custom-id/${customID}`, {
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
const queryByIDData = await queryByIDRes.json();
|
|
||||||
expect(queryByIDData.id).toStrictEqual(customID);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by a field within a group', async () => {
|
|
||||||
const text = 'laiwjefliajwe';
|
|
||||||
|
|
||||||
await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'super great title',
|
|
||||||
description: 'desc',
|
|
||||||
priority: 1,
|
|
||||||
nonLocalizedGroup: {
|
|
||||||
text,
|
|
||||||
},
|
|
||||||
localizedGroup: {
|
|
||||||
text,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
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 data2 = await queryRes2.json();
|
|
||||||
|
|
||||||
expect(queryRes2.status).toBe(200);
|
|
||||||
expect(data2.docs).toHaveLength(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Delete', () => {
|
|
||||||
it('should allow a post to be deleted', async () => {
|
|
||||||
const response = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title to be deleted',
|
|
||||||
description: englishPostDesc,
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
const docId = data.doc.id;
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
expect(docId).toBeDefined();
|
|
||||||
|
|
||||||
const deleteResponse = await fetch(`${url}/api/localized-posts/${docId}`, {
|
|
||||||
headers,
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
const deleteData = await deleteResponse.json();
|
|
||||||
expect(deleteResponse.status).toBe(200);
|
|
||||||
expect(deleteData.id).toBe(docId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Metadata', () => {
|
|
||||||
async function createPost(title, description) {
|
|
||||||
await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: title || uuid(),
|
|
||||||
description,
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should include metadata', async () => {
|
|
||||||
const desc = 'metadataDesc';
|
|
||||||
for (let i = 0; i < 12; i += 1) {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await createPost(null, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getResponse = await fetch(
|
|
||||||
`${url}/api/localized-posts?where[description][equals]=${desc}`,
|
|
||||||
);
|
|
||||||
const data = await getResponse.json();
|
|
||||||
|
|
||||||
expect(getResponse.status).toBe(200);
|
|
||||||
|
|
||||||
// TODO: Assert exact length once query bug is fixed
|
|
||||||
expect(data.docs.length).toBeGreaterThan(0);
|
|
||||||
expect(data.totalDocs).toBeGreaterThan(0);
|
|
||||||
expect(data.limit).toBe(10);
|
|
||||||
expect(data.page).toBe(1);
|
|
||||||
expect(data.pagingCounter).toBe(1);
|
|
||||||
expect(data.hasPrevPage).toBe(false);
|
|
||||||
expect(data.hasNextPage).toBe(true);
|
|
||||||
expect(data.prevPage).toBeNull();
|
|
||||||
expect(data.nextPage).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sort the results', async () => {
|
|
||||||
const desc = 'sort';
|
|
||||||
|
|
||||||
// Create 2 posts with different titles, same desc
|
|
||||||
const req1 = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'aaa',
|
|
||||||
description: desc,
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const req2 = await fetch(`${url}/api/localized-posts`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'zzz',
|
|
||||||
description: desc,
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const req1data = await req1.json();
|
|
||||||
const req2data = await req2.json();
|
|
||||||
const id1 = req1data.doc.id;
|
|
||||||
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 data = await getResponse.json();
|
|
||||||
|
|
||||||
expect(getResponse.status).toBe(200);
|
|
||||||
expect(data.docs).toHaveLength(2);
|
|
||||||
expect(data.docs[0].id).toStrictEqual(id1);
|
|
||||||
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 sortedData = await getResponseSorted.json();
|
|
||||||
|
|
||||||
expect(getResponse.status).toBe(200);
|
|
||||||
expect(sortedData.docs).toHaveLength(2);
|
|
||||||
// Opposite order from first request
|
|
||||||
expect(sortedData.docs[0].id).toStrictEqual(id2);
|
|
||||||
expect(sortedData.docs[1].id).toStrictEqual(id1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Field Access', () => {
|
|
||||||
it('should properly prevent / allow public users from reading a restricted field', async () => {
|
|
||||||
const firstArrayText1 = 'test 1';
|
|
||||||
const firstArrayText2 = 'test 2';
|
|
||||||
|
|
||||||
const response = await fetch(`${url}/api/localized-arrays`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
array: [
|
|
||||||
{
|
|
||||||
arrayText1: firstArrayText1,
|
|
||||||
arrayText2: 'test 2',
|
|
||||||
arrayText3: 'test 3',
|
|
||||||
allowPublicReadability: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
arrayText1: firstArrayText2,
|
|
||||||
arrayText2: 'test 2',
|
|
||||||
arrayText3: 'test 3',
|
|
||||||
allowPublicReadability: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
const docId = data.doc.id;
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
expect(data.doc.array[1].arrayText1).toStrictEqual(firstArrayText2);
|
|
||||||
|
|
||||||
const unauthenticatedResponse = await fetch(`${url}/api/localized-arrays/${docId}`, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(unauthenticatedResponse.status).toBe(200);
|
|
||||||
const unauthenticatedData = await unauthenticatedResponse.json();
|
|
||||||
|
|
||||||
// This string should be allowed to come back
|
|
||||||
expect(unauthenticatedData.array[0].arrayText1).toBe(firstArrayText1);
|
|
||||||
|
|
||||||
// This string should be prevented from coming back
|
|
||||||
expect(unauthenticatedData.array[1].arrayText1).toBeUndefined();
|
|
||||||
|
|
||||||
const authenticatedResponse = await fetch(`${url}/api/localized-arrays/${docId}`, {
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
|
|
||||||
const authenticatedData = await authenticatedResponse.json();
|
|
||||||
|
|
||||||
// If logged in, we should get this field back
|
|
||||||
expect(authenticatedData.array[1].arrayText1).toStrictEqual(firstArrayText2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Unique', () => {
|
|
||||||
it('should prevent unique fields from duplicating data', async () => {
|
|
||||||
const nonUniqueTitle = 'title';
|
|
||||||
|
|
||||||
const response = await fetch(`${url}/api/uniques`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: nonUniqueTitle,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
expect(data.doc.title).toStrictEqual(nonUniqueTitle);
|
|
||||||
|
|
||||||
const failedResponse = await fetch(`${url}/api/uniques`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: nonUniqueTitle,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(failedResponse.status).toStrictEqual(500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Custom ID', () => {
|
|
||||||
const document = {
|
|
||||||
id: 1,
|
|
||||||
name: 'name',
|
|
||||||
};
|
|
||||||
let data;
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
// create document
|
|
||||||
const create = await fetch(`${url}/api/custom-id`, {
|
|
||||||
body: JSON.stringify(document),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
data = await create.json();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create collections with custom ID', async () => {
|
|
||||||
expect(data.doc.id).toBe(document.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should read collections by custom ID', async () => {
|
|
||||||
const response = await fetch(`${url}/api/custom-id/${document.id}`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
expect(result.id).toStrictEqual(document.id);
|
|
||||||
expect(result.name).toStrictEqual(document.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update collection by custom ID', async () => {
|
|
||||||
const updatedDoc = { id: 'cannot-update-id', name: 'updated' };
|
|
||||||
const response = await fetch(`${url}/api/custom-id/${document.id}`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(updatedDoc),
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
expect(result.doc.id).not.toStrictEqual(updatedDoc.id);
|
|
||||||
expect(result.doc.name).not.toStrictEqual(document.name);
|
|
||||||
expect(result.doc.name).toStrictEqual(updatedDoc.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should delete collection by custom ID', async () => {
|
|
||||||
const doc = {
|
|
||||||
id: 2,
|
|
||||||
name: 'delete me',
|
|
||||||
};
|
|
||||||
const createResponse = await fetch(`${url}/api/custom-id`, {
|
|
||||||
body: JSON.stringify(doc),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const result = await createResponse.json();
|
|
||||||
const response = await fetch(`${url}/api/custom-id/${result.doc.id}`, {
|
|
||||||
headers,
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const deleteData = await response.json();
|
|
||||||
expect(deleteData.id).toBe(doc.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow querying by custom ID', async () => {
|
|
||||||
const response = await fetch(`${url}/api/custom-id?where[id][equals]=${document.id}`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const emptyResponse = await fetch(`${url}/api/custom-id?where[id][equals]=900`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
const emptyResult = await emptyResponse.json();
|
|
||||||
|
|
||||||
expect(result.docs).toHaveLength(1);
|
|
||||||
expect(emptyResult.docs).toHaveLength(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = null;
|
|
||||||
|
|
||||||
describe('DefaultValue - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('DefaultValues', () => {
|
|
||||||
let document;
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const result = await fetch(`${url}/api/default-values`, {
|
|
||||||
body: JSON.stringify({}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await result.json();
|
|
||||||
document = data.doc;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create with defaultValues saved', async () => {
|
|
||||||
expect(document.id).toBeDefined();
|
|
||||||
expect(document.function).toStrictEqual('function');
|
|
||||||
expect(document.asyncText).toStrictEqual('asyncFunction');
|
|
||||||
expect(document.array[0].arrayText1).toStrictEqual('Get out');
|
|
||||||
expect(document.group.nestedText1).toStrictEqual('this should take priority');
|
|
||||||
expect(document.group.nestedText2).toStrictEqual('nested default text 2');
|
|
||||||
expect(document.group.nestedText3).toStrictEqual('neat');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not overwrite other locales when updating', async () => {
|
|
||||||
const slug = 'updated';
|
|
||||||
const esSlug = 'spanish';
|
|
||||||
const createResult = await fetch(`${url}/api/default-values`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
text: 'unique',
|
|
||||||
slug: 'unique',
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const createData = await createResult.json();
|
|
||||||
|
|
||||||
const { id } = createData.doc;
|
|
||||||
|
|
||||||
const enResult = await fetch(`${url}/api/default-values/${id}?locale=en`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
slug,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const enData = await enResult.json();
|
|
||||||
|
|
||||||
const esResult = await fetch(`${url}/api/default-values/${id}?locale=es`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
slug: esSlug,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const esData = await esResult.json();
|
|
||||||
|
|
||||||
const allResult = await fetch(`${url}/api/default-values/${id}?locale=all`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
|
|
||||||
const allData = await allResult.json();
|
|
||||||
|
|
||||||
expect(createData.doc.slug).toStrictEqual('unique');
|
|
||||||
expect(enData.doc.slug).toStrictEqual(slug);
|
|
||||||
expect(esData.doc.slug).toStrictEqual(esSlug);
|
|
||||||
expect(allData.slug.en).toStrictEqual(slug);
|
|
||||||
expect(allData.slug.es).toStrictEqual(esSlug);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = null;
|
|
||||||
|
|
||||||
describe('Collections - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Endpoints', () => {
|
|
||||||
it('should GET a static endpoint', async () => {
|
|
||||||
const response = await fetch(`${url}/api/endpoints/say-hello/joe-bloggs`, {
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
},
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.message).toStrictEqual(`Hey Joey! Welcome to ${url}/api`);
|
|
||||||
});
|
|
||||||
it('should GET an endpoint with a parameter', async () => {
|
|
||||||
const response = await fetch(`${url}/api/endpoints/say-hello/George`, {
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
},
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.message).toStrictEqual('Hello George!');
|
|
||||||
});
|
|
||||||
it('should POST an endpoint with data', async () => {
|
|
||||||
const params = { name: 'George', age: 29 };
|
|
||||||
const response = await fetch(`${url}/api/endpoints/whoami`, {
|
|
||||||
body: JSON.stringify(params),
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.name).toStrictEqual(params.name);
|
|
||||||
expect(data.age).toStrictEqual(params.age);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = null;
|
|
||||||
|
|
||||||
describe('Collections - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Hooks', () => {
|
|
||||||
describe('Before', () => {
|
|
||||||
it('beforeChange', async () => {
|
|
||||||
const response = await fetch(`${url}/api/hooks`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title 1',
|
|
||||||
description: 'Original',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
hook: 'beforeChange', // Used by hook
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(201);
|
|
||||||
expect(data.doc.description).toStrictEqual('Original-beforeChangeSuffix');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('beforeDelete', async () => {
|
|
||||||
const createResponse = await fetch(`${url}/api/hooks`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title 2',
|
|
||||||
description: 'Original',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const createData = await createResponse.json();
|
|
||||||
const { id } = createData.doc;
|
|
||||||
|
|
||||||
const response = await fetch(`${url}/api/hooks/${id}`, {
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
hook: 'beforeDelete', // Used by hook
|
|
||||||
},
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
// Intentionally afterDeleteHook - beforeDelete hook is setting header in order to trigger afterDelete hook
|
|
||||||
expect(data.afterDeleteHook).toStrictEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('After', () => {
|
|
||||||
it('afterRead', async () => {
|
|
||||||
const response = await fetch(`${url}/api/hooks`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title 3',
|
|
||||||
description: 'afterRead',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
hook: 'afterRead', // Used by hook
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
const getResponse = await fetch(`${url}/api/hooks/${data.doc.id}`);
|
|
||||||
const getResponseData = await getResponse.json();
|
|
||||||
expect(getResponse.status).toBe(200);
|
|
||||||
expect(getResponseData.afterReadHook).toStrictEqual(true);
|
|
||||||
expect(getResponseData.findMany).toBeUndefined();
|
|
||||||
|
|
||||||
const getManyResponse = await fetch(`${url}/api/hooks`);
|
|
||||||
const getManyResponseData = await getManyResponse.json();
|
|
||||||
|
|
||||||
expect(getManyResponseData.docs[0].findMany).toStrictEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('afterChange', async () => {
|
|
||||||
const createResponse = await fetch(`${url}/api/hooks`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title 4',
|
|
||||||
description: 'Original',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const createData = await createResponse.json();
|
|
||||||
const { id } = createData.doc;
|
|
||||||
|
|
||||||
const response = await fetch(`${url}/api/hooks/${id}`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
description: 'afterChange',
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
...headers,
|
|
||||||
hook: 'afterChange', // Used by hook
|
|
||||||
},
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.doc.afterChangeHook).toStrictEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('afterDelete', async () => {
|
|
||||||
const createResponse = await fetch(`${url}/api/hooks`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
title: 'title 5',
|
|
||||||
description: 'Original',
|
|
||||||
priority: 1,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const createData = await createResponse.json();
|
|
||||||
const { id } = createData.doc;
|
|
||||||
|
|
||||||
const response = await fetch(`${url}/api/hooks/${id}`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
hook: 'afterDelete', // Used by hook
|
|
||||||
},
|
|
||||||
method: 'delete',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
expect(data.afterDeleteHook).toStrictEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
import { GraphQLClient } from 'graphql-request';
|
|
||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL, routes } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = null;
|
|
||||||
|
|
||||||
describe('GeoJSON', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${serverURL}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Point Field - REST', () => {
|
|
||||||
let location = [10, 20];
|
|
||||||
const localizedPoint = [30, 40];
|
|
||||||
const group = { point: [15, 25] };
|
|
||||||
let doc;
|
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const create = await fetch(`${serverURL}/api/geolocation`, {
|
|
||||||
body: JSON.stringify({ location, localizedPoint, group }),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
({ doc } = await create.json());
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create and read collections with points', async () => {
|
|
||||||
expect(doc.id).toBeDefined();
|
|
||||||
expect(doc.location).toStrictEqual(location);
|
|
||||||
expect(doc.localizedPoint).toStrictEqual(localizedPoint);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query where near point', async () => {
|
|
||||||
const [lng, lat] = location;
|
|
||||||
const hitResponse = await fetch(`${serverURL}/api/geolocation?where[location][near]=${lng + 0.01},${lat + 0.01},10000`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const hitData = await hitResponse.json();
|
|
||||||
const hitDocs = hitData.docs;
|
|
||||||
|
|
||||||
const missResponse = await fetch(`${serverURL}/api/geolocation?where[location][near]=-${lng},-${lat},5000`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const missData = await missResponse.json();
|
|
||||||
const missDocs = missData.docs;
|
|
||||||
|
|
||||||
expect(hitDocs).toHaveLength(1);
|
|
||||||
expect(missDocs).toHaveLength(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query where near localized point', async () => {
|
|
||||||
const [lng, lat] = localizedPoint;
|
|
||||||
const hitResponse = await fetch(`${serverURL}/api/geolocation?where[localizedPoint][near]=${lng + 0.01},${lat + 0.01},10000`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const hitData = await hitResponse.json();
|
|
||||||
const hitDocs = hitData.docs;
|
|
||||||
|
|
||||||
const missResponse = await fetch(`${serverURL}/api/geolocation?where[localizedPoint][near]=-${lng},-${lat},5000`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const missData = await missResponse.json();
|
|
||||||
const missDocs = missData.docs;
|
|
||||||
|
|
||||||
expect(hitDocs).toHaveLength(1);
|
|
||||||
expect(missDocs).toHaveLength(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query near a nested point', async () => {
|
|
||||||
const [x, y] = group.point;
|
|
||||||
const hitResponse = await fetch(`${serverURL}/api/geolocation?where[group.point][near]=${x + 0.01},${y + 0.01},10000`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const hitData = await hitResponse.json();
|
|
||||||
const hitDocs = hitData.docs;
|
|
||||||
|
|
||||||
const missResponse = await fetch(`${serverURL}/api/geolocation?where[group.point][near]=-${x},-${y},5000`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const missData = await missResponse.json();
|
|
||||||
const missDocs = missData.docs;
|
|
||||||
|
|
||||||
expect(hitDocs).toHaveLength(1);
|
|
||||||
expect(missDocs).toHaveLength(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should save with non-required point', async () => {
|
|
||||||
location = undefined;
|
|
||||||
|
|
||||||
const create = await fetch(`${serverURL}/api/geolocation`, {
|
|
||||||
body: JSON.stringify({ location }),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { doc } = await create.json();
|
|
||||||
|
|
||||||
expect(doc.id).toBeDefined();
|
|
||||||
expect(doc.location).toStrictEqual(location);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('Point Field - GraphQL', () => {
|
|
||||||
const url = `${serverURL}${routes.api}${routes.graphQL}`;
|
|
||||||
let client = null;
|
|
||||||
const location = [50, 60];
|
|
||||||
const localizedPoint = [70, 80];
|
|
||||||
const group = { point: [50.5, 60.5] };
|
|
||||||
let doc;
|
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
client = new GraphQLClient(url, { headers: { Authorization: `JWT ${token}` } });
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
createGeolocation (
|
|
||||||
data: {
|
|
||||||
location: [${location[0]}, ${location[1]}],
|
|
||||||
localizedPoint: [${localizedPoint[0]}, ${localizedPoint[1]}],
|
|
||||||
group: {
|
|
||||||
point: [${group.point[0]}, ${group.point[1]}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
location
|
|
||||||
localizedPoint
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { id } = response.createGeolocation;
|
|
||||||
// language=graphQL
|
|
||||||
const readQuery = `query {
|
|
||||||
Geolocation(id: "${id}") {
|
|
||||||
id
|
|
||||||
location
|
|
||||||
localizedPoint
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const readResponse = await client.request(readQuery);
|
|
||||||
doc = readResponse.Geolocation;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create and read collections with points', async () => {
|
|
||||||
expect(doc.id).toBeDefined();
|
|
||||||
expect(doc.location).toStrictEqual(location);
|
|
||||||
expect(doc.localizedPoint).toStrictEqual(localizedPoint);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query where near point', async () => {
|
|
||||||
const [lng, lat] = location;
|
|
||||||
// language=graphQL
|
|
||||||
const hitQuery = `query getGeos {
|
|
||||||
Geolocations(where: { location: { near: [${lng + 0.01},${lat + 0.01},10000]}}) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
location
|
|
||||||
localizedPoint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const hitResponse = await client.request(hitQuery);
|
|
||||||
const hitDocs = hitResponse.Geolocations.docs;
|
|
||||||
|
|
||||||
const missQuery = `query getGeos {
|
|
||||||
Geolocations(where: { location: { near: [${-lng},${-lat},10000]}}) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
location
|
|
||||||
localizedPoint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const missResponse = await client.request(missQuery);
|
|
||||||
const missDocs = missResponse.Geolocations.docs;
|
|
||||||
|
|
||||||
expect(hitDocs).toHaveLength(1);
|
|
||||||
expect(missDocs).toHaveLength(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should query where near a point in a group', async () => {
|
|
||||||
const [x, y] = group.point;
|
|
||||||
// language=graphQL
|
|
||||||
const hitQuery = `query getGeos {
|
|
||||||
Geolocations(where: { group__point: { near: [${x + 0.01},${y + 0.01},10000]}}) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
group {
|
|
||||||
point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const hitResponse = await client.request(hitQuery);
|
|
||||||
const hitDocs = hitResponse.Geolocations.docs;
|
|
||||||
|
|
||||||
const missQuery = `query getGeos {
|
|
||||||
Geolocations(where: { group__point: { near: [${-x},${-y},10000]}}) {
|
|
||||||
docs {
|
|
||||||
id
|
|
||||||
group {
|
|
||||||
point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const missResponse = await client.request(missQuery);
|
|
||||||
const missDocs = missResponse.Geolocations.docs;
|
|
||||||
|
|
||||||
expect(hitDocs).toHaveLength(1);
|
|
||||||
expect(missDocs).toHaveLength(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
import { PaginatedDocs } from '../../mongoose/types';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = null;
|
|
||||||
|
|
||||||
type RelationshipA = {
|
|
||||||
id: string
|
|
||||||
post?: string | RelationshipB
|
|
||||||
}
|
|
||||||
type RelationshipB = {
|
|
||||||
id: string
|
|
||||||
post?: (string | RelationshipA)[]
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Collections - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Relationships', () => {
|
|
||||||
let documentA;
|
|
||||||
let documentB;
|
|
||||||
let strictAccessDoc;
|
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const strictAccessRes = await fetch(`${url}/api/strict-access`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
address: '123 Test Lane',
|
|
||||||
city: 'Grand Rapids',
|
|
||||||
state: 'MI',
|
|
||||||
zip: 49504,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const strictAccessJSON = await strictAccessRes.json();
|
|
||||||
strictAccessDoc = strictAccessJSON.doc;
|
|
||||||
|
|
||||||
// create document a
|
|
||||||
const createA = await fetch(`${url}/api/relationship-a`, {
|
|
||||||
body: JSON.stringify({}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
const createAData = await createA.json();
|
|
||||||
// create document b, related to a
|
|
||||||
const createB = await fetch(`${url}/api/relationship-b`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
post: [createAData.doc.id],
|
|
||||||
strictAccess: strictAccessDoc.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
// update a to relate to b
|
|
||||||
const createBData = await createB.json();
|
|
||||||
documentB = createBData.doc;
|
|
||||||
const updateA = await fetch(`${url}/api/relationship-a/${createAData.doc.id}`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
post: documentB.id,
|
|
||||||
postMaxDepth: documentB.id,
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
const updateAData = await updateA.json();
|
|
||||||
documentA = updateAData.doc;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create and read collections with relationships', async () => {
|
|
||||||
expect(documentA.post).toBeDefined();
|
|
||||||
expect(documentB.post).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should prevent an unauthorized population of strict access', async () => {
|
|
||||||
const response = await fetch(`${url}/api/relationship-b/${documentB.id}`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
expect(typeof data.strictAccess).not.toBe('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should populate strict access when authorized', async () => {
|
|
||||||
const response = await fetch(`${url}/api/relationship-b/${documentB.id}`, {
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
expect(typeof data.strictAccess).toBe('object');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use depth to limit the number of relationships returned', async () => {
|
|
||||||
const response = await fetch(`${url}/api/relationship-a?depth=3`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const data: PaginatedDocs<RelationshipA> = await response.json();
|
|
||||||
const [depth0] = data.docs;
|
|
||||||
expect(depth0.id).toBe(documentA.id);
|
|
||||||
const depth1 = depth0.post as RelationshipB;
|
|
||||||
expect(depth1.id).toBe(documentB.id);
|
|
||||||
const [depth2] = depth1.post as RelationshipA[];
|
|
||||||
expect(depth2.id).toBe(documentA.id);
|
|
||||||
const depth3 = depth2.post as RelationshipB;
|
|
||||||
expect(depth3.id).toBe(documentB.id);
|
|
||||||
const [depth4] = depth3.post as RelationshipA[];
|
|
||||||
expect(depth4).not.toHaveProperty('post');
|
|
||||||
expect(depth4).toBe(documentA.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should respect max depth at the field level', async () => {
|
|
||||||
const response = await fetch(`${url}/api/relationship-a?depth=1`, {
|
|
||||||
headers,
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
const [doc] = data.docs;
|
|
||||||
// asserts postMaxDepth is not populated
|
|
||||||
expect(doc.postMaxDepth).toBe(documentB.id);
|
|
||||||
expect(doc.postMaxDepth).not.toHaveProperty('post');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a custom id relation', async () => {
|
|
||||||
const customID = {
|
|
||||||
id: 30,
|
|
||||||
name: 'custom',
|
|
||||||
};
|
|
||||||
|
|
||||||
const newCustomID = await fetch(`${url}/api/custom-id`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(customID),
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const custom = await newCustomID.json();
|
|
||||||
const response = await fetch(`${url}/api/relationship-a/${documentA.id}`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
...documentA,
|
|
||||||
post: documentB.id,
|
|
||||||
customID: [custom.doc.id],
|
|
||||||
}),
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
const { doc } = await response.json();
|
|
||||||
expect(doc.customID[0].id).toBe(customID.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow a custom id relation and parse the id type', async () => {
|
|
||||||
const customID = {
|
|
||||||
id: '40',
|
|
||||||
name: 'custom',
|
|
||||||
};
|
|
||||||
|
|
||||||
const newCustomID = await fetch(`${url}/api/custom-id`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(customID),
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const custom = await newCustomID.json();
|
|
||||||
const response = await fetch(`${url}/api/relationship-a/${documentA.id}`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
...documentA,
|
|
||||||
post: documentB.id,
|
|
||||||
customID: [custom.doc.id],
|
|
||||||
}),
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
const { doc } = await response.json();
|
|
||||||
|
|
||||||
expect(custom.doc.id).toBe(parseFloat(customID.id));
|
|
||||||
expect(doc.customID[0].id).toBe(parseFloat(customID.id));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use filterOptions to limit relationship options', async () => {
|
|
||||||
// update documentB to disable relations
|
|
||||||
await fetch(`${url}/api/relationship-b/${documentB.id}`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
disableRelation: true,
|
|
||||||
}),
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
// attempt to save relationship to documentB
|
|
||||||
const response = await fetch(`${url}/api/relationship-a/${documentA.id}`, {
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
filterRelationship: documentB.id,
|
|
||||||
}),
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
expect(result.errors).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
let headers = null;
|
|
||||||
|
|
||||||
describe('Validations - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
headers = {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Validations', () => {
|
|
||||||
let validation;
|
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const result = await fetch(`${url}/api/validations`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
validationOptions: 'ok',
|
|
||||||
text: 'test',
|
|
||||||
lessThan10: 9,
|
|
||||||
greaterThan10LessThan50: 20,
|
|
||||||
atLeast3Rows: [
|
|
||||||
{ greaterThan30: 40 },
|
|
||||||
{ greaterThan30: 50 },
|
|
||||||
{ greaterThan30: 60 },
|
|
||||||
],
|
|
||||||
array: [
|
|
||||||
{ lessThan20: 10 },
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await result.json();
|
|
||||||
validation = data.doc;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create with custom validation', async () => {
|
|
||||||
expect(validation.id).toBeDefined();
|
|
||||||
});
|
|
||||||
it('should update with custom validation', async () => {
|
|
||||||
const result = await fetch(`${url}/api/validations/${validation.id}`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
validationOptions: 'update',
|
|
||||||
}),
|
|
||||||
headers,
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await result.json();
|
|
||||||
validation = data.doc;
|
|
||||||
|
|
||||||
expect(validation.validationOptions).toStrictEqual('update');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
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('payload');
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
/**
|
|
||||||
* @jest-environment node
|
|
||||||
*/
|
|
||||||
|
|
||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
|
||||||
|
|
||||||
let token = null;
|
|
||||||
|
|
||||||
const navData = {
|
|
||||||
en: {
|
|
||||||
nav1: {
|
|
||||||
text: 'Navigation 1',
|
|
||||||
textarea: 'Some navigation text',
|
|
||||||
},
|
|
||||||
nav2: {
|
|
||||||
text: 'Navigation 2',
|
|
||||||
textarea: 'Some more navigation text',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
es: {
|
|
||||||
nav1: {
|
|
||||||
text: 'Navegación 1',
|
|
||||||
textarea: 'algún texto de navegación',
|
|
||||||
},
|
|
||||||
nav2: {
|
|
||||||
text: 'Navegación 2',
|
|
||||||
textarea: 'un poco más de texto de navegación',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Globals - REST', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const response = await fetch(`${url}/api/admins/login`, {
|
|
||||||
body: JSON.stringify({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
({ token } = data);
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Create', () => {
|
|
||||||
it('should create one', async () => {
|
|
||||||
const response = await fetch(`${url}/api/globals/navigation-array`, {
|
|
||||||
|
|
||||||
body: JSON.stringify({
|
|
||||||
array: [
|
|
||||||
{
|
|
||||||
text: navData.en.nav1.text,
|
|
||||||
textarea: navData.en.nav1.textarea,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const data = await response.json();
|
|
||||||
const { text, textarea } = data.result.array[0];
|
|
||||||
expect(text).toStrictEqual(navData.en.nav1.text);
|
|
||||||
expect(textarea).toStrictEqual(navData.en.nav1.textarea);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Update', () => {
|
|
||||||
it('should update one', async () => {
|
|
||||||
const response = await fetch(`${url}/api/globals/navigation-array`, {
|
|
||||||
|
|
||||||
body: JSON.stringify({
|
|
||||||
array: [
|
|
||||||
{
|
|
||||||
text: navData.en.nav1.text,
|
|
||||||
textarea: navData.en.nav1.textarea,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: navData.en.nav2.text,
|
|
||||||
textarea: navData.en.nav2.textarea,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const data = await response.json();
|
|
||||||
expect(data.result.array).toHaveLength(2);
|
|
||||||
const { text, textarea } = data.result.array[1];
|
|
||||||
expect(text).toStrictEqual(navData.en.nav2.text);
|
|
||||||
expect(textarea).toStrictEqual(navData.en.nav2.textarea);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow Spanish update', async () => {
|
|
||||||
const response = await fetch(`${url}/api/globals/navigation-array?locale=es`, {
|
|
||||||
|
|
||||||
body: JSON.stringify({
|
|
||||||
array: [
|
|
||||||
{
|
|
||||||
text: navData.es.nav1.text,
|
|
||||||
textarea: navData.es.nav1.textarea,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: navData.es.nav2.text,
|
|
||||||
textarea: navData.es.nav2.textarea,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const data = await response.json();
|
|
||||||
expect(data.result.array).toHaveLength(2);
|
|
||||||
const { text, textarea } = data.result.array[0];
|
|
||||||
expect(text).toStrictEqual(navData.es.nav1.text);
|
|
||||||
expect(textarea).toStrictEqual(navData.es.nav1.textarea);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Read', () => {
|
|
||||||
it('should read one', async () => {
|
|
||||||
const response = await fetch(`${url}/api/globals/navigation-array`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const data = await response.json();
|
|
||||||
const { text, textarea } = data.array[0];
|
|
||||||
expect(text).toStrictEqual(navData.en.nav1.text);
|
|
||||||
expect(textarea).toStrictEqual(navData.en.nav1.textarea);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should read Spanish', async () => {
|
|
||||||
const response = await fetch(`${url}/api/globals/navigation-array?locale=es`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const data = await response.json();
|
|
||||||
const { text, textarea } = data.array[0];
|
|
||||||
expect(text).toStrictEqual(navData.es.nav1.text);
|
|
||||||
expect(textarea).toStrictEqual(navData.es.nav1.textarea);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Endpoints', () => {
|
|
||||||
it('should respond with number of navigation items', async () => {
|
|
||||||
const response = await fetch(`${url}/api/globals/navigation-array/count`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `JWT ${token}`,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
|
||||||
const data = await response.json();
|
|
||||||
expect(data.count).toStrictEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/**
|
|
||||||
* @jest-environment node
|
|
||||||
*/
|
|
||||||
import { request, GraphQLClient } from 'graphql-request';
|
|
||||||
import getConfig from '../../config/load';
|
|
||||||
import { email, password } from '../../mongoose/testCredentials';
|
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
|
||||||
|
|
||||||
const config = getConfig();
|
|
||||||
|
|
||||||
const url = `${config.serverURL}${config.routes.api}${config.routes.graphQL}`;
|
|
||||||
|
|
||||||
let client = null;
|
|
||||||
let token = null;
|
|
||||||
|
|
||||||
describe('GrahpQL Preferences', () => {
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
const query = `
|
|
||||||
mutation {
|
|
||||||
loginAdmin(
|
|
||||||
email: "${email}",
|
|
||||||
password: "${password}"
|
|
||||||
) {
|
|
||||||
token
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await request(url, query);
|
|
||||||
|
|
||||||
token = response.loginAdmin.token;
|
|
||||||
|
|
||||||
client = new GraphQLClient(url, { headers: { Authorization: `JWT ${token}` } });
|
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Update', () => {
|
|
||||||
it('should allow a preference to be saved', async () => {
|
|
||||||
const key = 'preference-key';
|
|
||||||
const value = 'preference-value';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
updatePreference(key: "${key}", value: "${value}") {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const data = response.updatePreference;
|
|
||||||
|
|
||||||
expect(data.key).toBe(key);
|
|
||||||
expect(data.value).toBe(value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Read', () => {
|
|
||||||
it('should be able to read user preference', async () => {
|
|
||||||
const key = 'preference-key';
|
|
||||||
const value = 'preference-value';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
updatePreference(key: "${key}", value: "${value}") {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { key: responseKey, value: responseValue } = response.updatePreference;
|
|
||||||
// language=graphQL
|
|
||||||
const readQuery = `query {
|
|
||||||
Preference(key: "${responseKey}") {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const readResponse = await client.request(readQuery);
|
|
||||||
|
|
||||||
expect(responseKey).toStrictEqual(key);
|
|
||||||
expect(readResponse.Preference.key).toStrictEqual(key);
|
|
||||||
expect(responseValue).toStrictEqual(value);
|
|
||||||
expect(readResponse.Preference.value).toStrictEqual(value);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Delete', () => {
|
|
||||||
it('should be able to delete a preference', async () => {
|
|
||||||
const key = 'gql-delete';
|
|
||||||
const value = 'description';
|
|
||||||
|
|
||||||
// language=graphQL
|
|
||||||
const query = `mutation {
|
|
||||||
updatePreference(key: "${key}" value: "${value}") {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const response = await client.request(query);
|
|
||||||
|
|
||||||
const { key: responseKey } = response.updatePreference;
|
|
||||||
// language=graphQL
|
|
||||||
const deleteMutation = `mutation {
|
|
||||||
deletePreference(key: "${key}") {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const deleteResponse = await client.request(deleteMutation);
|
|
||||||
const deleteKey = deleteResponse.deletePreference.key;
|
|
||||||
|
|
||||||
expect(responseKey).toStrictEqual(key);
|
|
||||||
expect(deleteKey).toStrictEqual(key);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null when query key is not found', async () => {
|
|
||||||
const key = 'bad-key';
|
|
||||||
const readQuery = `query {
|
|
||||||
Preference(key: "${key}") {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
const response = await client.request(readQuery);
|
|
||||||
|
|
||||||
expect(response.Preference).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
3
test/access-control/int.todo-spec.ts
Normal file
3
test/access-control/int.todo-spec.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
describe('array stuff', () => {
|
||||||
|
it.todo('should properly prevent / allow public users from reading a restricted field');
|
||||||
|
});
|
||||||
@@ -87,6 +87,7 @@ describe('collections-rest', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Querying', () => {
|
describe('Querying', () => {
|
||||||
|
it.todo('should allow querying by a field within a group');
|
||||||
describe('Relationships', () => {
|
describe('Relationships', () => {
|
||||||
let post: Post;
|
let post: Post;
|
||||||
let relation: Relation;
|
let relation: Relation;
|
||||||
|
|||||||
@@ -29,6 +29,21 @@ type FindArgs = {
|
|||||||
slug?: string;
|
slug?: string;
|
||||||
query?: Where;
|
query?: Where;
|
||||||
auth?: boolean;
|
auth?: boolean;
|
||||||
|
depth?: number
|
||||||
|
page?: number
|
||||||
|
limit?: number
|
||||||
|
};
|
||||||
|
|
||||||
|
type FindByIDArgs = {
|
||||||
|
id: string;
|
||||||
|
slug?: string;
|
||||||
|
query?: Where;
|
||||||
|
auth?: boolean;
|
||||||
|
options?: {
|
||||||
|
depth?: number
|
||||||
|
page?: number
|
||||||
|
limit?: number
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type UpdateArgs<T = any> = {
|
type UpdateArgs<T = any> = {
|
||||||
@@ -133,14 +148,10 @@ export class RESTClient {
|
|||||||
const options = {
|
const options = {
|
||||||
headers: {
|
headers: {
|
||||||
...headers,
|
...headers,
|
||||||
Authorization: '',
|
Authorization: args?.auth !== false && this.token ? `JWT ${this.token}` : '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (args?.auth) {
|
|
||||||
options.headers.Authorization = `JWT ${this.token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const slug = args?.slug || this.defaultSlug;
|
const slug = args?.slug || this.defaultSlug;
|
||||||
const whereQuery = qs.stringify(args?.query ? { where: args.query } : {}, {
|
const whereQuery = qs.stringify(args?.query ? { where: args.query } : {}, {
|
||||||
addQueryPrefix: true,
|
addQueryPrefix: true,
|
||||||
@@ -169,9 +180,18 @@ export class RESTClient {
|
|||||||
return { status, doc: json.doc };
|
return { status, doc: json.doc };
|
||||||
}
|
}
|
||||||
|
|
||||||
async findByID<T = any>(id: string, args?: { slug?: string }): Promise<DocResponse<T>> {
|
async findByID<T = any>(args: FindByIDArgs): Promise<DocResponse<T>> {
|
||||||
const response = await fetch(`${this.serverURL}/api/${args?.slug || this.defaultSlug}/${id}`, {
|
const options = {
|
||||||
headers,
|
headers: {
|
||||||
|
...headers,
|
||||||
|
Authorization: args?.auth !== false && this.token ? `JWT ${this.token}` : '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const formattedOpts = qs.stringify(args?.options || {}, { addQueryPrefix: true });
|
||||||
|
const fetchURL = `${this.serverURL}/api/${args?.slug || this.defaultSlug}/${args.id}${formattedOpts}`;
|
||||||
|
const response = await fetch(fetchURL, {
|
||||||
|
headers: options.headers,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
const { status } = response;
|
const { status } = response;
|
||||||
|
|||||||
Reference in New Issue
Block a user