strapi/api-tests/plugins/graphql/crud.test.api.js
Fred Cox aa65f33dac fix(plugin-graphql): allow to use GET queries for graphql
GET queries are often advantagous for caching, cdns, etc
This removes a line that wasnt required, that blocked GET
queries from being authenticated on /graphql
2024-01-08 13:14:15 +00:00

621 lines
14 KiB
JavaScript

'use strict';
const { omit, prop } = require('lodash/fp');
// Helpers.
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;
const postModel = {
attributes: {
name: {
type: 'richtext',
},
bigint: {
type: 'biginteger',
},
nullable: {
type: 'string',
},
category: {
type: 'enumeration',
enum: ['BLOG', 'PRODUCT', 'TUTORIALS'],
},
},
singularName: 'post',
pluralName: 'posts',
displayName: 'Post',
description: '',
collectionName: '',
};
describe('Test Graphql API End to End', () => {
beforeAll(async () => {
await builder.addContentType(postModel).build();
strapi = await createStrapiInstance();
rq = await createAuthRequest({ strapi });
graphqlQuery = (body) => {
return rq({
url: '/graphql',
method: 'POST',
body,
});
};
});
afterAll(async () => {
await strapi.destroy();
await builder.cleanup();
});
describe('Test CRUD', () => {
const postsPayload = [
{ name: 'post 1', bigint: 1316130638171, nullable: 'value', category: 'BLOG' },
{ name: 'post 2', bigint: 1416130639261, nullable: null, category: 'PRODUCT' },
];
const data = {
posts: [],
};
test.each(postsPayload)('Create Post %o', async (post) => {
const res = await graphqlQuery({
query: /* GraphQL */ `
mutation createPost($data: PostInput!) {
createPost(data: $data) {
data {
attributes {
name
bigint
nullable
category
}
}
}
}
`,
variables: {
data: post,
},
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toEqual({
data: {
createPost: {
data: {
attributes: post,
},
},
},
});
});
test('List posts', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
posts {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
posts: {
data: postsPayload.map((entry) => ({
id: expect.any(String),
attributes: omit('id', entry),
})),
},
},
});
// assign for later use
data.posts = res.body.data.posts.data.map(({ id, attributes }) => ({ id, ...attributes }));
});
test('List posts with GET', async () => {
const graphqlQueryGET = (body) => {
return rq({
url: '/graphql',
method: 'GET',
qs: body,
});
};
const res = await graphqlQueryGET({
query: /* GraphQL */ `
{
posts {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
});
const { body } = res;
expect(res.statusCode).toBe(200);
expect(body).toMatchObject({
data: {
posts: {
data: postsPayload.map((entry) => ({
id: expect.any(String),
attributes: omit('id', entry),
})),
},
},
});
});
test('List posts with limit', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
posts(pagination: { limit: 1 }) {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
});
const expectedPost = data.posts[0];
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
posts: {
data: [
{
id: expectedPost.id,
attributes: omit('id', expectedPost),
},
],
},
},
});
});
test('List posts with sort', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
posts(sort: "name:desc") {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
});
const expectedPosts = [...data.posts].reverse().map((entry) => ({
id: expect.any(String),
attributes: omit('id', entry),
}));
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
posts: {
data: expectedPosts,
},
},
});
});
test('List posts with start', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
posts(pagination: { start: 1 }) {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
});
const expectedPost = data.posts[1];
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
posts: {
data: [
{
id: expectedPost.id,
attributes: omit('id', expectedPost),
},
],
},
},
});
});
test('Pagination counts are correct', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
posts(filters: { name: { eq: "post 2" } }) {
data {
id
attributes {
name
bigint
nullable
category
}
}
meta {
pagination {
total
pageSize
page
pageCount
}
}
}
}
`,
});
const expectedPost = data.posts[1];
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
posts: {
data: [
{
id: expectedPost.id,
attributes: omit('id', expectedPost),
},
],
meta: {
pagination: {
total: 1,
pageSize: 10,
page: 1,
pageCount: 1,
},
},
},
},
});
});
test.skip('List posts with `createdBy` and `updatedBy`', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
{
posts(start: 1) {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
});
expect(res.statusCode).toBe(200);
// no errors should be present in the response
expect(res.body.error).toBeUndefined();
// since the posts are created without AdminUser, it should return null
expect(res.body.data.posts[0].createdBy).toBeNull();
});
test.each([
[
{
name: { eq: 'post 1' },
bigint: { eq: 1316130638171 },
},
[postsPayload[0]],
],
[
{
category: { eq: 'BLOG' },
},
[postsPayload[0]],
],
[
{
name: { not: { eq: 'post 1' } },
bigint: { not: { eq: 1316130638171 } },
},
[postsPayload[1]],
],
[
{
category: { eqi: 'Blog' },
},
[postsPayload[0]],
],
[
{
name: { contains: 'post' },
},
postsPayload,
],
[
{
category: { contains: 'PRO' },
},
[postsPayload[1]],
],
[
{
name: { contains: 'post 1' },
},
[postsPayload[0]],
],
[
{
name: { containsi: 'Post' },
},
postsPayload,
],
[
{
name: { not: { containsi: 'Post 1' } },
},
[postsPayload[1]],
],
[
{
name: { in: ['post 1', 'post 2', 'post 3'] },
},
postsPayload,
],
[
{
name: { not: { in: ['post 2'] } },
},
[postsPayload[0]],
],
[
{
or: [{ name: { in: ['post 2'] } }, { bigint: { eq: 1316130638171 } }],
},
[postsPayload[0], postsPayload[1]],
],
[
{
and: [{ or: [{ name: { in: ['post 2'] } }, { bigint: { eq: 1316130638171 } }] }],
},
[postsPayload[0], postsPayload[1]],
],
[
{
and: [
{
or: [
{ name: { in: ['post 2'] } },
{ or: [{ bigint: { eq: 1316130638171 } }, { nullable: { not: { null: true } } }] },
],
},
],
},
[postsPayload[0], postsPayload[1]],
],
])('List posts with filters clause %o', async (filters, expected) => {
const res = await graphqlQuery({
query: /* GraphQL */ `
query findPosts($filters: PostFiltersInput) {
posts(filters: $filters) {
data {
attributes {
name
bigint
nullable
category
}
}
}
}
`,
variables: {
filters,
},
});
expect(res.statusCode).toBe(200);
const { data: posts } = res.body.data.posts;
// same length
expect(posts.length).toBe(expected.length);
// all the posts returned are in the expected array
posts.map(prop('attributes')).forEach((post) => {
expect(expected.map(omit('id'))).toEqual(expect.arrayContaining([post]));
});
// all expected values are in the result
expected.forEach((expectedPost) => {
expect(posts.map(prop('attributes'))).toEqual(
expect.arrayContaining([omit('id', expectedPost)])
);
});
});
test('Get One Post', async () => {
const res = await graphqlQuery({
query: /* GraphQL */ `
query getPost($id: ID!) {
post(id: $id) {
data {
id
attributes {
name
bigint
nullable
category
}
}
}
}
`,
variables: {
id: data.posts[0].id,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
post: {
data: {
id: data.posts[0].id,
attributes: omit('id', data.posts[0]),
},
},
},
});
});
test('Update Post', async () => {
const newName = 'new post name';
const res = await graphqlQuery({
query: /* GraphQL */ `
mutation updatePost($id: ID!, $data: PostInput!) {
updatePost(id: $id, data: $data) {
data {
id
attributes {
name
}
}
}
}
`,
variables: {
id: data.posts[0].id,
data: {
name: newName,
},
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
updatePost: {
data: {
id: data.posts[0].id,
attributes: {
name: newName,
},
},
},
},
});
const newPost = res.body.data.updatePost.data;
data.posts[0] = {
id: newPost.id,
...newPost.attributes,
};
});
test('Delete Posts', async () => {
for (const post of data.posts) {
const res = await graphqlQuery({
query: /* GraphQL */ `
mutation deletePost($id: ID!) {
deletePost(id: $id) {
data {
id
attributes {
name
nullable
bigint
category
}
}
}
}
`,
variables: {
id: post.id,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
deletePost: {
data: {
id: post.id,
attributes: omit('id', post),
},
},
},
});
}
});
});
});