Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

739 lines
25 KiB

// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
public class GraphQLQueriesTests : GraphQLTestBase
{
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public async Task Should_return_empty_object_for_empty_query(string query)
{
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_return_multiple_assets_when_querying_assets()
{
const string query = @"
query {
queryAssets(search: ""my-query"", take: 30, skip: 5) {
id
version
created
createdBy
lastModified
lastModifiedBy
url
thumbnailUrl
sourceUrl
mimeType
fileName
fileSize
fileVersion
isImage
pixelWidth
pixelHeight
}
}";
var asset = CreateAsset(Guid.NewGuid());
var assets = new List<IAssetEntity> { asset };
A.CallTo(() => assetRepository.QueryAsync(app.Id, "?$take=30&$skip=5&$search=my-query"))
.Returns(ResultList.Create(assets, 0));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
queryAssets = new dynamic[]
{
new
{
id = asset.Id,
version = 1,
created = asset.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = asset.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"assets/{asset.Id}",
thumbnailUrl = $"assets/{asset.Id}?width=100",
sourceUrl = $"assets/source/{asset.Id}",
mimeType = "image/png",
fileName = "MyFile.png",
fileSize = 1024,
fileVersion = 123,
isImage = true,
pixelWidth = 800,
pixelHeight = 600
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_return_multiple_assets_with_total_when_querying_assets_with_total()
{
const string query = @"
query {
queryAssetsWithTotal(search: ""my-query"", take: 30, skip: 5) {
total
items {
id
version
created
createdBy
lastModified
lastModifiedBy
url
thumbnailUrl
sourceUrl
mimeType
fileName
fileSize
fileVersion
isImage
pixelWidth
pixelHeight
}
}
}";
var asset = CreateAsset(Guid.NewGuid());
var assets = new List<IAssetEntity> { asset };
A.CallTo(() => assetRepository.QueryAsync(app.Id, "?$take=30&$skip=5&$search=my-query"))
.Returns(ResultList.Create(assets, 10));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
queryAssetsWithTotal = new
{
total = 10,
items = new dynamic[]
{
new
{
id = asset.Id,
version = 1,
created = asset.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = asset.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"assets/{asset.Id}",
thumbnailUrl = $"assets/{asset.Id}?width=100",
sourceUrl = $"assets/source/{asset.Id}",
mimeType = "image/png",
fileName = "MyFile.png",
fileSize = 1024,
fileVersion = 123,
isImage = true,
pixelWidth = 800,
pixelHeight = 600
}
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_return_single_asset_when_finding_asset()
{
var assetId = Guid.NewGuid();
var asset = CreateAsset(Guid.NewGuid());
var query = $@"
query {{
findAsset(id: ""{assetId}"") {{
id
version
created
createdBy
lastModified
lastModifiedBy
url
thumbnailUrl
sourceUrl
mimeType
fileName
fileSize
fileVersion
isImage
pixelWidth
pixelHeight
}}
}}";
A.CallTo(() => assetRepository.FindAssetAsync(assetId))
.Returns(asset);
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findAsset = new
{
id = asset.Id,
version = 1,
created = asset.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = asset.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"assets/{asset.Id}",
thumbnailUrl = $"assets/{asset.Id}?width=100",
sourceUrl = $"assets/source/{asset.Id}",
mimeType = "image/png",
fileName = "MyFile.png",
fileSize = 1024,
fileVersion = 123,
isImage = true,
pixelWidth = 800,
pixelHeight = 600
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_return_multiple_contents_when_querying_contents()
{
const string query = @"
query {
queryMySchemaContents(top: 30, skip: 5) {
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {
myString {
de
}
myNumber {
iv
}
myBoolean {
iv
}
myDatetime {
iv
}
myJson {
iv
}
myGeolocation {
iv
}
myTags {
iv
}
}
}
}";
var content = CreateContent(Guid.NewGuid(), Guid.Empty, Guid.Empty);
var contents = new List<IContentEntity> { content };
A.CallTo(() => contentQuery.QueryAsync(app, schema.Id.ToString(), user, false, "?$top=30&$skip=5"))
.Returns((schema, ResultList.Create(contents, 0)));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
queryMySchemaContents = new dynamic[]
{
new
{
id = content.Id,
version = 1,
created = content.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = content.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{content.Id}",
data = new
{
myString = new
{
de = "value"
},
myNumber = new
{
iv = 1
},
myBoolean = new
{
iv = true
},
myDatetime = new
{
iv = content.LastModified.ToDateTimeUtc()
},
myJson = new
{
iv = new
{
value = 1
}
},
myGeolocation = new
{
iv = new
{
latitude = 10,
longitude = 20
}
},
myTags = new
{
iv = new[]
{
"tag1",
"tag2"
}
}
}
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_return_multiple_contents_with_total_when_querying_contents_with_total()
{
const string query = @"
query {
queryMySchemaContentsWithTotal(top: 30, skip: 5) {
total
items {
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {
myString {
de
}
myNumber {
iv
}
myBoolean {
iv
}
myDatetime {
iv
}
myJson {
iv
}
myGeolocation {
iv
}
myTags {
iv
}
}
}
}
}";
var content = CreateContent(Guid.NewGuid(), Guid.Empty, Guid.Empty);
var contents = new List<IContentEntity> { content };
A.CallTo(() => contentQuery.QueryAsync(app, schema.Id.ToString(), user, false, "?$top=30&$skip=5"))
.Returns((schema, ResultList.Create(contents, 10)));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
queryMySchemaContentsWithTotal = new
{
total = 10,
items = new dynamic[]
{
new
{
id = content.Id,
version = 1,
created = content.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = content.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{content.Id}",
data = new
{
myString = new
{
de = "value"
},
myNumber = new
{
iv = 1
},
myBoolean = new
{
iv = true
},
myDatetime = new
{
iv = content.LastModified.ToDateTimeUtc()
},
myJson = new
{
iv = new
{
value = 1
}
},
myGeolocation = new
{
iv = new
{
latitude = 10,
longitude = 20
}
},
myTags = new
{
iv = new[]
{
"tag1",
"tag2"
}
}
}
}
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_return_single_content_when_finding_content()
{
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, Guid.Empty, Guid.Empty);
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {{
myString {{
de
}}
myNumber {{
iv
}}
myBoolean {{
iv
}}
myDatetime {{
iv
}}
myJson {{
iv
}}
myGeolocation {{
iv
}}
myTags {{
iv
}}
}}
}}
}}";
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findMySchemaContent = new
{
id = content.Id,
version = 1,
created = content.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = content.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{content.Id}",
data = new
{
myString = new
{
de = "value"
},
myNumber = new
{
iv = 1
},
myBoolean = new
{
iv = true
},
myDatetime = new
{
iv = content.LastModified.ToDateTimeUtc()
},
myJson = new
{
iv = new
{
value = 1
}
},
myGeolocation = new
{
iv = new
{
latitude = 10,
longitude = 20
}
},
myTags = new
{
iv = new[]
{
"tag1",
"tag2"
}
}
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_also_fetch_referenced_contents_when_field_is_included_in_query()
{
var contentRefId = Guid.NewGuid();
var contentRef = CreateContent(contentRefId, Guid.Empty, Guid.Empty);
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, contentRefId, Guid.Empty);
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
data {{
myReferences {{
iv {{
id
}}
}}
}}
}}
}}";
var refContents = new List<IContentEntity> { contentRef };
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
A.CallTo(() => contentQuery.QueryAsync(app, schema.Id.ToString(), user, false, A<HashSet<Guid>>.That.Matches(x => x.Contains(contentRefId))))
.Returns((schema, ResultList.Create(refContents, 0)));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findMySchemaContent = new
{
id = content.Id,
data = new
{
myReferences = new
{
iv = new[]
{
new
{
id = contentRefId
}
}
}
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_also_fetch_referenced_assets_when_field_is_included_in_query()
{
var assetRefId = Guid.NewGuid();
var assetRef = CreateAsset(assetRefId);
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, Guid.Empty, assetRefId);
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
data {{
myAssets {{
iv {{
id
}}
}}
}}
}}
}}";
var refAssets = new List<IAssetEntity> { assetRef };
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
A.CallTo(() => assetRepository.QueryAsync(app.Id, A<HashSet<Guid>>.That.Matches(x => x.Contains(assetRefId))))
.Returns(ResultList.Create(refAssets, 0));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findMySchemaContent = new
{
id = content.Id,
data = new
{
myAssets = new
{
iv = new[]
{
new
{
id = assetRefId
}
}
}
}
}
}
};
AssertResult(expected, result);
}
[Fact]
public async Task Should_not_return_data_when_field_not_part_of_content()
{
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, Guid.Empty, Guid.Empty, new NamedContentData());
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {{
myInvalid {{
iv
}}
}}
}}
}}";
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = (object)null
};
AssertResult(expected, result, false);
}
}
}