diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index ecf10b8854..0681900d88 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -4,11 +4,11 @@ contact_links:
url: https://github.com/umbraco/Umbraco-CMS/discussions/new?category=features-and-ideas
about: Start a new discussion when you have ideas or feature requests, eventually discussions can turn into plans
- name: ⁉️ Support Question
- url: https://our.umbraco.com
+ url: https://forum.umbraco.com
about: This issue tracker is NOT meant for support questions. If you have a question, please join us on the forum.
- name: 📖 Documentation Issue
url: https://github.com/umbraco/UmbracoDocs/issues
about: Documentation issues should be reported on the Umbraco documentation repository.
- name: 🔐 Security Issue
- url: https://umbraco.com/about-us/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
+ url: https://umbraco.com/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
about: Discovered a Security Issue in Umbraco?
diff --git a/.github/README.md b/.github/README.md
index f4e3f76009..63b908daed 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -4,8 +4,8 @@
[](https://www.nuget.org/packages/Umbraco.Cms)
[](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=301)
[](CONTRIBUTING.md)
+[](https://forum.umbraco.com)
[](https://discord.gg/umbraco)
-[](https://discord-chats.umbraco.com)

diff --git a/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj b/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj
index d6fbf7ab37..3193533266 100644
--- a/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj
+++ b/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj
@@ -26,23 +26,36 @@
-
+
+
+
+
+
+
+
+
..\Umbraco.Web.UI.Client\
- wwwroot\umbraco\backoffice
+ $(ProjectDir)wwwroot\umbraco\backoffice
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
@@ -61,27 +74,46 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
..\Umbraco.Web.UI.Login\
- wwwroot\umbraco\login
+ $(ProjectDir)wwwroot\umbraco\login
-
-
-
-
+
+
+
+
+
+
-
+
-
+
@@ -99,4 +131,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/ContentWithTiptap.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/ContentWithTiptap.spec.ts
index 4bc167f795..d08ca78c3b 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/ContentWithTiptap.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/ContentWithTiptap.spec.ts
@@ -1,27 +1,40 @@
-import {ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers';
-import {expect} from "@playwright/test";
+import {
+ ConstantHelper,
+ NotificationConstantHelper,
+ test,
+} from "@umbraco/playwright-testhelpers";
+import { expect } from "@playwright/test";
-const contentName = 'TestContent';
-const documentTypeName = 'TestDocumentTypeForContent';
-const customDataTypeName = 'Test RTE Tiptap';
+const contentName = "TestContent";
+const documentTypeName = "TestDocumentTypeForContent";
+const customDataTypeName = "Test RTE Tiptap";
let customDataTypeId = null;
-test.beforeEach(async ({umbracoApi}) => {
- customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(customDataTypeName);
+test.beforeEach(async ({ umbracoApi }) => {
+ customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(
+ customDataTypeName
+ );
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
await umbracoApi.document.ensureNameNotExists(contentName);
});
-test.afterEach(async ({umbracoApi}) => {
+test.afterEach(async ({ umbracoApi }) => {
await umbracoApi.document.ensureNameNotExists(contentName);
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
await umbracoApi.dataType.ensureNameNotExists(customDataTypeName);
});
-test('can create content with empty RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test("can create content with empty RTE Tiptap property editor", async ({
+ umbracoApi,
+ umbracoUi,
+}) => {
// Arrange
- const expectedState = 'Draft';
- await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const expectedState = "Draft";
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -41,11 +54,18 @@ test('can create content with empty RTE Tiptap property editor', async ({umbraco
expect(contentData.values).toEqual([]);
});
-test('can create content with non-empty RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test("can create content with non-empty RTE Tiptap property editor", async ({
+ umbracoApi,
+ umbracoUi,
+}) => {
// Arrange
- const expectedState = 'Draft';
- const inputText = 'Test Tiptap here';
- await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const expectedState = "Draft";
+ const inputText = "Test Tiptap here";
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -63,14 +83,24 @@ test('can create content with non-empty RTE Tiptap property editor', async ({umb
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.markup).toEqual('' + inputText + '
');
+ expect(contentData.values[0].value.markup).toEqual(
+ "" + inputText + "
"
+ );
});
-test('can publish content with RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test("can publish content with RTE Tiptap property editor", async ({
+ umbracoApi,
+ umbracoUi,
+}) => {
// Arrange
- const expectedState = 'Published';
- const inputText = 'Test Tiptap here';
- const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const expectedState = "Published";
+ const inputText = "Test Tiptap here";
+ const documentTypeId =
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -81,51 +111,72 @@ test('can publish content with RTE Tiptap property editor', async ({umbracoApi,
await umbracoUi.content.clickSaveAndPublishButton();
// Assert
- //await umbracoUi.content.doesSuccessNotificationsHaveCount(2);
+ //await umbracoUi.content.doesSuccessNotificationsHaveCount(2);
await umbracoUi.content.isErrorNotificationVisible(false);
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.markup).toEqual('' + inputText + '
');
+ expect(contentData.values[0].value.markup).toEqual(
+ "" + inputText + "
"
+ );
});
-test.fixme('can add a media in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test.fixme(
+ "can add a media in RTE Tiptap property editor",
+ async ({ umbracoApi, umbracoUi }) => {
+ // Arrange
+ const iconTitle = "Media Picker";
+ const imageName = "Test Image For Content";
+ await umbracoApi.media.ensureNameNotExists(imageName);
+ await umbracoApi.media.createDefaultMediaWithImage(imageName);
+ const documentTypeId =
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
+ await umbracoApi.document.createDefaultDocument(
+ contentName,
+ documentTypeId
+ );
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
+ // fix this
+ await umbracoUi.content.selectMediaWithName(imageName);
+ await umbracoUi.content.clickChooseModalButton();
+ await umbracoUi.content.clickMediaCaptionAltTextModalSubmitButton();
+ await umbracoUi.content.clickSaveButton();
+
+ // Assert
+ //await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
+ await umbracoUi.content.isErrorNotificationVisible(false);
+ expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy();
+ const contentData = await umbracoApi.document.getByName(contentName);
+ expect(contentData.values[0].value.markup).toContain("
{
// Arrange
- const iconTitle = 'Media Picker';
- const imageName = 'Test Image For Content';
- await umbracoApi.media.ensureNameNotExists(imageName);
- await umbracoApi.media.createDefaultMediaWithImage(imageName);
- const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
- await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
- await umbracoUi.goToBackOffice();
- await umbracoUi.content.goToSection(ConstantHelper.sections.content);
-
- // Act
- await umbracoUi.content.goToContentWithName(contentName);
- await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
- // fix this
- await umbracoUi.content.selectMediaWithName(imageName);
- await umbracoUi.content.clickChooseModalButton();
- await umbracoUi.content.clickMediaCaptionAltTextModalSubmitButton();
- await umbracoUi.content.clickSaveButton();
-
- // Assert
- //await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
- await umbracoUi.content.isErrorNotificationVisible(false);
- expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy();
- const contentData = await umbracoApi.document.getByName(contentName);
- expect(contentData.values[0].value.markup).toContain('
{
- // Arrange
- const iconTitle = 'Embed';
- const videoURL = 'https://www.youtube.com/watch?v=Yu29dE-0OoI';
- const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const iconTitle = "Embed";
+ const videoURL = "https://www.youtube.com/watch?v=Yu29dE-0OoI";
+ const documentTypeId =
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -144,14 +195,22 @@ test('can add a video in RTE Tiptap property editor', async ({umbracoApi, umbrac
await umbracoUi.content.isErrorNotificationVisible(false);
expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy();
const contentData = await umbracoApi.document.getByName(contentName);
- expect(contentData.values[0].value.markup).toContain('data-embed-url');
+ expect(contentData.values[0].value.markup).toContain("data-embed-url");
expect(contentData.values[0].value.markup).toContain(videoURL);
});
-test('cannot submit an empty link in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test("cannot submit an empty link in RTE Tiptap property editor", async ({
+ umbracoApi,
+ umbracoUi,
+}) => {
// Arrange
- const iconTitle = 'Link';
- const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const iconTitle = "Link";
+ const documentTypeId =
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -160,21 +219,31 @@ test('cannot submit an empty link in RTE Tiptap property editor', async ({umbrac
await umbracoUi.content.goToContentWithName(contentName);
await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
await umbracoUi.content.clickManualLinkButton();
- await umbracoUi.content.enterLink('');
- await umbracoUi.content.enterAnchorOrQuerystring('');
- await umbracoUi.content.enterLinkTitle('');
+ await umbracoUi.content.enterLink("");
+ await umbracoUi.content.enterAnchorOrQuerystring("");
+ await umbracoUi.content.enterLinkTitle("");
await umbracoUi.content.clickAddButton();
// Assert
- await umbracoUi.content.isTextWithMessageVisible(ConstantHelper.validationMessages.emptyLinkPicker);
+ await umbracoUi.content.isTextWithMessageVisible(
+ ConstantHelper.validationMessages.emptyLinkPicker
+ );
});
// TODO: Remove skip when the front-end ready. Currently it still accept the empty link with an anchor or querystring
// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/17411
-test.skip('cannot submit an empty URL with an anchor or querystring in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test.skip("cannot submit an empty URL with an anchor or querystring in RTE Tiptap property editor", async ({
+ umbracoApi,
+ umbracoUi,
+}) => {
// Arrange
- const iconTitle = 'Link';
- const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const iconTitle = "Link";
+ const documentTypeId =
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -183,26 +252,42 @@ test.skip('cannot submit an empty URL with an anchor or querystring in RTE Tipta
await umbracoUi.content.goToContentWithName(contentName);
await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
await umbracoUi.content.clickManualLinkButton();
- await umbracoUi.content.enterLink('');
- await umbracoUi.content.enterAnchorOrQuerystring('#value');
+ await umbracoUi.content.enterLink("");
+ await umbracoUi.content.enterAnchorOrQuerystring("#value");
await umbracoUi.content.clickAddButton();
// Assert
- await umbracoUi.content.isTextWithMessageVisible(ConstantHelper.validationMessages.emptyLinkPicker);
+ await umbracoUi.content.isTextWithMessageVisible(
+ ConstantHelper.validationMessages.emptyLinkPicker
+ );
});
// TODO: Remove skip when the front-end ready. Currently it is impossible to link to unpublished document
// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/17974
-test.skip('can insert a link to an unpublished document in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+test.skip("can insert a link to an unpublished document in RTE Tiptap property editor", async ({
+ umbracoApi,
+ umbracoUi,
+}) => {
// Arrange
- const iconTitle = 'Link';
- const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ const iconTitle = "Link";
+ const documentTypeId =
+ await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(
+ documentTypeName,
+ customDataTypeName,
+ customDataTypeId
+ );
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
// Create a document to link
- const documentTypeForLinkedDocumentName = 'TestDocumentType';
- const documentTypeForLinkedDocumentId = await umbracoApi.documentType.createDefaultDocumentTypeWithAllowAsRoot(documentTypeForLinkedDocumentName);
- const linkedDocumentName = 'LinkedDocument';
- await umbracoApi.document.createDefaultDocument(linkedDocumentName, documentTypeForLinkedDocumentId);
+ const documentTypeForLinkedDocumentName = "TestDocumentType";
+ const documentTypeForLinkedDocumentId =
+ await umbracoApi.documentType.createDefaultDocumentTypeWithAllowAsRoot(
+ documentTypeForLinkedDocumentName
+ );
+ const linkedDocumentName = "LinkedDocument";
+ await umbracoApi.document.createDefaultDocument(
+ linkedDocumentName,
+ documentTypeForLinkedDocumentId
+ );
await umbracoUi.goToBackOffice();
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
@@ -211,7 +296,7 @@ test.skip('can insert a link to an unpublished document in RTE Tiptap property e
await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
await umbracoUi.content.clickDocumentLinkButton();
await umbracoUi.content.selectLinkByName(linkedDocumentName);
- await umbracoUi.content.clickButtonWithName('Choose');
+ await umbracoUi.content.clickButtonWithName("Choose");
await umbracoUi.content.clickAddButton();
await umbracoUi.content.clickSaveButton();
@@ -220,6 +305,8 @@ test.skip('can insert a link to an unpublished document in RTE Tiptap property e
await umbracoUi.content.isErrorNotificationVisible(false);
// Clean
- await umbracoApi.documentType.ensureNameNotExists(documentTypeForLinkedDocumentName);
+ await umbracoApi.documentType.ensureNameNotExists(
+ documentTypeForLinkedDocumentName
+ );
await umbracoApi.document.ensureNameNotExists(linkedDocumentName);
-});
\ No newline at end of file
+});
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/TiptapToolbar.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/TiptapToolbar.spec.ts
new file mode 100644
index 0000000000..3f4cf6d572
--- /dev/null
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/RichTextEditor/TiptapToolbar.spec.ts
@@ -0,0 +1,190 @@
+import {ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers';
+import {expect} from "@playwright/test";
+
+const contentName = 'TestContent';
+const documentTypeName = 'TestDocumentTypeForContent';
+const customDataTypeName = 'Test RTE Tiptap';
+
+test.beforeEach(async ({umbracoApi}) => {
+ await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
+ await umbracoApi.document.ensureNameNotExists(contentName);
+});
+
+test.afterEach(async ({umbracoApi}) => {
+ await umbracoApi.document.ensureNameNotExists(contentName);
+ await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
+ await umbracoApi.dataType.ensureNameNotExists(customDataTypeName);
+});
+
+test('can add a media in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const iconTitle = 'Media Picker';
+ const imageName = 'Test Image For Content';
+ await umbracoApi.media.ensureNameNotExists(imageName);
+ await umbracoApi.media.createDefaultMediaWithImage(imageName);
+ const customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
+ await umbracoUi.content.selectMediaWithName(imageName);
+ await umbracoUi.content.clickChooseModalButton();
+ await umbracoUi.content.clickMediaCaptionAltTextModalSubmitButton();
+ await umbracoUi.content.clickSaveAndPublishButton();
+
+ // Assert
+ await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
+ await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
+ expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy();
+ const contentData = await umbracoApi.document.getByName(contentName);
+ expect(contentData.values[0].value.markup).toContain('
{
+ // Arrange
+ const iconTitle = 'Embed';
+ const videoURL = 'https://www.youtube.com/watch?v=Yu29dE-0OoI';
+ const customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
+ await umbracoUi.content.enterEmbeddedURL(videoURL);
+ await umbracoUi.content.clickEmbeddedRetrieveButton();
+ await umbracoUi.content.waitForEmbeddedPreviewVisible();
+ await umbracoUi.content.clickEmbeddedMediaModalConfirmButton();
+ await umbracoUi.content.clickSaveButton();
+
+ // Assert
+ await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
+ expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy();
+ const contentData = await umbracoApi.document.getByName(contentName);
+ expect(contentData.values[0].value.markup).toContain('data-embed-url');
+ expect(contentData.values[0].value.markup).toContain(videoURL);
+});
+
+test('cannot submit an empty link in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const iconTitle = 'Link';
+ const customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
+ await umbracoUi.content.clickManualLinkButton();
+ await umbracoUi.content.enterLink('');
+ await umbracoUi.content.enterAnchorOrQuerystring('');
+ await umbracoUi.content.enterLinkTitle('');
+ await umbracoUi.content.clickAddButton();
+
+ // Assert
+ await umbracoUi.content.isTextWithMessageVisible(ConstantHelper.validationMessages.emptyLinkPicker);
+});
+
+// TODO: Remove skip when the front-end ready. Currently it still accept the empty link with an anchor or querystring
+// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/17411
+test.skip('cannot submit an empty URL with an anchor or querystring in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const iconTitle = 'Link';
+ const customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
+ await umbracoUi.content.clickManualLinkButton();
+ await umbracoUi.content.enterLink('');
+ await umbracoUi.content.enterAnchorOrQuerystring('#value');
+ await umbracoUi.content.clickAddButton();
+
+ // Assert
+ await umbracoUi.content.isTextWithMessageVisible(ConstantHelper.validationMessages.emptyLinkPicker);
+});
+
+// TODO: Remove skip when the front-end ready. Currently it is impossible to link to unpublished document
+// Issue link: https://github.com/umbraco/Umbraco-CMS/issues/17974
+test.skip('can insert a link to an unpublished document in RTE Tiptap property editor', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const iconTitle = 'Link';
+ const customDataTypeId = await umbracoApi.dataType.createDefaultTiptapDataType(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ // Create a document to link
+ const documentTypeForLinkedDocumentName = 'TestDocumentType';
+ const documentTypeForLinkedDocumentId = await umbracoApi.documentType.createDefaultDocumentTypeWithAllowAsRoot(documentTypeForLinkedDocumentName);
+ const linkedDocumentName = 'LinkedDocument';
+ await umbracoApi.document.createDefaultDocument(linkedDocumentName, documentTypeForLinkedDocumentId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.clickTipTapToolbarIconWithTitle(iconTitle);
+ await umbracoUi.content.clickDocumentLinkButton();
+ await umbracoUi.content.selectLinkByName(linkedDocumentName);
+ await umbracoUi.content.clickButtonWithName('Choose');
+ await umbracoUi.content.clickAddButton();
+ await umbracoUi.content.clickSaveButton();
+
+ // Assert
+ await umbracoUi.content.isSuccessNotificationVisible();
+
+ // Clean
+ await umbracoApi.documentType.ensureNameNotExists(documentTypeForLinkedDocumentName);
+ await umbracoApi.document.ensureNameNotExists(linkedDocumentName);
+});
+
+test('can view word count', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const inputText = 'Test Tiptap here!!!';
+ const expectedWordCount = 3;
+ const customDataTypeId = await umbracoApi.dataType.createTiptapDataTypeWithWordCountStatusbar(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.enterRTETipTapEditor(inputText);
+
+ // Assert
+ await umbracoUi.content.doesTiptapHaveWordCount(expectedWordCount);
+});
+
+test('can view element path', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const inputText = 'This is Tiptap test';
+ const expectedElementPath = 'p';
+ const customDataTypeId = await umbracoApi.dataType.createTiptapDataTypeWithElementPathStatusbar(customDataTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, customDataTypeName, customDataTypeId);
+ await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.enterRTETipTapEditor(inputText);
+
+ // Assert
+ await umbracoUi.content.doesElementPathHaveText(expectedElementPath);
+});
\ No newline at end of file
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent/BulkTrashContent.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent/BulkTrashContent.spec.ts
new file mode 100644
index 0000000000..957c330e65
--- /dev/null
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent/BulkTrashContent.spec.ts
@@ -0,0 +1,93 @@
+import {ConstantHelper, test} from '@umbraco/playwright-testhelpers';
+import {expect} from "@playwright/test";
+
+let collectionId = '';
+const contentName = 'TestContent';
+const documentTypeName = 'TestDocumentTypeForContent';
+const childDocumentTypeName = 'TestChildDocumentType';
+const firstChildContentName = 'First Child Content';
+const secondChildContentName = 'Second Child Content';
+const collectionDataTypeName = 'List View - Content';
+const referenceHeadline = ConstantHelper.trashDeleteDialogMessage.bulkReferenceHeadline;
+const documentPickerName = ['TestPicker', 'DocumentTypeForPicker'];
+
+test.beforeEach(async ({umbracoApi}) => {
+ await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
+ await umbracoApi.document.ensureNameNotExists(contentName);
+ const collectionDataTypeData = await umbracoApi.dataType.getByName(collectionDataTypeName);
+ collectionId = collectionDataTypeData.id;
+});
+
+test.afterEach(async ({umbracoApi}) => {
+ await umbracoApi.document.ensureNameNotExists(contentName);
+ await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
+ await umbracoApi.documentType.ensureNameNotExists(childDocumentTypeName);
+ await umbracoApi.document.emptyRecycleBin();
+});
+
+test('can bulk trash content nodes without a relation', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const childDocumentTypeId = await umbracoApi.documentType.createDefaultDocumentType(childDocumentTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithAllowedChildNodeAndCollectionId(documentTypeName, childDocumentTypeId, collectionId);
+ const contentId = await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoApi.document.createDefaultDocumentWithParent(firstChildContentName, childDocumentTypeId, contentId);
+ await umbracoApi.document.createDefaultDocumentWithParent(secondChildContentName, childDocumentTypeId, contentId);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.selectContentWithNameInListView(firstChildContentName);
+ await umbracoUi.content.selectContentWithNameInListView(secondChildContentName);
+ await umbracoUi.content.clickTrashSelectedListItems();
+ // Verify the references list not displayed
+ await umbracoUi.content.isReferenceHeadlineVisible(false);
+ await umbracoUi.content.clickConfirmTrashButton();
+
+ // // Assert
+ await umbracoUi.content.isSuccessNotificationVisible();
+ expect(await umbracoApi.document.doesNameExist(firstChildContentName)).toBeFalsy();
+ expect(await umbracoApi.document.doesNameExist(secondChildContentName)).toBeFalsy();
+ await umbracoUi.content.isItemVisibleInRecycleBin(firstChildContentName);
+ await umbracoUi.content.isItemVisibleInRecycleBin(secondChildContentName);
+ expect(await umbracoApi.document.doesItemExistInRecycleBin(firstChildContentName)).toBeTruthy();
+ expect(await umbracoApi.document.doesItemExistInRecycleBin(secondChildContentName)).toBeTruthy();
+});
+
+test('can bulk trash content nodes with a relation', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const childDocumentTypeId = await umbracoApi.documentType.createDefaultDocumentType(childDocumentTypeName);
+ const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithAllowedChildNodeAndCollectionId(documentTypeName, childDocumentTypeId, collectionId);
+ const contentId = await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
+ await umbracoApi.document.publish(contentId);
+ const firstChildContentId = await umbracoApi.document.createDefaultDocumentWithParent(firstChildContentName, childDocumentTypeId, contentId);
+ await umbracoApi.document.publish(firstChildContentId);
+ await umbracoApi.document.createDefaultDocumentWithParent(secondChildContentName, childDocumentTypeId, contentId);
+ // Create a document that has a document picker with firstChildContentName
+ await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName[0], firstChildContentName, firstChildContentId, documentPickerName[1]);
+ await umbracoUi.goToBackOffice();
+ await umbracoUi.content.goToSection(ConstantHelper.sections.content);
+
+ // Act
+ await umbracoUi.content.goToContentWithName(contentName);
+ await umbracoUi.content.selectContentWithNameInListView(firstChildContentName);
+ await umbracoUi.content.selectContentWithNameInListView(secondChildContentName);
+ await umbracoUi.content.clickTrashSelectedListItems();
+ // Verify the references list
+ await umbracoUi.content.doesReferenceHeadlineHaveText(referenceHeadline);
+ await umbracoUi.content.doesReferenceItemsHaveCount(1);
+ await umbracoUi.content.isReferenceItemNameVisible(firstChildContentName);
+ await umbracoUi.content.clickConfirmTrashButton();
+
+ // // Assert
+ await umbracoUi.content.isSuccessNotificationVisible();
+ expect(await umbracoApi.document.doesNameExist(firstChildContentName)).toBeFalsy();
+ expect(await umbracoApi.document.doesNameExist(secondChildContentName)).toBeFalsy();
+ await umbracoUi.content.isItemVisibleInRecycleBin(firstChildContentName);
+ await umbracoUi.content.isItemVisibleInRecycleBin(secondChildContentName);
+ expect(await umbracoApi.document.doesItemExistInRecycleBin(firstChildContentName)).toBeTruthy();
+ expect(await umbracoApi.document.doesItemExistInRecycleBin(secondChildContentName)).toBeTruthy();
+
+ // Clean
+ await umbracoApi.documentType.ensureNameNotExists(documentPickerName[1]);
+});
\ No newline at end of file
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent/TrashContent.spec.ts
similarity index 99%
rename from tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent.spec.ts
rename to tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent/TrashContent.spec.ts
index c008ea38ba..4214ff691a 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/TrashContent/TrashContent.spec.ts
@@ -6,7 +6,7 @@ const contentName = 'TestContent';
const documentTypeName = 'TestDocumentTypeForContent';
const dataTypeName = 'Textstring';
const contentText = 'This is test content text';
-const referenceHeadline = 'The following items depend on this';
+const referenceHeadline = ConstantHelper.trashDeleteDialogMessage.referenceHeadline;
const documentPickerName = ['TestPicker', 'DocumentTypeForPicker'];
test.beforeEach(async ({umbracoApi}) => {
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/RichTextEditor.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/RichTextEditor.spec.ts
index 62b8dc3928..2660e106d0 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/RichTextEditor.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/RichTextEditor.spec.ts
@@ -61,8 +61,8 @@ test('tiptap is the default property editor in rich text editor', async ({umbrac
await umbracoUi.dataType.goToDataType(dataTypeName);
// Assert
- //await umbracoUi.dataType.doesSettingHaveValue(ConstantHelper.tipTapSettings);
- //await umbracoUi.dataType.doesSettingItemsHaveCount(ConstantHelper.tipTapSettings);
+ await umbracoUi.dataType.doesSettingHaveValue(ConstantHelper.tipTapSettings);
+ await umbracoUi.dataType.doesSettingItemsHaveCount(ConstantHelper.tipTapSettings);
await umbracoUi.dataType.doesPropertyEditorHaveName(tipTapPropertyEditorName);
await umbracoUi.dataType.doesPropertyEditorHaveAlias(tipTapAlias);
await umbracoUi.dataType.doesPropertyEditorHaveUiAlias(tipTapUiAlias);
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/Tiptap.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/Tiptap.spec.ts
index ceb6231434..f502a878d0 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/Tiptap.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/Tiptap.spec.ts
@@ -127,6 +127,7 @@ test('can add an available block', async ({umbracoApi, umbracoUi}) => {
await umbracoUi.dataType.goToDataType(tipTapName);
// Act
+ await umbracoUi.dataType.isExtensionItemChecked('Block', false);
await umbracoUi.dataType.addAvailableBlocks(elementTypeName);
await umbracoUi.dataType.clickSaveButton();
@@ -134,6 +135,8 @@ test('can add an available block', async ({umbracoApi, umbracoUi}) => {
//await umbracoUi.dataType.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
await umbracoUi.dataType.isErrorNotificationVisible(false);
expect(await umbracoApi.dataType.doesRTEContainBlocks(tipTapName, [elementTypeId])).toBeTruthy();
+ // Verify that "Block" extension is enable
+ await umbracoUi.dataType.isExtensionItemChecked('Block');
// Clean
await umbracoApi.documentType.ensureNameNotExists(elementTypeName);
@@ -238,3 +241,38 @@ test('can disable extensions item', async ({umbracoApi, umbracoUi}) => {
expect(extensionsValue.value.length).toBe(extensionsCount - 1);
expect(extensionsValue.value).not.toContain(extensionItemName);
});
+
+test('can add a statusbar', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const statusbarName = 'Word Count';
+ const statusbarApiValue = 'Umb.Tiptap.Statusbar.WordCount';
+ await umbracoApi.dataType.createDefaultTiptapDataType(tipTapName);
+ await umbracoUi.dataType.goToDataType(tipTapName);
+
+ // Act
+ await umbracoUi.dataType.clickStatusbarItemInToolboxWithName(statusbarName);
+ await umbracoUi.dataType.clickSaveButton();
+
+ // Assert
+ await umbracoUi.dataType.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
+ const tipTapData = await umbracoApi.dataType.getByName(tipTapName);
+ const statusbarValue = tipTapData.values.find(value => value.alias === 'statusbar');
+ expect(statusbarValue.value).toEqual([[statusbarApiValue]]);
+});
+
+test('can remove a statusbar', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const statusbarName = 'Word Count';
+ await umbracoApi.dataType.createTiptapDataTypeWithWordCountStatusbar(tipTapName);
+ await umbracoUi.dataType.goToDataType(tipTapName);
+
+ // Act
+ await umbracoUi.dataType.clickStatusbarItemWithName(statusbarName);
+ await umbracoUi.dataType.clickSaveButton();
+
+ // Assert
+ await umbracoUi.dataType.doesSuccessNotificationHaveText(NotificationConstantHelper.success.saved);
+ const tipTapData = await umbracoApi.dataType.getByName(tipTapName);
+ const statusbarValue = tipTapData.values.find(value => value.alias === 'statusbar');
+ expect(statusbarValue).toBeFalsy();
+});
\ No newline at end of file
diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/Media.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/Media.spec.ts
index 627e16b7ad..c90dc3ae23 100644
--- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/Media.spec.ts
+++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/Media.spec.ts
@@ -178,6 +178,8 @@ test('can trash a media item', async ({umbracoApi, umbracoUi}) => {
// Act
await umbracoUi.media.clickActionsMenuForName(mediaFileName);
await umbracoUi.media.clickTrashButton();
+ // Verify the references list not displayed
+ await umbracoUi.content.isReferenceHeadlineVisible(false);
await umbracoUi.media.clickConfirmTrashButton();
// Assert
@@ -250,3 +252,79 @@ test('can empty the recycle bin', async ({umbracoApi, umbracoUi}) => {
expect(await umbracoApi.media.doesNameExist(mediaFileName)).toBeFalsy();
expect(await umbracoApi.media.doesMediaItemExistInRecycleBin(mediaFileName)).toBeFalsy();
});
+
+test('can trash a media node with a relation', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const documentPickerName = ['TestPicker', 'DocumentTypeForPicker'];
+ await umbracoApi.media.emptyRecycleBin();
+ await umbracoApi.media.createDefaultMediaFile(mediaFileName);
+ await umbracoApi.media.doesNameExist(mediaFileName);
+ // Create a document that have media picker is firstMediaFileName
+ await umbracoApi.document.createDefaultDocumentWithOneMediaLink(documentPickerName[0], mediaFileName, documentPickerName[1]);
+ await umbracoUi.media.goToSection(ConstantHelper.sections.media);
+
+ // Act
+ await umbracoUi.media.clickActionsMenuForName(mediaFileName);
+ await umbracoUi.media.clickTrashButton();
+ // Verify the references list
+ await umbracoUi.media.doesReferenceHeadlineHaveText(ConstantHelper.trashDeleteDialogMessage.referenceHeadline);
+ await umbracoUi.media.doesReferenceItemsHaveCount(1);
+ await umbracoUi.media.isReferenceItemNameVisible(documentPickerName[0]);
+ await umbracoUi.media.clickConfirmTrashButton();
+
+ // Assert
+ await umbracoUi.media.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
+ await umbracoUi.media.isItemVisibleInRecycleBin(mediaFileName);
+ expect(await umbracoApi.media.doesNameExist(mediaFileName)).toBeFalsy();
+ expect(await umbracoApi.media.doesMediaItemExistInRecycleBin(mediaFileName)).toBeTruthy();
+
+ // Clean
+ await umbracoApi.media.emptyRecycleBin();
+ await umbracoApi.document.ensureNameNotExists(documentPickerName[0]);
+ await umbracoApi.documentType.ensureNameNotExists(documentPickerName[1]);
+});
+
+test('can bulk trash media nodes with a relation', async ({umbracoApi, umbracoUi}) => {
+ // Arrange
+ const firstMediaFileName = 'FirstMediaFile';
+ const secondMediaFileName = 'SecondMediaFile';
+ const documentPickerName1 = ['TestPicker1', 'DocumentTypeForPicker1'];
+ const documentPickerName2 = ['TestPicker2', 'DocumentTypeForPicker2'];
+ await umbracoApi.media.emptyRecycleBin();
+ await umbracoApi.media.createDefaultMediaFile(firstMediaFileName);
+ await umbracoApi.media.createDefaultMediaFile(secondMediaFileName);
+ // Create a document that has a media picker with firstMediaFileName
+ await umbracoApi.document.createDefaultDocumentWithOneMediaLink(documentPickerName1[0], firstMediaFileName, documentPickerName1[1]);
+ // Create a document that has a media picker with secondMediaFileName
+ await umbracoApi.document.createDefaultDocumentWithOneMediaLink(documentPickerName2[0], secondMediaFileName, documentPickerName2[1]);
+
+ // Act
+ await umbracoUi.media.goToSection(ConstantHelper.sections.media);
+ await umbracoUi.media.selectMediaWithName(firstMediaFileName);
+ await umbracoUi.media.selectMediaWithName(secondMediaFileName);
+ await umbracoUi.media.clickBulkTrashButton();
+ // Verify the references list
+ await umbracoUi.media.doesReferenceHeadlineHaveText(ConstantHelper.trashDeleteDialogMessage.bulkReferenceHeadline);
+ await umbracoUi.media.doesReferenceItemsHaveCount(2);
+ await umbracoUi.media.isReferenceItemNameVisible(firstMediaFileName);
+ await umbracoUi.media.isReferenceItemNameVisible(secondMediaFileName);
+ await umbracoUi.media.clickConfirmTrashButton();
+
+ // Assert
+ await umbracoUi.media.isSuccessNotificationVisible();
+ expect(await umbracoApi.media.doesNameExist(firstMediaFileName)).toBeFalsy();
+ expect(await umbracoApi.media.doesNameExist(secondMediaFileName)).toBeFalsy();
+ expect(await umbracoApi.media.doesMediaItemExistInRecycleBin(firstMediaFileName)).toBeTruthy();
+ expect(await umbracoApi.media.doesMediaItemExistInRecycleBin(secondMediaFileName)).toBeTruthy();
+ await umbracoUi.media.isItemVisibleInRecycleBin(firstMediaFileName);
+ await umbracoUi.media.isItemVisibleInRecycleBin(secondMediaFileName, true, false);
+
+ // Clean
+ await umbracoApi.media.ensureNameNotExists(firstMediaFileName);
+ await umbracoApi.media.ensureNameNotExists(secondMediaFileName);
+ await umbracoApi.document.ensureNameNotExists(documentPickerName1[0]);
+ await umbracoApi.documentType.ensureNameNotExists(documentPickerName1[1]);
+ await umbracoApi.document.ensureNameNotExists(documentPickerName2[0]);
+ await umbracoApi.documentType.ensureNameNotExists(documentPickerName2[1]);
+ await umbracoApi.media.emptyRecycleBin();
+});
\ No newline at end of file