From 9ce4acb53cd234c12c09422fd530fb4bec56abb2 Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Thu, 20 Nov 2025 16:50:30 +0700 Subject: [PATCH 1/6] Added api helper for smtp --- lib/helpers/ApiHelpers.ts | 3 +++ lib/helpers/SmtpApiHelper.ts | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 lib/helpers/SmtpApiHelper.ts diff --git a/lib/helpers/ApiHelpers.ts b/lib/helpers/ApiHelpers.ts index fce41df..a048638 100644 --- a/lib/helpers/ApiHelpers.ts +++ b/lib/helpers/ApiHelpers.ts @@ -35,6 +35,7 @@ import {LoginApiHelper} from "./LoginApiHelper"; import {WebhookApiHelper} from "./WebhookApiHelper"; import {MediaDeliveryApiHelper} from './differentAppSettingsHelpers/MediaDeliveryApiHelper'; import {ContentDeliveryApiHelper} from "./differentAppSettingsHelpers/ContentDeliveryApiHelper"; +import {SmtpApiHelper} from './SmtpApiHelper'; export class ApiHelpers { baseUrl: string = umbracoConfig.environment.baseUrl; @@ -73,6 +74,7 @@ export class ApiHelpers { webhook: WebhookApiHelper; mediaDeliveryApi: MediaDeliveryApiHelper; contentDeliveryApi: ContentDeliveryApiHelper; + smtp: SmtpApiHelper; constructor(page: Page) { this.page = page; @@ -110,6 +112,7 @@ export class ApiHelpers { this.webhook = new WebhookApiHelper(this, this.page); this.mediaDeliveryApi = new MediaDeliveryApiHelper(this); this.contentDeliveryApi = new ContentDeliveryApiHelper(this); + this.smtp= new SmtpApiHelper(this); } async getAccessToken() { diff --git a/lib/helpers/SmtpApiHelper.ts b/lib/helpers/SmtpApiHelper.ts new file mode 100644 index 0000000..ac705a8 --- /dev/null +++ b/lib/helpers/SmtpApiHelper.ts @@ -0,0 +1,37 @@ +import {ApiHelpers} from "./ApiHelpers"; + +export class SmtpApiHelper { + api: ApiHelpers; + private smtpBaseUrl = 'http://localhost:5000'; // Default smtp4dev URL, can be configured + + constructor(api: ApiHelpers) { + this.api = api; + } + + async getAllEmails() { + const response = await this.api.page.request.get(this.smtpBaseUrl + '/api/messages', { + ignoreHTTPSErrors: true + }); + return await response.json(); + } + + async deleteAllEmails() { + const response = await this.api.page.request.delete(this.smtpBaseUrl + '/api/messages/*', { + ignoreHTTPSErrors: true + }); + return response.status(); + } + + async findEmailBySubject(subject: string) { + const emails = await this.getAllEmails(); + const foundEmail = emails.results.find((email: any) => + email.subject && email.subject.toLowerCase().includes(subject.toLowerCase()) + ); + return foundEmail || null; + } + + async doesNotificationEmailWithSubjectExist(actionName: string, contentName: string) { + const expectedSubject = `Notification about ${actionName} performed on ${contentName}` + return this.findEmailBySubject(expectedSubject); + } +} \ No newline at end of file From 7da76e2584dfd64ec8a671309dc78b52a42dde8d Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Thu, 20 Nov 2025 16:50:54 +0700 Subject: [PATCH 2/6] Updated api helper for document notifications --- lib/helpers/DocumentApiHelper.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/helpers/DocumentApiHelper.ts b/lib/helpers/DocumentApiHelper.ts index 39b2c60..8d16743 100644 --- a/lib/helpers/DocumentApiHelper.ts +++ b/lib/helpers/DocumentApiHelper.ts @@ -1637,5 +1637,22 @@ export class DocumentApiHelper { entityType: 'document-property-value' }); return await this.update(documentId, documentData); - } + } + + async getNotifications(id: string) { + const response = await this.api.get(this.api.baseUrl + '/umbraco/management/api/v1/document/' + id + '/notifications'); + return await response.json(); + } + + async updatetNotifications(id: string, subscribedActionIds: string[] = []) { + const updateData = { + "subscribedActionIds": subscribedActionIds + }; + return await this.api.put(this.api.baseUrl + '/umbraco/management/api/v1/document/' + id + '/notifications', updateData); + } + + async doesNotificationExist(id: string, actionId: string) { + const notifications = await this.getNotifications(id); + return notifications.some((notification) => notification.actionId === actionId && notification.subscribed === true); + } } \ No newline at end of file From c10aead705eace4859d63a11d7d504c0a3ee15fb Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Thu, 20 Nov 2025 16:51:16 +0700 Subject: [PATCH 3/6] Updated ui helper for document notification --- lib/helpers/ContentUiHelper.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/helpers/ContentUiHelper.ts b/lib/helpers/ContentUiHelper.ts index ba4afc8..a66b5b2 100644 --- a/lib/helpers/ContentUiHelper.ts +++ b/lib/helpers/ContentUiHelper.ts @@ -1794,4 +1794,10 @@ export class ContentUiHelper extends UiBaseLocators { async isChooseButtonVisible(isVisible: boolean = true) { await expect(this.chooseBtn).toBeVisible({visible: isVisible}); } + + async clickDocumentNotificationOptionWithName(name: string) { + const notificationOptionLocator = this.page.locator('umb-document-notifications-modal [id$="' + name + '"]').locator('#toggle'); + await expect(notificationOptionLocator).toBeVisible(); + await notificationOptionLocator.click(); + } } \ No newline at end of file From ed5a7493d38579a9e5a1c1db00ac403f4e6ca8a0 Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Thu, 20 Nov 2025 16:51:57 +0700 Subject: [PATCH 4/6] Moved ui helper for restore button to UiBaseLocator --- lib/helpers/MediaUiHelper.ts | 4 +--- lib/helpers/UiBaseLocators.ts | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/helpers/MediaUiHelper.ts b/lib/helpers/MediaUiHelper.ts index b076a3d..62d3886 100644 --- a/lib/helpers/MediaUiHelper.ts +++ b/lib/helpers/MediaUiHelper.ts @@ -8,7 +8,6 @@ export class MediaUiHelper extends UiBaseLocators { private readonly mediaSearchTxt: Locator; private readonly trashBtn: Locator; private readonly restoreThreeDotsBtn: Locator; - private readonly restoreBtn: Locator; private readonly confirmEmptyRecycleBinBtn: Locator; private readonly mediaCreateBtn: Locator; private readonly mediaListHeader: Locator; @@ -33,7 +32,6 @@ export class MediaUiHelper extends UiBaseLocators { this.mediaSearchTxt = page.getByLabel('Search', {exact: true}); this.trashBtn = page.getByLabel(/^Trash(…)?$/); this.restoreThreeDotsBtn = page.getByRole('button', {name: 'Restore…'}); - this.restoreBtn = page.getByLabel('Restore', {exact: true}); this.confirmEmptyRecycleBinBtn = page.locator('#confirm').getByLabel('Empty Recycle Bin', {exact: true}); this.mediaCreateBtn = this.page.locator('umb-collection-toolbar').getByLabel('Create'); this.mediaListView = this.page.locator('umb-media-table-collection-view'); @@ -87,7 +85,7 @@ export class MediaUiHelper extends UiBaseLocators { await this.clickActionsMenuForName(name); await this.restoreThreeDotsBtn.click(); await this.page.waitForTimeout(1000); - await this.restoreBtn.click(); + await this.clickRestoreButton(); } async waitForMediaToBeTrashed() { diff --git a/lib/helpers/UiBaseLocators.ts b/lib/helpers/UiBaseLocators.ts index 7d2c9b7..f5b252d 100644 --- a/lib/helpers/UiBaseLocators.ts +++ b/lib/helpers/UiBaseLocators.ts @@ -155,6 +155,7 @@ export class UiBaseLocators { public readonly createDocumentBlueprintModal: Locator; public readonly entityItem: Locator; public readonly sectionLinks: Locator; + public readonly restoreBtn: Locator; constructor(page: Page) { this.page = page; @@ -313,6 +314,7 @@ export class UiBaseLocators { this.openedModal = page.locator('uui-modal-container[backdrop]'); this.uiLoader = page.locator('uui-loader'); this.entityItem = page.locator('umb-entity-item-ref'); + this.restoreBtn = page.getByLabel('Restore', {exact: true}); } async clickActionsMenuForNameInSectionSidebar(name: string) { @@ -1443,4 +1445,9 @@ export class UiBaseLocators { async isWorkspaceViewTabWithAliasVisible(alias: string, isVisible: boolean = true) { await expect(this.page.getByTestId('workspace:view-link:' + alias)).toBeVisible({visible: isVisible}); } + + async clickRestoreButton() { + await expect(this.restoreBtn).toBeVisible(); + await this.restoreBtn.click(); + } } From e0d0f19695b19a6020112b11c782b75b4de1aa24 Mon Sep 17 00:00:00 2001 From: Nhu Dinh Date: Thu, 20 Nov 2025 16:54:39 +0700 Subject: [PATCH 5/6] Bumped version of test helper --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c4e7947..eb0783c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@umbraco/playwright-testhelpers", - "version": "17.0.10", + "version": "17.0.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@umbraco/playwright-testhelpers", - "version": "17.0.10", + "version": "17.0.11", "license": "MIT", "dependencies": { "@umbraco/json-models-builders": "2.0.42", diff --git a/package.json b/package.json index e6a28a6..d65ff78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@umbraco/playwright-testhelpers", - "version": "17.0.10", + "version": "17.0.11", "description": "Test helpers for making playwright tests for Umbraco solutions", "main": "dist/lib/index.js", "files": [ From 8473ebfc47724d05ce24e5b5aa934daecf587f57 Mon Sep 17 00:00:00 2001 From: Andreas Zerbst Date: Thu, 20 Nov 2025 13:10:35 +0100 Subject: [PATCH 6/6] Fixed indentation --- lib/helpers/ApiHelpers.ts | 2 +- lib/helpers/DocumentApiHelper.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/helpers/ApiHelpers.ts b/lib/helpers/ApiHelpers.ts index a048638..de8d4a1 100644 --- a/lib/helpers/ApiHelpers.ts +++ b/lib/helpers/ApiHelpers.ts @@ -112,7 +112,7 @@ export class ApiHelpers { this.webhook = new WebhookApiHelper(this, this.page); this.mediaDeliveryApi = new MediaDeliveryApiHelper(this); this.contentDeliveryApi = new ContentDeliveryApiHelper(this); - this.smtp= new SmtpApiHelper(this); + this.smtp = new SmtpApiHelper(this); } async getAccessToken() { diff --git a/lib/helpers/DocumentApiHelper.ts b/lib/helpers/DocumentApiHelper.ts index 8d16743..c080dcd 100644 --- a/lib/helpers/DocumentApiHelper.ts +++ b/lib/helpers/DocumentApiHelper.ts @@ -1638,7 +1638,7 @@ export class DocumentApiHelper { }); return await this.update(documentId, documentData); } - + async getNotifications(id: string) { const response = await this.api.get(this.api.baseUrl + '/umbraco/management/api/v1/document/' + id + '/notifications'); return await response.json(); @@ -1652,7 +1652,7 @@ export class DocumentApiHelper { } async doesNotificationExist(id: string, actionId: string) { - const notifications = await this.getNotifications(id); + const notifications = await this.getNotifications(id); return notifications.some((notification) => notification.actionId === actionId && notification.subscribed === true); } } \ No newline at end of file