Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

31033 end to end e2e setup for the new content editor #31044

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 59 additions & 55 deletions e2e/dotcms-e2e-node/frontend/index.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,88 @@
const fs = require('fs');
const path = require('path');
const xml2js = require('xml2js');
const fs = require("fs");
const path = require("path");
const xml2js = require("xml2js");

const summaryResults = {
completed: 0,
errors: 0,
failures: 0,
skipped: 0
completed: 0,
errors: 0,
failures: 0,
skipped: 0,
};

// Default configurations
const defaultE2eTestsResultsDir = '../target/failsafe-reports'; // Default results directory
const defaultE2eTestsResultsDir = "../target/failsafe-reports"; // Default results directory

// Function to generate failsafe-summary.xml
const generateFailsafeSummaryXml = (e2eTestsResultsDir) => {
const builder = new xml2js.Builder();
const result = summaryResults.failures > 0 ? 255 : 0;
const xmlObj = {
'failsafe-summary': {
$: { result: result },
completed: summaryResults.completed,
errors: summaryResults.errors,
failures: summaryResults.failures,
skipped: summaryResults.skipped
}
};
const builder = new xml2js.Builder();
const result = summaryResults.failures > 0 ? 255 : 0;
const xmlObj = {
"failsafe-summary": {
$: { result: result },
completed: summaryResults.completed,
errors: summaryResults.errors,
failures: summaryResults.failures,
skipped: summaryResults.skipped,
},
};

if (summaryResults.failures > 0) {
xmlObj['failsafe-summary']['failureMessage'] = 'There are test failures.';
}
if (summaryResults.failures > 0) {
xmlObj["failsafe-summary"]["failureMessage"] = "There are test failures.";
}

const xml = builder.buildObject(xmlObj);
const xml = builder.buildObject(xmlObj);

fs.writeFileSync(path.join(e2eTestsResultsDir, 'failsafe-summary.xml'), xml, 'utf8');
}
fs.writeFileSync(
path.join(e2eTestsResultsDir, "failsafe-summary.xml"),
xml,
"utf8",
);
};

const processTestsResults = async () => {
const parser = new xml2js.Parser();
const xml = fs.readFileSync(process.env.PLAYWRIGHT_JUNIT_OUTPUT_FILE, 'utf8');
const xmlDoc = await parser.parseStringPromise(xml);
const parser = new xml2js.Parser();
const xml = fs.readFileSync(process.env.PLAYWRIGHT_JUNIT_OUTPUT_FILE, "utf8");
const xmlDoc = await parser.parseStringPromise(xml);

xmlDoc.testsuites.testsuite.forEach((ts) => {
const tests = parseInt(ts.tests || '0');
const errors = parseInt(ts.errors || '0');
const failures = parseInt(ts.failures || '0');
const skipped = parseInt(ts.skipped || '0');
summaryResults.completed += tests;
summaryResults.errors += errors;
summaryResults.failures += failures;
summaryResults.skipped += skipped;
});
xmlDoc.testsuites.testsuite.forEach((ts) => {
const tests = parseInt(ts.tests || "0");
const errors = parseInt(ts.errors || "0");
const failures = parseInt(ts.failures || "0");
const skipped = parseInt(ts.skipped || "0");
summaryResults.completed += tests;
summaryResults.errors += errors;
summaryResults.failures += failures;
summaryResults.skipped += skipped;
});
};

