Merge remote-tracking branch 'origin/release/15.0' into v15/dev

# Conflicts:
#	src/Umbraco.Core/Services/DocumentUrlService.cs
#	src/Umbraco.Web.UI.Client
#	tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentNavigationServiceBaseTests.cs
This commit is contained in:
Jacob Overgaard
2024-10-17 09:02:19 +02:00
79 changed files with 2264 additions and 323 deletions

View File

@@ -106,4 +106,34 @@ public partial class DocumentNavigationServiceTests
Assert.AreNotEqual(GreatGrandchild1.Key, copiedGreatGrandChild1.Key);
});
}
[Test]
[TestCase(null)] // Content root
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573")] // Grandchild 1
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF")] // Child 3
[TestCase("F381906C-223C-4466-80F7-B63B4EE073F8")] // Grandchild 4
public async Task Copying_Content_Adds_It_Last(Guid? parentKey)
{
// Act
var copyAttempt = await ContentEditingService.CopyAsync(Grandchild1.Key, parentKey, false, true, Constants.Security.SuperUserKey);
Guid copiedItemKey = copyAttempt.Result.Key;
// Assert
if (parentKey is null)
{
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(copiedItemKey, rootKeys.Last());
}
else
{
DocumentNavigationQueryService.TryGetChildrenKeys(parentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(copiedItemKey, childrenKeys.Last());
}
}
}

View File

@@ -1,6 +1,5 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.ContentEditing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
@@ -37,7 +36,7 @@ public partial class DocumentNavigationServiceTests
// Arrange
DocumentNavigationQueryService.TryGetChildrenKeys(Child1.Key, out IEnumerable<Guid> initialChildrenKeys);
var initialChild1ChildrenCount = initialChildrenKeys.Count();
var createModel = CreateContentCreateModel("Child1Child", Guid.NewGuid(), Child1.Key);
var createModel = CreateContentCreateModel("Grandchild 3", Guid.NewGuid(), Child1.Key);
// Act
var createAttempt = await ContentEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
@@ -55,4 +54,37 @@ public partial class DocumentNavigationServiceTests
Assert.IsTrue(childrenList.Contains(createdItemKey));
});
}
[Test]
[TestCase(null)] // Content root
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573")] // Grandchild 1
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF")] // Child 3
[TestCase("F381906C-223C-4466-80F7-B63B4EE073F8")] // Grandchild 4
public async Task Creating_Child_Content_Adds_It_As_The_Last_Child(Guid? parentKey)
{
// Arrange
Guid newNodeKey = Guid.NewGuid();
var createModel = CreateContentCreateModel("Child", newNodeKey, parentKey);
// Act
await ContentEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
// Assert
if (parentKey is null)
{
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(newNodeKey, rootKeys.Last());
}
else
{
DocumentNavigationQueryService.TryGetChildrenKeys(parentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(newNodeKey, childrenKeys.Last());
}
}
}

View File

@@ -39,4 +39,42 @@ public partial class DocumentNavigationServiceTests
}
});
}
// TODO: Add more test cases
[Test]
public async Task Sort_Order_Of_Siblings_Updates_When_Deleting_Content_And_Adding_New_One()
{
// Arrange
Guid nodeToDelete = Child3.Key;
Guid node = Child1.Key;
// Act
await ContentEditingService.DeleteAsync(nodeToDelete, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterDeletion);
var siblingsKeysAfterDeletionList = siblingsKeysAfterDeletion.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(1, siblingsKeysAfterDeletionList.Count);
Assert.AreEqual(Child2.Key, siblingsKeysAfterDeletionList[0]);
});
// Create a new sibling under the same parent
var key = Guid.NewGuid();
var createModel = CreateContentCreateModel("Child 4", key, Root.Key);
await ContentEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterCreation);
var siblingsKeysAfterCreationList = siblingsKeysAfterCreation.ToList();
// Verify sibling order after creating the new content
Assert.Multiple(() =>
{
Assert.AreEqual(2, siblingsKeysAfterCreationList.Count);
Assert.AreEqual(Child2.Key, siblingsKeysAfterCreationList[0]);
Assert.AreEqual(key, siblingsKeysAfterCreationList[1]);
});
}
}

View File

@@ -94,4 +94,72 @@ public partial class DocumentNavigationServiceTests
Assert.AreEqual(beforeMoveDescendants, afterMoveDescendants);
});
}
[Test]
[TestCase(null)] // Content root
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF")] // Child 3
[TestCase("F381906C-223C-4466-80F7-B63B4EE073F8")] // Grandchild 4
public async Task Moving_Content_Adds_It_Last(Guid? targetParentKey)
{
// Arrange
Guid nodeToMove = Grandchild1.Key;
// Act
await ContentEditingService.MoveAsync(nodeToMove, targetParentKey, Constants.Security.SuperUserKey);
// Assert
if (targetParentKey is null)
{
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(nodeToMove, rootKeys.Last());
}
else
{
DocumentNavigationQueryService.TryGetChildrenKeys(targetParentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(nodeToMove, childrenKeys.Last());
}
}
// TODO: Add more test cases
[Test]
public async Task Sort_Order_Of_Siblings_Updates_When_Moving_Content_And_Adding_New_One()
{
// Arrange
Guid nodeToMove = Child3.Key;
Guid node = Child1.Key;
// Act
await ContentEditingService.MoveAsync(nodeToMove, null, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterMoving);
var siblingsKeysAfterMovingList = siblingsKeysAfterMoving.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(1, siblingsKeysAfterMovingList.Count);
Assert.AreEqual(Child2.Key, siblingsKeysAfterMovingList[0]);
});
// Create a new sibling under the same parent
var key = Guid.NewGuid();
var createModel = CreateContentCreateModel("Child 4", key, Root.Key);
await ContentEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterCreation);
var siblingsKeysAfterCreationList = siblingsKeysAfterCreation.ToList();
// Verify sibling order after creating the new content
Assert.Multiple(() =>
{
Assert.AreEqual(2, siblingsKeysAfterCreationList.Count);
Assert.AreEqual(Child2.Key, siblingsKeysAfterCreationList[0]);
Assert.AreEqual(key, siblingsKeysAfterCreationList[1]);
});
}
}

View File

