Skip to content

Commit

Permalink
Testing running test on pipeline after some configuration (#30932)
Browse files Browse the repository at this point in the history
### Proposed Changes
* Content Search Portlet integrity test 
* Content Editing tests 

### Checklist
- [x] Tests
  • Loading branch information
bryanboza authored Dec 13, 2024
1 parent 65f39f4 commit cb72fba
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 39 deletions.
2 changes: 1 addition & 1 deletion e2e/dotcms-e2e-node/frontend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ CI=false
DEV=false
BASE_URL=http://localhost:8080
HEADLESS=false
RETRIES=1
RETRIES=0
WORKERS=1
REUSE_SERVER=false
INCLUDE_HTML=true
Expand Down
2 changes: 1 addition & 1 deletion e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const addContent = {
/**
* Locators for the Rich Text functionality.
*/
export const richText = {
export const contentGeneric = {
locator: "articleContent (Generic)",
label: "Content (Generic)"
}
Expand Down
12 changes: 9 additions & 3 deletions e2e/dotcms-e2e-node/frontend/tests/contentSearch/contentData.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
/**
* Content to add a Rich Text content
*/
export const richTextContent = {
export const genericContent1 = {
title: "Automation Test",
body: "This is a sample content"
body: "This is a sample content",
newTitle : "Automation Test edited",
newBody : "This is a sample content edited"
}

/**
* Content actions text content locators
*/
export const contentProperties = {
language: "English (US)",
publishWfAction: "Publish"
publishWfAction: "Publish",
unpublishWfAction: "Unpublish",
unlockWfAction: "Unlock",
archiveWfAction: "Archive",
deleteWfAction: "Delete"
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {expect, test} from '@playwright/test';
import {dotCMSUtils, waitForVisibleAndCallback} from '../../utils/dotCMSUtils';
import {
GroupEntriesLocators,
MenuEntriesLocators,
ToolEntriesLocators
} from '../../locators/navigation/menuLocators';
import {ContentUtils} from "../../utils/contentUtils";
import {iFramesLocators, contentGeneric} from "../../locators/globalLocators";
import {genericContent1, contentProperties} from "./contentData";
import {assert} from "console";

const cmsUtils = new dotCMSUtils();

/**
* Test to navigate to the content portlet and login to the dotCMS instance
* @param page
*/
test.beforeEach('Navigate to content portlet', async ({page}) => {
// Instance the menu Navigation locators
const menuLocators = new MenuEntriesLocators(page);
const groupsLocators = new GroupEntriesLocators(page);
const toolsLocators = new ToolEntriesLocators(page);

// Get the username and password from the environment variables
const username = process.env.USERNAME as string;
const password = process.env.PASSWORD as string;

// Login to dotCMS
await cmsUtils.login(page, username, password);
await cmsUtils.navigate(menuLocators.EXPAND, groupsLocators.CONTENT, toolsLocators.SEARCH_ALL);

// Validate the portlet title
const breadcrumbLocator = page.locator('p-breadcrumb');
await waitForVisibleAndCallback(breadcrumbLocator, () => expect(breadcrumbLocator).toContainText('Search All'));
});


test('Add a new pice of content', async ({page}) => {
const contentUtils = new ContentUtils(page);
const iframe = page.frameLocator(iFramesLocators.main_iframe);

// Adding new rich text content
await contentUtils.addNewContentAction(page, contentGeneric.locator, contentGeneric.label);
await contentUtils.fillRichTextForm(page, genericContent1.title, genericContent1.body, contentProperties.publishWfAction);
await waitForVisibleAndCallback(iframe.locator('#results_table tbody tr').first(), async () => {});

await contentUtils.validateContentExist(page, genericContent1.title).then(assert);
});

/**
* Test to edit an existing piece of content
*/
test('Edit a piece of content', async ({page}) => {
const contentUtils = new ContentUtils(page);
const iframe = page.frameLocator(iFramesLocators.main_iframe);

// Edit the content
await contentUtils.editContent(page, genericContent1.title, genericContent1.newTitle, genericContent1.newBody, contentProperties.publishWfAction);
await waitForVisibleAndCallback(iframe.locator('#results_table tbody tr').first(), async () => {});

await contentUtils.validateContentExist(page, genericContent1.newTitle).then(assert);
});


/**
* Test to delete an existing piece of content
*/
test('Delete a piece of content', async ({ page }) => {
const contentUtils = new ContentUtils(page);
// Delete the content
await contentUtils.deleteContent(page, genericContent1.newTitle);
}
);



Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {expect, test} from '@playwright/test';
import {dotCMSUtils, waitForVisibleAndCallback} from '../../utils/dotCMSUtils';
import {ContentUtils} from '../../utils/contentUtils';
import {addContent, iFramesLocators, richText} from '../../locators/globalLocators';
import {addContent, iFramesLocators, contentGeneric} from '../../locators/globalLocators';
import {
GroupEntriesLocators,
MenuEntriesLocators,
ToolEntriesLocators
} from '../../locators/navigation/menuLocators';
import {contentProperties, richTextContent} from './contentData';
import {contentProperties, genericContent1} from './contentData';

const cmsUtils = new dotCMSUtils();

Expand All @@ -32,8 +32,6 @@ test.beforeEach('Navigate to content portlet', async ({page}) => {
// Validate the portlet title
const breadcrumbLocator = page.locator('p-breadcrumb');
await waitForVisibleAndCallback(breadcrumbLocator, () => expect(breadcrumbLocator).toContainText('Search All'));

await expect(page.locator('p-breadcrumb')).toContainText('Search All');
});


Expand All @@ -55,16 +53,16 @@ test('Search filter', async ({page}) => {
const iframe = page.frameLocator(iFramesLocators.main_iframe);

// Adding new rich text content
await contentUtils.addNewContentAction(page, richText.locator, richText.label);
await contentUtils.fillRichTextForm(page, richTextContent.title, richTextContent.body, contentProperties.publishWfAction);
await contentUtils.addNewContentAction(page, contentGeneric.locator, contentGeneric.label);
await contentUtils.fillRichTextForm(page, genericContent1.title, genericContent1.body, contentProperties.publishWfAction);

// Validate the content has been created
await expect.soft(iframe.getByRole('link', {name: 'Automation Test'}).first()).toBeVisible();
await iframe.locator('#allFieldTB').fill(richTextContent.title);
await expect.soft(iframe.getByRole('link', {name: genericContent1.title}).first()).toBeVisible();
await iframe.locator('#allFieldTB').fill(genericContent1.title);
await page.keyboard.press('Enter');

//validate the search filter is working
await expect(iframe.getByRole('link', {name: 'Automation Test'}).first()).toBeVisible();
await expect(iframe.getByRole('link', {name: genericContent1.title}).first()).toBeVisible();
});

/**
Expand Down
156 changes: 144 additions & 12 deletions e2e/dotcms-e2e-node/frontend/utils/contentUtils.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import {Page, expect, FrameLocator} from '@playwright/test';
import { iFramesLocators, richText } from '../locators/globalLocators';
import { waitForVisibleAndCallback} from './dotCMSUtils';
import {expect, FrameLocator, Locator, Page} from '@playwright/test';
import {contentGeneric, iFramesLocators} from '../locators/globalLocators';
import {waitForVisibleAndCallback} from './dotCMSUtils';
import {contentProperties} from "../tests/contentSearch/contentData";

export class ContentUtils {
page: Page;

constructor(page: Page) {
this.page = page;
this.page = page;
}

/**
* Fill the rich text form
* @param page
* @param page
* @param title
* @param body
* @param action
Expand All @@ -19,7 +21,7 @@ export class ContentUtils {
const dotIframe = page.frameLocator(iFramesLocators.dot_iframe);

const headingLocator = page.getByRole('heading');
await waitForVisibleAndCallback(headingLocator, () => expect.soft(headingLocator).toContainText(richText.label));
await waitForVisibleAndCallback(headingLocator, () => expect.soft(headingLocator).toContainText(contentGeneric.label));

//Fill title
await dotIframe.locator('#title').fill(title);
Expand All @@ -28,10 +30,10 @@ export class ContentUtils {

//await dotIframe.locator(iFramesLocators.wysiwygFrame).contentFrame().locator('#tinymce').fill(body);
//Click on action
await dotIframe.getByText(action).click();
await dotIframe.getByText(action).first().click();
//Wait for the content to be saved

await expect(dotIframe.getByText('Content saved')).toBeVisible({ timeout: 9000 });
await expect(dotIframe.getByText('Content saved')).toBeVisible({timeout: 9000});
await expect(dotIframe.getByText('Content saved')).toBeHidden();
//Click on close
const closeBtnLocator = page.getByTestId('close-button').getByRole('button');
Expand Down Expand Up @@ -82,17 +84,147 @@ export class ContentUtils {
* Show query on the content portlet
* @param iframe
*/
async showQuery(iframe : FrameLocator) {
const createOptionsBtnLocator = iframe.getByRole('button', { name: 'createOptions' });
async showQuery(iframe: FrameLocator) {
const createOptionsBtnLocator = iframe.getByRole('button', {name: 'createOptions'});
await waitForVisibleAndCallback(createOptionsBtnLocator, () => createOptionsBtnLocator.click());

//Validate the search button has a sub-menu
await expect (iframe.getByLabel('Search ▼').getByText('Search')).toBeVisible();
await expect (iframe.getByText('Show Query')).toBeVisible();
await expect(iframe.getByLabel('Search ▼').getByText('Search')).toBeVisible();
await expect(iframe.getByText('Show Query')).toBeVisible();

// Click on show query
await iframe.getByText('Show Query').click();
}

/**
* Validate if the content exists in the results table on the content portlet
* @param page
* @param title
*/
async validateContentExist(page: Page, title: string) {
const iframe = page.frameLocator(iFramesLocators.main_iframe);

await iframe.locator('#results_table tbody tr').first().waitFor({ state: 'visible' });
const secondCell = iframe.locator('#results_table tbody tr:nth-of-type(2) td:nth-of-type(2)');
const hasAutomationLink = await secondCell.locator(`a:has-text("${title}")`).count() > 0;

console.log(`The content with the title ${title} ${hasAutomationLink ? 'exists' : 'does not exist'}`);
return hasAutomationLink;
}

/**
* Get the content element from the results table on the content portlet
* @param page
* @param title
*/
async getContentElement(page: Page, title: string): Promise<Locator | null> {
const iframe = page.frameLocator(iFramesLocators.main_iframe);

await iframe.locator('#results_table tbody tr').first().waitFor({ state: 'visible' });
const secondCell = iframe.locator('#results_table tbody tr:nth-of-type(2) td:nth-of-type(2)');
const element = secondCell.locator(`a:has-text("${title}")`);

const elementCount = await element.count();
if (elementCount > 0) {
return element.first();
} else {
console.log(`The content with the title ${title} does not exist`);
return null;
}
}

/**
* Edit content on the content portlet
* @param page
* @param title
* @param newTitle
* @param newBody
* @param action
*/
async editContent(page: Page, title: string, newTitle: string, newBody: string, action: string) {
const iframe = page.frameLocator(iFramesLocators.main_iframe);
const contentElement = await this.getContentElement(page, title);
if (contentElement) {
await contentElement.click();
}else {
console.log('Content not found');
return;
}
await this.fillRichTextForm(page, newTitle, newBody, action);
}

/**
* Delete content on the content portlet
* @param page
* @param title
*/
async deleteContent(page: Page, title: string) {
const iframe = page.frameLocator(iFramesLocators.main_iframe);

while (await this.getContentState(page, title) !== null) {
const contentState = await this.getContentState(page, title);

if (contentState === 'published') {
await this.performWorkflowAction(page, title, contentProperties.unpublishWfAction);
} else if (contentState === 'draft') {
await this.performWorkflowAction(page, title, contentProperties.archiveWfAction);
await iframe.getByRole('link', { name: 'Advanced' }).click();
await iframe.locator('#widget_showingSelect div').first().click();
const dropDownMenu = iframe.getByRole('option', { name: 'Archived' });
await waitForVisibleAndCallback(dropDownMenu, () => dropDownMenu.click());
await page.waitForTimeout(1000)
} else if (contentState === 'archived') {
await this.performWorkflowAction(page, title, contentProperties.deleteWfAction);
return;
}

await page.waitForLoadState();
}
}

/**
* Perform workflow action for some specific content
* @param page
* @param title
* @param action
*/
async performWorkflowAction(page: Page, title: string, action: string) {
const iframe = page.frameLocator(iFramesLocators.main_iframe);
const contentElement = await this.getContentElement(page, title);
if (contentElement) {
await contentElement.click({
button: 'right'
});
}
const actionBtnLocator = iframe.getByRole('menuitem', { name: action });
await waitForVisibleAndCallback(actionBtnLocator, () => actionBtnLocator.getByText(action).click());
await expect.soft(iframe.getByText('Workflow executed')).toBeVisible();
await expect.soft(iframe.getByText('Workflow executed')).toBeHidden();
}

async getContentState(page: Page, title: string): Promise<string | null> {
const iframe = page.frameLocator(iFramesLocators.main_iframe);
await iframe.locator('#results_table tbody tr').first().waitFor({ state: 'visible' });

const titleCell = iframe.locator('#results_table tbody tr:nth-of-type(2) td:nth-of-type(2)');
const element = titleCell.locator(`a:has-text("${title}")`);
const elementCount = await element.count();
if (elementCount > 0) {
const stateColumn = iframe.locator('#results_table tbody tr:nth-of-type(2) td:nth-of-type(3)');
const targetDiv = stateColumn.locator('div#icon');
return await targetDiv.getAttribute('class');
} else {
console.log('Content not found');
return null;
}
}


}







Loading

0 comments on commit cb72fba

Please sign in to comment.