V16 QA Added acceptance tests for Webhook (#19545)

* Added tests for webhook

* Added tests for webhook trigger

* Bumped version

* Make all Webhook tests run in the pipeline

* Fixed comment

* Reverted npm command
This commit is contained in:
Nhu Dinh
2025-06-17 10:55:30 +02:00
committed by GitHub
parent 50272f7401
commit e6791246e4
4 changed files with 441 additions and 12 deletions

View File

@@ -7,8 +7,8 @@
"name": "acceptancetest",
"hasInstallScript": true,
"dependencies": {
"@umbraco/json-models-builders": "^2.0.35",
"@umbraco/playwright-testhelpers": "^16.0.23",
"@umbraco/json-models-builders": "^2.0.36",
"@umbraco/playwright-testhelpers": "^16.0.25",
"camelize": "^1.0.0",
"dotenv": "^16.3.1",
"node-fetch": "^2.6.7"
@@ -58,20 +58,19 @@
}
},
"node_modules/@umbraco/json-models-builders": {
"version": "2.0.35",
"resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-2.0.35.tgz",
"integrity": "sha512-9qHvp7j8Lhj2x4xxWYz+ovRyoSnJIl4eLbSAst4nODCNqXSTWOy3+mzho3SeYWeil00/r0zXExHoXklVYi4iKA==",
"version": "2.0.36",
"resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-2.0.36.tgz",
"integrity": "sha512-vQLL/y2ZIqrhCBe61W6YuA/C3KjGkva90WA09YfQuPL9HujOkJpVaP7KjJ0F8bBxwURy9tzMBFBLUz5fOdbkxQ==",
"dependencies": {
"camelize": "^1.0.1"
}
},
"node_modules/@umbraco/playwright-testhelpers": {
"version": "16.0.23",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-16.0.23.tgz",
"integrity": "sha512-9By0jqdscFh5pRFCpBEvoOCOpEOUG9eoSGvyLPnWjiJtfTCSm2OHARX8QcP5vCU65TO59w7JwUcXBTExaRIFXg==",
"license": "MIT",
"version": "16.0.25",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-16.0.25.tgz",
"integrity": "sha512-IvRkkrTIxlXbg2dw0RhAUgkb7KSBJCyktK6zJynOORgZ5RXRae19hqKk7yEu2EwJpTstl6m9AzoVf1x4b94x5w==",
"dependencies": {
"@umbraco/json-models-builders": "2.0.35",
"@umbraco/json-models-builders": "2.0.36",
"node-fetch": "^2.6.7"
}
},

View File