@@ -6,7 +6,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class DocumentNavigationServiceTests
{
[Test]
public async Task Structure_Updates_When_Moving_Content_To_Recycle_Bin()
public async Task Parent_And_Descendants_Are_Updated_When_Content_Is_Moved_To_Recycle_Bin()
{
// Arrange
Guid nodeToMoveToRecycleBin = Child3.Key;
@@ -19,7 +19,7 @@ public partial class DocumentNavigationServiceTests
DocumentNavigationQueryService.TryGetDescendantsKeys(nodeToMoveToRecycleBin, out IEnumerable<Guid> initialDescendantsKeys);
var beforeMoveDescendants = initialDescendantsKeys.ToList();
DocumentNavigationQueryService.TryGetChildrenKeys(originalParentKey.Value, out IEnumerable<Guid> initialParentChildrenKeys);
var beforeMoveParentSiblingsCount = initialParentChildrenKeys.Count();
var beforeMoveParentChildrenCount = initialParentChildrenKeys.Count();
// Act
await ContentEditingService.MoveToRecycleBinAsync(nodeToMoveToRecycleBin, Constants.Security.SuperUserKey);
@@ -30,7 +30,7 @@ public partial class DocumentNavigationServiceTests
DocumentNavigationQueryService.TryGetDescendantsKeysInBin(nodeToMoveToRecycleBin, out IEnumerable<Guid> afterMoveDescendantsKeys);
var afterMoveDescendants = afterMoveDescendantsKeys.ToList();
DocumentNavigationQueryService.TryGetChildrenKeys((Guid)originalParentKey, out IEnumerable<Guid> afterMoveParentChildrenKeys);
var afterMoveParentSiblingsCount = afterMoveParentChildrenKeys.Count();
var afterMoveParentChildrenCount = afterMoveParentChildrenKeys.Count();
DocumentNavigationQueryService.TryGetSiblingsKeysInBin(nodeInRecycleBin, out IEnumerable<Guid> afterMoveRecycleBinSiblingsKeys);
var afterMoveRecycleBinSiblingsCount = afterMoveRecycleBinSiblingsKeys.Count();
@@ -42,8 +42,78 @@ public partial class DocumentNavigationServiceTests
Assert.IsNull(updatedParentKeyInRecycleBin); // Verify the node's parent is now located at the root of the recycle bin (null)
Assert.AreEqual(beforeMoveDescendants, afterMoveDescendants);
Assert.AreEqual(beforeMoveParentSiblingsCount - 1, afterMoveParentSiblingsCount);
Assert.AreEqual(beforeMoveParentChildrenCount - 1, afterMoveParentChildrenCount);
Assert.AreEqual(beforeMoveRecycleBinSiblingsCount + 1, afterMoveRecycleBinSiblingsCount);
});
}
// TODO: Add more test cases
[Test]
public async Task Sort_Order_Of_Siblings_Updates_When_Moving_Content_To_Recycle_Bin_And_Adding_New_One()
{
// Arrange
Guid nodeToMoveToRecycleBin = Child3.Key;
Guid node = Child1.Key;
// Act
await ContentEditingService.MoveToRecycleBinAsync(nodeToMoveToRecycleBin, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterDeletion);
var siblingsKeysAfterDeletionList = siblingsKeysAfterDeletion.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(1, siblingsKeysAfterDeletionList.Count);
Assert.AreEqual(Child2.Key, siblingsKeysAfterDeletionList[0]);
});
// Create a new sibling under the same parent
var key = Guid.NewGuid();
var createModel = CreateContentCreateModel("Child 4", key, Root.Key);
await ContentEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterCreation);
var siblingsKeysAfterCreationList = siblingsKeysAfterCreation.ToList();
// Verify sibling order after creating the new content
Assert.Multiple(() =>
{
Assert.AreEqual(2, siblingsKeysAfterCreationList.Count);
Assert.AreEqual(Child2.Key, siblingsKeysAfterCreationList[0]);
Assert.AreEqual(key, siblingsKeysAfterCreationList[1]);
});
}
[Test]
public async Task Sort_Order_Of_Chilldren_Is_Maintained_When_Moving_Content_To_Recycle_Bin()
{
// Arrange
Guid nodeToMoveToRecycleBin = Child1.Key;
// Create a new grandchild under Child1
var key = Guid.NewGuid();
var createModel = CreateContentCreateModel("Grandchild 3", key, nodeToMoveToRecycleBin);
await ContentEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
DocumentNavigationQueryService.TryGetChildrenKeys(nodeToMoveToRecycleBin, out IEnumerable<Guid> childrenKeysBeforeDeletion);
var childrenKeysBeforeDeletionList = childrenKeysBeforeDeletion.ToList();
// Act
await ContentEditingService.MoveToRecycleBinAsync(nodeToMoveToRecycleBin, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetChildrenKeysInBin(nodeToMoveToRecycleBin, out IEnumerable<Guid> childrenKeysAfterDeletion);
var childrenKeysAfterDeletionList = childrenKeysAfterDeletion.ToList();
// Verify children order in the bin
Assert.Multiple(() =>
{
Assert.AreEqual(3, childrenKeysAfterDeletionList.Count);
Assert.AreEqual(Grandchild1.Key, childrenKeysAfterDeletionList[0]);
Assert.AreEqual(Grandchild2.Key, childrenKeysAfterDeletionList[1]);
Assert.AreEqual(key, childrenKeysAfterDeletionList[2]);
Assert.IsTrue(childrenKeysBeforeDeletionList.SequenceEqual(childrenKeysAfterDeletionList));
});
}
}

View File

@@ -50,4 +50,37 @@ public partial class DocumentNavigationServiceTests
Assert.AreEqual(targetParentKey, restoredItemParentKey);
});
}
[Test]
[TestCase(null)] // Content root
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573")] // Grandchild 1
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
public async Task Restoring_Content_Adds_It_Last(Guid? targetParentKey)
{
// Arrange
Guid nodeToRestore = Child3.Key;
// Move node to recycle bin
await ContentEditingService.MoveToRecycleBinAsync(nodeToRestore, Constants.Security.SuperUserKey);
// Act
await ContentEditingService.RestoreAsync(nodeToRestore, targetParentKey, Constants.Security.SuperUserKey);
// Assert
if (targetParentKey is null)
{
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(nodeToRestore, rootKeys.Last());
}
else
{
DocumentNavigationQueryService.TryGetChildrenKeys(targetParentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(nodeToRestore, childrenKeys.Last());
}
}
}

View File

