diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts
index 1da0c016f0..ba6637c693 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataTypes/dataTypes.spec.ts
@@ -48,6 +48,7 @@ test.describe('DataTypes', () => {
// Save
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
await umbracoUi.isSuccessNotificationVisible();
+ await page.locator('span:has-text("×")').click();
// Assert
const expected = `
Lorem ipsum dolor sit amet
`;
@@ -158,6 +159,7 @@ test.describe('DataTypes', () => {
await umbracoUi.setEditorHeaderName('UrlPickerContent');
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
await umbracoUi.isSuccessNotificationVisible();
+ await page.locator('span:has-text("×")').click();
await page.locator('.umb-node-preview-add').click();
// Should really try and find a better way to do this, but umbracoTreeItem tries to click the content pane in the background
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts
new file mode 100644
index 0000000000..998a738e2f
--- /dev/null
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/ModelsBuilder/modelsbuilder.spec.ts
@@ -0,0 +1,283 @@
+import {AliasHelper, ApiHelpers, ConstantHelper, test, UiHelpers} from '@umbraco/playwright-testhelpers';
+import {
+ ContentBuilder,
+ DocumentTypeBuilder,
+} from "@umbraco/json-models-builders";
+
+test.describe('Modelsbuilder tests', () => {
+
+ test.beforeEach(async ({page, umbracoApi}) => {
+ await umbracoApi.login();
+ });
+
+ test('Can create and render content', async ({page, umbracoApi, umbracoUi}) => {
+ const docTypeName = "TestDocument";
+ const docTypeAlias = AliasHelper.toAlias(docTypeName);
+ const contentName = "Home";
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+
+ const docType = new DocumentTypeBuilder()
+ .withName(docTypeName)
+ .withAlias(docTypeAlias)
+ .withAllowAsRoot(true)
+ .withDefaultTemplate(docTypeAlias)
+ .addTab()
+ .withName("Content")
+ .addTextBoxProperty()
+ .withAlias("title")
+ .done()
+ .done()
+ .build();
+
+ await umbracoApi.documentTypes.save(docType);
+ await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels;
+@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
+@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
+@{
+\tLayout = null;
+}
+
+@Model.Title
`);
+
+ // Time to manually create the content
+ await umbracoUi.createContentWithDocumentType(docTypeName);
+ await umbracoUi.setEditorHeaderName(contentName);
+ // Fortunately for us the input field of a text box has the alias of the property as an id :)
+ await page.locator("#title").type("Hello world!")
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
+ await umbracoUi.isSuccessNotificationVisible();
+ // Ensure that we can render it on the frontend = we can compile the models and views
+ await umbracoApi.content.verifyRenderedContent("/", "Hello world!
", true);
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+ });
+
+ test('Can update document type without updating view', async ({page, umbracoApi, umbracoUi}) => {
+ const docTypeName = "TestDocument";
+ const docTypeAlias = AliasHelper.toAlias(docTypeName);
+ const propertyAlias = "title";
+ const propertyValue = "Hello world!"
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+
+ const docType = new DocumentTypeBuilder()
+ .withName(docTypeName)
+ .withAlias(docTypeAlias)
+ .withAllowAsRoot(true)
+ .withDefaultTemplate(docTypeAlias)
+ .addTab()
+ .withName("Content")
+ .addTextBoxProperty()
+ .withAlias(propertyAlias)
+ .done()
+ .done()
+ .build();
+
+ const savedDocType = await umbracoApi.documentTypes.save(docType);
+ await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels;
+@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
+@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
+@{
+\tLayout = null;
+}
+
+@Model.Title
`);
+
+ const content = new ContentBuilder()
+ .withContentTypeAlias(savedDocType["alias"])
+ .withAction("publishNew")
+ .addVariant()
+ .withName("Home")
+ .withSave(true)
+ .withPublish(true)
+ .addProperty()
+ .withAlias(propertyAlias)
+ .withValue(propertyValue)
+ .done()
+ .done()
+ .build()
+
+ await umbracoApi.content.save(content);
+
+ // Navigate to the document type
+ await umbracoUi.goToSection(ConstantHelper.sections.settings);
+ await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["Document Types", docTypeName]));
+ // Add a new property (this might cause a version error if the viewcache is not cleared, hence this test
+ await page.locator('.umb-box-content >> [data-element="property-add"]').click();
+ await page.locator('[data-element="property-name"]').type("Second Title");
+ await page.locator('[data-element="editor-add"]').click();
+ await page.locator('[input-id="datatype-search"]').type("Textstring");
+ await page.locator('.umb-card-grid >> [title="Textstring"]').click();
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.submit));
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
+ await umbracoUi.isSuccessNotificationVisible();
+
+ // Now that the content is updated and the models are rebuilt, ensure that we can still render the frontend.
+ await umbracoApi.content.verifyRenderedContent("/", "" + propertyValue + "
", true)
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+ });
+
+ test('Can update view without updating document type', async ({page, umbracoApi, umbracoUi}) => {
+ const docTypeName = "TestDocument";
+ const docTypeAlias = AliasHelper.toAlias(docTypeName);
+ const propertyAlias = "title";
+ const propertyValue = "Hello world!"
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+
+ const docType = new DocumentTypeBuilder()
+ .withName(docTypeName)
+ .withAlias(docTypeAlias)
+ .withAllowAsRoot(true)
+ .withDefaultTemplate(docTypeAlias)
+ .addTab()
+ .withName("Content")
+ .addTextBoxProperty()
+ .withAlias(propertyAlias)
+ .done()
+ .done()
+ .build();
+
+ const savedDocType = await umbracoApi.documentTypes.save(docType);
+ await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels;
+@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
+@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
+@{
+\tLayout = null;
+}
+
+@Model.Title
`);
+
+ const content = new ContentBuilder()
+ .withContentTypeAlias(savedDocType["alias"])
+ .withAction("publishNew")
+ .addVariant()
+ .withName("Home")
+ .withSave(true)
+ .withPublish(true)
+ .addProperty()
+ .withAlias(propertyAlias)
+ .withValue(propertyValue)
+ .done()
+ .done()
+ .build()
+
+ await umbracoApi.content.save(content);
+
+ // Navigate to the document type
+ await umbracoUi.goToSection(ConstantHelper.sections.settings);
+ await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["templates", docTypeName]));
+ const editor = await page.locator('.ace_content');
+ await editor.click();
+ // We only have to type out the opening tag, the editor adds the closing tag automatically.
+ await editor.type("Edited")
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save))
+
+ await umbracoUi.isSuccessNotificationVisible();
+ await umbracoApi.content.verifyRenderedContent("/", "
" + propertyValue + "
Edited
", true)
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+ });
+
+ test('Can update view and document type', async ({page, umbracoApi, umbracoUi}) => {
+ const docTypeName = "TestDocument";
+ const docTypeAlias = AliasHelper.toAlias(docTypeName);
+ const propertyAlias = "title";
+ const propertyValue = "Hello world!"
+ const contentName = "Home";
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName);
+
+ const docType = new DocumentTypeBuilder()
+ .withName(docTypeName)
+ .withAlias(docTypeAlias)
+ .withAllowAsRoot(true)
+ .withDefaultTemplate(docTypeAlias)
+ .addTab()
+ .withName("Content")
+ .addTextBoxProperty()
+ .withAlias(propertyAlias)
+ .done()
+ .done()
+ .build();
+
+ const savedDocType = await umbracoApi.documentTypes.save(docType);
+ await umbracoApi.templates.edit(docTypeName, `@using Umbraco.Cms.Web.Common.PublishedModels;
+@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
+@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
+@{
+\tLayout = null;
+}
+
+@Model.Title
`);
+
+ const content = new ContentBuilder()
+ .withContentTypeAlias(savedDocType["alias"])
+ .withAction("publishNew")
+ .addVariant()
+ .withName(contentName)
+ .withSave(true)
+ .withPublish(true)
+ .addProperty()
+ .withAlias(propertyAlias)
+ .withValue(propertyValue)
+ .done()
+ .done()
+ .build()
+
+ await umbracoApi.content.save(content);
+
+ // Navigate to the document type
+ await umbracoUi.goToSection(ConstantHelper.sections.settings);
+ await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["Document Types", docTypeName]));
+ // Add a new property (this might cause a version error if the viewcache is not cleared, hence this test
+ await page.locator('.umb-box-content >> [data-element="property-add"]').click();
+ await page.locator('[data-element="property-name"]').type("Bod");
+ await page.locator('[data-element="editor-add"]').click();
+ await page.locator('[input-id="datatype-search"]').type("Textstring");
+ await page.locator('.umb-card-grid >> [title="Textstring"]').click();
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.submit));
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
+ await umbracoUi.isSuccessNotificationVisible();
+ await page.locator('span:has-text("×")').click();
+
+ // Update the template
+ await umbracoUi.clickElement(umbracoUi.getTreeItem("settings", ["templates", docTypeName]));
+ const editor = await page.locator('.ace_content');
+ await editor.click();
+ // We only have to type out the opening tag, the editor adds the closing tag automatically.
+ await editor.type("@Model.Bod")
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save))
+ await umbracoUi.isSuccessNotificationVisible();
+ await page.locator('span:has-text("×")').click();
+
+ // Navigate to the content section and update the content
+ await umbracoUi.goToSection(ConstantHelper.sections.content);
+ await umbracoUi.refreshContentTree();
+ await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [contentName]));
+ await page.locator("#bod").type("Fancy body text");
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish))
+
+ await umbracoApi.content.verifyRenderedContent("/", "
" + propertyValue + "
Fancy body text
", true);
+
+ await umbracoApi.content.deleteAllContent();
+ await umbracoApi.documentTypes.ensureNameNotExists(docTypeName);
+ await umbracoApi.templates.ensureNameNotExists(docTypeName)
+ });
+});
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts
index ba91e6ba82..86eff05eec 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Packages/packages.spec.ts
@@ -88,7 +88,8 @@ test.describe('Packages', () => {
// Navigate pack to packages and Assert the file is created
// Waits until the button download is visible
- await page.locator('[label-key="general_download"]').isVisible();
+ await expect(await page.locator('[label-key="general_download"]')).toBeVisible({timeout: 60000});
+
// Checks if the packages was created
const doesExist = await umbracoApi.packages.doesNameExist(packageName);
await expect(doesExist).toBe(true);
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts
index c54907d315..895bff5366 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/macro.spec.ts
@@ -31,6 +31,7 @@ test.describe('Macros', () => {
// Adds partial view to macro
await page.locator('[data-element="property-label-macroPartialViewPickerProperty"]').click();
+
await page.locator('[data-element="tree-item-' + partialViewName + '.cshtml"]').click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts
index d1a375ef6e..e49cecde54 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/relationTypes.spec.ts
@@ -30,11 +30,9 @@ test.describe('Relation Types', () => {
await page.selectOption('select[name="relationType-child"]', {label: "Media"});
await form.locator('[name="relationType-isdependency"]').last().click({force: true});
await form.locator('.btn-primary').click();
+ await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save))
+ await umbracoUi.isSuccessNotificationVisible();
- await page.waitForNavigation();
-
- expect(page.url()).toContain("#/settings/relationTypes/edit/");
-
//Clean up
await umbracoApi.relationTypes.ensureNameNotExists(name);
});
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
index 76f030d6bc..e616f11dad 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
@@ -20,7 +20,7 @@
-
+