// ========================================================================== // Squidex Headless CMS // ================================ ========================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System.Text.RegularExpressions; using System.Threading.Tasks; using FakeItEasy; using GraphQL; using GraphQL.NewtonsoftJson; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Shared; using Xunit; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { public class GraphQLMutationTests : GraphQLTestBase { private readonly DomainId contentId = DomainId.NewGuid(); private readonly IEnrichedContentEntity content; private readonly CommandContext commandContext = new CommandContext(new PatchContent(), A.Dummy()); public GraphQLMutationTests() { content = TestContent.Create(appId, schemaId, contentId, schemaRefId1.Id, schemaRefId2.Id, null); A.CallTo(() => commandBus.PublishAsync(A.Ignored)) .Returns(commandContext); } [Fact] public async Task Should_return_error_when_user_has_no_permission_to_create() { var query = @" mutation { createMySchemaContent(data: { myNumber: { iv: 42 } }) { id } }"; var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn); var expected = new { data = new { createMySchemaContent = (object?)null }, errors = new[] { new { message = "You do not have the necessary permission.", locations = new[] { new { line = 3, column = 19 } } } } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync(A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_return_single_content_when_creating_content() { var query = @" mutation { createMySchemaContent(data: , publish: true) { } }".Replace("", GetDataString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsCreate); var expected = new { data = new { createMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.SchemaId.Equals(schemaId) && x.ExpectedVersion == EtagVersion.Any && x.Publish && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_single_content_when_creating_content_with_custom_id() { var query = @" mutation { createMySchemaContent(data: , id: ""123"", publish: true) { } }".Replace("", GetDataString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsCreate); var expected = new { data = new { createMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.SchemaId.Equals(schemaId) && x.ExpectedVersion == EtagVersion.Any && x.ContentId == DomainId.Create("123") && x.Publish && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_single_content_when_creating_content_with_variable() { var query = @" mutation OP($data: MySchemaDataInputDto!) { createMySchemaContent(data: $data, publish: true) { } }".Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsCreate); var expected = new { data = new { createMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.SchemaId.Equals(schemaId) && x.ExpectedVersion == EtagVersion.Any && x.Publish && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_error_when_user_has_no_permission_to_update() { var query = @" mutation { updateMySchemaContent(id: """", data: { myNumber: { iv: 42 } }) { id } }".Replace("", contentId.ToString()); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn); var expected = new { data = new { updateMySchemaContent = (object?)null }, errors = new[] { new { message = "You do not have the necessary permission.", locations = new[] { new { line = 3, column = 19 } } } } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync(A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_return_single_content_when_updating_content() { var query = @" mutation { updateMySchemaContent(id: """", data: , expectedVersion: 10) { } }".Replace("", contentId.ToString()).Replace("", GetDataString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsUpdateOwn); var expected = new { data = new { updateMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.ContentId == content.Id && x.ExpectedVersion == 10 && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_single_content_when_updating_content_with_variable() { var query = @" mutation OP($data: MySchemaDataInputDto!) { updateMySchemaContent(id: """", data: $data, expectedVersion: 10) { } }".Replace("", contentId.ToString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsUpdateOwn); var expected = new { data = new { updateMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.ContentId == content.Id && x.ExpectedVersion == 10 && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_error_when_user_has_no_permission_to_upsert() { var query = @" mutation { upsertMySchemaContent(id: """", data: { myNumber: { iv: 42 } }) { id } }".Replace("", contentId.ToString()); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn); var expected = new { data = new { upsertMySchemaContent = (object?)null }, errors = new[] { new { message = "You do not have the necessary permission.", locations = new[] { new { line = 3, column = 19 } } } } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync(A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_return_single_content_when_upserting_content() { var query = @" mutation { upsertMySchemaContent(id: """", data: , publish: true, expectedVersion: 10) { } }".Replace("", contentId.ToString()).Replace("", GetDataString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsUpsert); var expected = new { data = new { upsertMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.ContentId == content.Id && x.ExpectedVersion == 10 && x.Publish && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_single_content_when_upserting_content_with_variable() { var query = @" mutation OP($data: MySchemaDataInputDto!) { upsertMySchemaContent(id: """", data: $data, publish: true, expectedVersion: 10) { } }".Replace("", contentId.ToString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsUpsert); var expected = new { data = new { upsertMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.ContentId == content.Id && x.ExpectedVersion == 10 && x.Publish && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_error_when_user_has_no_permission_to_patch() { var query = @" mutation { patchMySchemaContent(id: """", data: { myNumber: { iv: 42 } }) { id } }".Replace("", contentId.ToString()); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn); var expected = new { data = new { patchMySchemaContent = (object?)null }, errors = new[] { new { message = "You do not have the necessary permission.", locations = new[] { new { line = 3, column = 19 } } } } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync(A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_return_single_content_when_patching_content() { var query = @" mutation { patchMySchemaContent(id: """", data: , expectedVersion: 10) { } }".Replace("", contentId.ToString()).Replace("", GetDataString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query }, Permissions.AppContentsUpdateOwn); var expected = new { data = new { patchMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.ContentId == content.Id && x.ExpectedVersion == 10 && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_single_content_when_patching_content_with_variable() { var query = @" mutation OP($data: MySchemaDataInputDto!) { patchMySchemaContent(id: """", data: $data, expectedVersion: 10) { } }".Replace("", contentId.ToString()).Replace("", TestContent.AllFields); commandContext.Complete(content); var result = await ExecuteAsync( new GraphQLQuery { Query = query, Inputs = GetInput() }, Permissions.AppContentsUpdateOwn); var expected = new { data = new { patchMySchemaContent = TestContent.Response(content) } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => x.ContentId == content.Id && x.ExpectedVersion == 10 && x.Data.Equals(content.Data)))) .MustHaveHappened(); } [Fact] public async Task Should_return_error_when_user_has_no_permission_to_change_status() { var query = @" mutation { changeMySchemaContent(id: """", status: ""Published"") { id } }".Replace("", contentId.ToString()); var result = await ExecuteAsync(new GraphQLQuery { Query = query }, Permissions.AppContentsReadOwn); var expected = new { data = new { changeMySchemaContent = (object?)null }, errors = new[] { new { message = "You do not have the necessary permission.", locations = new[] { new { line = 3, column = 19 } } } } }; AssertResult(expected, result); A.CallTo(() => commandBus.PublishAsync(A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_return_single_content_when_changing_status() { var dueTime = SystemClock.Instance.GetCurrentInstant().WithoutMs(); var query = @" mutation { changeMySchemaContent(id: """", status: ""Published"", dueTime: ""