@@ -0,0 +1,199 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.ContentEditing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class DocumentNavigationServiceTests
{
[Test]
public async Task Structure_Updates_When_Reversing_Children_Sort_Order()
{
// Arrange
Guid nodeToSortItsChildren = Root.Key;
DocumentNavigationQueryService.TryGetChildrenKeys(nodeToSortItsChildren, out IEnumerable<Guid> initialChildrenKeys);
List<Guid> initialChildrenKeysList = initialChildrenKeys.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(3, initialChildrenKeysList.Count);
// Assert initial order
Assert.AreEqual(Child1.Key, initialChildrenKeysList[0]);
Assert.AreEqual(Child2.Key, initialChildrenKeysList[1]);
Assert.AreEqual(Child3.Key, initialChildrenKeysList[2]);
});
IEnumerable<SortingModel> sortingModels = initialChildrenKeys
.Reverse()
.Select((key, index) => new SortingModel { Key = key, SortOrder = index });
// Act
await ContentEditingService.SortAsync(nodeToSortItsChildren, sortingModels, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetChildrenKeys(nodeToSortItsChildren, out IEnumerable<Guid> sortedChildrenKeys);
List<Guid> sortedChildrenKeysList = sortedChildrenKeys.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(Child3.Key, sortedChildrenKeysList[0]);
Assert.AreEqual(Child2.Key, sortedChildrenKeysList[1]);
Assert.AreEqual(Child1.Key, sortedChildrenKeysList[2]);
});
var expectedChildrenKeysList = initialChildrenKeys.Reverse().ToList();
// Check that the order matches what is expected
Assert.IsTrue(expectedChildrenKeysList.SequenceEqual(sortedChildrenKeysList));
}
[Test]
public async Task Structure_Updates_When_Children_Have_Custom_Sort_Order()
{
// Arrange
Guid node = Root.Key;
var customSortingModels = new List<SortingModel>
{
new() { Key = Child2.Key, SortOrder = 0 }, // Move Child 2 to the position 1
new() { Key = Child3.Key, SortOrder = 1 }, // Move Child 3 to the position 2
new() { Key = Child1.Key, SortOrder = 2 }, // Move Child 1 to the position 3
};
// Act
await ContentEditingService.SortAsync(node, customSortingModels, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetChildrenKeys(node, out IEnumerable<Guid> sortedChildrenKeys);
List<Guid> sortedChildrenKeysList = sortedChildrenKeys.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(Child2.Key, sortedChildrenKeysList[0]);
Assert.AreEqual(Child3.Key, sortedChildrenKeysList[1]);
Assert.AreEqual(Child1.Key, sortedChildrenKeysList[2]);
});
var expectedChildrenKeysList = customSortingModels
.OrderBy(x => x.SortOrder)
.Select(x => x.Key)
.ToList();
// Check that the order matches what is expected
Assert.IsTrue(expectedChildrenKeysList.SequenceEqual(sortedChildrenKeysList));
}
[Test]
public async Task Structure_Updates_When_Sorting_Items_At_Root()
{
// Arrange
var anotherRootCreateModel = CreateContentCreateModel("Root 2", Guid.NewGuid(), Constants.System.RootKey);
await ContentEditingService.CreateAsync(anotherRootCreateModel, Constants.Security.SuperUserKey);
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> initialRootKeys);
var sortingModels = initialRootKeys
.Reverse()
.Select((rootKey, index) => new SortingModel { Key = rootKey, SortOrder = index });
// Act
await ContentEditingService.SortAsync(Constants.System.RootKey, sortingModels, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> sortedRootKeys);
var expectedRootKeysList = initialRootKeys.Reverse().ToList();
// Check that the order matches what is expected
Assert.IsTrue(expectedRootKeysList.SequenceEqual(sortedRootKeys));
}
[Test]
public async Task Descendants_Are_Returned_In_Correct_Order_After_Children_Are_Reordered()
{
// Arrange
Guid node = Root.Key;
DocumentNavigationQueryService.TryGetDescendantsKeys(node, out IEnumerable<Guid> initialDescendantsKeys);
var customSortingModels = new List<SortingModel>
{
new() { Key = Child3.Key, SortOrder = 0 }, // Move Child 3 to the position 1
new() { Key = Child1.Key, SortOrder = 1 }, // Move Child 1 to the position 2
new() { Key = Child2.Key, SortOrder = 2 }, // Move Child 2 to the position 3
};
var expectedDescendantsOrder = new List<Guid>
{
Child3.Key, Grandchild4.Key, // Child 3 and its descendants
Child1.Key, Grandchild1.Key, Grandchild2.Key, // Child 1 and its descendants
Child2.Key, Grandchild3.Key, GreatGrandchild1.Key, // Child 2 and its descendants
};
// Act
await ContentEditingService.SortAsync(node, customSortingModels, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetDescendantsKeys(node, out IEnumerable<Guid> updatedDescendantsKeys);
List<Guid> updatedDescendantsKeysList = updatedDescendantsKeys.ToList();
Assert.Multiple(() =>
{
Assert.IsFalse(initialDescendantsKeys.SequenceEqual(updatedDescendantsKeysList));
Assert.IsTrue(expectedDescendantsOrder.SequenceEqual(updatedDescendantsKeysList));
});
}
[Test]
[TestCase(1, 2, 0, new[] { "B606E3FF-E070-4D46-8CB9-D31352029FDF", "C6173927-0C59-4778-825D-D7B9F45D8DDE" })] // Custom sort order: Child 3, Child 1, Child 2; Expected order: Child 3, Child 1
[TestCase(0, 1, 2, new[] { "C6173927-0C59-4778-825D-D7B9F45D8DDE", "B606E3FF-E070-4D46-8CB9-D31352029FDF" })] // Custom sort order: Child 1, Child 2, Child 3; Expected order: Child 1, Child 3
[TestCase(2, 0, 1, new[] { "B606E3FF-E070-4D46-8CB9-D31352029FDF", "C6173927-0C59-4778-825D-D7B9F45D8DDE" })] // Custom sort order: Child 2, Child 3, Child 1; Expected order: Child 3, Child 1
public async Task Siblings_Are_Returned_In_Correct_Order_After_Sorting(int sortOrder1, int sortOrder2, int sortOrder3, string[] expectedSiblings)
{
// Arrange
Guid node = Child2.Key;
var customSortingModels = new List<SortingModel>
{
new() { Key = Child1.Key, SortOrder = sortOrder1 }, // Move Child 1 to the position sortOrder1
new() { Key = Child2.Key, SortOrder = sortOrder2 }, // Move Child 2 to the position sortOrder2
new() { Key = Child3.Key, SortOrder = sortOrder3 }, // Move Child 3 to the position sortOrder3
};
Guid[] expectedSiblingsOrder = Array.ConvertAll(expectedSiblings, Guid.Parse);
// Act
await ContentEditingService.SortAsync(Root.Key, customSortingModels, Constants.Security.SuperUserKey); // Using the parent key here
// Assert
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> sortedSiblingsKeys);
var sortedSiblingsKeysList = sortedSiblingsKeys.ToList();
Assert.IsTrue(expectedSiblingsOrder.SequenceEqual(sortedSiblingsKeysList));
}
[Test]
public async Task Siblings_Are_Returned_In_Correct_Order_After_Sorting_At_Root()
{
// Arrange
Guid node = Root.Key;
var anotherRootCreateModel1 = CreateContentCreateModel("Root 2", Guid.NewGuid(), Constants.System.RootKey);
await ContentEditingService.CreateAsync(anotherRootCreateModel1, Constants.Security.SuperUserKey);
var anotherRootCreateModel2 = CreateContentCreateModel("Root 3", Guid.NewGuid(), Constants.System.RootKey);
await ContentEditingService.CreateAsync(anotherRootCreateModel2, Constants.Security.SuperUserKey);
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> initialRootKeys);
var sortingModels = initialRootKeys
.Reverse()
.Select((rootKey, index) => new SortingModel { Key = rootKey, SortOrder = index });
var expectedSiblingsKeysList = initialRootKeys.Reverse().Where(k => k != node).ToList();
// Act
await ContentEditingService.SortAsync(Constants.System.RootKey, sortingModels, Constants.Security.SuperUserKey);
// Assert
DocumentNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> sortedSiblingsKeys);
var sortedSiblingsKeysList = sortedSiblingsKeys.ToList();
Assert.IsTrue(expectedSiblingsKeysList.SequenceEqual(sortedSiblingsKeysList));
}
}

View File

@@ -63,9 +63,9 @@ public class DocumentUrlServiceTest : UmbracoIntegrationTestWithContent
{
var isoCode = (await LanguageService.GetDefaultLanguageAsync()).IsoCode;
var actual = DocumentUrlService.GetUrlSegment(Trashed.Key, isoCode, true);
Assert.IsNull(DocumentUrlService.GetUrlSegment(Trashed.Key, isoCode, true));
Assert.IsNull(DocumentUrlService.GetUrlSegment(Trashed.Key, isoCode, false));
Assert.IsNull(actual);
}
//TODO test with the urlsegment property value!
@@ -120,9 +120,40 @@ public class DocumentUrlServiceTest : UmbracoIntegrationTestWithContent
[Test]
public void No_Published_Route_when_not_published()
{
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/text-page-1", "en-US", null, true));
Assert.IsNull(DocumentUrlService.GetDocumentKeyByRoute("/text-page-1", "en-US", null, false));
}
[Test]
public void Unpublished_Pages_Are_not_available()
{
//Arrange
ContentService.PublishBranch(Textpage, true, new[] { "*" });
Assert.Multiple(() =>
{
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/", "en-US", null, true));
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/", "en-US", null, false));
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/text-page-1", "en-US", null, true));
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/text-page-1", "en-US", null, false));
});
//Act
ContentService.Unpublish(Textpage );
Assert.Multiple(() =>
{
//The unpublished page self
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/", "en-US", null, true));
Assert.IsNull(DocumentUrlService.GetDocumentKeyByRoute("/", "en-US", null, false));
//A descendant of the unpublished page
Assert.IsNotNull(DocumentUrlService.GetDocumentKeyByRoute("/text-page-1", "en-US", null, true));
Assert.IsNull(DocumentUrlService.GetDocumentKeyByRoute("/text-page-1", "en-US", null, false));
});
}
[Test]
[TestCase("/text-page-1/sub-page-1", "en-US", true, ExpectedResult = "DF49F477-12F2-4E33-8563-91A7CC1DCDBB")]
@@ -181,10 +212,24 @@ public class DocumentUrlServiceTest : UmbracoIntegrationTestWithContent
// Publish both the main root and the second root with descendants
if (loadDraft is false)
{
ContentService.PublishBranch(Textpage, true, new[] { "*" });
ContentService.PublishBranch(secondRoot, true, new[] { "*" });
}
return DocumentUrlService.GetDocumentKeyByRoute(route, isoCode, null, loadDraft)?.ToString()?.ToUpper();
}
//TODO test cases:
// - Find the root, when a domain is set
// - Find a nested child, when a domain is set
// - Find the root when no domain is set and hideTopLevelNodeFromPath is true
// - Find a nested child of item in the root top when no domain is set and hideTopLevelNodeFromPath is true
// - Find a nested child of item in the root bottom when no domain is set and hideTopLevelNodeFromPath is true
// - Find the root when no domain is set and hideTopLevelNodeFromPath is false
// - Find a nested child of item in the root top when no domain is set and hideTopLevelNodeFromPath is false
// - Find a nested child of item in the root bottom when no domain is set and hideTopLevelNodeFromPath is false
// - All of the above when having Constants.Conventions.Content.UrlName set to a value
}

View File

@@ -11,7 +11,7 @@ public partial class MediaNavigationServiceTests
// Arrange
MediaNavigationQueryService.TryGetSiblingsKeys(Album.Key, out IEnumerable<Guid> initialSiblingsKeys);
var initialRootNodeSiblingsCount = initialSiblingsKeys.Count();
var createModel = CreateMediaCreateModel("Root Image", Guid.NewGuid(), ImageMediaType.Key);
var createModel = CreateMediaCreateModel("Album 2", Guid.NewGuid(), FolderMediaType.Key);
// Act
var createAttempt = await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
@@ -54,4 +54,32 @@ public partial class MediaNavigationServiceTests
Assert.IsTrue(childrenList.Contains(createdItemKey));
});
}
[Test]
[TestCase(null)] // Media root
[TestCase("1CD97C02-8534-4B72-AE9E-AE52EC94CF31")] // Album
[TestCase("139DC977-E50F-4382-9728-B278C4B7AC6A")] // Sub-album 1
[TestCase("DBCAFF2F-BFA4-4744-A948-C290C432D564")] // Sub-album 2
[TestCase("E0B23D56-9A0E-4FC4-BD42-834B73B4C7AB")] // Sub-sub-album 1
public async Task Creating_Child_Media_Adds_It_As_The_Last_Child(Guid? parentKey)
{
// Arrange
Guid newNodeKey = Guid.NewGuid();
var createModel = CreateMediaCreateModel("Child Image", newNodeKey, ImageMediaType.Key, parentKey);
// Act
await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
// Assert
if (parentKey is null)
{
MediaNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(newNodeKey, rootKeys.Last());
}
else
{
MediaNavigationQueryService.TryGetChildrenKeys(parentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(newNodeKey, childrenKeys.Last());
}
}
}

