diff --git a/build/nightly-E2E-test-pipelines.yml b/build/nightly-E2E-test-pipelines.yml index 8ed64d6030..ba4e3d13e4 100644 --- a/build/nightly-E2E-test-pipelines.yml +++ b/build/nightly-E2E-test-pipelines.yml @@ -564,6 +564,23 @@ stages: CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient additionalEnvironmentVariables: false + # EntityDataPicker + WindowsEntityDataPicker: + vmImage: "windows-latest" + testFolder: "EntityDataPicker" + port: '' + testCommand: "npx playwright test --project=entityDataPicker" + CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True + CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient + additionalEnvironmentVariables: false + LinuxEntityDataPicker: + vmImage: "ubuntu-latest" + testFolder: "EntityDataPicker" + port: '' + testCommand: "npx playwright test --project=entityDataPicker" + CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True + CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient + additionalEnvironmentVariables: false pool: vmImage: $(vmImage) steps: diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index 86ba4e15b1..509985c5b1 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -7,7 +7,7 @@ "name": "acceptancetest", "hasInstallScript": true, "dependencies": { - "@umbraco/json-models-builders": "^2.0.41", + "@umbraco/json-models-builders": "^2.0.42", "@umbraco/playwright-testhelpers": "^17.0.6", "camelize": "^1.0.0", "dotenv": "^16.3.1", diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index ca7c4b3f6f..7528914b7d 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -22,10 +22,10 @@ "typescript": "^4.8.3" }, "dependencies": { - "@umbraco/json-models-builders": "^2.0.41", + "@umbraco/json-models-builders": "^2.0.42", "@umbraco/playwright-testhelpers": "^17.0.6", "camelize": "^1.0.0", "dotenv": "^16.3.1", "node-fetch": "^2.6.7" } -} \ No newline at end of file +} diff --git a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts index 72776856bd..f31d53bcee 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/playwright.config.ts @@ -65,6 +65,17 @@ export default defineConfig({ storageState: STORAGE_STATE } }, + { + name: 'entityDataPicker', + testMatch: 'EntityDataPicker/**/*.spec.ts', + dependencies: ['setup'], + use: { + ...devices['Desktop Chrome'], + // Use prepared auth state. + ignoreHTTPSErrors: true, + storageState: STORAGE_STATE + } + }, { name: 'deliveryApi', testMatch: 'DeliveryApi/**', diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/collection-api.js b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/collection-api.js new file mode 100644 index 0000000000..4a1f014e0d --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/collection-api.js @@ -0,0 +1,73 @@ +import {UmbControllerBase} from "@umbraco-cms/backoffice/class-api"; + +export class ExampleCustomPickerCollectionPropertyEditorDataSource extends UmbControllerBase { + collectionPickableFilter = (item) => item.isPickable; + + async requestCollection(args) { + const data = { + items: customItems, + total: customItems.length, + }; + + return {data}; + } + + async requestItems(uniques) { + const items = customItems.filter((x) => uniques.includes(x.unique)); + return {data: items}; + } + + async search(args) { + const items = customItems.filter((item) => + item.name?.toLowerCase().includes(args.query.toLowerCase()) + ); + const total = items.length; + + const data = { + items, + total, + }; + + return {data}; + } +} + +export {ExampleCustomPickerCollectionPropertyEditorDataSource as api}; + +const customItems = [ + { + unique: "1", + entityType: "example", + name: "Example 1", + icon: "icon-shape-triangle", + isPickable: true, + }, + { + unique: "2", + entityType: "example", + name: "Example 2", + icon: "icon-shape-triangle", + isPickable: true, + }, + { + unique: "3", + entityType: "example", + name: "Example 3", + icon: "icon-shape-triangle", + isPickable: true, + }, + { + unique: "4", + entityType: "example", + name: "Example 4", + icon: "icon-shape-triangle", + isPickable: false, + }, + { + unique: "5", + entityType: "example", + name: "Example 5", + icon: "icon-shape-triangle", + isPickable: true, + }, +]; diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/tree-api.js b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/tree-api.js new file mode 100644 index 0000000000..3fc7a208d9 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/tree-api.js @@ -0,0 +1,129 @@ +import {UmbControllerBase} from "@umbraco-cms/backoffice/class-api"; + +export class MyPickerDataSource extends UmbControllerBase { + treePickableFilter = (treeItem) => + !!treeItem.unique && treeItem.entityType === "example"; + + searchPickableFilter = (searchItem) => + !!searchItem.unique && searchItem.entityType === "example"; + + async requestTreeRoot() { + const root = { + unique: null, + name: "Examples", + icon: "icon-folder", + hasChildren: true, + entityType: "example-root", + isFolder: true, + }; + + return {data: root}; + } + + async requestTreeRootItems() { + const rootItems = customItems.filter((item) => item.parent.unique === null); + + const data = { + items: rootItems, + total: rootItems.length, + }; + + return {data}; + } + + async requestTreeItemsOf(args) { + const items = customItems.filter( + (item) => + item.parent.entityType === args.parent.entityType && + item.parent.unique === args.parent.unique + ); + + const data = { + items: items, + total: items.length, + }; + + return {data}; + } + + async requestTreeItemAncestors() { + // TODO: implement when needed + return {data: []}; + } + + async requestItems(uniques) { + const items = customItems.filter((x) => uniques.includes(x.unique)); + return {data: items}; + } + + async search(args) { + const result = customItems.filter((item) => + item.name.toLowerCase().includes(args.query.toLowerCase()) + ); + + const data = { + items: result, + total: result.length, + }; + + return {data}; + } +} + +export {MyPickerDataSource as api}; + +const customItems = [ + { + unique: "1", + entityType: "example", + name: "Example 1", + icon: "icon-shape-triangle", + parent: {unique: null, entityType: "example-root"}, + isFolder: false, + hasChildren: false, + }, + { + unique: "2", + entityType: "example", + name: "Example 2", + icon: "icon-shape-triangle", + parent: {unique: null, entityType: "example-root"}, + isFolder: false, + hasChildren: false, + }, + { + unique: "3", + entityType: "example", + name: "Example 3", + icon: "icon-shape-triangle", + parent: {unique: null, entityType: "example-root"}, + isFolder: false, + hasChildren: false, + }, + { + unique: "4", + entityType: "example", + name: "Example 4", + icon: "icon-shape-triangle", + parent: {unique: "6", entityType: "example-folder"}, + isFolder: false, + hasChildren: false, + }, + { + unique: "5", + entityType: "example", + name: "Example 5", + icon: "icon-shape-triangle", + parent: {unique: "6", entityType: "example-folder"}, + isFolder: false, + hasChildren: false, + }, + { + unique: "6", + entityType: "example-folder", + name: "Example Folder 1", + parent: {unique: null, entityType: "example-root"}, + isFolder: true, + hasChildren: true, + }, +]; diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/umbraco-package.json b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/umbraco-package.json new file mode 100644 index 0000000000..08cbc8163d --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/App_Plugins/picker-data-source/umbraco-package.json @@ -0,0 +1,30 @@ +{ + "name": "My Picker Data Source", + "alias": "My.PickerDataSource", + "extensions": [ + { + "type": "propertyEditorDataSource", + "dataSourceType": "Umb.DataSourceType.Picker", + "alias": "My.PickerDataSource.Tree", + "name": "My Picker Tree Data Source", + "api": "/App_Plugins/picker-data-source/tree-api.js", + "meta": { + "icon": "icon-database", + "label": "My Picker Tree Data Source", + "description": "Some description goes here" + } + }, + { + "type": "propertyEditorDataSource", + "dataSourceType": "Umb.DataSourceType.Picker", + "alias": "My.PickerDataSource.Collection", + "name": "My Picker Collection Data Source", + "api": "/App_Plugins/picker-data-source/collection-api.js", + "meta": { + "icon": "icon-database", + "label": "My Picker Collection Data Source", + "description": "Some description goes here" + } + } + ] +} diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/appsettings.json b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/appsettings.json new file mode 100644 index 0000000000..49d90bb593 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/AdditionalSetup/appsettings.json @@ -0,0 +1,58 @@ +{ + "$schema": "appsettings-schema.json", + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "System": "Warning" + } + }, + "WriteTo": [ + { + "Name": "Async", + "Args": { + "Configure": [ + { + "Name": "Console" + } + ] + } + } + ] + }, + "Umbraco": { + "CMS": { + "Unattended": { + "InstallUnattended": true, + "UnattendedUserName": "Playwright Test", + "UnattendedUserEmail": "playwright@umbraco.com", + "UnattendedUserPassword": "UmbracoAcceptance123!" + }, + "Content": { + "ContentVersionCleanupPolicy": { + "EnableCleanup": false + } + }, + "Global": { + "DisableElectionForSingleServer": true, + "InstallMissingDatabase": true, + "Id": "00000000-0000-0000-0000-000000000042", + "VersionCheckPeriod": 0, + "UseHttps": true + }, + "HealthChecks": { + "Notification": { + "Enabled": false + } + }, + "KeepAlive": { + "DisableKeepAliveTask": true + }, + "WebRouting": { + "UmbracoApplicationUrl": "https://localhost:44331/" + } + } + } +} \ No newline at end of file diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/Content/EntityPickerCollection.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/Content/EntityPickerCollection.spec.ts new file mode 100644 index 0000000000..6e03d37ab2 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/Content/EntityPickerCollection.spec.ts @@ -0,0 +1,127 @@ +import {ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers'; +import {expect} from "@playwright/test"; + +const contentName = 'TestContent'; +const documentTypeName = 'TestDocumentTypeForContent'; +const dataTypeName = 'EntityPickerWithCollection'; +const collectionDataSourceAlias = 'My.PickerDataSource.Collection'; + +test.beforeEach(async ({umbracoUi}) => { + await umbracoUi.goToBackOffice(); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.document.ensureNameNotExists(contentName); + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test('can create empty content with an entity picker using the collection data source', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Draft'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, collectionDataSourceAlias); + await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.enterContentName(contentName); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); + expect(contentData.values).toEqual([]); +}); + +test('can create content with an entity picker using the collection data source that has an item', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Draft'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, collectionDataSourceAlias); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 1'); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); + expect(contentData.values[0].value.ids[0]).toEqual('1'); +}); + +test('can create content with an entity picker using the collection data source that has multiple items', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Draft'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, collectionDataSourceAlias); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 1'); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 3'); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 5'); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); + expect(contentData.values[0].value.ids[0]).toEqual('1'); + expect(contentData.values[0].value.ids[1]).toEqual('3'); + expect(contentData.values[0].value.ids[2]).toEqual('5'); +}); + +test('can not create content with an entity picker using the collection data source that has more items than max amount', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataTypeWithMinAndMaxValues(dataTypeName, collectionDataSourceAlias, 0, 2); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 1'); + await umbracoUi.content.isChooseButtonVisible(true); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 3'); + + // Assert + // The choose button should be disabled when the max amount is reached + await umbracoUi.content.isChooseButtonVisible(false); +}); + +test('can not create content with an entity picker using the collection data source that has less items than min amount', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Published'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataTypeWithMinAndMaxValues(dataTypeName, collectionDataSourceAlias, 2, 5); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 1'); + await umbracoUi.content.isTextWithExactNameVisible('This field need more items'); + await umbracoUi.content.clickSaveAndPublishButton(); + await umbracoUi.content.doesErrorNotificationHaveText(NotificationConstantHelper.error.documentCouldNotBePublished); + await umbracoUi.content.chooseCollectionMenuItemWithName('Example 3'); + + // Assert + await umbracoUi.content.clickSaveAndPublishButton(); + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); +}); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/Content/EntityPickerTree.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/Content/EntityPickerTree.spec.ts new file mode 100644 index 0000000000..494974c511 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/Content/EntityPickerTree.spec.ts @@ -0,0 +1,127 @@ +import {ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers'; +import {expect} from "@playwright/test"; + +const contentName = 'TestContent'; +const documentTypeName = 'TestDocumentTypeForContent'; +const dataTypeName = 'EntityPickerWithTree'; +const treeDataSourceAlias = 'My.PickerDataSource.Tree'; + +test.beforeEach(async ({umbracoUi}) => { + await umbracoUi.goToBackOffice(); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.document.ensureNameNotExists(contentName); + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test('can create empty content with an entity picker using the tree data source', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Draft'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, treeDataSourceAlias); + await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.enterContentName(contentName); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); + expect(contentData.values).toEqual([]); +}); + +test('can create content with an entity picker using the tree data source that has an item', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Draft'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, treeDataSourceAlias); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 1'); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); + expect(contentData.values[0].value.ids[0]).toEqual('1'); +}); + +test('can create content with an entity picker using the tree data source that has multiple items', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Draft'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, treeDataSourceAlias); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 1'); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 3'); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 5', ['Example Folder 1']); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); + expect(contentData.values[0].value.ids[0]).toEqual('1'); + expect(contentData.values[0].value.ids[1]).toEqual('3'); + expect(contentData.values[0].value.ids[2]).toEqual('5'); +}); + +test('can not create content with an entity picker using the tree data source that has more items than max amount', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataTypeWithMinAndMaxValues(dataTypeName, treeDataSourceAlias, 0, 2); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 1'); + await umbracoUi.content.isChooseButtonVisible(true); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 5', ['Example Folder 1']); + + // Assert + // The choose button should be disabled when the max amount is reached + await umbracoUi.content.isChooseButtonVisible(false); +}); + +test('can not create content with an entity picker using the tree data source that has less items than min amount', async ({umbracoApi, umbracoUi}) => { + // Arrange + const expectedState = 'Published'; + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataTypeWithMinAndMaxValues(dataTypeName, treeDataSourceAlias, 2, 5); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId); + await umbracoApi.document.createDefaultDocument(contentName, documentTypeId); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.goToContentWithName(contentName); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 1'); + await umbracoUi.content.isTextWithExactNameVisible('This field need more items'); + await umbracoUi.content.clickSaveAndPublishButton(); + await umbracoUi.content.doesErrorNotificationHaveText(NotificationConstantHelper.error.documentCouldNotBePublished); + await umbracoUi.content.chooseTreeMenuItemWithName('Example 5', ['Example Folder 1']); + + // Assert + await umbracoUi.content.clickSaveAndPublishButton(); + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.variants[0].state).toBe(expectedState); +}); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/DataType/EntityPickerCollection.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/DataType/EntityPickerCollection.spec.ts new file mode 100644 index 0000000000..1096ebdb4f --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/DataType/EntityPickerCollection.spec.ts @@ -0,0 +1,33 @@ +import {ConstantHelper, test} from '@umbraco/playwright-testhelpers'; +import {expect} from "@playwright/test"; + +const dataTypeName = 'EntityPickerWithCollection'; + +test.beforeEach(async ({umbracoUi, umbracoApi}) => { + await umbracoUi.goToBackOffice(); + await umbracoUi.dataType.goToSection(ConstantHelper.sections.settings); + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test('can create an entity picker data type with the collection data source', async ({umbracoApi, umbracoUi}) => { + // Act + await umbracoUi.dataType.clickActionsMenuForName('Data Types'); + await umbracoUi.dataType.clickCreateActionMenuOption(); + await umbracoUi.dataType.clickDataTypeButton(); + await umbracoUi.dataType.enterDataTypeName(dataTypeName); + await umbracoUi.dataType.clickSelectAPropertyEditorButton(); + await umbracoUi.dataType.selectAPropertyEditor('Entity Data Picker'); + await umbracoUi.dataType.clickChooseDataSourceButton(); + await umbracoUi.dataType.clickButtonWithName('My Picker Collection Data Source'); + await umbracoUi.dataType.clickChooseModalButton(); + await umbracoUi.dataType.clickSaveButton(); + + // Assert + await umbracoUi.dataType.waitForDataTypeToBeCreated(); + await umbracoUi.dataType.isDataTypeTreeItemVisible(dataTypeName); + expect(await umbracoApi.dataType.doesNameExist(dataTypeName)).toBeTruthy(); +}); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/DataType/EntityPickerTree.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/DataType/EntityPickerTree.spec.ts new file mode 100644 index 0000000000..90c04b5e95 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/DataType/EntityPickerTree.spec.ts @@ -0,0 +1,33 @@ +import {ConstantHelper, test} from '@umbraco/playwright-testhelpers'; +import {expect} from "@playwright/test"; + +const dataTypeName = 'EntityPickerWithTree'; + +test.beforeEach(async ({umbracoUi, umbracoApi}) => { + await umbracoUi.goToBackOffice(); + await umbracoUi.dataType.goToSection(ConstantHelper.sections.settings); + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test('can create an entity picker data type with tree data source', async ({umbracoApi, umbracoUi}) => { + // Act + await umbracoUi.dataType.clickActionsMenuForName('Data Types'); + await umbracoUi.dataType.clickCreateActionMenuOption(); + await umbracoUi.dataType.clickDataTypeButton(); + await umbracoUi.dataType.enterDataTypeName(dataTypeName); + await umbracoUi.dataType.clickSelectAPropertyEditorButton(); + await umbracoUi.dataType.selectAPropertyEditor('Entity Data Picker'); + await umbracoUi.dataType.clickChooseDataSourceButton(); + await umbracoUi.dataType.clickButtonWithName('My Picker Tree Data Source'); + await umbracoUi.dataType.clickChooseModalButton(); + await umbracoUi.dataType.clickSaveButton(); + + // Assert + await umbracoUi.dataType.waitForDataTypeToBeCreated(); + await umbracoUi.dataType.isDataTypeTreeItemVisible(dataTypeName); + expect(await umbracoApi.dataType.doesNameExist(dataTypeName)).toBeTruthy(); +}); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/RenderedContent/EntityPickerCollection.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/RenderedContent/EntityPickerCollection.spec.ts new file mode 100644 index 0000000000..824d22b1d2 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/RenderedContent/EntityPickerCollection.spec.ts @@ -0,0 +1,39 @@ +import {AliasHelper, test} from '@umbraco/playwright-testhelpers'; + +const contentName = 'TestContent'; +const documentTypeName = 'TestDocumentTypeForContent'; +const templateName = 'EntityPickerCollectionTemplate'; +const dataTypeName = 'EntityPickerWithCollection'; +const propertyName = 'TestProperty'; +const collectionDataSourceAlias = 'My.PickerDataSource.Collection'; + +// Ids for Example 4 and Example 2 +const items = {ids: ['4', '2']}; + +test.beforeEach(async ({umbracoUi}) => { + await umbracoUi.goToBackOffice(); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.document.ensureNameNotExists(contentName); + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.template.ensureNameNotExists(templateName); + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test('can render content with an entity picker using the collection data source', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, collectionDataSourceAlias); + const templateId = await umbracoApi.template.createTemplateWithEntityDataPickerValue(templateName, propertyName); + const contentKey = await umbracoApi.document.createPublishedDocumentWithValue(contentName, items, dataTypeId, templateId, propertyName, documentTypeName); + const contentURL = await umbracoApi.document.getDocumentUrl(contentKey); + + // Act + await umbracoUi.contentRender.navigateToRenderedContentPage(contentURL); + + // Assert + await umbracoUi.contentRender.doesDataSourceRenderValueHaveText(collectionDataSourceAlias); + for (const value of items.ids) { + await umbracoUi.contentRender.doesContentRenderValueContainText(value); + } +}); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/RenderedContent/EntityPickerTree.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/RenderedContent/EntityPickerTree.spec.ts new file mode 100644 index 0000000000..192a0f8dd3 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/EntityDataPicker/RenderedContent/EntityPickerTree.spec.ts @@ -0,0 +1,39 @@ +import {AliasHelper, test} from '@umbraco/playwright-testhelpers'; + +const contentName = 'TestContent'; +const documentTypeName = 'TestDocumentTypeForContent'; +const templateName = 'EntityPickerTreeTemplate'; +const dataTypeName = 'EntityPickerWithTree'; +const propertyName = 'TestProperty'; +const treeDataSourceAlias = 'My.PickerDataSource.Tree'; + +// Ids for Example 4 and Example 2 +const items = {ids: ['4', '2']}; + +test.beforeEach(async ({umbracoUi}) => { + await umbracoUi.goToBackOffice(); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.document.ensureNameNotExists(contentName); + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.template.ensureNameNotExists(templateName); + await umbracoApi.dataType.ensureNameNotExists(dataTypeName); +}); + +test('can render content with an entity picker using the tree data source', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeId = await umbracoApi.dataType.createEntityDataPickerDataType(dataTypeName, treeDataSourceAlias); + const templateId = await umbracoApi.template.createTemplateWithEntityDataPickerValue(templateName, propertyName); + const contentKey = await umbracoApi.document.createPublishedDocumentWithValue(contentName, items, dataTypeId, templateId, propertyName, documentTypeName); + const contentURL = await umbracoApi.document.getDocumentUrl(contentKey); + + // Act + await umbracoUi.contentRender.navigateToRenderedContentPage(contentURL); + + // Assert + await umbracoUi.contentRender.doesDataSourceRenderValueHaveText(treeDataSourceAlias); + for (const value of items.ids) { + await umbracoUi.contentRender.doesContentRenderValueContainText(value); + } +});