@@ -20,8 +20,8 @@
"typescript": "^4.8.3"
},
"dependencies": {
"@umbraco/json-models-builders": "^2.0.35",
"@umbraco/playwright-testhelpers": "^16.0.23",
"@umbraco/json-models-builders": "^2.0.36",
"@umbraco/playwright-testhelpers": "^16.0.25",
"camelize": "^1.0.0",
"dotenv": "^16.3.1",
"node-fetch": "^2.6.7"

View File

@@ -0,0 +1,188 @@
import {expect} from "@playwright/test";
import {test} from '@umbraco/playwright-testhelpers';
const webhookName = 'Test Webhook';
let webhookSiteToken = '';
test.beforeEach(async ({umbracoUi, umbracoApi}) => {
await umbracoApi.webhook.ensureNameNotExists(webhookName);
await umbracoUi.goToBackOffice();
webhookSiteToken = await umbracoApi.webhook.generateWebhookSiteToken();
});
test.afterEach(async ({umbracoApi}) => {
await umbracoApi.webhook.ensureNameNotExists(webhookName);
});
test('can create a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const event = 'Content Deleted';
const webhookSiteUrl = umbracoApi.webhook.webhookSiteUrl + webhookSiteToken;
await umbracoUi.webhook.goToWebhooks();
// Act
await umbracoUi.webhook.clickWebhookCreateButton();
await umbracoUi.webhook.enterWebhookName(webhookName);
await umbracoUi.webhook.enterUrl(webhookSiteUrl);
await umbracoUi.webhook.clickChooseEventButton();
await umbracoUi.webhook.clickTextButtonWithName(event);
await umbracoUi.webhook.clickSubmitButton();
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesNameExist(webhookName)).toBeTruthy();
expect(await umbracoApi.webhook.doesWebhookHaveUrl(webhookName, webhookSiteUrl)).toBeTruthy();
expect(await umbracoApi.webhook.doesWebhookHaveEvent(webhookName, event)).toBeTruthy();
await umbracoApi.webhook.isWebhookEnabled(webhookName);
});
test('can update webhook name', async ({umbracoApi, umbracoUi}) => {
// Arrange
const updatedName = 'Updated Webhook';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken);
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.enterWebhookName(updatedName);
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesNameExist(updatedName)).toBeTruthy();
expect(await umbracoApi.webhook.doesNameExist(webhookName)).toBeFalsy();
});
test('can delete a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken);
await umbracoUi.webhook.goToWebhooks();
// Act
await umbracoUi.webhook.clickDeleteWebhookWithName(webhookName);
await umbracoUi.webhook.clickConfirmToDeleteButton();
// Assert
expect(await umbracoApi.webhook.doesNameExist(webhookName)).toBeFalsy();
});
test('can add content type for a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const contentTypeName = 'Test Document Type For Webhook';
const documentTypeId = await umbracoApi.documentType.createDefaultDocumentType(contentTypeName);
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken);
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickChooseContentTypeButton();
await umbracoUi.webhook.clickModalMenuItemWithName(contentTypeName);
await umbracoUi.webhook.clickChooseModalButton();
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesNameExist(webhookName)).toBeTruthy();
expect(await umbracoApi.webhook.doesWebhookHaveContentTypeId(webhookName, documentTypeId)).toBeTruthy();
// Clean
await umbracoApi.documentType.ensureNameNotExists(contentTypeName);
});
test('can add header for a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const headerName = 'test-header-name';
const headerValue = 'test-header-value';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken);
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickAddHeadersButton();
await umbracoUi.webhook.enterHeaderName(headerName);
await umbracoUi.webhook.enterHeaderValue(headerValue);
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesNameExist(webhookName)).toBeTruthy();
expect(await umbracoApi.webhook.doesWebhookHaveHeader(webhookName, headerName, headerValue)).toBeTruthy();
});
test('can disable a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken);
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickEnabledToggleButton();
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesNameExist(webhookName)).toBeTruthy();
await umbracoApi.webhook.isWebhookEnabled(webhookName, false);
});
test('cannot remove all events from a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const event = 'Content Deleted';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickRemoveButtonForName(event);
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.content.isErrorNotificationVisible();
});
test('can remove a content type from a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const event = 'Media Saved';
const mediaTypeName = 'Audio';
const mediaTypeData = await umbracoApi.mediaType.getByName(mediaTypeName);
await umbracoApi.webhook.createWebhookForSpecificContentType(webhookName, webhookSiteToken, event, mediaTypeName);
expect(await umbracoApi.webhook.doesWebhookHaveContentTypeId(webhookName, mediaTypeData.id)).toBeTruthy();
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickRemoveButtonForName(mediaTypeName);
await umbracoUi.webhook.clickConfirmRemoveButton();
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesWebhookHaveContentTypeId(webhookName, mediaTypeData.id)).toBeFalsy();
});
test('can remove a header from a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const event = 'Content Published';
const headerName = 'test-header-name';
const headerValue = 'automation-test';
await umbracoApi.webhook.createWebhookWithHeader(webhookName, webhookSiteToken, event, headerName, headerValue);
expect(await umbracoApi.webhook.doesWebhookHaveHeader(webhookName, headerName, headerValue)).toBeTruthy();
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickHeaderRemoveButton();
await umbracoUi.webhook.clickSaveButton();
// Assert
await umbracoUi.webhook.isSuccessStateVisibleForSaveButton();
expect(await umbracoApi.webhook.doesWebhookHaveHeader(webhookName, headerName, headerValue)).toBeFalsy();
});
test('cannot add both content event and media event for a webhook', async ({umbracoApi, umbracoUi}) => {
// Arrange
const event = 'Content Published';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
await umbracoUi.webhook.goToWebhookWithName(webhookName);
// Act
await umbracoUi.webhook.clickChooseEventButton();
// Assert
await umbracoUi.webhook.isModalMenuItemWithNameDisabled('Media Saved');
await umbracoUi.webhook.isModalMenuItemWithNameDisabled('Media Deleted');
});