View File

@@ -37,4 +37,42 @@ public partial class MediaNavigationServiceTests
}
});
}
// TODO: Add more test cases
[Test]
public async Task Sort_Order_Of_Siblings_Updates_When_Deleting_Media_And_Adding_New_One()
{
// Arrange
Guid nodeToDelete = SubAlbum2.Key;
Guid node = Image1.Key;
// Act
await MediaEditingService.DeleteAsync(nodeToDelete, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterDeletion);
var siblingsKeysAfterDeletionList = siblingsKeysAfterDeletion.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(1, siblingsKeysAfterDeletionList.Count);
Assert.AreEqual(SubAlbum1.Key, siblingsKeysAfterDeletionList[0]);
});
// Create a new sibling under the same parent
var key = Guid.NewGuid();
var createModel = CreateMediaCreateModel("Child Image", key, ImageMediaType.Key, Album.Key);
await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterCreation);
var siblingsKeysAfterCreationList = siblingsKeysAfterCreation.ToList();
// Verify sibling order after creating the new media
Assert.Multiple(() =>
{
Assert.AreEqual(2, siblingsKeysAfterCreationList.Count);
Assert.AreEqual(SubAlbum1.Key, siblingsKeysAfterCreationList[0]);
Assert.AreEqual(key, siblingsKeysAfterCreationList[1]);
});
}
}

View File

@@ -94,4 +94,68 @@ public partial class MediaNavigationServiceTests
Assert.AreEqual(beforeMoveDescendants, afterMoveDescendants);
});
}
[Test]
[TestCase(null)] // Media root
[TestCase("1CD97C02-8534-4B72-AE9E-AE52EC94CF31")] // Album
[TestCase("DBCAFF2F-BFA4-4744-A948-C290C432D564")] // Sub-album 2
[TestCase("E0B23D56-9A0E-4FC4-BD42-834B73B4C7AB")] // Sub-sub-album 1
public async Task Moving_Media_Adds_It_Last(Guid? targetParentKey)
{
// Arrange
Guid nodeToMove = Image2.Key;
// Act
await MediaEditingService.MoveAsync(nodeToMove, targetParentKey, Constants.Security.SuperUserKey);
// Assert
if (targetParentKey is null)
{
MediaNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(nodeToMove, rootKeys.Last());
}
else
{
MediaNavigationQueryService.TryGetChildrenKeys(targetParentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(nodeToMove, childrenKeys.Last());
}
}
// TODO: Add more test cases
[Test]
public async Task Sort_Order_Of_Siblings_Updates_When_Moving_Media_And_Adding_New_One()
{
// Arrange
Guid nodeToMove = SubAlbum2.Key;
Guid node = Image1.Key;
// Act
await MediaEditingService.MoveAsync(nodeToMove, null, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterMoving);
var siblingsKeysAfterMovingList = siblingsKeysAfterMoving.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(1, siblingsKeysAfterMovingList.Count);
Assert.AreEqual(SubAlbum1.Key, siblingsKeysAfterMovingList[0]);
});
// Create a new sibling under the same parent
var key = Guid.NewGuid();
var createModel = CreateMediaCreateModel("Child Image", key, ImageMediaType.Key, Album.Key);
await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterCreation);
var siblingsKeysAfterCreationList = siblingsKeysAfterCreation.ToList();
// Verify sibling order after creating the new media
Assert.Multiple(() =>
{
Assert.AreEqual(2, siblingsKeysAfterCreationList.Count);
Assert.AreEqual(SubAlbum1.Key, siblingsKeysAfterMovingList[0]);
Assert.AreEqual(key, siblingsKeysAfterCreationList[1]);
});
}
}

View File

@@ -45,4 +45,74 @@ public partial class MediaNavigationServiceTests
Assert.AreEqual(beforeMoveRecycleBinSiblingsCount + 1, afterMoveRecycleBinSiblingsCount);
});
}
// TODO: Add more test cases
[Test]
public async Task Sort_Order_Of_Siblings_Updates_When_Moving_Media_To_Recycle_Bin_And_Adding_New_One()
{
// Arrange
Guid nodeToMoveToRecycleBin = SubAlbum2.Key;
Guid node = Image1.Key;
// Act
await MediaEditingService.MoveToRecycleBinAsync(nodeToMoveToRecycleBin, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterDeletion);
var siblingsKeysAfterDeletionList = siblingsKeysAfterDeletion.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(1, siblingsKeysAfterDeletionList.Count);
Assert.AreEqual(SubAlbum1.Key, siblingsKeysAfterDeletionList[0]);
});
// Create a new sibling under the same parent
var key = Guid.NewGuid();
var createModel = CreateMediaCreateModel("Child Image", key, ImageMediaType.Key, Album.Key);
await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> siblingsKeysAfterCreation);
var siblingsKeysAfterCreationList = siblingsKeysAfterCreation.ToList();
// Verify sibling order after creating the new media
Assert.Multiple(() =>
{
Assert.AreEqual(2, siblingsKeysAfterCreationList.Count);
Assert.AreEqual(SubAlbum1.Key, siblingsKeysAfterDeletionList[0]);
Assert.AreEqual(key, siblingsKeysAfterCreationList[1]);
});
}
[Test]
public async Task Sort_Order_Of_Chilldren_Is_Maintained_When_Moving_Media_To_Recycle_Bin()
{
// Arrange
Guid nodeToMoveToRecycleBin = SubAlbum1.Key;
// Create a new grandchild under Child1
var key = Guid.NewGuid();
var createModel = CreateMediaCreateModel("Image 5", key, ImageMediaType.Key, nodeToMoveToRecycleBin);
await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
MediaNavigationQueryService.TryGetChildrenKeys(nodeToMoveToRecycleBin, out IEnumerable<Guid> childrenKeysBeforeDeletion);
var childrenKeysBeforeDeletionList = childrenKeysBeforeDeletion.ToList();
// Act
await MediaEditingService.MoveToRecycleBinAsync(nodeToMoveToRecycleBin, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetChildrenKeysInBin(nodeToMoveToRecycleBin, out IEnumerable<Guid> childrenKeysAfterDeletion);
var childrenKeysAfterDeletionList = childrenKeysAfterDeletion.ToList();
// Verify children order in the bin
Assert.Multiple(() =>
{
Assert.AreEqual(3, childrenKeysAfterDeletionList.Count);
Assert.AreEqual(Image2.Key, childrenKeysAfterDeletionList[0]);
Assert.AreEqual(Image3.Key, childrenKeysAfterDeletionList[1]);
Assert.AreEqual(key, childrenKeysAfterDeletionList[2]);
Assert.IsTrue(childrenKeysBeforeDeletionList.SequenceEqual(childrenKeysAfterDeletionList));
});
}
}

View File

@@ -50,4 +50,33 @@ public partial class MediaNavigationServiceTests
Assert.AreEqual(targetParentKey, restoredItemParentKey);
});
}
[Test]
[TestCase(null)] // Media root
[TestCase("139DC977-E50F-4382-9728-B278C4B7AC6A")] // Sub-album 1
[TestCase("DBCAFF2F-BFA4-4744-A948-C290C432D564")] // Sub-album 2
[TestCase("E0B23D56-9A0E-4FC4-BD42-834B73B4C7AB")] // Sub-sub-album 1
public async Task Restoring_Content_Adds_It_Last(Guid? targetParentKey)
{
// Arrange
Guid nodeToRestore = Image1.Key;
// Move node to recycle bin
await MediaEditingService.MoveToRecycleBinAsync(nodeToRestore, Constants.Security.SuperUserKey);
// Act
await MediaEditingService.RestoreAsync(nodeToRestore, targetParentKey, Constants.Security.SuperUserKey);
// Assert
if (targetParentKey is null)
{
MediaNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
Assert.AreEqual(nodeToRestore, rootKeys.Last());
}
else
{
MediaNavigationQueryService.TryGetChildrenKeys(targetParentKey.Value, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(nodeToRestore, childrenKeys.Last());
}
}
}