/**
* Main function to process command line arguments and run the script.
* Parses command line arguments for named parameters.
*/
async function main() {
const e2eTestsResultsDir = path.resolve(__dirname, defaultE2eTestsResultsDir);
// Ensure results directory exists
if (!fs.existsSync(e2eTestsResultsDir)) {
fs.mkdirSync(e2eTestsResultsDir, { recursive: true });
}
const e2eTestsResultsDir = path.resolve(__dirname, defaultE2eTestsResultsDir);
// Ensure results directory exists
if (!fs.existsSync(e2eTestsResultsDir)) {
fs.mkdirSync(e2eTestsResultsDir, { recursive: true });
}

try {
await processTestsResults();
generateFailsafeSummaryXml(e2eTestsResultsDir);
try {
await processTestsResults();
generateFailsafeSummaryXml(e2eTestsResultsDir);

if (summaryResults.failures > 0) {
console.error('Some E2E tests failed.');
process.exit(0);
}
} catch (error) {
console.error('An error occurred:', error);
process.exit(1);
if (summaryResults.failures > 0) {
console.error("Some E2E tests failed.");
process.exit(0);
}
} catch (error) {
console.error("An error occurred:", error);
process.exit(1);
}
}

// Run the main function and handle any errors
main().catch((err) => {
console.error('Unhandled error:', err);
process.exit(1);
console.error("Unhandled error:", err);
process.exit(1);
});
49 changes: 24 additions & 25 deletions e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,47 @@
* Locators for the iframes in the main page.
*/
export const iFramesLocators = {
main_iframe: 'iframe[name="detailFrame"]',
dot_iframe: 'dot-iframe-dialog iframe[name="detailFrame"]',
wysiwygFrame: 'iframe[title="Rich Text Area\\. Press ALT-F9 for menu\\. Press ALT-F10 for toolbar\\. Press ALT-0 for help"]',
dataTestId: '[data-testid="iframe"]'
}
main_iframe: 'iframe[name="detailFrame"]',
dot_iframe: 'dot-iframe-dialog iframe[name="detailFrame"]',
wysiwygFrame:
'iframe[title="Rich Text Area\\. Press ALT-F9 for menu\\. Press ALT-F10 for toolbar\\. Press ALT-0 for help"]',
dataTestId: '[data-testid="iframe"]',
};

/**
* Locators for the login functionality.
*/
export const loginLocators = {
userNameInput: 'input[id="inputtext"]',
passwordInput: 'input[id="password"]',
loginBtn: 'submitButton'
}
userNameInput: 'input[id="inputtext"]',
passwordInput: 'input[id="password"]',
loginBtn: "submitButton",
};

/**
* Locators for the Add Content functionality.
*/
export const addContent = {
addBtn: '#dijit_form_DropDownButton_0',
addNewContentSubMenu: 'Add New Content',
addNewMenuLabel: '▼'
}
addBtn: "#dijit_form_DropDownButton_0",
addNewContentSubMenu: "Add New Content",
addNewMenuLabel: "▼",
};

/**
* Locators for the Rich Text functionality.
*/
export const contentGeneric = {
locator: "articleContent (Generic)",
label: "Content (Generic)"
}
locator: "articleContent (Generic)",
label: "Content (Generic)",
};

export const fileAsset = {
locator: "attach_fileFile Asset",
label: "File Asset"
}
locator: "attach_fileFile Asset",
label: "File Asset",
};

export const pageAsset = {
locator: "descriptionPage",
label: "Page"
}

export {
} from './navigation/menuLocators';
locator: "descriptionPage",
label: "Page",
};

export {} from "./navigation/menuLocators";
61 changes: 31 additions & 30 deletions e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,49 @@
import {Page, Locator} from '@playwright/test';
import { Page, Locator } from "@playwright/test";

export class GroupEntriesLocators {
readonly SITE: Locator;
readonly CONTENT: Locator;
readonly SCHEMA: Locator;

constructor(page: Page) {
this.SITE = page.getByText('Site', {exact: true});
this.CONTENT = page.getByRole('complementary').getByText('Content', {exact: true});
this.SCHEMA = page.getByText('Schema');

}
readonly SITE: Locator;
readonly CONTENT: Locator;
readonly SCHEMA: Locator;

constructor(page: Page) {
this.SITE = page.getByText("Site", { exact: true });
this.CONTENT = page
.getByRole("complementary")
.getByText("Content", { exact: true });
this.SCHEMA = page.getByText("Schema");
}
}