View File

@@ -0,0 +1,242 @@
import {expect} from "@playwright/test";
import {ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers';
// Webhook
const webhookName = 'Test Webhook';
let webhookSiteToken = '';
// Content
const documentName = 'Test Webhook Content';
const documentTypeName = 'TestDocumentTypeForWebhook';
let documentTypeId = '';
// Media
const mediaName = 'Test Webhook Media';
const mediaTypeName = 'Image';
test.beforeEach(async ({umbracoApi}) => {
await umbracoApi.webhook.ensureNameNotExists(webhookName);
webhookSiteToken = await umbracoApi.webhook.generateWebhookSiteToken();
documentTypeId = await umbracoApi.documentType.createDefaultDocumentTypeWithAllowAsRoot(documentTypeName);
});
test.afterEach(async ({umbracoApi}) => {
await umbracoApi.webhook.ensureNameNotExists(webhookName);
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
await umbracoApi.document.ensureNameNotExists(documentName);
await umbracoApi.media.ensureNameNotExists(mediaName);
});
test('can trigger when content is published', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Content Published';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
await umbracoApi.document.createDefaultDocument(documentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.content);
// Act
await umbracoUi.content.goToContentWithName(documentName);
await umbracoUi.content.clickSaveAndPublishButton();
// Assert
await umbracoUi.content.isSuccessStateVisibleForSaveAndPublishButton();
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(documentName);
});
test('can trigger when content is deleted', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Content Deleted';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
const contentId = await umbracoApi.document.createDefaultDocument(documentName, documentTypeId);
await umbracoApi.document.moveToRecycleBin(contentId);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.content);
// Act
await umbracoUi.content.clickEmptyRecycleBinButton();
await umbracoUi.content.clickConfirmEmptyRecycleBinButton();
// Assert
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.emptiedRecycleBin);
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(contentId);
});
test('can trigger when content is unpublished', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Content Unpublished';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
const contentId = await umbracoApi.document.createDefaultDocument(documentName, documentTypeId);
await umbracoApi.document.publish(contentId);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.content);
// Act
await umbracoUi.content.clickActionsMenuForContent(documentName);
await umbracoUi.content.clickUnpublishActionMenuOption();
await umbracoUi.content.clickConfirmToUnpublishButton();
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.unpublished);
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(contentId);
});
test('can trigger when media is saved', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Media Saved';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
const mediaId = await umbracoApi.media.createDefaultMediaWithImage(mediaName);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.media);
// Act
await umbracoUi.media.goToMediaWithName(mediaName);
await umbracoUi.media.clickSaveButton();
await umbracoUi.content.isSuccessStateVisibleForSaveButton();
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(mediaName);
expect(webhookSiteData[0].content).toContain(mediaId);
});
test('can trigger when media is deleted', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Media Deleted';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event);
const mediaId = await umbracoApi.media.createDefaultMediaWithImage(mediaName);
await umbracoApi.media.trashMediaItem(mediaName);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.media);
// Act
await umbracoUi.media.isItemVisibleInRecycleBin(mediaName);
await umbracoUi.media.deleteMediaItem(mediaName);
await umbracoUi.media.waitForMediaToBeTrashed();
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(mediaId);
});
test('can trigger the webhook for a specific media type', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Media Deleted';
const secondMediaName = 'Test Second Media';
await umbracoApi.webhook.createWebhookForSpecificContentType(webhookName, webhookSiteToken, event, mediaTypeName);
const mediaId = await umbracoApi.media.createDefaultMediaWithImage(mediaName);
const secondMediaId = await umbracoApi.media.createDefaultMediaWithArticle(secondMediaName);
await umbracoApi.media.trashMediaItem(mediaName);
await umbracoApi.media.trashMediaItem(secondMediaName);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.media);
// Act
await umbracoUi.media.isItemVisibleInRecycleBin(mediaName);
await umbracoUi.media.deleteMediaItem(mediaName);
await umbracoUi.media.deleteMediaItem(secondMediaName);
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(mediaId);
expect(webhookSiteData[0].content).not.toContain(secondMediaId);
// Clean
await umbracoApi.media.ensureNameNotExists(secondMediaName);
});
test('can trigger the webhook for a specific content type', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Content Published';
const secondDocumentName = 'Second Test Webhook Content';
const secondDocumentTypeName = 'SecondTestDocumentTypeForWebhook';
const secondDocumentTypeId = await umbracoApi.documentType.createDefaultDocumentTypeWithAllowAsRoot(secondDocumentTypeName);
await umbracoApi.document.createDefaultDocument(secondDocumentName, secondDocumentTypeId);
await umbracoApi.webhook.createWebhookForSpecificContentType(webhookName, webhookSiteToken, event, documentTypeName);
await umbracoApi.document.createDefaultDocument(documentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.content);
// Act
await umbracoUi.content.clickActionsMenuForContent(documentName);
await umbracoUi.content.clickPublishActionMenuOption();
await umbracoUi.content.clickConfirmToPublishButton();
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
await umbracoUi.content.clickActionsMenuForContent(secondDocumentName);
await umbracoUi.content.clickPublishActionMenuOption();
await umbracoUi.content.clickConfirmToPublishButton();
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].content).toContain(documentName);
expect(webhookSiteData[0].content).not.toContain(secondDocumentName);
// Clean
await umbracoApi.documentType.ensureNameNotExists(secondDocumentTypeName);
await umbracoApi.document.ensureNameNotExists(secondDocumentName);
});
test('cannot trigger when the webhook is disabled', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Content Published';
await umbracoApi.webhook.createDefaultWebhook(webhookName, webhookSiteToken, event, false);
await umbracoApi.document.createDefaultDocument(documentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.content);
// Act
await umbracoUi.content.clickActionsMenuForContent(documentName);
await umbracoUi.content.clickPublishActionMenuOption();
await umbracoUi.content.clickConfirmToPublishButton();
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken, 7000);
expect(webhookSiteData).toBeFalsy();
});
test('can custom header for the webhook request', async ({umbracoApi, umbracoUi}) => {
test.slow();
// Arrange
const event = 'Content Published';
const headerName = 'test-header-name';
const headerValue = 'automation-test';
await umbracoApi.webhook.createWebhookWithHeader(webhookName, webhookSiteToken, event, headerName, headerValue);
await umbracoApi.document.createDefaultDocument(documentName, documentTypeId);
await umbracoUi.goToBackOffice();
await umbracoUi.webhook.goToSection(ConstantHelper.sections.content);
// Act
await umbracoUi.content.clickActionsMenuForContent(documentName);
await umbracoUi.content.clickPublishActionMenuOption();
await umbracoUi.content.clickConfirmToPublishButton();
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
// Assert
const webhookSiteData = await umbracoApi.webhook.getWebhookSiteRequestResponse(webhookSiteToken);
expect(webhookSiteData[0].headers[headerName]).toEqual([headerValue]);
});