Skip to content

Commit

Permalink
#30682: Content Search portlet integrity test cases implemented in E…
Browse files Browse the repository at this point in the history
…2E tests. Piggy back to fix flaky IT.
  • Loading branch information
bryanboza authored and victoralfaro-dotcms committed Nov 29, 2024
1 parent 3dd6041 commit 6617c43
Show file tree
Hide file tree
Showing 20 changed files with 1,297 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ public void test_validateModelsUsage() throws Exception {
final JSONObjectAIRequest request = JSONObjectAIRequest.builder().withUserId("jon.snow").build();
validator.validateModelsUsage(appConfig.getModel(), request);

verify(systemMessageEventUtil, atLeast(2))
.pushMessage(any(SystemMessage.class), anyList());
verify(systemMessageEventUtil, atLeastOnce()).pushMessage(any(SystemMessage.class), anyList());
}
}
88 changes: 88 additions & 0 deletions e2e/dotcms-e2e-node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Running E2E Tests

If you are reading this it's because somehow you are interested in running dotCMS End-to-End tests locally.
Basically there are two main flavors for achieving this:

## Maven way
dotCMS' core is a Maven multi module project. One submodule is `e2e` which in turn is a parent project for its two submodules: `e2e-dotcms-java` anda `e2e-dotmcs-node`.

Since we are only interested in the last one as we will probably deprecate the Java one, here it's how you call the entire suite:

### Node.js
```shell
./mvnw -pl :dotcms-e2e-node verify -De2e.test.skip=false
```
As every other test in out projects, if it has one or more dependencies, Maven will take care of their lifecycle.
Hence you will see Docker containers for database, Elastic Search, Wiremock and (obviously) dotCMS itself being started up and killed down as the tests run.

BTW, E2E will against a dotCMS container from the latest locally built image.

```shell
./mvnw -pl :dotcms-e2e-java verify -De2e.test.skip=false -Pdebug-suspend-e2e-tests
```

To manually kill the E2E dependencies run:
```shell
./mvnw -pl :dotcms-e2e-java,:dotcms-e2e-node -Pdocker-stop -De2e.test.skip=false
```

Two advantages of running E2E tests this way is that:
- Everything is taken care for you
- It runs pretty similar to how it's done in our pipeline

Disadvantages:
- Could take longer if you are adding E2E tests to a feature you are working so probably for that matter the "FrontEnd guy" approach works better for you.

## FrontEnd guys way
E2E tests are implemented using Playwright so you will need the following as pre-requisites:
- Node & NPM
- Yarn
- Playwright

Assuming that you at least have Node, NPM and Yarn installed, to install project in yarn run:
```shell
yarn install --frozen-lockfile
```

To install Playwright and its dependencies:
```shell
yarn global add playwright
yarn playwright install-deps
```

Now that we have these packages installed we need to start dotCMS (with its dependencies). This is usually done by calling on a `docker-compose.yml` file of your preference with all the services needed to have a healthy dotCMS instance.

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

```json lines
"scripts": {
"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",
"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"
}
```
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
```
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

So, assuming that you are a frontend developer and you are still implementing a feature using the `start-dev` script will make much sense since it will run `nx` to start the app in the `4200` port.
```shell
yarn run start-dev
```

To run a specific E2E test:
```shell
yarn run start-dev -- login.spec.ts
```

To run E2E tests located in specific folder(s):
```shell
yarn run start-dev -- tests/login tests/contentSearch
```
9 changes: 9 additions & 0 deletions e2e/dotcms-e2e-node/frontend/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
CI=false
DEV=false
BASE_URL=http://localhost:8080
HEADLESS=false
RETRIES=0
REUSE_SERVER=false
INCLUDE_HTML=true

USERNAME=[email protected]
PASSWORD=admin

4 changes: 4 additions & 0 deletions e2e/dotcms-e2e-node/frontend/.env.ci
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
CI=true
HEADLESS=true
RETRIES=1
INCLUDE_HTML=false
REUSE_SERVER=true
3 changes: 3 additions & 0 deletions e2e/dotcms-e2e-node/frontend/.env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This env assumes that there is an instance of nx is running listening on port 4200
DEV=true
BASE_URL=http://localhost:4200
2 changes: 1 addition & 1 deletion e2e/dotcms-e2e-node/frontend/.env.local
Original file line number Diff line number Diff line change
@@ -1 +1 @@
BASE_URL=http://localhost:4200
REUSE_SERVER=true
38 changes: 38 additions & 0 deletions e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* 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"]'
}

/**
* Locators for the login functionality.
*/
export const loginLocators = {
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: '▼'
}

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

export {
} from './navigation/menuLocators';

48 changes: 48 additions & 0 deletions e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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');

}
}

/**
* 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' });
}
}

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

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();

}
}
Loading

0 comments on commit 6617c43

Please sign in to comment.