View File

@@ -0,0 +1,199 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.ContentEditing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class MediaNavigationServiceTests
{
[Test]
public async Task Structure_Updates_When_Reversing_Children_Sort_Order()
{
// Arrange
Guid nodeToSortItsChildren = Album.Key;
MediaNavigationQueryService.TryGetChildrenKeys(nodeToSortItsChildren, out IEnumerable<Guid> initialChildrenKeys);
List<Guid> initialChildrenKeysList = initialChildrenKeys.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(3, initialChildrenKeysList.Count);
// Assert initial order
Assert.AreEqual(Image1.Key, initialChildrenKeysList[0]);
Assert.AreEqual(SubAlbum1.Key, initialChildrenKeysList[1]);
Assert.AreEqual(SubAlbum2.Key, initialChildrenKeysList[2]);
});
IEnumerable<SortingModel> sortingModels = initialChildrenKeys
.Reverse()
.Select((key, index) => new SortingModel { Key = key, SortOrder = index });
// Act
await MediaEditingService.SortAsync(nodeToSortItsChildren, sortingModels, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetChildrenKeys(nodeToSortItsChildren, out IEnumerable<Guid> sortedChildrenKeys);
List<Guid> sortedChildrenKeysList = sortedChildrenKeys.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(SubAlbum2.Key, sortedChildrenKeysList[0]);
Assert.AreEqual(SubAlbum1.Key, sortedChildrenKeysList[1]);
Assert.AreEqual(Image1.Key, sortedChildrenKeysList[2]);
});
var expectedChildrenKeysList = initialChildrenKeys.Reverse().ToList();
// Check that the order matches what is expected
Assert.IsTrue(expectedChildrenKeysList.SequenceEqual(sortedChildrenKeysList));
}
[Test]
public async Task Structure_Updates_When_Children_Have_Custom_Sort_Order()
{
// Arrange
Guid node = Album.Key;
var customSortingModels = new List<SortingModel>
{
new() { Key = SubAlbum1.Key, SortOrder = 0 }, // Move Sub-album 1 to the position 1
new() { Key = SubAlbum2.Key, SortOrder = 1 }, // Move Sub-album 2 to the position 2
new() { Key = Image1.Key, SortOrder = 2 }, // Move Image 1 to the position 3
};
// Act
await MediaEditingService.SortAsync(node, customSortingModels, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetChildrenKeys(node, out IEnumerable<Guid> sortedChildrenKeys);
List<Guid> sortedChildrenKeysList = sortedChildrenKeys.ToList();
Assert.Multiple(() =>
{
Assert.AreEqual(SubAlbum1.Key, sortedChildrenKeysList[0]);
Assert.AreEqual(SubAlbum2.Key, sortedChildrenKeysList[1]);
Assert.AreEqual(Image1.Key, sortedChildrenKeysList[2]);
});
var expectedChildrenKeysList = customSortingModels
.OrderBy(x => x.SortOrder)
.Select(x => x.Key)
.ToList();
// Check that the order matches what is expected
Assert.IsTrue(expectedChildrenKeysList.SequenceEqual(sortedChildrenKeysList));
}
[Test]
public async Task Structure_Updates_When_Sorting_Items_At_Root()
{
// Arrange
var anotherRootCreateModel = CreateMediaCreateModel("Album 2", Guid.NewGuid(), FolderMediaType.Key, Constants.System.RootKey);
await MediaEditingService.CreateAsync(anotherRootCreateModel, Constants.Security.SuperUserKey);
MediaNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> initialRootKeys);
var sortingModels = initialRootKeys
.Reverse()
.Select((rootKey, index) => new SortingModel { Key = rootKey, SortOrder = index });
// Act
await MediaEditingService.SortAsync(Constants.System.RootKey, sortingModels, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> sortedRootKeys);
var expectedRootKeysList = initialRootKeys.Reverse().ToList();
// Check that the order matches what is expected
Assert.IsTrue(expectedRootKeysList.SequenceEqual(sortedRootKeys));
}
[Test]
public async Task Descendants_Are_Returned_In_Correct_Order_After_Children_Are_Reordered()
{
// Arrange
Guid node = Album.Key;
MediaNavigationQueryService.TryGetDescendantsKeys(node, out IEnumerable<Guid> initialDescendantsKeys);
var customSortingModels = new List<SortingModel>
{
new() { Key = SubAlbum2.Key, SortOrder = 0 }, // Move Sub-album 2 to the position 1
new() { Key = Image1.Key, SortOrder = 1 }, // Move Image 1 to the position 2
new() { Key = SubAlbum1.Key, SortOrder = 2 }, // Move Sub-album 1 to the position 3
};
var expectedDescendantsOrder = new List<Guid>
{
SubAlbum2.Key, SubSubAlbum1.Key, Image4.Key, // Sub-album 2 and its descendants
Image1.Key, // Image 1
SubAlbum1.Key, Image2.Key, Image3.Key, // Sub-album 1 and its descendants
};
// Act
await MediaEditingService.SortAsync(node, customSortingModels, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetDescendantsKeys(node, out IEnumerable<Guid> updatedDescendantsKeys);
List<Guid> updatedDescendantsKeysList = updatedDescendantsKeys.ToList();
Assert.Multiple(() =>
{
Assert.IsFalse(initialDescendantsKeys.SequenceEqual(updatedDescendantsKeysList));
Assert.IsTrue(expectedDescendantsOrder.SequenceEqual(updatedDescendantsKeysList));
});
}
[Test]
[TestCase(1, 2, 0, new[] { "DBCAFF2F-BFA4-4744-A948-C290C432D564", "03976EBE-A942-4F24-9885-9186E99AEF7C" })] // Custom sort order: Sub-album 2, Image 1, Sub-album 1; Expected order: Sub-album 2, Image 1
[TestCase(0, 1, 2, new[] { "03976EBE-A942-4F24-9885-9186E99AEF7C", "DBCAFF2F-BFA4-4744-A948-C290C432D564" })] // Custom sort order: Image 1, Sub-album 1, Sub-album 2; Expected order: Image 1, Sub-album 2
[TestCase(2, 0, 1, new[] { "DBCAFF2F-BFA4-4744-A948-C290C432D564", "03976EBE-A942-4F24-9885-9186E99AEF7C" })] // Custom sort order: Sub-album 1, Sub-album 2, Image 1; Expected order: Sub-album 2, Image 1
public async Task Siblings_Are_Returned_In_Correct_Order_After_Sorting(int sortOrder1, int sortOrder2, int sortOrder3, string[] expectedSiblings)
{
// Arrange
Guid node = SubAlbum1.Key;
var customSortingModels = new List<SortingModel>
{
new() { Key = Image1.Key, SortOrder = sortOrder1 }, // Move Image 1 to the position sortOrder1
new() { Key = SubAlbum1.Key, SortOrder = sortOrder2 }, // Move Sub-album 1 to the position sortOrder2
new() { Key = SubAlbum2.Key, SortOrder = sortOrder3 }, // Move Sub-album 2 to the position sortOrder3
};
Guid[] expectedSiblingsOrder = Array.ConvertAll(expectedSiblings, Guid.Parse);
// Act
await MediaEditingService.SortAsync(Album.Key, customSortingModels, Constants.Security.SuperUserKey); // Using the parent key here
// Assert
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> sortedSiblingsKeys);
var sortedSiblingsKeysList = sortedSiblingsKeys.ToList();
Assert.IsTrue(expectedSiblingsOrder.SequenceEqual(sortedSiblingsKeysList));
}
[Test]
public async Task Siblings_Are_Returned_In_Correct_Order_After_Sorting_At_Root()
{
// Arrange
Guid node = Album.Key;
var anotherRootCreateModel1 = CreateMediaCreateModel("Album 2", Guid.NewGuid(), FolderMediaType.Key, Constants.System.RootKey);
await MediaEditingService.CreateAsync(anotherRootCreateModel1, Constants.Security.SuperUserKey);
var anotherRootCreateModel2 = CreateMediaCreateModel("Album 3", Guid.NewGuid(), FolderMediaType.Key, Constants.System.RootKey);
await MediaEditingService.CreateAsync(anotherRootCreateModel2, Constants.Security.SuperUserKey);
MediaNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> initialRootKeys);
var sortingModels = initialRootKeys
.Reverse()
.Select((rootKey, index) => new SortingModel { Key = rootKey, SortOrder = index });
var expectedSiblingsKeysList = initialRootKeys.Reverse().Where(k => k != node).ToList();
// Act
await MediaEditingService.SortAsync(Constants.System.RootKey, sortingModels, Constants.Security.SuperUserKey);
// Assert
MediaNavigationQueryService.TryGetSiblingsKeys(node, out IEnumerable<Guid> sortedSiblingsKeys);
var sortedSiblingsKeysList = sortedSiblingsKeys.ToList();
Assert.IsTrue(expectedSiblingsKeysList.SequenceEqual(sortedSiblingsKeysList));
}
}

