test: remove all old tests
This commit is contained in:
@@ -2,6 +2,7 @@ module.exports = {
|
||||
verbose: true,
|
||||
testEnvironment: 'node',
|
||||
testMatch: [
|
||||
'**/src/**/*.spec.ts',
|
||||
'**/test/**/*int.spec.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', () => {
|
||||
it.todo('should allow querying by a field within a group');
|
||||
describe('Relationships', () => {
|
||||
let post: Post;
|
||||
let relation: Relation;
|
||||
|
||||
@@ -29,6 +29,21 @@ type FindArgs = {
|
||||
slug?: string;
|
||||
query?: Where;
|
||||
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> = {
|
||||
@@ -133,14 +148,10 @@ export class RESTClient {
|
||||
const options = {
|
||||
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 whereQuery = qs.stringify(args?.query ? { where: args.query } : {}, {
|
||||
addQueryPrefix: true,
|
||||
@@ -169,9 +180,18 @@ export class RESTClient {
|
||||
return { status, doc: json.doc };
|
||||
}
|
||||
|
||||
async findByID<T = any>(id: string, args?: { slug?: string }): Promise<DocResponse<T>> {
|
||||
const response = await fetch(`${this.serverURL}/api/${args?.slug || this.defaultSlug}/${id}`, {
|
||||
headers,
|
||||
async findByID<T = any>(args: FindByIDArgs): Promise<DocResponse<T>> {
|
||||
const options = {
|
||||
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',
|
||||
});
|
||||
const { status } = response;
|
||||
|
||||
Reference in New Issue
Block a user