Merge branch 'release/17.0' into v17/dev

# Conflicts:
#	version.json
This commit is contained in:
Niels Lyngsø
2025-10-29 20:04:40 +01:00
69 changed files with 473 additions and 766 deletions

View File

@@ -7,8 +7,8 @@
"name": "acceptancetest",
"hasInstallScript": true,
"dependencies": {
"@umbraco/json-models-builders": "^2.0.40",
"@umbraco/playwright-testhelpers": "^17.0.0-beta.7",
"@umbraco/json-models-builders": "^2.0.41",
"@umbraco/playwright-testhelpers": "^17.0.0-beta.10",
"camelize": "^1.0.0",
"dotenv": "^16.3.1",
"node-fetch": "^2.6.7"
@@ -67,9 +67,9 @@
}
},
"node_modules/@umbraco/playwright-testhelpers": {
"version": "17.0.0-beta.7",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-17.0.0-beta.7.tgz",
"integrity": "sha512-5fhmVVSpJkH6Inx8nA9qqqvZzYuPdDxJdQF2IzY0oSf8C0eti+TJ2BKrYfTLmZTfVqmHUas72BMGser5pfpl9A==",
"version": "17.0.0-beta.10",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-17.0.0-beta.10.tgz",
"integrity": "sha512-ePvtWK2IG/j3TIL1w7xkZR63FHM32hIjZxaxJOQ4rYNuVxBKT7TTKEvASfdwpDBFnlAN186xZRGA9KJq+Jxijg==",
"license": "MIT",
"dependencies": {
"@umbraco/json-models-builders": "2.0.41",

View File

@@ -21,8 +21,8 @@
"typescript": "^4.8.3"
},
"dependencies": {
"@umbraco/json-models-builders": "^2.0.40",
"@umbraco/playwright-testhelpers": "^17.0.0-beta.7",
"@umbraco/json-models-builders": "^2.0.41",
"@umbraco/playwright-testhelpers": "^17.0.0-beta.10",
"camelize": "^1.0.0",
"dotenv": "^16.3.1",
"node-fetch": "^2.6.7"

View File

@@ -21,7 +21,7 @@ test('can create a data type using create options', async ({umbracoApi, umbracoU
await umbracoUi.dataType.clickDataTypesMenu();
// Act
await umbracoUi.dataType.clickCreateActionWithOptionName('New Data Type');
await umbracoUi.dataType.clickCreateActionWithOptionName('Data Type');
await umbracoUi.dataType.enterDataTypeName(dataTypeName);
await umbracoUi.dataType.clickSelectAPropertyEditorButton();
await umbracoUi.dataType.selectAPropertyEditor('Text Box');
@@ -60,7 +60,7 @@ test('can create a data type in a folder using create options', async ({umbracoA
await umbracoUi.dataType.goToDataType(dataTypeFolderName);
// Act
await umbracoUi.dataType.clickCreateActionWithOptionName('New Data Type');
await umbracoUi.dataType.clickCreateActionWithOptionName('Data Type');
await umbracoUi.dataType.enterDataTypeName(dataTypeName);
await umbracoUi.dataType.clickSelectAPropertyEditorButton();
await umbracoUi.dataType.selectAPropertyEditor('Text Box');

View File

@@ -9,7 +9,6 @@ test('can click on buttons', {tag: '@release'}, async ({umbracoUi}) => {
// Arrange
const getTheHelpYouNeedDocumentationUrl = 'https://docs.umbraco.com/umbraco-cms';
const goToTheForumUrl = 'https://forum.umbraco.com/';
const chatWithTheCommunityUrl = 'https://discord.umbraco.com';
const getCertifiedUrl = 'https://umbraco.com/training/';
const getTheHelpYouNeedSupportUrl = 'https://umbraco.com/support/';
const watchTheVideosUrl = 'https://www.youtube.com/c/UmbracoLearningBase';
@@ -20,7 +19,6 @@ test('can click on buttons', {tag: '@release'}, async ({umbracoUi}) => {
// Assert
await umbracoUi.welcomeDashboard.doesButtonWithLabelInBoxHaveLink('Get the help you need', 'Documentation', getTheHelpYouNeedDocumentationUrl);
await umbracoUi.welcomeDashboard.doesButtonWithLabelInBoxHaveLink('Go to the forum', 'Community', goToTheForumUrl);
await umbracoUi.welcomeDashboard.doesButtonWithLabelInBoxHaveLink('Chat with the community', 'Community', chatWithTheCommunityUrl);
await umbracoUi.welcomeDashboard.doesButtonWithLabelInBoxHaveLink('Get Certified', 'Training', getCertifiedUrl);
await umbracoUi.welcomeDashboard.doesButtonWithLabelInBoxHaveLink('Get the help you need', 'Support', getTheHelpYouNeedSupportUrl);
await umbracoUi.welcomeDashboard.doesButtonWithLabelInBoxHaveLink('Watch the videos', 'Videos', watchTheVideosUrl);

View File

@@ -9,7 +9,6 @@ const allPermissions = {
'Create',
'Notifications',
'Publish',
'Set permissions',
'Unpublish',
'Update',
'Duplicate',
@@ -25,7 +24,6 @@ const allPermissions = {
'Umb.Document.Create',
'Umb.Document.Notifications',
'Umb.Document.Publish',
'Umb.Document.Permissions',
'Umb.Document.Unpublish',
'Umb.Document.Update',
'Umb.Document.Duplicate',

View File

@@ -30,15 +30,12 @@ test('the default configuration of Administrators is correct', {tag: '@release'}
"Umb.Document.PublicAccess",
"Umb.Document.CultureAndHostnames",
"Umb.Document.Publish",
"Umb.Document.Permissions",
"Umb.Document.Unpublish",
"Umb.Document.Read",
"Umb.Document.CreateBlueprint",
"Umb.Document.Notifications",
"Umb.Document.PropertyValue.Read",
"Umb.Document.PropertyValue.Write"
];
const granularPermissions = [];
const granularPermissions: any = [];
const hasAccessToAllLanguages = true;
const documentRootAccess = true;
const mediaRootAccess = true;
@@ -50,8 +47,8 @@ test('the default configuration of Administrators is correct', {tag: '@release'}
// Act
await umbracoUi.userGroup.doesSettingHaveValue('Assign access', ConstantHelper.userGroupAssignAccessSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Default permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Granular permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document Property Value permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesPermissionsSettingsHaveValue(ConstantHelper.userGroupPermissionsSettings);
await umbracoUi.userGroup.doesUserGroupHavePermissionEnabled(uiPermissions);
await umbracoUi.userGroup.doesUserGroupHaveSections(uiSections);
@@ -88,10 +85,8 @@ test('the default configuration of Editors is correct', {tag: '@release'}, async
"Umb.Document.Read",
"Umb.Document.CreateBlueprint",
"Umb.Document.Notifications",
"Umb.Document.PropertyValue.Read",
"Umb.Document.PropertyValue.Write"
];
const granularPermissions = [];
const granularPermissions: string[] = [];
const hasAccessToAllLanguages = true;
const documentRootAccess = true;
const mediaRootAccess = true;
@@ -103,8 +98,8 @@ test('the default configuration of Editors is correct', {tag: '@release'}, async
// Act
await umbracoUi.userGroup.doesSettingHaveValue('Assign access', ConstantHelper.userGroupAssignAccessSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Default permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Granular permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document Property Value permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesPermissionsSettingsHaveValue(ConstantHelper.userGroupPermissionsSettings);
await umbracoUi.userGroup.doesUserGroupHavePermissionEnabled(uiPermissions);
await umbracoUi.userGroup.doesUserGroupHaveSections(uiSections);
@@ -123,9 +118,9 @@ test('the default configuration of Editors is correct', {tag: '@release'}, async
test('the default configuration of Sensitive data is correct', {tag: '@release'}, async ({umbracoApi, umbracoUi}) => {
// Arrange
const userGroupName = 'Sensitive data';
const sections = [];
const fallbackPermissions = [];
const granularPermissions = [];
const sections: string[] = [];
const fallbackPermissions: string[] = [];
const granularPermissions: string[] = [];
const hasAccessToAllLanguages = false;
const documentRootAccess = false;
const mediaRootAccess = false;
@@ -137,8 +132,8 @@ test('the default configuration of Sensitive data is correct', {tag: '@release'}
// Act
await umbracoUi.userGroup.doesSettingHaveValue('Assign access', ConstantHelper.userGroupAssignAccessSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Default permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Granular permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document Property Value permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesPermissionsSettingsHaveValue(ConstantHelper.userGroupPermissionsSettings);
await umbracoUi.userGroup.doesUserGroupHavePermissionEnabled(uiPermissions);
await umbracoUi.userGroup.doesUserGroupHaveSections(uiSections);
@@ -161,10 +156,8 @@ test('the default configuration of Translators data is correct', {tag: '@release
const fallbackPermissions = [
"Umb.Document.Update",
"Umb.Document.Read",
"Umb.Document.PropertyValue.Read",
"Umb.Document.PropertyValue.Write"
];
const granularPermissions = [];
const granularPermissions: string[] = [];
const hasAccessToAllLanguages = true;
const documentRootAccess = true;
const mediaRootAccess = true;
@@ -176,14 +169,15 @@ test('the default configuration of Translators data is correct', {tag: '@release
// Act
await umbracoUi.userGroup.doesSettingHaveValue('Assign access', ConstantHelper.userGroupAssignAccessSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Default permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Granular permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document Property Value permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesPermissionsSettingsHaveValue(ConstantHelper.userGroupPermissionsSettings);
await umbracoUi.userGroup.doesUserGroupHavePermissionEnabled(uiPermissions);
await umbracoUi.userGroup.doesUserGroupHaveSections(uiSections);
await umbracoUi.userGroup.doesUserGroupSectionsHaveCount(uiSections.length);
expect(await umbracoApi.userGroup.doesUserGroupHaveSections(userGroupName, sections)).toBeTruthy();
expect(await umbracoApi.userGroup.doesUserGroupHaveFallbackPermissions(userGroupName, fallbackPermissions)).toBeTruthy();
// Fixme - Uncomment this when the front-end is ready. Currently the fallbackPermissions includes some unnecessary values such as ":", "5", "T"
// expect(await umbracoApi.userGroup.doesUserGroupHaveFallbackPermissions(userGroupName, fallbackPermissions)).toBeTruthy();
const userGroupData = await umbracoApi.userGroup.getByName(userGroupName);
expect(userGroupData.hasAccessToAllLanguages).toEqual(hasAccessToAllLanguages);
expect(userGroupData.documentRootAccess).toEqual(documentRootAccess);
@@ -200,10 +194,8 @@ test('the default configuration of Writers data is correct', {tag: '@release'},
"Umb.Document.Update",
"Umb.Document.Read",
"Umb.Document.Notifications",
"Umb.Document.PropertyValue.Read",
"Umb.Document.PropertyValue.Write"
];
const granularPermissions = [];
const granularPermissions: string[] = [];
const hasAccessToAllLanguages = true;
const documentRootAccess = true;
const mediaRootAccess = true;
@@ -215,15 +207,15 @@ test('the default configuration of Writers data is correct', {tag: '@release'},
// Act
await umbracoUi.userGroup.doesSettingHaveValue('Assign access', ConstantHelper.userGroupAssignAccessSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Default permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Granular permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document permissions', ConstantHelper.userGroupDefaultPermissionsSettings);
await umbracoUi.userGroup.doesSettingHaveValue('Document Property Value permissions', ConstantHelper.userGroupGranularPermissionsSettings);
await umbracoUi.userGroup.doesPermissionsSettingsHaveValue(ConstantHelper.userGroupPermissionsSettings);
await umbracoUi.userGroup.doesUserGroupHavePermissionEnabled(uiPermissions);
await umbracoUi.userGroup.doesUserGroupHaveSections(uiSections);
await umbracoUi.userGroup.doesUserGroupSectionsHaveCount(uiSections.length);
expect(await umbracoApi.userGroup.doesUserGroupHaveSections(userGroupName, sections)).toBeTruthy();
// Fixme - Uncomment this when the front-end is ready. Currently the fallbackPermissions includes some unnecessary values such as ":", "5", "T"
//expect(await umbracoApi.userGroup.doesUserGroupHaveFallbackPermissions(userGroupName, fallbackPermissions)).toBeTruthy();
// expect(await umbracoApi.userGroup.doesUserGroupHaveFallbackPermissions(userGroupName, fallbackPermissions)).toBeTruthy();
const userGroupData = await umbracoApi.userGroup.getByName(userGroupName);
expect(userGroupData.hasAccessToAllLanguages).toEqual(hasAccessToAllLanguages);
expect(userGroupData.documentRootAccess).toEqual(documentRootAccess);

View File

@@ -1,41 +0,0 @@
using System.Linq.Expressions;
using System.Net;
using Umbraco.Cms.Api.Management.Controllers.Help;
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Help;
public class GetHelpControllerTests : ManagementApiUserGroupTestBase<GetHelpController>
{
protected override Expression<Func<GetHelpController, object>> MethodSelector =>
x => x.Get(CancellationToken.None, "TestSection", "TestTree", 0, 100, "https://our.umbraco.com");
protected override UserGroupAssertionModel AdminUserGroupAssertionModel => new()
{
ExpectedStatusCode = HttpStatusCode.BadRequest
};
protected override UserGroupAssertionModel EditorUserGroupAssertionModel => new()
{
ExpectedStatusCode = HttpStatusCode.BadRequest
};
protected override UserGroupAssertionModel SensitiveDataUserGroupAssertionModel => new()
{
ExpectedStatusCode = HttpStatusCode.BadRequest
};
protected override UserGroupAssertionModel TranslatorUserGroupAssertionModel => new()
{
ExpectedStatusCode = HttpStatusCode.BadRequest
};
protected override UserGroupAssertionModel WriterUserGroupAssertionModel => new()
{
ExpectedStatusCode = HttpStatusCode.BadRequest
};
protected override UserGroupAssertionModel UnauthorizedUserGroupAssertionModel => new()
{
ExpectedStatusCode = HttpStatusCode.Unauthorized
};
}

View File

@@ -132,7 +132,7 @@ public class TypeLoaderTests
public void GetDataEditors()
{
var types = _typeLoader.GetDataEditors();
Assert.AreEqual(41, types.Count());
Assert.AreEqual(42, types.Count());
}
/// <summary>

View File

@@ -0,0 +1,95 @@
using System.Globalization;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models.Validation;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.Serialization;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
[TestFixture]
public class EntityDataPickerPropertyValueEditorTests
{
[TestCase(1, false)]
[TestCase(2, true)]
[TestCase(3, true)]
public void Validates_Is_Greater_Than_Or_Equal_To_Configured_Min(int numberOfSelections, bool expectedSuccess)
{
var editor = CreateValueEditor();
var value = new EntityDataPickerPropertyEditor.EntityDataPickerDto
{
Ids = [.. Enumerable.Range(1, numberOfSelections).Select(i => i.ToString())],
};
var serializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
var serializedValue = serializer.Serialize(value);
var result = editor.Validate(serializedValue, false, null, PropertyValidationContext.Empty());
if (expectedSuccess)
{
Assert.IsEmpty(result);
}
else
{
Assert.AreEqual(1, result.Count());
var validationResult = result.First();
Assert.AreEqual("validation_entriesShort", validationResult.ErrorMessage);
}
}
[TestCase(3, true)]
[TestCase(4, true)]
[TestCase(5, false)]
public void Validates_Is_Less_Than_Or_Equal_To_Configured_Max(int numberOfSelections, bool expectedSuccess)
{
var editor = CreateValueEditor();
var value = new EntityDataPickerPropertyEditor.EntityDataPickerDto
{
Ids = [.. Enumerable.Range(1, numberOfSelections).Select(i => i.ToString())],
};
var serializer = new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory());
var serializedValue = serializer.Serialize(value);
var result = editor.Validate(serializedValue, false, null, PropertyValidationContext.Empty());
if (expectedSuccess)
{
Assert.IsEmpty(result);
}
else
{
Assert.AreEqual(1, result.Count());
var validationResult = result.First();
Assert.AreEqual("validation_entriesExceed", validationResult.ErrorMessage);
}
}
private static EntityDataPickerPropertyEditor.EntityDataPickerPropertyValueEditor CreateValueEditor()
{
var localizedTextServiceMock = new Mock<ILocalizedTextService>();
localizedTextServiceMock.Setup(x => x.Localize(
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<CultureInfo>(),
It.IsAny<IDictionary<string, string>>()))
.Returns((string key, string alias, CultureInfo culture, IDictionary<string, string> args) => $"{key}_{alias}");
return new EntityDataPickerPropertyEditor.EntityDataPickerPropertyValueEditor(
Mock.Of<IShortStringHelper>(),
new SystemTextJsonSerializer(new DefaultJsonSerializerEncoderFactory()),
Mock.Of<IIOHelper>(),
new DataEditorAttribute("alias"),
localizedTextServiceMock.Object)
{
ConfigurationObject = new EntityDataPickerConfiguration
{
DataSource = "testDataSource",
ValidationLimit = new EntityDataPickerConfiguration.NumberRange
{
Min = 2,
Max = 4
}
},
};
}
}