View File

@@ -0,0 +1,216 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Handlers;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Infrastructure.DependencyInjection;
using Umbraco.Cms.Infrastructure.Examine;
using Umbraco.Cms.Infrastructure.Examine.DependencyInjection;
using Umbraco.Cms.Infrastructure.HostedServices;
using Umbraco.Cms.Infrastructure.Search;
using Umbraco.Cms.Tests.Common.Attributes;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Mock)]
public class PublishStatusServiceTest : UmbracoIntegrationTestWithContent
{
protected IPublishStatusQueryService PublishStatusQueryService => GetRequiredService<IPublishStatusQueryService>();
private const string DefaultCulture = "en-US";
protected override void CustomTestSetup(IUmbracoBuilder builder)
{
builder.Services.AddUnique<IServerMessenger, ScopedRepositoryTests.LocalServerMessenger>();
builder.AddNotificationHandler<ContentTreeChangeNotification, ContentTreeChangeDistributedCacheNotificationHandler>();
}
[Test]
public async Task InitializeAsync_loads_from_db()
{
var randomCulture = "da-DK";
var sut = new PublishStatusService(
GetRequiredService<ILogger<PublishStatusService>>(),
GetRequiredService<IPublishStatusRepository>(),
GetRequiredService<ICoreScopeProvider>()
);
Assert.Multiple(() =>
{
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage3.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Trashed.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage3.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Trashed.Key, randomCulture));
});
// Act
var publishResults = ContentService.PublishBranch(Textpage, true, new[] { "*" });
await sut.InitializeAsync(CancellationToken.None);
Assert.Multiple(() =>
{
Assert.IsTrue(publishResults.All(x=>x.Result == PublishResultType.SuccessPublish));
Assert.IsTrue(sut.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsTrue(sut.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsTrue(sut.IsDocumentPublished(Subpage.Key, DefaultCulture));
Assert.IsTrue(sut.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsTrue(sut.IsDocumentPublished(Subpage3.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Trashed.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage3.Key, randomCulture));
Assert.IsFalse(sut.IsDocumentPublished(Trashed.Key, randomCulture));
});
}
[Test]
public async Task AddOrUpdateStatusWithDescendantsAsync()
{
var randomCulture = "da-DK";
var sut = new PublishStatusService(
GetRequiredService<ILogger<PublishStatusService>>(),
GetRequiredService<IPublishStatusRepository>(),
GetRequiredService<ICoreScopeProvider>()
);
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, DefaultCulture));
// Act
var publishResults = ContentService.PublishBranch(Textpage, true, new[] { "*" });
await sut.AddOrUpdateStatusWithDescendantsAsync(Textpage.Key, CancellationToken.None);
Assert.IsTrue(sut.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsTrue(sut.IsDocumentPublished(Subpage.Key, DefaultCulture)); // Updated due to being an descendant
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, randomCulture)); // Do not exist
Assert.IsFalse(sut.IsDocumentPublished(Subpage.Key, randomCulture)); // Do not exist
}
[Test]
public async Task AddOrUpdateStatusAsync()
{
var randomCulture = "da-DK";
var sut = new PublishStatusService(
GetRequiredService<ILogger<PublishStatusService>>(),
GetRequiredService<IPublishStatusRepository>(),
GetRequiredService<ICoreScopeProvider>()
);
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, DefaultCulture));
// Act
var publishResults = ContentService.PublishBranch(Textpage, true, new[] { "*" });
await sut.AddOrUpdateStatusAsync(Textpage.Key, CancellationToken.None);
Assert.IsTrue(sut.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsFalse(sut.IsDocumentPublished(Subpage.Key, DefaultCulture)); // Not updated
Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, randomCulture)); // Do not exist
Assert.IsFalse(sut.IsDocumentPublished(Subpage.Key, randomCulture)); // Do not exist
}
[Test]
public void When_Nothing_is_publised_all_return_false()
{
var randomCulture = "da-DK";
Assert.Multiple(() =>
{
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage3.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Trashed.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Textpage.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage3.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Trashed.Key, randomCulture));
});
}
[Test]
public void Unpublish_leads_to_unpublised_in_this_service()
{
var grandchild = ContentBuilder.CreateSimpleContent(ContentType, "Grandchild", Subpage2.Id);
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
ContentService.Save(grandchild, -1, contentSchedule);
var publishResults = ContentService.PublishBranch(Textpage, true, new[] { "*" });
var randomCulture = "da-DK";
var subPage2FromDB = ContentService.GetById(Subpage2.Key);
var publishResult = ContentService.Unpublish(subPage2FromDB);
Assert.Multiple(() =>
{
Assert.IsTrue(publishResults.All(x=>x.Result == PublishResultType.SuccessPublish));
Assert.IsTrue(publishResult.Success);
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(grandchild.Key, DefaultCulture)); // grandchild is still published, but it will not be routable
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Textpage.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(grandchild.Key, randomCulture));
});
}
[Test]
public void When_Branch_is_publised_default_language_return_true()
{
var publishResults = ContentService.PublishBranch(Textpage, true, new[] { "*" });
var randomCulture = "da-DK";
Assert.Multiple(() =>
{
Assert.IsTrue(publishResults.All(x=>x.Result == PublishResultType.SuccessPublish));
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(Textpage.Key, DefaultCulture));
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(Subpage.Key, DefaultCulture));
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, DefaultCulture));
Assert.IsTrue(PublishStatusQueryService.IsDocumentPublished(Subpage3.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Trashed.Key, DefaultCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Textpage.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage2.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Subpage3.Key, randomCulture));
Assert.IsFalse(PublishStatusQueryService.IsDocumentPublished(Trashed.Key, randomCulture));
});
}
}

View File

@@ -28,6 +28,8 @@ public class BlockListPropertyEditorTests : UmbracoIntegrationTest
private PropertyEditorCollection PropertyEditorCollection => GetRequiredService<PropertyEditorCollection>();
private ILanguageService LanguageService => GetRequiredService<ILanguageService>();
[Test]
public async Task Can_Track_References()
{
@@ -147,9 +149,89 @@ public class BlockListPropertyEditorTests : UmbracoIntegrationTest
var tags = valueEditor.GetTags(content.GetValue("blocks"), null, null).ToArray();
Assert.AreEqual(3, tags.Length);
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag One"));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Two"));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Three"));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag One" && tag.LanguageId == null));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Two" && tag.LanguageId == null));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Three" && tag.LanguageId == null));
}
[Test]
public async Task Can_Track_Tags_For_Block_Level_Variance()
{
var result = await LanguageService.CreateAsync(
new Language("da-DK", "Danish"), Constants.Security.SuperUserKey);
Assert.IsTrue(result.Success);
var daDkId = result.Result.Id;
var elementType = ContentTypeBuilder.CreateAllTypesContentType("myElementType", "My Element Type");
elementType.IsElement = true;
elementType.Variations = ContentVariation.Culture;
elementType.PropertyTypes.First(p => p.Alias == "tags").Variations = ContentVariation.Culture;
ContentTypeService.Save(elementType);
var blockListContentType = await CreateBlockListContentType(elementType);
blockListContentType.Variations = ContentVariation.Culture;
ContentTypeService.Save(blockListContentType);
var contentElementKey = Guid.NewGuid();
var blockListValue = new BlockListValue
{
Layout = new Dictionary<string, IEnumerable<IBlockLayoutItem>>
{
{
Constants.PropertyEditors.Aliases.BlockList,
new IBlockLayoutItem[]
{
new BlockListLayoutItem { ContentKey = contentElementKey }
}
}
},
ContentData =
[
new()
{
Key = contentElementKey,
ContentTypeAlias = elementType.Alias,
ContentTypeKey = elementType.Key,
Values =
[
new ()
{
Alias = "tags",
// this is a little skewed, but the tags editor expects a serialized array of strings
Value = JsonSerializer.Serialize(new[] { "Tag One EN", "Tag Two EN", "Tag Three EN" }),
Culture = "en-US"
},
new ()
{
Alias = "tags",
// this is a little skewed, but the tags editor expects a serialized array of strings
Value = JsonSerializer.Serialize(new[] { "Tag One DA", "Tag Two DA", "Tag Three DA" }),
Culture = "da-DK"
}
]
}
]
};
var blocksPropertyValue = JsonSerializer.Serialize(blockListValue);
var content = new ContentBuilder()
.WithContentType(blockListContentType)
.WithCultureName("en-US", "My Blocks EN")
.WithCultureName("da-DK", "My Blocks DA")
.WithPropertyValues(new { blocks = blocksPropertyValue })
.Build();
ContentService.Save(content);
var valueEditor = await GetValueEditor(blockListContentType);
var tags = valueEditor.GetTags(content.GetValue("blocks"), null, null).ToArray();
Assert.AreEqual(6, tags.Length);
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag One EN" && tag.LanguageId == 1));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Two EN" && tag.LanguageId == 1));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Three EN" && tag.LanguageId == 1));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag One DA" && tag.LanguageId == daDkId));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Two DA" && tag.LanguageId == daDkId));
Assert.IsNotNull(tags.Single(tag => tag.Text == "Tag Three DA" && tag.LanguageId == daDkId));
}
[Test]

