From 58766dd3b21f7cf37a6cc17d31e275739699374a Mon Sep 17 00:00:00 2001 From: Victor Alfaro Date: Mon, 2 Dec 2024 16:01:25 -0600 Subject: [PATCH] Issue 30682 automate regression testing for content editing vico (#30817) Co-authored-by: Bryan --- .../ai/validator/AIAppValidatorTest.java | 3 +- e2e/dotcms-e2e-node/README.md | 88 +++ e2e/dotcms-e2e-node/frontend/.env | 9 + e2e/dotcms-e2e-node/frontend/.env.ci | 4 + e2e/dotcms-e2e-node/frontend/.env.dev | 3 + e2e/dotcms-e2e-node/frontend/.env.local | 2 +- .../frontend/locators/globalLocators.ts | 38 ++ .../locators/navigation/menuLocators.ts | 48 ++ .../frontend/package-lock.json | 569 ++++++++++++++++++ e2e/dotcms-e2e-node/frontend/package.json | 3 +- .../frontend/playwright.config.ts | 35 +- .../tests/contentSearch/contentData.ts | 17 + .../contentSearch/portletIntegrity.spec.ts | 199 ++++++ .../frontend/tests/login/credentialsData.ts | 36 ++ .../frontend/tests/login/login.spec.ts | 47 ++ .../frontend/tests/login/translations.spec.ts | 29 + .../frontend/tests/welcome.spec.ts | 8 - .../frontend/utils/contentUtils.ts | 88 +++ .../frontend/utils/dotCMSUtils.ts | 33 + e2e/dotcms-e2e-node/frontend/yarn.lock | 120 ++-- 20 files changed, 1297 insertions(+), 82 deletions(-) create mode 100644 e2e/dotcms-e2e-node/README.md create mode 100644 e2e/dotcms-e2e-node/frontend/.env.dev create mode 100644 e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts create mode 100644 e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts create mode 100644 e2e/dotcms-e2e-node/frontend/package-lock.json create mode 100644 e2e/dotcms-e2e-node/frontend/tests/contentSearch/contentData.ts create mode 100644 e2e/dotcms-e2e-node/frontend/tests/contentSearch/portletIntegrity.spec.ts create mode 100644 e2e/dotcms-e2e-node/frontend/tests/login/credentialsData.ts create mode 100644 e2e/dotcms-e2e-node/frontend/tests/login/login.spec.ts create mode 100644 e2e/dotcms-e2e-node/frontend/tests/login/translations.spec.ts delete mode 100644 e2e/dotcms-e2e-node/frontend/tests/welcome.spec.ts create mode 100644 e2e/dotcms-e2e-node/frontend/utils/contentUtils.ts create mode 100644 e2e/dotcms-e2e-node/frontend/utils/dotCMSUtils.ts diff --git a/dotcms-integration/src/test/java/com/dotcms/ai/validator/AIAppValidatorTest.java b/dotcms-integration/src/test/java/com/dotcms/ai/validator/AIAppValidatorTest.java index dbdfe5291968..fc91f78b8786 100644 --- a/dotcms-integration/src/test/java/com/dotcms/ai/validator/AIAppValidatorTest.java +++ b/dotcms-integration/src/test/java/com/dotcms/ai/validator/AIAppValidatorTest.java @@ -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()); } } diff --git a/e2e/dotcms-e2e-node/README.md b/e2e/dotcms-e2e-node/README.md new file mode 100644 index 000000000000..e91295ed7e44 --- /dev/null +++ b/e2e/dotcms-e2e-node/README.md @@ -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 +``` diff --git a/e2e/dotcms-e2e-node/frontend/.env b/e2e/dotcms-e2e-node/frontend/.env index ad03f2f58dc1..e5fb472550f5 100644 --- a/e2e/dotcms-e2e-node/frontend/.env +++ b/e2e/dotcms-e2e-node/frontend/.env @@ -1,2 +1,11 @@ CI=false +DEV=false BASE_URL=http://localhost:8080 +HEADLESS=false +RETRIES=0 +REUSE_SERVER=false +INCLUDE_HTML=true + +USERNAME=admin@dotcms.com +PASSWORD=admin + diff --git a/e2e/dotcms-e2e-node/frontend/.env.ci b/e2e/dotcms-e2e-node/frontend/.env.ci index 8711f95abe93..18974e89fee2 100644 --- a/e2e/dotcms-e2e-node/frontend/.env.ci +++ b/e2e/dotcms-e2e-node/frontend/.env.ci @@ -1 +1,5 @@ CI=true +HEADLESS=true +RETRIES=1 +INCLUDE_HTML=false +REUSE_SERVER=true \ No newline at end of file diff --git a/e2e/dotcms-e2e-node/frontend/.env.dev b/e2e/dotcms-e2e-node/frontend/.env.dev new file mode 100644 index 000000000000..a7026e76a32a --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/.env.dev @@ -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 diff --git a/e2e/dotcms-e2e-node/frontend/.env.local b/e2e/dotcms-e2e-node/frontend/.env.local index f6c5e51966eb..b337350a023d 100644 --- a/e2e/dotcms-e2e-node/frontend/.env.local +++ b/e2e/dotcms-e2e-node/frontend/.env.local @@ -1 +1 @@ -BASE_URL=http://localhost:4200 \ No newline at end of file +REUSE_SERVER=true \ No newline at end of file diff --git a/e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts b/e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts new file mode 100644 index 000000000000..ef759cb80f46 --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/locators/globalLocators.ts @@ -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'; + diff --git a/e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts b/e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts new file mode 100644 index 000000000000..34bbedd8d8bc --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/locators/navigation/menuLocators.ts @@ -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(); + + } +} \ No newline at end of file diff --git a/e2e/dotcms-e2e-node/frontend/package-lock.json b/e2e/dotcms-e2e-node/frontend/package-lock.json new file mode 100644 index 000000000000..9857fd05b6c6 --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/package-lock.json @@ -0,0 +1,569 @@ +{ + "name": "frontend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "jsdom": "^25.0.1", + "xml2js": "^0.6.2" + }, + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/node": "^22.5.4", + "dotenv": "^16.4.5" + } + }, + "node_modules/@playwright/test": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz", + "integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.48.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "license": "MIT", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/playwright": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz", + "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.48.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz", + "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, + "node_modules/tldts": { + "version": "6.1.47", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.47.tgz", + "integrity": "sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.47" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.47", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.47.tgz", + "integrity": "sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA==", + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + } + } +} diff --git a/e2e/dotcms-e2e-node/frontend/package.json b/e2e/dotcms-e2e-node/frontend/package.json index ef141b79fde0..ec5bafc6d277 100644 --- a/e2e/dotcms-e2e-node/frontend/package.json +++ b/e2e/dotcms-e2e-node/frontend/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "devDependencies": { - "@playwright/test": "^1.47.0", + "@playwright/test": "^1.48.2", "@types/node": "^22.5.4", "dotenv": "^16.4.5" }, @@ -15,6 +15,7 @@ "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" } diff --git a/e2e/dotcms-e2e-node/frontend/playwright.config.ts b/e2e/dotcms-e2e-node/frontend/playwright.config.ts index 1e8d8fc026ed..d2594862903d 100644 --- a/e2e/dotcms-e2e-node/frontend/playwright.config.ts +++ b/e2e/dotcms-e2e-node/frontend/playwright.config.ts @@ -1,6 +1,7 @@ -import dotenv from 'dotenv'; +import * as dotenv from 'dotenv'; import * as path from "node:path"; import { defineConfig, devices } from '@playwright/test'; +import {ReporterDescription} from "playwright/types/test"; const resolveEnvs = () => { const envFiles = ['.env']; @@ -9,6 +10,8 @@ const resolveEnvs = () => { envFiles.push('.env.local'); } else if (process.env.CURRENT_ENV === 'ci') { envFiles.push('.env.ci'); + } else if (process.env.CURRENT_ENV === 'dev') { + envFiles.push('.env.dev'); } envFiles.forEach((file) => { @@ -19,7 +22,20 @@ const resolveEnvs = () => { }); }; +const resolveReporter = () => { + const reporter: ReporterDescription[] = [ + ['junit'], + ['github'] + ]; + if (!!process.env.INCLUDE_HTML) { + reporter.push(['html']) + } + + return reporter; +} + resolveEnvs(); +const reporter = resolveReporter(); /** * See https://playwright.dev/docs/test-configuration. @@ -31,20 +47,19 @@ export default defineConfig({ /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, + retries: parseInt(process.env.RETRIES), /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [ - ['junit'], - ['github'] - ], + timeout: 30000, + + reporter, /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { baseURL: process.env.BASE_URL, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', - headless: process.env.CI === 'true', + headless: !!process.env.HEADLESS, }, /* Configure projects for major browsers */ projects: [ @@ -53,7 +68,7 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'] }, }, - { + /*{ name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, @@ -61,12 +76,12 @@ export default defineConfig({ { name: 'webkit', use: { ...devices['Desktop Safari'] }, - }, + },*/ ], webServer: { command: 'nx serve dotcms-ui', cwd: '../../../core-web', url: process.env.BASE_URL + '/dotAdmin', - reuseExistingServer: !!process.env.CI, + reuseExistingServer: !!process.env.REUSE_SERVER } }); diff --git a/e2e/dotcms-e2e-node/frontend/tests/contentSearch/contentData.ts b/e2e/dotcms-e2e-node/frontend/tests/contentSearch/contentData.ts new file mode 100644 index 000000000000..f57860e32692 --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/tests/contentSearch/contentData.ts @@ -0,0 +1,17 @@ +/** + * Content to add a Rich Text content + */ +export const richTextContent = { + title: "Automation Test", + body: "This is a sample content" +} + +/** + * Content actions text content locators + */ +export const contentProperties = { + language: "English (US)", + publishWfAction: "Publish" +} + + diff --git a/e2e/dotcms-e2e-node/frontend/tests/contentSearch/portletIntegrity.spec.ts b/e2e/dotcms-e2e-node/frontend/tests/contentSearch/portletIntegrity.spec.ts new file mode 100644 index 000000000000..0bbd5db94c02 --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/tests/contentSearch/portletIntegrity.spec.ts @@ -0,0 +1,199 @@ +import {expect, test} from '@playwright/test'; +import {dotCMSUtils} from '../../utils/dotCMSUtils'; +import {ContentUtils} from '../../utils/contentUtils'; +import {addContent, iFramesLocators, richText} from '../../locators/globalLocators'; +import { + GroupEntriesLocators, + MenuEntriesLocators, + ToolEntriesLocators +} from '../../locators/navigation/menuLocators'; +import {contentProperties, richTextContent} from './contentData'; + +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 + await expect(page.locator('p-breadcrumb')).toContainText('Search All'); +}); + + +/** + * Test to validate the portlet title + * @param page + */ +test('Validate portlet title', async ({page}) => { + await expect(page.locator('p-breadcrumb')).toContainText('Search All'); +}); + + +/** + * Test to validate the filter is present and usable in the content portlet + * @param page + */ +test('Search filter', async ({page}) => { + const contentUtils = new ContentUtils(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); + + // 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 page.keyboard.press('Enter'); + + //validate the search filter is working + await expect(iframe.getByRole('link', {name: 'Automation Test'}).first()).toBeVisible(); +}); + +/** + * Test to validate the views are working in the content portlet + * @param page + */ +test('Validate views buttons', async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + + await iframe.getByLabel('List', {exact: true}).isVisible(); + await iframe.getByLabel('Card').isVisible(); + + // Click on the card view + await iframe.getByLabel('Card').click(); + await iframe.locator('.hydrated > dot-contentlet-thumbnail > .hydrated').first().isVisible(); +}); + +/** + * Test to validate the add content button is present and functional + * @param page + */ +test('Validate add content button is present and functional', async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + + await iframe.locator(addContent.addBtn).click(); + await expect(iframe.getByLabel(addContent.addNewMenuLabel).getByText(addContent.addNewContentSubMenu)).toBeVisible(); +}); + + +/** + * Test to validate the behavior of the bulk Workflow actions button + * @param page + */ +test('Validate bulk Workflow actions', async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + + // Validate the button is present and disabled by default + const workflowActionsButton = iframe.getByRole('button', {name: 'Available Workflow Actions'}); + await expect(workflowActionsButton).toBeDisabled(); + + // Check the checkbox and validate the button is enabled + await iframe.locator('#checkbox0').check(); + await expect(workflowActionsButton).toBeEnabled(); + + // Click on the button and validate the dialog is present + await workflowActionsButton.click(); + await expect(iframe.locator('.dijitDialog[role="dialog"]').first()).toBeVisible(); +}); + + +/** + * Test to validate the search query is generating the correct results + * @param page + */ +test('Validate the search query', async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + await new ContentUtils(page).showQuery(iframe); + await expect(iframe.locator('#queryResults')).toBeVisible(); +}); + +/** + * Test to validate the API button is working in the search query modal + * @param page + */ +test('Validate the API link in search query modal is working', async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + await new ContentUtils(page).showQuery(iframe); + + // Wait for the new tab to open + const queryModal = page.waitForEvent('popup'); + await iframe.getByText('API', {exact: true}).click(); + const newPage = await queryModal; + + // Validate the new tab has opened + await newPage.waitForLoadState(); + expect(newPage.url()).toContain('about:blank'); + + //close the new tab + await newPage.close(); +}); + +/** + * Test to validate the clear button in the search filter + * @param page + */ +test("Validate the clear button in the search filter", async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + + //expand the search filter + await iframe.getByRole('link', {name: 'Advanced'}).click(); + + // Select the workflow in the search filter + await iframe.locator('#widget_scheme_id [data-dojo-attach-point="_buttonNode"]').click(); + await iframe.getByRole('option', {name: 'System Workflow'}).click(); + await page.waitForTimeout(1000); + + // Select the step in the search filter + await iframe.locator('div[id=\'widget_step_id\'] div[data-dojo-attach-point=\'_buttonNode\']').click(); + await iframe.getByRole('option', {name: 'New'}).click(); + + // Select the Show in the search filter + await iframe.locator('#widget_showingSelect [data-dojo-attach-point="_buttonNode"]').click(); + await iframe.getByRole('option', {name: 'Unpublished'}).click(); + + // Click on clear button + await iframe.getByLabel('Clear').click(); + + // Validate the search filter has been cleared + expect(await iframe.locator('input[name="scheme_id_select"]').getAttribute('value')).toBe('catchall'); + expect(await iframe.locator('input[name="step_id_select"]').getAttribute('value')).toBe('catchall'); + expect(await iframe.locator('#showingSelect').getAttribute('value')).toBe('All'); +}); + +/** + * Test to validate the hide button in the search filter + * @param page + */ +test('Validate the hide button collapse the filter', async ({page}) => { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + + await expect(iframe.getByRole('button', {name: 'Search'})).toBeVisible(); + await iframe.getByRole('link', {name: 'Advanced'}).click(); + + await page.waitForTimeout(1000); + await expect(iframe.getByRole('link', {name: 'Advanced'})).not.toBeVisible(); + + // Click on the hide button + await iframe.getByRole('link', {name: 'Hide'}).click(); + await page.waitForTimeout(1000); + + // Validate the filter has been collapsed + await expect(iframe.getByRole('link', {name: 'Advanced'})).toBeVisible(); +}); + + diff --git a/e2e/dotcms-e2e-node/frontend/tests/login/credentialsData.ts b/e2e/dotcms-e2e-node/frontend/tests/login/credentialsData.ts new file mode 100644 index 000000000000..8f46ed4bc30a --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/tests/login/credentialsData.ts @@ -0,0 +1,36 @@ +/** + * This is a valid user that can do everything + */ +export const admin1 = { + username: "admin@dotcms.com", + password: "admin" +} + +/** + * This is a limited user that can only view the content + */ +export const limited1 = { + username: "chris@dotcms.com", + password: "chris" +} + +/** + * Combination of a valid user and wrong password + */ +export const wrong1 = { + username: "admin@dotcms.com", + password: "password" +} + +/** + * Combination of a wrong user and valid password + */ +export const wrong2 = { + username: "chris2@dotcms.com", + password: "chris" +} + + + + + diff --git a/e2e/dotcms-e2e-node/frontend/tests/login/login.spec.ts b/e2e/dotcms-e2e-node/frontend/tests/login/login.spec.ts new file mode 100644 index 000000000000..fc0d2b6c56e2 --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/tests/login/login.spec.ts @@ -0,0 +1,47 @@ +import {test, expect} from '@playwright/test'; +import {admin1, limited1, wrong1, wrong2} from './credentialsData'; + + +const validCredentials = [ + {username: admin1.username, password: admin1.password}, // admin user +]; + +/** + * Test to validate the login functionality with valid credentials + */ +validCredentials.forEach(({username, password}) => { + test(`Login with Valid Credentials: ${username}`, async ({page}) => { + await page.goto('/dotAdmin'); + + await page.fill('input[id="inputtext"]', username); + await page.fill('input[id="password"]', password); + await page.getByTestId('submitButton').click(); + + // Assertion and further test steps + await expect(page.getByRole('link', {name: 'Getting Started'})).toBeVisible(); + }); +}); + + +const invalidCredentials = [ + {username: wrong1.username, password: wrong1.password}, // Valid username, invalid password + {username: wrong2.username, password: wrong2.password}, // Invalid username, valid password +]; + +/** + * Test to validate the login functionality with invalid credentials + */ +invalidCredentials.forEach(credentials => { + test(`Login with invalid Credentials: ${credentials.username}`, async ({page}) => { + const {username, password} = credentials; + + await page.goto('/dotAdmin'); + + await page.fill('input[id="inputtext"]', username); + await page.fill('input[id="password"]', password); + await page.getByTestId('submitButton').click(); + + // Assertion and further test steps + await expect(page.getByTestId('message')).toBeVisible({timeout: 30000}); + }); +}); \ No newline at end of file diff --git a/e2e/dotcms-e2e-node/frontend/tests/login/translations.spec.ts b/e2e/dotcms-e2e-node/frontend/tests/login/translations.spec.ts new file mode 100644 index 000000000000..a09148114b1b --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/tests/login/translations.spec.ts @@ -0,0 +1,29 @@ +import {expect, test} from '@playwright/test'; +import {assert} from 'console'; + +const languages = [ + {language: 'español (España)', translation: '¡Bienvenido!'}, + {language: 'italiano (Italia)', translation: 'Benvenuto!'}, + {language: 'français (France)', translation: 'Bienvenue !'}, + {language: 'Deutsch (Deutschland)', translation: 'Willkommen!'}, + {language: '中文 (中国)', translation: '欢迎'}, + {language: 'Nederlands (Nederland)', translation: 'Welkom!'}, + {language: 'русский (Россия)', translation: 'Добро пожаловать!'}, + {language: 'suomi (Suomi)', translation: 'Tervetuloa!'} +]; + +/** + * Test to validate the translations of the login page + */ +languages.forEach(list => { + test(`Validate Translation: ${list.language}`, async ({page}) => { + const {language, translation} = list; + + await page.goto('/dotAdmin'); + await page.getByLabel('dropdown trigger').click(); + await page.getByText(language).click(); + + // Assertion of the translation + assert(await expect(page.getByTestId('header')).toContainText(translation)); + }); +}); diff --git a/e2e/dotcms-e2e-node/frontend/tests/welcome.spec.ts b/e2e/dotcms-e2e-node/frontend/tests/welcome.spec.ts deleted file mode 100644 index a29905b6737d..000000000000 --- a/e2e/dotcms-e2e-node/frontend/tests/welcome.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { test, expect } from '@playwright/test'; - -test('has title', async ({ page }) => { - await page.goto('/dotAdmin'); - - // Expect h3 to contain a substring. - expect(await page.locator('h3').textContent()).toContain('Welcome!'); -}); diff --git a/e2e/dotcms-e2e-node/frontend/utils/contentUtils.ts b/e2e/dotcms-e2e-node/frontend/utils/contentUtils.ts new file mode 100644 index 000000000000..27417a82cb5c --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/utils/contentUtils.ts @@ -0,0 +1,88 @@ +import {Page, expect, FrameLocator} from '@playwright/test'; +import { iFramesLocators, richText } from '../locators/globalLocators'; + + +export class ContentUtils { + page: Page; + constructor(page: Page) { + this.page = page; + } + + /** + * Fill the rich text form + * @param page + * @param title + * @param body + * @param action + */ + async fillRichTextForm(page: Page, title: string, body: string, action: string) { + const dotIframe = page.frameLocator(iFramesLocators.dot_iframe); + await expect.soft( page.getByRole('heading')).toContainText(richText.label); + + //Fill title + await dotIframe.locator('#title').fill(title); + //Fill body + await dotIframe.locator('#block-editor-body div').nth(1).fill(body); + + //await dotIframe.locator(iFramesLocators.wysiwygFrame).contentFrame().locator('#tinymce').fill(body); + //Click on action + await dotIframe.getByText(action).click(); + //Wait for the content to be saved + + + await expect(dotIframe.getByText('Content saved')).toBeVisible({ timeout: 9000 }); + await expect(dotIframe.getByText('Content saved')).toBeHidden(); + //Click on close + await page.getByTestId('close-button').getByRole('button').click(); + } + + /** + * Add new content action on the content portlet + * @param page + * @param typeLocator + * @param typeString + */ + async addNewContentAction(page: Page, typeLocator: string, typeString: string) { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + await expect(iframe.locator('#structure_inode')).toBeVisible(); + await page.waitForTimeout(1000); + await iframe.locator('#widget_structure_inode div').first().click(); + await page.waitForTimeout(1000); + await iframe.getByText(typeLocator).click(); + await iframe.locator('#dijit_form_DropDownButton_0').click(); + await expect(iframe.getByLabel('actionPrimaryMenu')).toBeVisible(); + await iframe.getByLabel('▼').getByText('Add New Content').click(); + await expect(page.getByRole('heading')).toHaveText(typeString); + }; + + /** + * Select content type on filter on the content portlet + * @param page + * @param typeLocator + * @param typeString + */ + async selectTypeOnFilter(page: Page, typeLocator: string, typeString: string) { + const iframe = page.frameLocator(iFramesLocators.main_iframe); + + await expect.soft(iframe.locator('#structure_inode')).toBeVisible(); + await iframe.locator('#widget_structure_inode div').first().click(); + await iframe.getByText(typeLocator).click(); + } + + /** + * Show query on the content portlet + * @param iframe + */ + async showQuery(iframe : FrameLocator) { + await iframe.getByRole('button', { name: 'createOptions' }).click(); + + //Validate the search button has a sub-menu + 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(); + } +} + + diff --git a/e2e/dotcms-e2e-node/frontend/utils/dotCMSUtils.ts b/e2e/dotcms-e2e-node/frontend/utils/dotCMSUtils.ts new file mode 100644 index 000000000000..80d3c5ec1ab8 --- /dev/null +++ b/e2e/dotcms-e2e-node/frontend/utils/dotCMSUtils.ts @@ -0,0 +1,33 @@ +import { Page, expect, Locator } from '@playwright/test'; +import { loginLocators } from '../locators/globalLocators'; + +export class dotCMSUtils { + page: Page; + + /** + * Login to dotCMS + * @param page + * @param username + * @param password + */ + async login(page: Page, username: string, password: string) { + await page.goto('/dotAdmin'); + await page.waitForLoadState() + await page.fill(loginLocators.userNameInput, username); + await page.fill(loginLocators.passwordInput, password); + await page.getByTestId(loginLocators.loginBtn).click(); + await expect(page.getByRole('link', { name: 'Getting Started' })).toBeVisible(); + } + + /** + * Navigate to the content portlet providing the menu, group and tool locators + * @param menu + * @param group + * @param tool + */ + async navigate(menu : Locator, group : Locator, tool : Locator) { + await menu.click(); + await group.click(); + await tool.click(); + } +}; \ No newline at end of file diff --git a/e2e/dotcms-e2e-node/frontend/yarn.lock b/e2e/dotcms-e2e-node/frontend/yarn.lock index ef4eefe0e1c8..b24babe5f978 100644 --- a/e2e/dotcms-e2e-node/frontend/yarn.lock +++ b/e2e/dotcms-e2e-node/frontend/yarn.lock @@ -2,84 +2,84 @@ # yarn lockfile v1 -"@playwright/test@^1.47.0": - version "1.47.0" - resolved "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz#69fc55b10754147cc20021afbfa05747d4961bf0" - integrity sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA== +"@playwright/test@^1.48.2": + version "1.48.2" + resolved "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz" + integrity sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw== dependencies: - playwright "1.47.0" + playwright "1.48.2" "@types/node@^22.5.4": version "22.5.4" - resolved "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz#83f7d1f65bc2ed223bdbf57c7884f1d5a4fa84e8" + resolved "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz" integrity sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg== dependencies: undici-types "~6.19.2" agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== dependencies: debug "^4.3.4" asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" cssstyle@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz#161faee382af1bafadb6d3867a92a19bcb4aea70" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz" integrity sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA== dependencies: rrweb-cssom "^0.7.1" data-urls@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz" integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== dependencies: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -debug@4, debug@^4.3.4: +debug@^4.3.4, debug@4: version "4.3.7" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: ms "^2.1.3" decimal.js@^10.4.3: version "10.4.3" - resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== dotenv@^16.4.5: version "16.4.5" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== entities@^4.4.0: version "4.5.0" - resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== form-data@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" @@ -88,19 +88,19 @@ form-data@^4.0.0: fsevents@2.3.2: version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== html-encoding-sniffer@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz" integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== dependencies: whatwg-encoding "^3.1.1" http-proxy-agent@^7.0.2: version "7.0.2" - resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== dependencies: agent-base "^7.1.0" @@ -108,7 +108,7 @@ http-proxy-agent@^7.0.2: https-proxy-agent@^7.0.5: version "7.0.5" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz" integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== dependencies: agent-base "^7.0.2" @@ -116,19 +116,19 @@ https-proxy-agent@^7.0.5: iconv-lite@0.6.3: version "0.6.3" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" is-potential-custom-element-name@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== jsdom@^25.0.1: version "25.0.1" - resolved "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz#536ec685c288fc8a5773a65f82d8b44badcc73ef" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz" integrity sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw== dependencies: cssstyle "^4.1.0" @@ -155,137 +155,137 @@ jsdom@^25.0.1: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.12: version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" ms@^2.1.3: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== nwsapi@^2.2.12: version "2.2.12" - resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz" integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== parse5@^7.1.2: version "7.1.2" - resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== dependencies: entities "^4.4.0" -playwright-core@1.47.0: - version "1.47.0" - resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz#b54ec060fd83e5c2e46b63986b5ebb5e96ace427" - integrity sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg== +playwright-core@1.48.2: + version "1.48.2" + resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz" + integrity sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA== -playwright@1.47.0: - version "1.47.0" - resolved "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz#fb9b028883fad11362f9ff63ce7ba44bda0bf626" - integrity sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww== +playwright@1.48.2: + version "1.48.2" + resolved "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz" + integrity sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ== dependencies: - playwright-core "1.47.0" + playwright-core "1.48.2" optionalDependencies: fsevents "2.3.2" punycode@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== rrweb-cssom@^0.7.1: version "0.7.1" - resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" + resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz" integrity sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg== "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sax@>=0.6.0: version "1.4.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + resolved "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== saxes@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + resolved "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz" integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== dependencies: xmlchars "^2.2.0" symbol-tree@^3.2.4: version "3.2.4" - resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== tldts-core@^6.1.47: version "6.1.47" - resolved "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.47.tgz#bb6deb97abb6ef04243af60968d2d0055a65cbd7" + resolved "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.47.tgz" integrity sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA== tldts@^6.1.32: version "6.1.47" - resolved "https://registry.npmjs.org/tldts/-/tldts-6.1.47.tgz#bab4edf5867e2bbd763e72d9435289de97b082df" + resolved "https://registry.npmjs.org/tldts/-/tldts-6.1.47.tgz" integrity sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw== dependencies: tldts-core "^6.1.47" tough-cookie@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz#6b6518e2b5c070cf742d872ee0f4f92d69eac1af" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz" integrity sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q== dependencies: tldts "^6.1.32" tr46@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + resolved "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz" integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== dependencies: punycode "^2.3.1" undici-types@~6.19.2: version "6.19.8" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== w3c-xmlserializer@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz" integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== dependencies: xml-name-validator "^5.0.0" webidl-conversions@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== whatwg-encoding@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz" integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== dependencies: iconv-lite "0.6.3" whatwg-mimetype@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz" integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== whatwg-url@^14.0.0: version "14.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz#00baaa7fd198744910c4b1ef68378f2200e4ceb6" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz" integrity sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw== dependencies: tr46 "^5.0.0" @@ -293,17 +293,17 @@ whatwg-url@^14.0.0: ws@^8.18.0: version "8.18.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== xml-name-validator@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz" integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== xml2js@^0.6.2: version "0.6.2" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz" integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== dependencies: sax ">=0.6.0" @@ -311,10 +311,10 @@ xml2js@^0.6.2: xmlbuilder@~11.0.0: version "11.0.1" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==