strapi/tests/api/plugins/graphql/relations.test.api.js

906 lines
22 KiB
JavaScript
Raw Normal View History

'use strict';
// Helpers.
2021-09-21 19:38:15 +02:00
const { pick } = require('lodash/fp');
const { createTestBuilder } = require('api-tests/builder');
const { createStrapiInstance } = require('api-tests/strapi');
const { createAuthRequest } = require('api-tests/request');
const builder = createTestBuilder();
let strapi;
let rq;
let graphqlQuery;
2021-09-21 19:38:15 +02:00
// Utils
const selectFields = pick(['name', 'color']);
const rgbColorComponent = {
attributes: {
name: {
type: 'text',
},
red: {
type: 'integer',
},
green: {
type: 'integer',
},
blue: {
type: 'integer',
},
},
2021-11-02 18:27:49 +01:00
displayName: 'rgbColor',
};
2024-03-05 19:33:27 +01:00
const articleModel = {
2019-11-14 16:37:57 +01:00
attributes: {
name: {
type: 'richtext',
},
2019-11-14 16:37:57 +01:00
content: {
type: 'richtext',
},
2019-11-14 16:37:57 +01:00
},
2024-03-05 19:33:27 +01:00
singularName: 'article',
pluralName: 'articles',
displayName: 'Article',
description: '',
collectionName: '',
};
const labelModel = {
2019-11-14 16:37:57 +01:00
attributes: {
name: {
type: 'richtext',
},
2024-03-05 19:33:27 +01:00
articles: {
2021-07-08 18:15:32 +02:00
type: 'relation',
relation: 'manyToMany',
2024-03-05 19:33:27 +01:00
target: 'api::article.article',
2019-11-14 16:37:57 +01:00
targetAttribute: 'labels',
},
color: {
type: 'component',
component: 'default.rgb-color',
repeatable: false,
},
2019-11-14 16:37:57 +01:00
},
singularName: 'label',
pluralName: 'labels',
displayName: 'Label',
description: '',
collectionName: '',
};
const carModel = {
attributes: {
name: {
type: 'text',
},
},
singularName: 'car',
pluralName: 'cars',
displayName: 'Car',
description: '',
collectionName: '',
};
const personModel = {
attributes: {
name: {
type: 'text',
},
privateName: {
type: 'text',
private: true,
},
privateCars: {
2021-07-08 18:15:32 +02:00
type: 'relation',
relation: 'oneToMany',
2021-08-06 18:09:49 +02:00
target: 'api::car.car',
targetAttribute: 'person',
private: true,
},
},
displayName: 'Person',
singularName: 'person',
pluralName: 'people',
description: '',
collectionName: '',
};
describe('Test Graphql Relations API End to End', () => {
beforeAll(async () => {
await builder
.addComponent(rgbColorComponent)
2024-03-05 19:33:27 +01:00
.addContentTypes([articleModel, labelModel, carModel, personModel])
.build();
strapi = await createStrapiInstance();
rq = await createAuthRequest({ strapi });
2022-08-08 23:33:39 +02:00
graphqlQuery = (body) => {
return rq({
url: '/graphql',
method: 'POST',
body,
});
};
});
afterAll(async () => {
await strapi.destroy();
await builder.cleanup();
});
describe('Test relations features', () => {
2022-08-08 15:50:34 +02:00
const data = {
labels: [],
2024-03-05 19:33:27 +01:00
articles: [],
people: [],
cars: [],
};
const labelsPayload = [
{ name: 'label 1', color: null },
{ name: 'label 2', color: null },
{ name: 'labelWithColor', color: { name: 'tomato', red: 255, green: 99, blue: 71 } },
];
2024-03-05 19:33:27 +01:00
const articlesPayload = [{ name: 'article 1' }, { name: 'article 2' }];
2022-08-08 23:33:39 +02:00
test.each(labelsPayload)('Create label %o', async (label) => {
const res = await graphqlQuery({
query: /* GraphQL */ `
2021-09-21 19:38:15 +02:00
mutation createLabel($data: LabelInput!) {
createLabel(data: $data) {
data {
attributes {
name
2021-09-21 19:38:15 +02:00
color {
name
red
green
blue
}
}
}
}
}
`,
variables: {
2021-09-21 19:38:15 +02:00
data: label,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
createLabel: {
2021-09-21 19:38:15 +02:00
data: {
attributes: label,
},
},
},
});
});
test('List labels', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
}
}
}
}
`,
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
labels_connection: {
data: labelsPayload.map((label) => ({
documentId: expect.any(String),
attributes: label,
})),
2021-09-21 19:38:15 +02:00
},
},
});
// assign for later use
2024-03-05 19:33:27 +01:00
data.labels = data.labels.concat(res.body.data.labels_connection.data);
});
2024-03-05 19:33:27 +01:00
test.each(articlesPayload)('Create article linked to every labels %o', async (article) => {
const res = await graphqlQuery({
query: /* GraphQL */ `
2024-03-05 19:33:27 +01:00
mutation createArticle($data: ArticleInput!) {
createArticle(data: $data) {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
}
}
2019-04-09 18:35:49 +02:00
}
}
}
}
}
`,
variables: {
2021-09-21 19:38:15 +02:00
data: {
2024-03-05 19:33:27 +01:00
...article,
labels: data.labels.map((t) => t.documentId),
},
},
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
createArticle: {
2021-09-21 19:38:15 +02:00
data: {
2024-03-05 19:33:27 +01:00
documentId: expect.any(String),
2021-09-21 19:38:15 +02:00
attributes: {
2024-03-05 19:33:27 +01:00
...selectFields(article),
labels_connection: {
2021-09-21 19:38:15 +02:00
data: expect.arrayContaining(data.labels),
},
},
},
},
},
});
2021-09-21 19:38:15 +02:00
2024-03-05 19:33:27 +01:00
data.articles.push(body.data.createArticle.data);
});
2024-03-05 19:33:27 +01:00
test('List articles with labels', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
articles_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
}
}
}
}
}
}
}
`,
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
2019-04-09 18:35:49 +02:00
data: {
2024-03-05 19:33:27 +01:00
articles_connection: {
data: expect.arrayContaining(data.articles),
2021-09-21 19:38:15 +02:00
},
2019-04-09 18:35:49 +02:00
},
});
// assign for later use
2024-03-05 19:33:27 +01:00
data.articles = res.body.data.articles_connection.data;
});
2024-03-05 19:33:27 +01:00
test('List Labels with articles', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
2024-03-05 19:33:27 +01:00
articles_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
}
}
}
}
}
}
}
`,
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
labels_connection: {
2021-09-21 19:38:15 +02:00
data: expect.arrayContaining(
2022-08-08 23:33:39 +02:00
data.labels.map((label) => ({
2024-03-05 19:33:27 +01:00
documentId: label.documentId,
2021-09-21 19:38:15 +02:00
attributes: {
...label.attributes,
2024-03-05 19:33:27 +01:00
articles_connection: {
2021-09-21 19:38:15 +02:00
data: expect.arrayContaining(
2024-03-05 19:33:27 +01:00
data.articles.map((article) => ({
documentId: article.documentId,
attributes: selectFields(article.attributes),
2021-09-21 19:38:15 +02:00
}))
),
},
},
}))
),
},
},
});
// assign for later use
2024-03-05 19:33:27 +01:00
data.labels = res.body.data.labels_connection.data;
});
2024-03-05 19:33:27 +01:00
test('List labels with articles paginated', async () => {
2023-02-06 19:09:05 +01:00
const res = await graphqlQuery({
query: /* GraphQL */ `
query labels($pagination: PaginationArg!) {
2024-03-05 19:33:27 +01:00
labels_connection {
2023-02-06 19:09:05 +01:00
data {
2024-03-05 19:33:27 +01:00
documentId
2023-02-06 19:09:05 +01:00
attributes {
name
color {
name
red
green
blue
}
2024-03-05 19:33:27 +01:00
articles_connection(pagination: $pagination) {
2023-02-06 19:09:05 +01:00
data {
2024-03-05 19:33:27 +01:00
documentId
2023-02-06 19:09:05 +01:00
attributes {
name
}
}
}
}
}
}
}
`,
variables: {
pagination: {
page: 1,
pageSize: 1,
},
},
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
labels_connection: {
2023-02-06 19:09:05 +01:00
data: expect.arrayContaining(
data.labels.map((label) => ({
2024-03-05 19:33:27 +01:00
documentId: label.documentId,
2023-02-06 19:09:05 +01:00
attributes: {
...label.attributes,
2024-03-05 19:33:27 +01:00
articles_connection: {
2023-02-06 19:09:05 +01:00
data: expect.arrayContaining(
2024-03-05 19:33:27 +01:00
data.articles.slice(0, 1).map((article) => ({
documentId: article.documentId,
attributes: selectFields(article.attributes),
2023-02-06 19:09:05 +01:00
}))
),
},
},
}))
),
},
},
});
// assign for later use
2024-03-05 19:33:27 +01:00
data.labels = res.body.data.labels_connection.data;
2023-02-06 19:09:05 +01:00
});
2023-09-27 11:56:41 +02:00
test('Deep query', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
articles_connection(filters: { labels: { name: { contains: "label 1" } } }) {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
}
2023-09-27 11:56:41 +02:00
}
}
}
}
}
}
`,
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
articles_connection: {
data: expect.arrayContaining(data.articles),
2023-09-27 11:56:41 +02:00
},
},
});
});
test('Deep query with empty object param', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
articles_connection(filters: { labels: { name: {} } }) {
2023-09-27 11:56:41 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2023-09-27 11:56:41 +02:00
attributes {
name
2024-03-05 19:33:27 +01:00
labels_connection {
2023-09-27 11:56:41 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2023-09-27 11:56:41 +02:00
attributes {
name
color {
name
red
green
blue
}
}
2021-09-21 19:38:15 +02:00
}
}
}
}
}
}
`,
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
articles_connection: {
data: expect.arrayContaining(data.articles),
2021-09-21 19:38:15 +02:00
},
},
});
});
2024-03-05 19:33:27 +01:00
test('Update Article relations removes correctly a relation', async () => {
const article = data.articles[0];
2021-09-21 19:38:15 +02:00
const labels = [data.labels[0]];
2024-03-05 19:33:27 +01:00
// if I remove a label from an article is it working
const res = await graphqlQuery({
query: /* GraphQL */ `
2024-03-05 19:33:27 +01:00
mutation updateArticle($documentId: ID!, $data: ArticleInput!) {
updateArticle(documentId: $documentId, data: $data) {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
}
}
}
}
}
}
}
`,
variables: {
2024-03-05 19:33:27 +01:00
documentId: article.documentId,
2021-09-21 19:38:15 +02:00
data: {
2024-03-05 19:33:27 +01:00
labels: labels.map((label) => label.documentId),
},
},
});
expect(res.body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
updateArticle: {
2021-09-21 19:38:15 +02:00
data: {
2024-03-05 19:33:27 +01:00
documentId: article.documentId,
2021-09-21 19:38:15 +02:00
attributes: {
2024-03-05 19:33:27 +01:00
...selectFields(article.attributes),
labels_connection: {
2022-08-08 23:33:39 +02:00
data: labels.map((label) => ({
2024-03-05 19:33:27 +01:00
documentId: label.documentId,
2021-09-21 19:38:15 +02:00
attributes: {
...selectFields(label.attributes),
color: null,
},
})),
},
},
},
},
},
});
});
2024-03-05 19:33:27 +01:00
test('Delete Labels and test Articles relations', async () => {
2022-08-08 15:50:34 +02:00
for (const label of data.labels) {
const res = await graphqlQuery({
query: /* GraphQL */ `
2024-03-05 19:33:27 +01:00
mutation deleteLabel($documentId: ID!) {
deleteLabel(documentId: $documentId) {
documentId
}
}
`,
variables: {
2024-03-05 19:33:27 +01:00
documentId: label.documentId,
},
});
expect(res.statusCode).toBe(200);
2019-08-23 14:15:24 +02:00
expect(res.body).toMatchObject({
data: {
deleteLabel: {
2024-03-05 19:33:27 +01:00
documentId: label.documentId,
2019-08-23 14:15:24 +02:00
},
},
});
}
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
articles_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
2024-03-05 19:33:27 +01:00
labels_connection {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
color {
name
red
green
blue
}
}
}
}
}
}
}
}
`,
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
articles_connection: {
2021-09-21 19:38:15 +02:00
data: expect.arrayContaining(
2024-03-05 19:33:27 +01:00
data.articles.map((article) => ({
documentId: article.documentId,
2021-09-21 19:38:15 +02:00
attributes: {
2024-03-05 19:33:27 +01:00
...selectFields(article.attributes),
labels_connection: { data: [] },
2021-09-21 19:38:15 +02:00
},
}))
),
},
},
});
});
2024-03-05 19:33:27 +01:00
test('Delete Articles', async () => {
for (const article of data.articles) {
const res = await graphqlQuery({
query: /* GraphQL */ `
2024-03-05 19:33:27 +01:00
mutation deleteArticle($documentId: ID!) {
deleteArticle(documentId: $documentId) {
documentId
}
}
`,
variables: {
2024-03-05 19:33:27 +01:00
documentId: article.documentId,
},
});
expect(res.statusCode).toBe(200);
2019-08-23 14:15:24 +02:00
expect(res.body).toMatchObject({
data: {
2024-03-05 19:33:27 +01:00
deleteArticle: {
documentId: article.documentId,
2019-08-23 14:15:24 +02:00
},
},
});
}
});
test('Create person', async () => {
const person = {
name: 'Chuck Norris',
};
2021-09-21 19:38:15 +02:00
const res = await graphqlQuery({
query: /* GraphQL */ `
2021-09-21 19:38:15 +02:00
mutation createPerson($data: PersonInput!) {
createPerson(data: $data) {
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
}
}
}
}
`,
variables: {
2021-09-21 19:38:15 +02:00
data: person,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
createPerson: {
2021-09-21 19:38:15 +02:00
data: {
2024-03-05 19:33:27 +01:00
documentId: expect.anything(),
2021-09-21 19:38:15 +02:00
attributes: {
name: person.name,
},
},
},
},
});
2021-09-21 19:38:15 +02:00
data.people.push(res.body.data.createPerson.data);
});
test("Can't list a private field", async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
people_connection {
2021-09-21 19:38:15 +02:00
data {
attributes {
name
privateName
}
}
}
}
`,
});
expect(res.statusCode).toBe(400);
expect(res.body).toMatchObject({
errors: [
{
message: 'Cannot query field "privateName" on type "Person".',
},
],
});
});
test('Create a car linked to a person (oneToMany)', async () => {
const car = {
name: 'Peugeot 508',
2024-03-05 19:33:27 +01:00
person: data.people[0].documentId,
};
2021-09-21 19:38:15 +02:00
const res = await graphqlQuery({
query: /* GraphQL */ `
2021-09-21 19:38:15 +02:00
mutation createCar($data: CarInput!) {
createCar(data: $data) {
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
2021-09-21 19:38:15 +02:00
person {
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
attributes {
name
}
}
}
}
}
}
}
`,
variables: {
2021-09-21 19:38:15 +02:00
data: car,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
createCar: {
2021-09-21 19:38:15 +02:00
data: {
2024-03-05 19:33:27 +01:00
documentId: expect.anything(),
2021-09-21 19:38:15 +02:00
attributes: {
name: car.name,
person: {
data: data.people[0],
},
},
},
},
},
});
2024-03-05 19:33:27 +01:00
data.cars.push({ documentId: res.body.data.createCar.data.documentId });
});
test("Can't list a private oneToMany relation", async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
2024-03-05 19:33:27 +01:00
people_connection {
2021-09-21 19:38:15 +02:00
data {
attributes {
name
privateCars
}
}
}
}
`,
});
expect(res.statusCode).toBe(400);
expect(res.body).toMatchObject({
errors: [
{
message: 'Cannot query field "privateCars" on type "Person".',
},
],
});
});
test(`Can't edit a private relation `, async () => {
const newPerson = {
name: 'Check Norris Junior',
privateCars: [],
};
const mutationRes = await graphqlQuery({
query: /* GraphQL */ `
2024-03-05 19:33:27 +01:00
mutation updatePerson($documentId: ID!, $data: PersonInput!) {
updatePerson(documentId: $documentId, data: $data) {
2021-09-21 19:38:15 +02:00
data {
2024-03-05 19:33:27 +01:00
documentId
}
}
}
`,
variables: {
2024-03-05 19:33:27 +01:00
documentId: data.people[0].documentId,
2021-09-21 19:38:15 +02:00
data: newPerson,
},
});
2021-09-21 19:38:15 +02:00
expect(mutationRes.statusCode).toBe(400);
expect(mutationRes.body.errors[0].message).toBe(
`Variable "$data" got invalid value { name: "Check Norris Junior", privateCars: [] }; Field "privateCars" is not defined by type "PersonInput".`
);
const queryRes = await graphqlQuery({
query: /* GraphQL */ `
2024-03-05 19:33:27 +01:00
query ($documentId: ID!) {
car(documentId: $documentId) {
2021-09-21 19:38:15 +02:00
data {
attributes {
person {
data {
2024-03-05 19:33:27 +01:00
documentId
2021-09-21 19:38:15 +02:00
}
}
}
}
}
}
`,
variables: {
2024-03-05 19:33:27 +01:00
documentId: data.cars[0].documentId,
},
});
2021-09-21 19:38:15 +02:00
expect(queryRes.statusCode).toBe(200);
expect(queryRes.body).toEqual({
data: {
car: {
2021-09-21 19:38:15 +02:00
data: {
attributes: {
person: { data: { documentId: data.people[0].documentId } },
2021-09-21 19:38:15 +02:00
},
},
},
},
});
});
});
});