View File

@@ -194,6 +194,9 @@
<Compile Update="Umbraco.Core\Services\DocumentNavigationServiceTests.Restore.cs">
<DependentUpon>DocumentNavigationServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\DocumentNavigationServiceTests.Sort.cs">
<DependentUpon>DocumentNavigationServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\DocumentNavigationServiceTests.Update.cs">
<DependentUpon>DocumentNavigationServiceTests.cs</DependentUpon>
</Compile>
@@ -215,9 +218,15 @@
<Compile Update="Umbraco.Core\Services\MediaNavigationServiceTests.Rebuild.cs">
<DependentUpon>MediaNavigationServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\DocumentNavigationServiceTests.Sort.cs">
<DependentUpon>DocumentNavigationServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\MediaNavigationServiceTests.Restore.cs">
<DependentUpon>MediaNavigationServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\MediaNavigationServiceTests.Sort.cs">
<DependentUpon>MediaNavigationServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\MediaNavigationServiceTests.Update.cs">
<DependentUpon>MediaNavigationServiceTests.cs</DependentUpon>
</Compile>

View File

@@ -39,9 +39,8 @@ public class DataValueEditorReuseTests
var blockVarianceHandler = new BlockEditorVarianceHandler(Mock.Of<ILanguageService>());
_dataValueEditorFactoryMock
.Setup(m =>
m.Create<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>(It.IsAny<DataEditorAttribute>(), It.IsAny<BlockEditorDataConverter<BlockListValue, BlockListLayoutItem>>()))
m.Create<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>(It.IsAny<BlockEditorDataConverter<BlockListValue, BlockListLayoutItem>>()))
.Returns(() => new BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor(
new DataEditorAttribute("a"),
new BlockListEditorDataConverter(Mock.Of<IJsonSerializer>()),
_propertyEditorCollection,
_dataValueReferenceFactories,
@@ -51,9 +50,9 @@ public class DataValueEditorReuseTests
Mock.Of<ILogger<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>>(),
Mock.Of<IShortStringHelper>(),
Mock.Of<IJsonSerializer>(),
Mock.Of<IIOHelper>(),
Mock.Of<IPropertyValidationService>(),
blockVarianceHandler));
blockVarianceHandler,
Mock.Of<ILanguageService>()));
}
[Test]
@@ -99,7 +98,6 @@ public class DataValueEditorReuseTests
{
var blockListPropertyEditor = new BlockListPropertyEditor(
_dataValueEditorFactoryMock.Object,
_propertyEditorCollection,
Mock.Of<IIOHelper>(),
Mock.Of<IBlockValuePropertyIndexValueFactory>(),
Mock.Of<IJsonSerializer>());
@@ -111,7 +109,7 @@ public class DataValueEditorReuseTests
Assert.NotNull(dataValueEditor2);
Assert.AreNotSame(dataValueEditor1, dataValueEditor2);
_dataValueEditorFactoryMock.Verify(
m => m.Create<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>(It.IsAny<DataEditorAttribute>(), It.IsAny<BlockEditorDataConverter<BlockListValue, BlockListLayoutItem>>()),
m => m.Create<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>(It.IsAny<BlockEditorDataConverter<BlockListValue, BlockListLayoutItem>>()),
Times.Exactly(2));
}
@@ -120,7 +118,6 @@ public class DataValueEditorReuseTests
{
var blockListPropertyEditor = new BlockListPropertyEditor(
_dataValueEditorFactoryMock.Object,
_propertyEditorCollection,
Mock.Of<IIOHelper>(),
Mock.Of<IBlockValuePropertyIndexValueFactory>(),
Mock.Of<IJsonSerializer>());
@@ -134,7 +131,7 @@ public class DataValueEditorReuseTests
Assert.AreEqual("config", ((DataValueEditor)dataValueEditor2).ConfigurationObject);
Assert.AreNotSame(dataValueEditor1, dataValueEditor2);
_dataValueEditorFactoryMock.Verify(
m => m.Create<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>(It.IsAny<DataEditorAttribute>(), It.IsAny<BlockEditorDataConverter<BlockListValue, BlockListLayoutItem>>()),
m => m.Create<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>(It.IsAny<BlockEditorDataConverter<BlockListValue, BlockListLayoutItem>>()),
Times.Exactly(2));
}
}

View File