/**
* Locators for the tools in the menu
*/
export class ToolEntriesLocators {
readonly SEARCH_ALL: Locator;
readonly CONTENT_TYPES: Locator;
readonly CATEGORIES: Locator;


constructor(page: Page) {
this.SEARCH_ALL = page.getByRole('link', {name: 'Search All'});
this.CONTENT_TYPES = page.getByRole('link', {name: 'Content Types'});
this.CATEGORIES = page.getByRole('link', { name: 'Categories' });
}
readonly SEARCH_ALL: Locator;
readonly CONTENT_TYPES: Locator;
readonly CATEGORIES: Locator;

constructor(page: Page) {
this.SEARCH_ALL = page.getByRole("link", { name: "Search All" });
this.CONTENT_TYPES = page.getByRole("link", { name: "Content Types" });
this.CATEGORIES = page.getByRole("link", { name: "Categories" });
}
}

/**
* Locators for the menu entries
*/
export class MenuEntriesLocators {
readonly EXPAND: Locator;
readonly COLLAPSE: Locator;
readonly EXPAND: Locator;
readonly COLLAPSE: Locator;

constructor(page: Page) {
/*this.EXPAND = page.locator('button[ng-reflect-ng-class="[object Object]"]').first();
constructor(page: Page) {
/*this.EXPAND = page.locator('button[ng-reflect-ng-class="[object Object]"]').first();
this.COLLAPSE = page.locator('button[ng-reflect-ng-class="[object Object]"]').first();
this.EXPAND = page.locator('button[ng-reflect-ng-class="[object Object]"]');
this.COLLAPSE = page.locator('button[ng-reflect-ng-class="[object Object]"]');*/
this.EXPAND = page.getByRole('button', { name: '' });
this.COLLAPSE = page.locator('button[ng-reflect-ng-class="[object Object]"]').first();

}
}
this.EXPAND = page.getByRole("button", { name: "" });
this.COLLAPSE = page
.locator('button[ng-reflect-ng-class="[object Object]"]')
.first();
}
}
6 changes: 4 additions & 2 deletions e2e/dotcms-e2e-node/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"devDependencies": {
"@playwright/test": "^1.48.2",
"@types/node": "^22.5.4",
"dotenv": "^16.4.5"
"dotenv": "^16.4.5",
"prettier": "3.4.2"
},
"dependencies": {
"jsdom": "^25.0.1",
Expand All @@ -17,6 +18,7 @@
"start-local": "CURRENT_ENV=local yarn run start",
"start-dev": "CURRENT_ENV=dev yarn run start",
"start-ci": "CURRENT_ENV=ci yarn run start",
"post-testing": "PLAYWRIGHT_JUNIT_OUTPUT_FILE='../target/failsafe-reports/TEST-e2e-node-results.xml' node index.js"
"post-testing": "PLAYWRIGHT_JUNIT_OUTPUT_FILE='../target/failsafe-reports/TEST-e2e-node-results.xml' node index.js",
"format": "prettier --write ."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Page } from "@playwright/test";

export class ListingContentTypesPage {
constructor(private page: Page) {}

async goTo() {
await this.page.goto("/content-types-angular");
}
}
24 changes: 24 additions & 0 deletions e2e/dotcms-e2e-node/frontend/pages/listngContent.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Page } from "@playwright/test";

export class ListingContentPage {
constructor(private page: Page) {}
#addBtn = this.page.locator("span[widgetid='dijit_form_DropDownButton_0']");
#addNewContent = this.page.locator(
".dijitPopup tr[aria-label='Add New Content']",
);

async goTo(filter?: string) {
const urlPath = new URL("/c/content", this.page.url());

if (filter) {
urlPath.searchParams.set("filter", filter);
}

await this.page.goto(urlPath.toString());
}

async clickAddNewContent() {
await this.#addBtn.click();
await this.#addNewContent.click();
}
}
12 changes: 12 additions & 0 deletions e2e/dotcms-e2e-node/frontend/pages/textField.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { expect, Page } from "@playwright/test";

export class TextFieldPage {
constructor(private page: Page) {}

async fill(vairableName: string, value: string) {
const input = this.page.locator(`input#${vairableName}`);
await input.fill(value);

await expect(input).toHaveValue(value);
}
}
Loading
Loading