Skip to content

Commit

Permalink
chore(e2e): e2e setup for the new content editor (#31044)
Browse files Browse the repository at this point in the history
### Parent Issue

#31033 

### Proposed Changes
This pull request includes various changes primarily focused on code
formatting, adding new locators, and introducing new page classes for
the end-to-end tests. The most important changes include reformatting
the code for consistency, adding new locators for different elements,
and creating new page classes to handle content type forms and listings.

### Code Formatting and Consistency:
* Reformatted the code in
`e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts` and
`e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts` for
better readability and consistency.
[[1]](diffhunk://#diff-35aa7e942a2b3bf721b03086edd81cc7f9f6304c382d1f8d4f63154e8774d7ebL7-R49)
[[2]](diffhunk://#diff-31116070120de9d34d2d1bca1e15a77b893d11eacd3c4f35c19a97e6724a4728L1-R16)

### New Locators:
* Added new locators for `CONTENT_MODEL` in `GroupEntriesLocators` and
adjusted existing locators in `ToolEntriesLocators` and
`MenuEntriesLocators` in
`e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts`.
[[1]](diffhunk://#diff-31116070120de9d34d2d1bca1e15a77b893d11eacd3c4f35c19a97e6724a4728L1-R16)
[[2]](diffhunk://#diff-31116070120de9d34d2d1bca1e15a77b893d11eacd3c4f35c19a97e6724a4728L24-R31)
[[3]](diffhunk://#diff-31116070120de9d34d2d1bca1e15a77b893d11eacd3c4f35c19a97e6724a4728L40-R46)

### New Page Classes:
* Introduced `ContentTypeFormPage`, `ListingContentTypesPage`,
`ListingContentPage`, `NewEditContentFormPage`, and `TextFieldPage`
classes to handle various functionalities related to content types and
their forms in `e2e/dotcms-e2e-node/frontend/pages/`.
[[1]](diffhunk://#diff-8a92fb4f081c509fef96e8c7ef934f08860251636f6d3b5ddf4674d4732ab00cR1-R19)
[[2]](diffhunk://#diff-0140148c4a757211ea3d08718a3ffbbe868fbda924e0d776701cd8a3947d8627R1-R88)
[[3]](diffhunk://#diff-ecd9b86bb01f5d2e28c001b4dd295597b04fab47aae749e880d6e94680d70577R1-R24)
[[4]](diffhunk://#diff-375a304db645e11fdac5ae1dc88df576260e3eb312a5c685ecd6b9c65fb913f0R1-R14)
[[5]](diffhunk://#diff-a640fc59dabc83fde588d6a5b1e10403b8c0663512602001c73636961a31843aR1-R12)

### Package and Script Updates:
* Added `@faker-js/faker` dependency and updated the `start` script to
include `--ui` flag in `e2e/dotcms-e2e-node/frontend/package.json`.
[[1]](diffhunk://#diff-55df4fae14fead853fc15ad1d96168928f86342f5e8480fcab0b5690a181719cR8)
[[2]](diffhunk://#diff-55df4fae14fead853fc15ad1d96168928f86342f5e8480fcab0b5690a181719cL25-R30)

### Test File Adjustments:
* Reformatted and adjusted the test files for consistency and
readability, including `contentEditing.spec.ts` and `contentData.ts` in
`e2e/dotcms-e2e-node/frontend/tests/contentSearch/`.
[[1]](diffhunk://#diff-932c6ee4fda04337ff2a3c40079ff9aec9fb484641921760730a96a53d3c41afL1-R9)
[[2]](diffhunk://#diff-932c6ee4fda04337ff2a3c40079ff9aec9fb484641921760730a96a53d3c41afL21-R32)
[[3]](diffhunk://#diff-932c6ee4fda04337ff2a3c40079ff9aec9fb484641921760730a96a53d3c41afL42-R42)
[[4]](diffhunk://#diff-15b7d158a73d1a05b76e931e23509af650c9dd6a9f3c281244851f538a682b17L1-R30)
[[5]](diffhunk://#diff-15b7d158a73d1a05b76e931e23509af650c9dd6a9f3c281244851f538a682b17L31-R139)
[[6]](diffhunk://#diff-15b7d158a73d1a05b76e931e23509af650c9dd6a9f3c281244851f538a682b17L109-R223)

### Checklist
- [x] Tests
- [x] Translations
- [x] Security Implications Contemplated (add notes if applicable)

### Screenshots

<img width="1920" alt="Screenshot 2025-01-15 at 12 22 44 PM"
src="https://github.com/user-attachments/assets/f213b1f2-4a82-4031-a2e7-4fcb0a86fc66"
/>
  • Loading branch information
nicobytes authored Jan 17, 2025
1 parent 1f99806 commit 32195bc
Show file tree
Hide file tree
Showing 19 changed files with 1,430 additions and 902 deletions.
8 changes: 3 additions & 5 deletions e2e/dotcms-e2e-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Now that we have these packages installed we need to start dotCMS (with its depe

At `e2e/e2e-dotcms-node/frontend/package.json` you can find the available scripts you can call to execute the tests:

```json lines
```json
"scripts": {
"show-report": "if [[ \"$CURRENT_ENV\" != \"ci\" ]]; then fi",
"start": "PLAYWRIGHT_JUNIT_SUITE_ID=nodee2etestsuite PLAYWRIGHT_JUNIT_SUITE_NAME='E2E Node Test Suite' PLAYWRIGHT_JUNIT_OUTPUT_FILE='../target/failsafe-reports/TEST-e2e-node-results.xml' yarn playwright test ${PLAYWRIGHT_SPECIFIC} ${PLAYWRIGHT_DEBUG}; yarn run show-report",
Expand All @@ -89,12 +89,10 @@ At `e2e/e2e-dotcms-node/frontend/package.json` you can find the available script
"post-testing": "PLAYWRIGHT_JUNIT_OUTPUT_FILE='../target/failsafe-reports/TEST-e2e-node-results.xml' node index.js"
}
```

All these scripts assume that there is a dotCMS instance running at `8080` port.
- `start-local`: runs E2E tests against http://localhost:8080
- `start-dev`: runs E2E tests against http://localhost:4200, that means it runs a
```shell
nx serve dotcms-ui
```
- `start-dev`: runs E2E tests against http://localhost:4200, that means it runs a `nx serve dotcms-ui`
command before the tests on top of what is found on http://localhost:8080
- `start-ci`: runs E2E tests against http://localhost:8080 in `headless` mode which is how it's done in the pipeline

Expand Down
51 changes: 25 additions & 26 deletions e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,48 @@
* 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"]',
dot_edit_iframe: 'dot-edit-contentlet iframe[name="detailFrame"]',
}
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"]',
dot_edit_iframe: 'dot-edit-contentlet iframe[name="detailFrame"]',
};

/**
* 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,44 +1,45 @@
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;

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

}
}
readonly EXPAND: Locator;
readonly COLLAPSE: Locator;

constructor(page: Page) {
this.EXPAND = page.getByRole("button", { name: "" });
this.COLLAPSE = page
.locator('button[ng-reflect-ng-class="[object Object]"]')
.first();
}
}
3 changes: 3 additions & 0 deletions e2e/dotcms-e2e-node/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"devDependencies": {
"@axe-core/playwright": "^4.10.1",
"@eslint/js": "^9.17.0",
"@faker-js/faker": "9.3.0",
"@playwright/test": "^1.48.2",
"@types/node": "^22.5.4",
"@typescript-eslint/eslint-plugin": "^8.19.0",
Expand All @@ -28,6 +29,8 @@
"start-local": "CURRENT_ENV=local yarn run start",
"start-dev": "CURRENT_ENV=dev yarn run start",
"start-ci": "CURRENT_ENV=ci yarn run start",
"codegen": "yarn playwright codegen",
"ui": "yarn playwright test --ui",
"post-testing": "PLAYWRIGHT_JUNIT_OUTPUT_FILE='../target/failsafe-reports/TEST-e2e-node-results.xml' node index.js",
"format": "prettier --write .",
"lint": "eslint .",
Expand Down
19 changes: 19 additions & 0 deletions e2e/dotcms-e2e-node/frontend/pages/contentTypeForm.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Page } from "@playwright/test";

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

async fillNewContentType() {
await this.addTitleField();
}

async addTitleField() {
const dropZone = this.page.locator('div[dragula="fields-bag"]');
await this.page
.locator("li")
.getByText("Text", { exact: true })
.dragTo(dropZone);
await this.page.locator("input#name").fill("Text Field");
await this.page.getByTestId("dotDialogAcceptAction").click();
}
}
74 changes: 74 additions & 0 deletions e2e/dotcms-e2e-node/frontend/pages/listingContentTypes.pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { APIRequestContext, Page } from "@playwright/test";
import { updateFeatureFlag } from "../utils/api";

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

async goToUrl() {
await this.page.goto("/dotAdmin/#/content-types-angular");
}

async toggleNewContentEditor(boolean: boolean) {
await updateFeatureFlag(this.request, {
key: "DOT_FEATURE_FLAG_NEW_EDIT_PAGE",
value: boolean,
});
await updateFeatureFlag(this.request, {
key: "DOT_CONTENT_EDITOR2_ENABLED",
value: boolean,
});
await updateFeatureFlag(this.request, {
key: "DOT_CONTENT_EDITOR2_CONTENT_TYPE",
value: "*",
});
await this.page.reload();
}

async addNewContentType(name: string) {
await this.page.getByRole("button", { name: "" }).click();
await this.page.getByLabel("Content").locator("a").click();
await this.page
.locator('[data-test-id="content-type__new-content-banner"] div')
.nth(2)
.click();

await this.page.getByLabel("Content Name").fill(name);
await this.page.getByTestId("dotDialogAcceptAction").click();
}

async goToAddNewContentType(contentType: string) {
const capitalized =
contentType.charAt(0).toUpperCase() + contentType.slice(1);

await this.page
.getByTestId(`row-${capitalized}`)
.getByRole("link", { name: "View (0)" })
.click();
await this.page
.locator('iframe[name="detailFrame"]')
.contentFrame()
.locator("#dijit_form_DropDownButton_0")
.click();
await this.page
.locator('iframe[name="detailFrame"]')
.contentFrame()
.getByLabel("▼")
.getByText("Add New Content")
.click();
}

async deleteContentType(contentType: string) {
const capitalized =
contentType.charAt(0).toUpperCase() + contentType.slice(1);

await this.page
.getByTestId(`row-${capitalized}`)
.getByTestId("dot-menu-button")
.click();
await this.page.getByLabel("Delete").locator("a").click();
await this.page.getByRole("button", { name: "Delete" }).click();
}
}
36 changes: 36 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,36 @@
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 = "/dotAdmin/#c/content";
const urlParams = new URLSearchParams();

if (filter) {
urlParams.set("filter", filter);
}

await this.page.goto(`${urlPath}?${urlParams.toString()}`);
}

async clickAddNewContent() {
await this.#addBtn.click();
await this.#addNewContent.click();
}

async clickFirstContentRow() {
await this.page
.locator('iframe[name="detailFrame"]')
.contentFrame()
.locator("#results_table")
.locator("tr")
.nth(1)
.getByRole("link")
.click();
}
}
17 changes: 17 additions & 0 deletions e2e/dotcms-e2e-node/frontend/pages/newEditContentForm.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Page } from "@playwright/test";

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

async fillTextField(text: string) {
await this.page.getByTestId("textField").fill(text);
}

async save() {
await this.page.getByRole("button", { name: "Save" }).click();
}

async goToContent(id: string) {
await this.page.goto(`/dotAdmin/#/content/${id}`);
}
}
10 changes: 10 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,10 @@
import { Page } from "@playwright/test";

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

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

0 comments on commit 32195bc

Please sign in to comment.