@@ -171,7 +171,7 @@ public class ContentNavigationServiceBaseTests
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732", new[] { "56E29EA9-E224-4210-A59F-7C2C5C0C5CC7" })] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7", new string[0])] // Great-grandchild 1
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF", new[] { "F381906C-223C-4466-80F7-B63B4EE073F8" })] // Child 3
public void Can_Get_Children_From_Existing_Content_Key_In_Correct_Order(Guid parentKey, string[] children)
public void Can_Get_Children_From_Existing_Content_Key_In_Their_Order_Of_Creation(Guid parentKey, string[] children)
{
// Arrange
Guid[] expectedChildren = Array.ConvertAll(children, Guid.Parse);
@@ -235,7 +235,7 @@ public class ContentNavigationServiceBaseTests
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732", new[] { "56E29EA9-E224-4210-A59F-7C2C5C0C5CC7" })] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7", new string[0])] // Great-grandchild 1
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF", new[] { "F381906C-223C-4466-80F7-B63B4EE073F8" })] // Child 3
public void Can_Get_Descendants_From_Existing_Content_Key_In_Correct_Order(Guid parentKey, string[] descendants)
public void Can_Get_Descendants_From_Existing_Content_Key_In_Their_Order_Of_Creation(Guid parentKey, string[] descendants)
{
// Arrange
Guid[] expectedDescendants = Array.ConvertAll(descendants, Guid.Parse);
@@ -296,7 +296,7 @@ public class ContentNavigationServiceBaseTests
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE", new[] { "E48DD82A-7059-418E-9B82-CDD5205796CF" })] // Child 1
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", new[] { "C6173927-0C59-4778-825D-D7B9F45D8DDE", "E48DD82A-7059-418E-9B82-CDD5205796CF" })] // Grandchild 1
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7", new[] { "D63C1621-C74A-4106-8587-817DEE5FB732", "60E0E5C4-084E-4144-A560-7393BEAD2E96", "E48DD82A-7059-418E-9B82-CDD5205796CF" })] // Great-grandchild 1
public void Can_Get_Ancestors_From_Existing_Content_Key_In_Correct_Order(Guid childKey, string[] ancestors)
public void Can_Get_Ancestors_From_Existing_Content_Key_In_Correct_Order_Of_Creation(Guid childKey, string[] ancestors)
{
// Arrange
Guid[] expectedAncestors = Array.ConvertAll(ancestors, Guid.Parse);
@@ -395,7 +395,7 @@ public class ContentNavigationServiceBaseTests
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF", new string[0])] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE", new[] { "60E0E5C4-084E-4144-A560-7393BEAD2E96", "B606E3FF-E070-4D46-8CB9-D31352029FDF" })] // Child 1 - Child 2, Child 3
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", new[] { "A1B1B217-B02F-4307-862C-A5E22DB729EB" })] // Grandchild 1 - Grandchild 2
public void Can_Get_Siblings_Of_Existing_Content_Key_In_Correct_Order(Guid childKey, string[] siblings)
public void Can_Get_Siblings_Of_Existing_Content_Key_In_Their_Order_Of_Creation(Guid childKey, string[] siblings)
{
// Arrange
Guid[] expectedSiblings = Array.ConvertAll(siblings, Guid.Parse);
@@ -505,6 +505,30 @@ public class ContentNavigationServiceBaseTests
});
}
[Test]
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
public void Moving_Node_To_Bin_Adds_It_To_Recycle_Bin_Root_As_The_Last_Item(Guid keyOfNodeToRemove)
{
// Arrange
Guid nodeInRecycleBin1 = Grandchild1;
Guid nodeInRecycleBin2 = Child3;
_navigationService.MoveToBin(nodeInRecycleBin1);
_navigationService.MoveToBin(nodeInRecycleBin2);
// Act
_navigationService.MoveToBin(keyOfNodeToRemove);
// Assert
_navigationService.TryGetSiblingsKeysInBin(nodeInRecycleBin1, out IEnumerable<Guid> siblingsInBin);
Assert.AreEqual(siblingsInBin.Last(), keyOfNodeToRemove);
}
[Test]
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
@@ -607,6 +631,30 @@ public class ContentNavigationServiceBaseTests
});
}
[Test]
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573")] // Grandchild 1
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF")] // Child 3
[TestCase("F381906C-223C-4466-80F7-B63B4EE073F8")] // Grandchild 4
public void Adding_Node_To_Parent_Adds_It_As_The_Last_Child(Guid parentKey)
{
// Arrange
var newNodeKey = Guid.NewGuid();
// Act
_navigationService.Add(newNodeKey, parentKey);
// Assert
_navigationService.TryGetChildrenKeys(parentKey, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(newNodeKey, childrenKeys.Last());
}
[Test]
public void Cannot_Move_Node_When_Target_Parent_Does_Not_Exist()
{
@@ -770,10 +818,32 @@ public class ContentNavigationServiceBaseTests
}
[Test]
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", "60E0E5C4-084E-4144-A560-7393BEAD2E96", 0)] // Grandchild 1 to Child 2
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF", null, 1)] // Child 3 to content root
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96", "C6173927-0C59-4778-825D-D7B9F45D8DDE", 2)] // Child 2 to Child 1
public void Moved_Node_Has_The_Same_Amount_Of_Descendants(Guid nodeToMove, Guid? targetParentKey, int initialDescendantsCount)
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
[TestCase("C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Child 1
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573")] // Grandchild 1
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Child 2
[TestCase("D63C1621-C74A-4106-8587-817DEE5FB732")] // Grandchild 3
[TestCase("56E29EA9-E224-4210-A59F-7C2C5C0C5CC7")] // Great-grandchild 1
public void Moving_Node_To_Parent_Adds_It_As_The_Last_Child(Guid targetParentKey)
{
// Arrange
Guid nodeToMove = Grandchild4;
// Act
_navigationService.Move(nodeToMove, targetParentKey);
// Assert
_navigationService.TryGetChildrenKeys(targetParentKey, out IEnumerable<Guid> childrenKeys);
Assert.AreEqual(nodeToMove, childrenKeys.Last());
}
[Test]
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", 1, "60E0E5C4-084E-4144-A560-7393BEAD2E96", 0)] // Grandchild 1 to Child 2
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF", 1, null, 1)] // Child 3 to content root
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96", 2, "C6173927-0C59-4778-825D-D7B9F45D8DDE", 2)] // Child 2 to Child 1
public void Moved_Node_Has_The_Same_Amount_Of_Descendants(Guid nodeToMove, int sortOrder, Guid? targetParentKey, int initialDescendantsCount)
{
// Act
var result = _navigationService.Move(nodeToMove, targetParentKey);
@@ -789,10 +859,10 @@ public class ContentNavigationServiceBaseTests
}
[Test]
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF", "A1B1B217-B02F-4307-862C-A5E22DB729EB", 0)] // Child 3 to Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96", "B606E3FF-E070-4D46-8CB9-D31352029FDF", 1)] // Child 2 to Child 3
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", "60E0E5C4-084E-4144-A560-7393BEAD2E96", 2)] // Grandchild 1 to Child 2
public void Number_Of_Target_Parent_Descendants_Updates_When_Moving_Node_With_Descendants(Guid nodeToMove, Guid targetParentKey, int initialDescendantsCountOfTargetParent)
[TestCase("B606E3FF-E070-4D46-8CB9-D31352029FDF", 0, "A1B1B217-B02F-4307-862C-A5E22DB729EB", 0)] // Child 3 to Grandchild 2
[TestCase("60E0E5C4-084E-4144-A560-7393BEAD2E96", 1, "B606E3FF-E070-4D46-8CB9-D31352029FDF", 1)] // Child 2 to Child 3
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", 1, "60E0E5C4-084E-4144-A560-7393BEAD2E96", 2)] // Grandchild 1 to Child 2
public void Number_Of_Target_Parent_Descendants_Updates_When_Moving_Node_With_Descendants(Guid nodeToMove, int sortOrder, Guid targetParentKey, int initialDescendantsCountOfTargetParent)
{
// Arrange
// Get the number of descendants of the node to move

View File

@@ -117,6 +117,34 @@ public class HtmlLocalLinkParserTests
[TestCase(
"<a href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" title=\"world\"type=\"media\">world</a>",
"<a href=\"/media/1001/my-image.jpg\" title=\"world\">world</a>")]
[TestCase(
"<p><a type=\"document\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" title=\"world\">world</a></p><p><a href=\"/{localLink:7e21a725-b905-4c5f-86dc-8c41ec116e39}\" title=\"world\" type=\"media\">world</a></p>",
"<p><a href=\"/my-test-url\" title=\"world\">world</a></p><p><a href=\"/media/1001/my-image.jpg\" title=\"world\">world</a></p>")]
// attributes order should not matter
[TestCase(
"<a rel=\"noopener\" title=\"world\" type=\"document\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}\">world</a>",
"<a rel=\"noopener\" title=\"world\" href=\"/my-test-url\">world</a>")]
[TestCase(
"<a rel=\"noopener\" title=\"world\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" type=\"document\">world</a>",
"<a rel=\"noopener\" title=\"world\" href=\"/my-test-url\">world</a>")]
[TestCase(
"<a rel=\"noopener\" title=\"world\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}#anchor\" type=\"document\">world</a>",
"<a rel=\"noopener\" title=\"world\" href=\"/my-test-url#anchor\">world</a>")]
// anchors and query strings
[TestCase(
"<a type=\"document\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}#anchor\" title=\"world\">world</a>",
"<a href=\"/my-test-url#anchor\" title=\"world\">world</a>")]
[TestCase(
"<a type=\"document\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}?v=1\" title=\"world\">world</a>",
"<a href=\"/my-test-url?v=1\" title=\"world\">world</a>")]
// custom type ignored
[TestCase(
"<a type=\"custom\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" title=\"world\">world</a>",
"<a type=\"custom\" href=\"/{localLink:9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" title=\"world\">world</a>")]
// legacy
[TestCase(
"hello href=\"{localLink:1234}\" world ",
@@ -127,9 +155,15 @@ public class HtmlLocalLinkParserTests
[TestCase(
"hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ",
"hello href=\"/my-test-url\" world ")]
[TestCase(
"hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}#anchor\" world ",
"hello href=\"/my-test-url#anchor\" world ")]
[TestCase(
"hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ",
"hello href=\"/media/1001/my-image.jpg\" world ")]
[TestCase(
"hello href='{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}' world ",
"hello href='/media/1001/my-image.jpg' world ")]
// This one has an invalid char so won't match.
[TestCase(
@@ -137,7 +171,7 @@ public class HtmlLocalLinkParserTests
"hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
[TestCase(
"hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ",
"hello href=\"#\" world ")]
"hello href=\"\" world ")]
public void ParseLocalLinks(string input, string result)
{
// setup a mock URL provider which we'll use for testing