From 22b647d222bca0f2c7ad084bc3796d74347e9efa Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Fri, 13 Jun 2025 10:27:39 +0700 Subject: [PATCH 1/5] Added tests for granular document permission --- .../GranularPermissionsInContent.spec.ts | 363 ++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts new file mode 100644 index 000000000000..b529bdf02ad9 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts @@ -0,0 +1,363 @@ +import {ConstantHelper, NotificationConstantHelper, test} from "@umbraco/playwright-testhelpers"; +import {expect} from "@playwright/test"; + +// Document Type +const documentTypeName = 'DocumentType'; +const childDocumentTypeName = 'ChildDocumentType'; +let documentTypeId = null; +let childDocumentTypeId = null; + +// Document +const firstDocumentName = 'FirstDocumentName'; +const secondDocumentName = 'SecondDocumentName'; +const firstChildDocumentName = 'FirstChildDocumentName'; +const secondChildDocumentName = 'SecondChildDocumentName'; +let firstDocumentId = null; +let secondDocumentId = null; + +// Data Type +const dataTypeName = 'Textstring'; +let dataTypeId = null; +const documentText = 'This is test document text'; + +// Document Blueprint +const testDocumentName = 'TestDocument'; +const documentBlueprintName = 'TestBlueprintName'; + +// User +const testUser = ConstantHelper.testUserCredentials; +let testUserCookieAndToken = {cookie: "", accessToken: "", refreshToken: ""}; + +const userGroupName = 'TestUserGroup'; +let userGroupId = null; + +test.beforeEach(async ({umbracoApi}) => { + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName); + await umbracoApi.user.ensureNameNotExists(testUser.name); + await umbracoApi.userGroup.ensureNameNotExists(userGroupName); + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); + const dataType = await umbracoApi.dataType.getByName(dataTypeName); + dataTypeId = dataType.id; + childDocumentTypeId = await umbracoApi.documentType.createDefaultDocumentType(childDocumentTypeName); + documentTypeId = await umbracoApi.documentType.createDocumentTypeWithAllowedChildNodeAndDataType(documentTypeName, childDocumentTypeId, dataTypeName, dataTypeId); + firstDocumentId = await umbracoApi.document.createDocumentWithTextContent(firstDocumentName, documentTypeId, documentText, dataTypeName); + secondDocumentId = await umbracoApi.document.createDocumentWithTextContent(secondDocumentName, documentTypeId, documentText, dataTypeName); +}); + +test.afterEach(async ({umbracoApi}) => { + // Ensure we are logged in to admin + await umbracoApi.loginToAdminUser(testUserCookieAndToken.cookie, testUserCookieAndToken.accessToken, testUserCookieAndToken.refreshToken); + await umbracoApi.document.ensureNameNotExists(firstDocumentName); + await umbracoApi.document.ensureNameNotExists(secondDocumentName); + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName); + await umbracoApi.userGroup.ensureNameNotExists(userGroupName); + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); +}); + +test('can read a specific document with read permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithReadPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.userGroup.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.goToContentWithName(firstDocumentName); + + // Assert + await umbracoUi.content.doesDocumentHaveName(firstDocumentName); + await umbracoUi.content.goToContentWithName(secondDocumentName); + await umbracoUi.content.doesErrorNotificationHaveText(NotificationConstantHelper.error.permissionDenied); +}); + +test('can create document blueprint for a specific document with create document blueprint permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithCreateDocumentBlueprintPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickCreateBlueprintActionMenuOption(); + await umbracoUi.content.enterDocumentBlueprintName(documentBlueprintName); + await umbracoUi.content.clickSaveDocumentBlueprintButton(); + + // Assert + await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.documentBlueprintCreated); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +test('can delete a specific content with delete permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithDeletePermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickTrashActionMenuOption(); + await umbracoUi.content.clickConfirmTrashButton(); + + // Assert + await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +// TODO: find another test scenario +test.fixme('can create content from a specific content with create permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithCreatePermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(childDocumentTypeName); + await umbracoUi.content.enterContentName(testDocumentName); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(testDocumentName)).toBeTruthy(); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +test('can publish a specific content with publish permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithPublishPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickPublishActionMenuOption(); + await umbracoUi.content.clickConfirmToPublishButton(); + + // Assert + await umbracoUi.content.waitForContentToBePublished(); + expect(await umbracoApi.document.isDocumentPublished(firstDocumentId)).toBeTruthy(); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/19339 +test.skip('can set permissions for a specific content with set permissions permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithSetPermissionsPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + // await umbracoUi.content.clickSetPermissionsButton(); + // + // // Assert + // await umbracoUi.content.doesDocumentPermissionsDialogExist(); + // await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +test('can unpublish a specific content with unpublish permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + await umbracoApi.document.publish(firstDocumentId); + await umbracoApi.document.publish(secondDocumentId); + expect(await umbracoApi.document.isDocumentPublished(firstDocumentId)).toBeTruthy(); + expect(await umbracoApi.document.isDocumentPublished(secondDocumentId)).toBeTruthy(); + userGroupId = await umbracoApi.userGroup.createUserGroupWithUnpublishPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickUnpublishActionMenuOption(); + await umbracoUi.content.clickConfirmToUnpublishButton(); + + // Assert + await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.unpublished); + expect(await umbracoApi.document.isDocumentPublished(firstDocumentId)).toBeFalsy(); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); + expect(await umbracoApi.document.isDocumentPublished(secondDocumentId)).toBeTruthy(); +}); + +test('can update a specific content with update permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithUpdatePermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.goToContentWithName(firstDocumentName); + await umbracoUi.content.enterContentName(testDocumentName); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.isSuccessStateVisibleForSaveButton(); + expect(await umbracoApi.document.doesNameExist(testDocumentName)).toBeTruthy(); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +test('can duplicate a specific content with duplicate permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithDuplicatePermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + // Duplicate to root + await umbracoUi.content.clickDuplicateToActionMenuOption(); + await umbracoUi.content.clickLabelWithName('Content'); + await umbracoUi.content.clickDuplicateButton(); + + // Assert + await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.duplicated); + await umbracoUi.content.clickActionsMenuForContent(secondDocumentName); + await umbracoUi.content.isPermissionInActionsMenuVisible('Duplicate to…', false); +}); + +test('can move a specific content with move to permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + const moveToDocumentName = 'MoveToDocument'; + await umbracoApi.document.createDefaultDocumentWithParent(firstChildDocumentName, childDocumentTypeId, firstDocumentId); + await umbracoApi.document.createDocumentWithTextContent(moveToDocumentName, documentTypeId, documentText, dataTypeName); + userGroupId = await umbracoApi.userGroup.createUserGroupWithMoveToPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickCaretButtonForContentName(firstDocumentName); + await umbracoUi.content.clickActionsMenuForContent(firstChildDocumentName); + await umbracoUi.content.clickMoveToActionMenuOption(); + await umbracoUi.content.moveToContentWithName([], moveToDocumentName); + + // Assert + await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.moved); + await umbracoUi.content.clickActionsMenuForContent(secondDocumentName); + await umbracoUi.content.isPermissionInActionsMenuVisible('Move to…', false); + + // Clean + await umbracoApi.document.ensureNameNotExists(moveToDocumentName); + await umbracoApi.document.ensureNameNotExists(firstChildDocumentName); +}); + +// Needs a better way to assert +test.fixme('can sort children with sort children permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + await umbracoApi.document.createDefaultDocumentWithParent(childDocumentTwoName, childDocumentTypeId, rootDocumentId); + userGroupId = await umbracoApi.userGroup.createUserGroupWithSortChildrenPermission(userGroupName); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickSortChildrenActionMenuOption(); + + // TODO: uncomment when it is not flaky + // const childDocumentOneLocator = await umbracoUi.content.getButtonWithName(childDocumentOneName); + // const childDocumentTwoLocator = await umbracoUi.content.getButtonWithName(childDocumentTwoName) + // await umbracoUi.content.sortChildrenDragAndDrop(childDocumentOneLocator, childDocumentTwoLocator, 10, 0, 10); + await umbracoUi.content.clickSortButton(); + + // Assert + // TODO: uncomment when it is not flaky + await umbracoUi.content.clickCaretButtonForContentName(firstDocumentName); + await umbracoUi.content.doesIndexDocumentInTreeContainName(firstDocumentName, childDocumentTwoName, 0); + await umbracoUi.content.doesIndexDocumentInTreeContainName(firstDocumentName, childDocumentOneName, 1); +}); + +test('can set culture and hostnames for a specific content with culture and hostnames permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + const domainName = '/domain'; + userGroupId = await umbracoApi.userGroup.createUserGroupWithCultureAndHostnamesPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickCultureAndHostnamesActionMenuOption(); + await umbracoUi.content.clickAddNewDomainButton(); + await umbracoUi.content.enterDomain(domainName); + await umbracoUi.content.clickSaveModalButton(); + + // Assert + await umbracoUi.content.waitForDomainToBeCreated(); + const document = await umbracoApi.document.getByName(firstDocumentName); + const domains = await umbracoApi.document.getDomains(document.id); + expect(domains.domains[0].domainName).toEqual(domainName); + expect(domains.domains[0].isoCode).toEqual('en-US'); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); + +test('can set public access for a specific content with public access permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithPublicAccessPermissionForSpecificDocument(userGroupName, firstDocumentId); + const testMemberGroup = 'TestMemberGroup'; + await umbracoApi.memberGroup.ensureNameNotExists(testMemberGroup); + await umbracoApi.memberGroup.create(testMemberGroup); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickPublicAccessActionMenuOption(); + await umbracoUi.content.addGroupBasedPublicAccess(testMemberGroup, firstDocumentName); + + // Assert + await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.publicAccessSettingCreated); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); + + // Clean + await umbracoApi.memberGroup.ensureNameNotExists(testMemberGroup); +}); + +test('can rollback a specific content with rollback permission enabled', async ({umbracoApi, umbracoUi}) => { + // Arrange + userGroupId = await umbracoApi.userGroup.createUserGroupWithRollbackPermissionForSpecificDocument(userGroupName, firstDocumentId); + await umbracoApi.document.publish(firstDocumentId); + const updatedTextStringText = 'This is an updated textString text'; + const contentData = await umbracoApi.document.get(firstDocumentId); + contentData.values[0].value = updatedTextStringText; + await umbracoApi.document.update(firstDocumentId, contentData); + await umbracoApi.document.publish(firstDocumentId); + await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); + testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content, false); + + // Act + await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); + await umbracoUi.content.clickRollbackActionMenuOption(); + await umbracoUi.content.clickLatestRollBackItem(); + await umbracoUi.content.clickRollbackContainerButton(); + + // Assert + await umbracoUi.content.goToContentWithName(firstDocumentName); + await umbracoUi.content.doesDocumentPropertyHaveValue(dataTypeName, documentText); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); +}); From 4d521f2e4721f7a743df2fd9513549a33d4d769b Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Fri, 13 Jun 2025 10:56:50 +0700 Subject: [PATCH 2/5] Updated tests for Webhook --- .../GranularPermissionsInContent.spec.ts | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts index b529bdf02ad9..13f026d9240d 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts @@ -10,8 +10,7 @@ let childDocumentTypeId = null; // Document const firstDocumentName = 'FirstDocumentName'; const secondDocumentName = 'SecondDocumentName'; -const firstChildDocumentName = 'FirstChildDocumentName'; -const secondChildDocumentName = 'SecondChildDocumentName'; +const childDocumentName = 'ChildDocumentName'; let firstDocumentId = null; let secondDocumentId = null; @@ -36,7 +35,6 @@ test.beforeEach(async ({umbracoApi}) => { await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName); await umbracoApi.user.ensureNameNotExists(testUser.name); await umbracoApi.userGroup.ensureNameNotExists(userGroupName); - await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); const dataType = await umbracoApi.dataType.getByName(dataTypeName); dataTypeId = dataType.id; childDocumentTypeId = await umbracoApi.documentType.createDefaultDocumentType(childDocumentTypeName); @@ -53,7 +51,6 @@ test.afterEach(async ({umbracoApi}) => { await umbracoApi.documentType.ensureNameNotExists(documentTypeName); await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName); await umbracoApi.userGroup.ensureNameNotExists(userGroupName); - await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); }); test('can read a specific document with read permission enabled', async ({umbracoApi, umbracoUi}) => { @@ -75,6 +72,7 @@ test('can read a specific document with read permission enabled', async ({umbrac test('can create document blueprint for a specific document with create document blueprint permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); userGroupId = await umbracoApi.userGroup.createUserGroupWithCreateDocumentBlueprintPermissionForSpecificDocument(userGroupName, firstDocumentId); await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); @@ -90,6 +88,9 @@ test('can create document blueprint for a specific document with create document // Assert await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.documentBlueprintCreated); await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); + + // Clean + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); }); test('can delete a specific content with delete permission enabled', async ({umbracoApi, umbracoUi}) => { @@ -110,8 +111,7 @@ test('can delete a specific content with delete permission enabled', async ({umb await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); }); -// TODO: find another test scenario -test.fixme('can create content from a specific content with create permission enabled', async ({umbracoApi, umbracoUi}) => { +test('can create content from a specific content with create permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange userGroupId = await umbracoApi.userGroup.createUserGroupWithCreatePermissionForSpecificDocument(userGroupName, firstDocumentId); await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); @@ -121,14 +121,9 @@ test.fixme('can create content from a specific content with create permission en // Act await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); - await umbracoUi.content.clickCreateActionMenuOption(); - await umbracoUi.content.chooseDocumentType(childDocumentTypeName); - await umbracoUi.content.enterContentName(testDocumentName); - await umbracoUi.content.clickSaveButton(); // Assert - await umbracoUi.content.waitForContentToBeCreated(); - expect(await umbracoApi.document.doesNameExist(testDocumentName)).toBeTruthy(); + await umbracoUi.content.isPermissionInActionsMenuVisible('Create…'); await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); }); @@ -236,7 +231,7 @@ test('can duplicate a specific content with duplicate permission enabled', async test('can move a specific content with move to permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange const moveToDocumentName = 'MoveToDocument'; - await umbracoApi.document.createDefaultDocumentWithParent(firstChildDocumentName, childDocumentTypeId, firstDocumentId); + await umbracoApi.document.createDefaultDocumentWithParent(childDocumentName, childDocumentTypeId, firstDocumentId); await umbracoApi.document.createDocumentWithTextContent(moveToDocumentName, documentTypeId, documentText, dataTypeName); userGroupId = await umbracoApi.userGroup.createUserGroupWithMoveToPermissionForSpecificDocument(userGroupName, firstDocumentId); await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); @@ -246,7 +241,7 @@ test('can move a specific content with move to permission enabled', async ({umbr // Act await umbracoUi.content.clickCaretButtonForContentName(firstDocumentName); - await umbracoUi.content.clickActionsMenuForContent(firstChildDocumentName); + await umbracoUi.content.clickActionsMenuForContent(childDocumentName); await umbracoUi.content.clickMoveToActionMenuOption(); await umbracoUi.content.moveToContentWithName([], moveToDocumentName); @@ -257,14 +252,13 @@ test('can move a specific content with move to permission enabled', async ({umbr // Clean await umbracoApi.document.ensureNameNotExists(moveToDocumentName); - await umbracoApi.document.ensureNameNotExists(firstChildDocumentName); + await umbracoApi.document.ensureNameNotExists(childDocumentName); }); -// Needs a better way to assert -test.fixme('can sort children with sort children permission enabled', async ({umbracoApi, umbracoUi}) => { +test('can sort children with sort children permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange - await umbracoApi.document.createDefaultDocumentWithParent(childDocumentTwoName, childDocumentTypeId, rootDocumentId); - userGroupId = await umbracoApi.userGroup.createUserGroupWithSortChildrenPermission(userGroupName); + await umbracoApi.document.createDefaultDocumentWithParent(childDocumentName, childDocumentTypeId, firstDocumentId); + userGroupId = await umbracoApi.userGroup.createUserGroupWithSortChildrenPermissionForSpecificDocument(userGroupName, firstDocumentId); await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); await umbracoUi.goToBackOffice(); @@ -272,19 +266,13 @@ test.fixme('can sort children with sort children permission enabled', async ({um // Act await umbracoUi.content.clickActionsMenuForContent(firstDocumentName); - await umbracoUi.content.clickSortChildrenActionMenuOption(); - - // TODO: uncomment when it is not flaky - // const childDocumentOneLocator = await umbracoUi.content.getButtonWithName(childDocumentOneName); - // const childDocumentTwoLocator = await umbracoUi.content.getButtonWithName(childDocumentTwoName) - // await umbracoUi.content.sortChildrenDragAndDrop(childDocumentOneLocator, childDocumentTwoLocator, 10, 0, 10); - await umbracoUi.content.clickSortButton(); // Assert - // TODO: uncomment when it is not flaky - await umbracoUi.content.clickCaretButtonForContentName(firstDocumentName); - await umbracoUi.content.doesIndexDocumentInTreeContainName(firstDocumentName, childDocumentTwoName, 0); - await umbracoUi.content.doesIndexDocumentInTreeContainName(firstDocumentName, childDocumentOneName, 1); + await umbracoUi.content.isPermissionInActionsMenuVisible('Sort children…'); + await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); + + // Clean + await umbracoApi.document.ensureNameNotExists(childDocumentName); }); test('can set culture and hostnames for a specific content with culture and hostnames permission enabled', async ({umbracoApi, umbracoUi}) => { From 3bab9c3f6282000b43927e4da2db2a300c168ece Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Fri, 13 Jun 2025 10:57:11 +0700 Subject: [PATCH 3/5] Bumped version --- .../package-lock.json | 19 +++++++++---------- .../Umbraco.Tests.AcceptanceTest/package.json | 4 ++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index bc9cbdfc34cb..f2cabf43c3ff 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -7,8 +7,8 @@ "name": "acceptancetest", "hasInstallScript": true, "dependencies": { - "@umbraco/json-models-builders": "^2.0.35", - "@umbraco/playwright-testhelpers": "^16.0.23", + "@umbraco/json-models-builders": "^2.0.36", + "@umbraco/playwright-testhelpers": "^16.0.25", "camelize": "^1.0.0", "dotenv": "^16.3.1", "node-fetch": "^2.6.7" @@ -58,20 +58,19 @@ } }, "node_modules/@umbraco/json-models-builders": { - "version": "2.0.35", - "resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-2.0.35.tgz", - "integrity": "sha512-9qHvp7j8Lhj2x4xxWYz+ovRyoSnJIl4eLbSAst4nODCNqXSTWOy3+mzho3SeYWeil00/r0zXExHoXklVYi4iKA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-2.0.36.tgz", + "integrity": "sha512-vQLL/y2ZIqrhCBe61W6YuA/C3KjGkva90WA09YfQuPL9HujOkJpVaP7KjJ0F8bBxwURy9tzMBFBLUz5fOdbkxQ==", "dependencies": { "camelize": "^1.0.1" } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "16.0.23", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-16.0.23.tgz", - "integrity": "sha512-9By0jqdscFh5pRFCpBEvoOCOpEOUG9eoSGvyLPnWjiJtfTCSm2OHARX8QcP5vCU65TO59w7JwUcXBTExaRIFXg==", - "license": "MIT", + "version": "16.0.25", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-16.0.25.tgz", + "integrity": "sha512-IvRkkrTIxlXbg2dw0RhAUgkb7KSBJCyktK6zJynOORgZ5RXRae19hqKk7yEu2EwJpTstl6m9AzoVf1x4b94x5w==", "dependencies": { - "@umbraco/json-models-builders": "2.0.35", + "@umbraco/json-models-builders": "2.0.36", "node-fetch": "^2.6.7" } }, diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 5998bf61af50..78c09e9719ea 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -20,8 +20,8 @@ "typescript": "^4.8.3" }, "dependencies": { - "@umbraco/json-models-builders": "^2.0.35", - "@umbraco/playwright-testhelpers": "^16.0.23", + "@umbraco/json-models-builders": "^2.0.36", + "@umbraco/playwright-testhelpers": "^16.0.25", "camelize": "^1.0.0", "dotenv": "^16.3.1", "node-fetch": "^2.6.7" From 86eac637de6dde69fc020f7bf750b3042ecfb1fd Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Fri, 13 Jun 2025 10:58:22 +0700 Subject: [PATCH 4/5] Make all tests for granular permission run in the pipeline --- tests/Umbraco.Tests.AcceptanceTest/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 78c09e9719ea..f2846b9d7c40 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -9,7 +9,7 @@ "testSqlite": "npx playwright test DefaultConfig --grep-invert \"Users\"", "all": "npx playwright test", "createTest": "node createTest.js", - "smokeTest": "npx playwright test DefaultConfig --grep \"@smoke\"", + "smokeTest": "npx playwright test DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent", "smokeTestSqlite": "npx playwright test DefaultConfig --grep \"@smoke\" --grep-invert \"Users\"" }, "devDependencies": { From aaa55158d0629bd7c1d96500aa8c747b084c1693 Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Fri, 13 Jun 2025 13:23:22 +0700 Subject: [PATCH 5/5] Added issue link for the failing tests --- .../GranularPermissionsInContent.spec.ts | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts index 13f026d9240d..c659eec82023 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Users/Permissions/UserGroup/GranularPermissionsInContent.spec.ts @@ -33,6 +33,7 @@ let userGroupId = null; test.beforeEach(async ({umbracoApi}) => { await umbracoApi.documentType.ensureNameNotExists(documentTypeName); await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName); + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); await umbracoApi.user.ensureNameNotExists(testUser.name); await umbracoApi.userGroup.ensureNameNotExists(userGroupName); const dataType = await umbracoApi.dataType.getByName(dataTypeName); @@ -50,6 +51,7 @@ test.afterEach(async ({umbracoApi}) => { await umbracoApi.document.ensureNameNotExists(secondDocumentName); await umbracoApi.documentType.ensureNameNotExists(documentTypeName); await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName); + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); await umbracoApi.userGroup.ensureNameNotExists(userGroupName); }); @@ -67,12 +69,11 @@ test('can read a specific document with read permission enabled', async ({umbrac // Assert await umbracoUi.content.doesDocumentHaveName(firstDocumentName); await umbracoUi.content.goToContentWithName(secondDocumentName); - await umbracoUi.content.doesErrorNotificationHaveText(NotificationConstantHelper.error.permissionDenied); + await umbracoUi.content.isErrorNotificationVisible(); }); test('can create document blueprint for a specific document with create document blueprint permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange - await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); userGroupId = await umbracoApi.userGroup.createUserGroupWithCreateDocumentBlueprintPermissionForSpecificDocument(userGroupName, firstDocumentId); await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); testUserCookieAndToken = await umbracoApi.user.loginToUser(testUser.name, testUser.email, testUser.password); @@ -88,9 +89,6 @@ test('can create document blueprint for a specific document with create document // Assert await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.documentBlueprintCreated); await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); - - // Clean - await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); }); test('can delete a specific content with delete permission enabled', async ({umbracoApi, umbracoUi}) => { @@ -185,10 +183,10 @@ test('can unpublish a specific content with unpublish permission enabled', async await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.unpublished); expect(await umbracoApi.document.isDocumentPublished(firstDocumentId)).toBeFalsy(); await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); - expect(await umbracoApi.document.isDocumentPublished(secondDocumentId)).toBeTruthy(); }); -test('can update a specific content with update permission enabled', async ({umbracoApi, umbracoUi}) => { +// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/19286 +test.skip('can update a specific content with update permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange userGroupId = await umbracoApi.userGroup.createUserGroupWithUpdatePermissionForSpecificDocument(userGroupName, firstDocumentId); await umbracoApi.user.setUserPermissions(testUser.name, testUser.email, testUser.password, userGroupId); @@ -228,7 +226,8 @@ test('can duplicate a specific content with duplicate permission enabled', async await umbracoUi.content.isPermissionInActionsMenuVisible('Duplicate to…', false); }); -test('can move a specific content with move to permission enabled', async ({umbracoApi, umbracoUi}) => { +// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/19547 +test.skip('can move a specific content with move to permission enabled', async ({umbracoApi, umbracoUi}) => { // Arrange const moveToDocumentName = 'MoveToDocument'; await umbracoApi.document.createDefaultDocumentWithParent(childDocumentName, childDocumentTypeId, firstDocumentId); @@ -249,10 +248,6 @@ test('can move a specific content with move to permission enabled', async ({umbr await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.moved); await umbracoUi.content.clickActionsMenuForContent(secondDocumentName); await umbracoUi.content.isPermissionInActionsMenuVisible('Move to…', false); - - // Clean - await umbracoApi.document.ensureNameNotExists(moveToDocumentName); - await umbracoApi.document.ensureNameNotExists(childDocumentName); }); test('can sort children with sort children permission enabled', async ({umbracoApi, umbracoUi}) => { @@ -270,9 +265,6 @@ test('can sort children with sort children permission enabled', async ({umbracoA // Assert await umbracoUi.content.isPermissionInActionsMenuVisible('Sort children…'); await umbracoUi.content.isActionsMenuForNameVisible(secondDocumentName, false); - - // Clean - await umbracoApi.document.ensureNameNotExists(childDocumentName); }); test('can set culture and hostnames for a specific content with culture and hostnames permission enabled', async ({umbracoApi, umbracoUi}) => {