From cdded002f7edfef7431ad0331f656760473e2891 Mon Sep 17 00:00:00 2001 From: muhme Date: Wed, 20 Dec 2023 07:10:33 +0100 Subject: [PATCH] refactored test and installation - using Typescript in tests - moved helper methods into testHelper.ts - using wait-on instead of sleep (added NPM wait-on) - having all script output starting with "***" - adding build option to scripts/compose.sh - fixing some typos and improving some READMEs --- package-lock.json | 200 +++++++++++++++++ package.json | 3 + scripts/README.md | 6 +- scripts/clean.sh | 2 +- scripts/common.sh | 4 +- scripts/compose.sh | 11 +- scripts/cypress.sh | 2 +- scripts/exec.sh | 2 +- scripts/install.sh | 3 +- scripts/pack.sh | 6 +- scripts/test.sh | 4 +- test/README.md | 2 +- test/cypress/e2e/{test.cy.js => test.cy.ts} | 234 +++++++------------- test/cypress/e2e/testHelper.ts | 130 +++++++++++ test/cypress/joomla-cypress.d.ts | 13 ++ test/cypress/tsconfig.json | 8 + 16 files changed, 458 insertions(+), 172 deletions(-) rename test/cypress/e2e/{test.cy.js => test.cy.ts} (65%) create mode 100644 test/cypress/e2e/testHelper.ts create mode 100644 test/cypress/joomla-cypress.d.ts create mode 100644 test/cypress/tsconfig.json diff --git a/package-lock.json b/package-lock.json index f5ef1ce..3a9331f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,212 @@ "license": "MIT", "dependencies": { "joomla-cypress": "github:muhme/joomla-cypress#issue-9-fix-functions" + }, + "devDependencies": { + "wait-on": "^7.2.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, "node_modules/joomla-cypress": { "version": "0.0.18", "resolved": "git+ssh://git@github.com/muhme/joomla-cypress.git#c3c61627727b6cff01c1acdb9d6e6b1db42e059b", "license": "GPL-2.0+" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": 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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "dev": true, + "dependencies": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } } } } diff --git a/package.json b/package.json index 8c9179a..5ee0d9e 100644 --- a/package.json +++ b/package.json @@ -6,5 +6,8 @@ "license": "MIT", "dependencies": { "joomla-cypress": "github:muhme/joomla-cypress#issue-9-fix-functions" + }, + "devDependencies": { + "wait-on": "^7.2.0" } } diff --git a/scripts/README.md b/scripts/README.md index 407428d..15ade94 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -6,7 +6,7 @@ The scripts are used on the Mac command line, but should also work on Linux and | Script | Description | Additional Info | | --- | --- | --- | -| `scripts/compose.sh` | Delete the six Docker containers and build them new | | +| `scripts/compose.sh` | Delete the six Docker containers and build them new | - with optional argument `build` an docker compose build --no-cache is executed in advance | | `scripts/exec.sh` | Get access to the Joomla Docker container and **linking** the module source | - Linking maps the local host folder into the Joomla Docker container to test code changes immediately | | `scripts/cypress.sh` | Open Cypress in GUI mode on local host for desired Joomla version | Needs Cypress installed on host. | | `scripts/install.sh` | Install Joomla and module `mod_zitat_service_de` | - Using Cypress in headless mode
- With argument 3, 4, or 5 install this Joomla version; without argument install all three
- With environment variable `CYPRESS_OPTIONS`, e.g., `CYPRESS_OPTIONS="video=true" scripts/install.sh 5` | @@ -16,8 +16,8 @@ The scripts are used on the Mac command line, but should also work on Linux and And now you are ready for ... triple speed :smiley: with the creation of six Docker containers, the installation of Joomla and the modules three times and testing the module in all three Joomla versions with only one command line. ``` -$ scripts/compose.sh && sleep 5 && scripts/install.sh && scripts/test.sh +$ scripts/compose.sh && scripts/install.sh && scripts/test.sh ``` > [!WARNING] -> After using `scripts/exec.sh` the module folder inside Docker container is symbolic linked. If you uninstall the module you delete all source files in your host folder! :point_right: Inside container, you have to delete symbolic link before. +> After using `scripts/exec.sh` the module folder inside Docker container is symbolic linked. If you uninstall the module in Joomla, you will delete all source files in your host folder! :point_right: Inside container, you have to delete symbolic link before. diff --git a/scripts/clean.sh b/scripts/clean.sh index e45203f..0780940 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -6,5 +6,5 @@ # # clean.sh - delete all quote_joomla_* docker containers -echo 'Removing all docker containers quote_joomla_*' +echo '*** Removing all docker containers quote_joomla_*' docker ps -a --format '{{.Names}}' | grep '^quote_joomla_' | xargs docker rm -f diff --git a/scripts/common.sh b/scripts/common.sh index 75d6cee..d55827d 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -29,7 +29,7 @@ all_versions=(3 4 5) # checkVersion() { if [ "$#" -gt 1 ] || ([ "$#" -eq 1 ] && ! containsElement "$1" "${all_versions[@]}"); then - echo "Error: no argument (for all) or Joomla version from: ${all_versions[@]}" + echo "*** Error: no argument (for all) or Joomla version from: ${all_versions[@]}" exit 1 fi @@ -50,7 +50,7 @@ checkVersion() { # checkOneVersion() { if [ "$#" -ne 1 ] || ! containsElement "$1" "${all_versions[@]}"; then - echo "Error: needs Joomla version as one and only argument from: ${all_versions[@]}" + echo "*** Error: needs Joomla version as one and only argument from: ${all_versions[@]}" exit 1 fi } diff --git a/scripts/compose.sh b/scripts/compose.sh index a2bd795..dee353c 100755 --- a/scripts/compose.sh +++ b/scripts/compose.sh @@ -4,10 +4,15 @@ # This software is licensed under the MIT License. # For the full license text, see the LICENSE file in the project root or visit https://opensource.org/licenses/MIT # -# build.sh - delete the six docker containers and build them new +# compose.sh - delete the six docker containers and build them new -echo 'Removing all docker containers quote_joomla_*' +echo '*** Removing all docker containers quote_joomla_*' docker ps -a --format '{{.Names}}' | grep '^quote_joomla_' | xargs docker rm -f -echo 'Creating docker containers new' +if [ $# -eq 1 ] && [ "$1" = "build" ] ; then + echo '*** Docker compose build --no-cache' + docker compose build --no-cache +fi + +echo '*** Docker compose up' docker compose up -d diff --git a/scripts/cypress.sh b/scripts/cypress.sh index 6ea0ab8..5214ce4 100755 --- a/scripts/cypress.sh +++ b/scripts/cypress.sh @@ -9,5 +9,5 @@ source scripts/common.sh checkOneVersion $* -echo "open Cypress for Joomla $1" +echo "*** Open Cypress for Joomla $1" cd test && export "JOOMLA_VERSION=$1" && npx cypress open diff --git a/scripts/exec.sh b/scripts/exec.sh index 031d202..66f5c04 100755 --- a/scripts/exec.sh +++ b/scripts/exec.sh @@ -9,5 +9,5 @@ source scripts/common.sh checkOneVersion $* -echo "open Joomla $1 container and sym linking modules/mod_zitat_service_de" +echo "*** Open Joomla $1 container and sym linking modules/mod_zitat_service_de" docker exec -it "quote_joomla_$1" /bin/bash -c "cd /var/www/html/modules && rm -rf mod_zitat_service_de && ln -s /quote_joomla/src mod_zitat_service_de && ls -l mod_zitat_service_de && bash" diff --git a/scripts/install.sh b/scripts/install.sh index e10220b..b4b083b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -12,6 +12,7 @@ source scripts/common.sh checkVersion $* for version in ${versions[@]}; do - echo "installing Joomla $version and module mod_zitat_service_de" + echo "*** Installing Joomla $version and module mod_zitat_service_de" + node_modules/wait-on/bin/wait-on -l -t "60s" "http://localhost:200${version}" docker exec -it quote_joomla_cypress sh -c "JOOMLA_VERSION=$version cypress run --spec cypress/e2e/install.cy.js $config_cypress_options" done diff --git a/scripts/pack.sh b/scripts/pack.sh index 95c416e..17cbad7 100755 --- a/scripts/pack.sh +++ b/scripts/pack.sh @@ -32,7 +32,7 @@ calculate_hash() { shasum -a 512 "$FILE" | awk '{print $1}' # If neither command is found, print an error message else - echo "Error: Command sha512sum or shasum not found." >&2 + echo "*** Error: Command sha512sum or shasum not found." >&2 return 1 fi } @@ -46,7 +46,7 @@ ZIP="dist/mod_zitat_service_de_${VERSION}.zip" # module extension packed as ZIP UPDATE="dist/update.xml" if [ ! -f "$MANIFEST" ]; then - echo "Error: Missing file \"$MANIFEST\" – are you in project root directory?" + echo "*** Error: Missing file \"$MANIFEST\" – are you in project root directory?" exit 1 fi @@ -62,4 +62,4 @@ sed "s|\(.*\).*|\1${HASH}|; \ s|\(.*\)/download/.*/mod_zitat_service_de_.*\.zip\(.*\)|\1/download/${VERSION}/mod_zitat_service_de_${VERSION}.zip\2|" $UPDATE > $TMP && cp $TMP $UPDATE # work is done -echo "version $VERSION packed as $ZIP and $UPDATE updated" +echo "*** Version $VERSION packed as $ZIP and $UPDATE updated" diff --git a/scripts/test.sh b/scripts/test.sh index fca681e..41360ff 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -12,6 +12,6 @@ source scripts/common.sh checkVersion $* for version in ${versions[@]}; do - echo "testing module mod_zitat_service_de in Joomla $version" - docker exec -it quote_joomla_cypress sh -c "JOOMLA_VERSION=$version cypress run --spec cypress/e2e/test.cy.js $options" + echo "*** Testing module mod_zitat_service_de in Joomla $version" + docker exec -it quote_joomla_cypress sh -c "JOOMLA_VERSION=$version cypress run --spec cypress/e2e/test.cy.ts $options" done diff --git a/test/README.md b/test/README.md index df39b4e..ed8da0d 100644 --- a/test/README.md +++ b/test/README.md @@ -39,7 +39,7 @@ host$ scripts/install.sh 5 Running: install.cy.js (1 of 1) - Install Joomla 4 and module zitat-service + *** Install Joomla 5 and module zitat-service ✓ Install Joomla and module zitat-service (40084ms) (Run Finished) diff --git a/test/cypress/e2e/test.cy.js b/test/cypress/e2e/test.cy.ts similarity index 65% rename from test/cypress/e2e/test.cy.js rename to test/cypress/e2e/test.cy.ts index ec3c35a..d2cd29a 100644 --- a/test/cypress/e2e/test.cy.js +++ b/test/cypress/e2e/test.cy.ts @@ -9,115 +9,26 @@ // using doAdministratorLogin() from npm joomla-cypress, but most by Cypress 'native' as also supporting Joomla 3 import "joomla-cypress"; +import * as TestHelpers from "./testHelper"; describe(`Test module zitat-service.de for Joomla ${Cypress.env( "joomla_version" )}`, () => { const languages = ["de", "en", "es", "ja", "uk"]; - /** - * Set module options with: - * 1. backend login as admin - * 2. open the module zitat-service.de - * 3. reset all four module options to the default values - * 4. set given module options with #id to value - * 5. reset all three advanced options to the default values - * 6. set given advanced options with #id to value - * 7. save module configuration - */ - function setOption(options, advanced = {}) { - // 1. backend login as admin - if (Cypress.env("joomla_version") === "3") { - // do admin login by own - cy.visit("/administrator/index.php"); - cy.get("#mod-login-username").type(Cypress.env("username")); - cy.get("#mod-login-password").type(Cypress.env("password")); - cy.get("button.btn.btn-primary.btn-block.btn-large.login-button").click(); - } else { - cy.doAdministratorLogin(Cypress.env("username"), Cypress.env("password")); - } - - // 2. open the module zitat-service.de - cy.visit("/administrator/index.php?option=com_modules"); - //cy.searchForItem("zitat-service.de") - don't use as not available for Joomla 3 - cy.contains("a", "zitat-service.de").should("be.visible").click(); - - // 3. reset all four module options to the default values ('*', respective 'frontend' for language) - cy.get("#jform_params_user") - .invoke("val", "") - .trigger("change", { force: true }); - cy.get("#jform_params_author") - .invoke("val", "") - .trigger("change", { force: true }); - cy.get("#jform_params_category") - .invoke("val", "") - .trigger("change", { force: true }); - cy.get("#jform_params_language").select("", { force: true }); - - // 4. set given module options with #id to value - Object.entries(options).forEach(([id, value]) => { - cy.log(`Set module parameter "${id}" to "${value}"`); - cy.get(id).invoke("val", value).trigger("change", { force: true }); - }); - - // 5. reset all three advanced options to the default values (clear, respective 1 for the radio-button) - if (Cypress.env("joomla_version") === "3") { - // Joomla 3 uses the Bootstrap 2.x framework for its admin UI - cy.contains("li a", "Advanced").click(); - } else { - cy.get( - 'div[role="tablist"] button[aria-controls="attrib-advanced"]' - ).click(); - } - cy.get("#jform_params_target").clear(); - cy.get( - 'input[type="radio"][name="jform[params][script]"][value="1"]' - ).check(); - cy.get("#jform_params_height").clear({ force: true }); - - // 6. set given advanced options with #id to value - Object.entries(advanced).forEach(([id, value]) => { - if (value === "check") { - cy.log(`Check advanced parameter "${id}"`); - cy.get(id).check(); - cy.wait(3000); - } else { - cy.log(`Set advanced parameter "${id}" to "${value}"`); - cy.get(id).invoke("val", value).trigger("change", { force: true }); - } - }); - - // 7. save module configuration - cy.get("button.button-save").contains("Save & Close").click(); - // Check for the success message (Joomla 3 w/o final dot) - cy.contains(".alert-message", /Module saved\.?/, { timeout: 30000 }).should( - "be.visible" - ); - - // ignore backend admin logout + // user 'heikoAdmin' (id 1) has exactly one quote in each language + interface TestData { + quotation: string; + quotationLink: string; + source: string; + sourceLink?: string; + author?: string; + authorLink?: string; } - - /** - * do cy.visit() and check for deprecated notice - * @param string path - */ - function myVisit(path) { - cy.visit(path); - // wait for the body element to be available - cy.get("body").should(($body) => { - // get the text of the body element - const text = $body.text(); - // assert that the 'Deprecated: ' string is not present - expect(text).not.to.include("Deprecated: "); - // assert that the 'Warning: ' string is not present - expect(text).not.to.include("Warning: "); - // assert that the 'Error: ' string is not present - expect(text).not.to.include("Error: "); - }); + interface LanguageTestData { + [key: string]: TestData; } - - // user 'heikoAdmin' (id 1) has exactly one quote in each language - const heikoAdminTestData = { + const heikoAdminTestData: LanguageTestData = { de: { quotation: "der zankapfel schmeckt bitter", quotationLink: "https://www.zitat-service.de/de/quotations/1871", @@ -159,7 +70,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("JavaScript-based and set user and frontend multi-language test", () => { // choose user 'heikoAdmin' (id 1) as this one has exactly one quote in each language it("prepare multi-language test with choosing user 'heikoAdmin'", function () { - setOption({ "#jform_params_user": "1" }); + TestHelpers.setOption({ "#jform_params_user": "1" }); }); Object.entries(heikoAdminTestData).forEach( @@ -168,7 +79,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( { quotation, quotationLink, source, sourceLink, author, authorLink }, ]) => { it(`check the presence of quote elements in ${lang}`, () => { - myVisit("/index.php/" + lang); + TestHelpers.myVisit("/index.php/" + lang); //
only from JavaScript cy.get("#zitat-service").should("exist"); @@ -205,7 +116,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("Joomla-based and set user and frontend multi-language test", () => { // choose user 'heikoAdmin' (id 1) as this one has exactly one quote in each language it("prepare multi-language test with choosing user 'heikoAdmin' and query method 'from Joomla'", function () { - setOption( + TestHelpers.setOption( { "#jform_params_user": "1" }, { 'input[type="radio"][name="jform[params][script]"][value="0"]': @@ -220,7 +131,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( { quotation, quotationLink, source, sourceLink, author, authorLink }, ]) => { it(`check the presence of quote elements in ${lang}`, () => { - myVisit("/index.php/" + lang); + TestHelpers.myVisit("/index.php/" + lang); //
only from JavaScript cy.get("#zitat-service").should("not.exist"); @@ -256,7 +167,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("set author option", () => { // author Mark Twain (id 36) has 20 quotes in German and English it("prepare author test with choosing author 'Mark Twain'", function () { - setOption({ "#jform_params_author": "36" }); + TestHelpers.setOption({ "#jform_params_author": "36" }); }); // expected results @@ -273,31 +184,30 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( // five tests in the five languages languages.forEach((lang) => { - it(`check ${ - testData[lang] ? "the presence of quote for author" : "error" - } in ${lang}`, () => { - myVisit(`/index.php/${lang}`); - cy.get("#zitat-service").should("exist"); - if (testData[lang]) { - cy.get(".quote .source").contains(testData[lang].author); - if (testData[lang].authorLink) { - cy.get(".quote .source") - .find('a[href="' + testData[lang].authorLink + '"]') - .should("have.attr", "href", testData[lang].authorLink); + it(`check ${testData[lang] ? "the presence of quote for author" : "error" + } in ${lang}`, () => { + TestHelpers.myVisit(`/index.php/${lang}`); + cy.get("#zitat-service").should("exist"); + if (testData[lang]) { + cy.get(".quote .source").contains(testData[lang].author); + if (testData[lang].authorLink) { + cy.get(".quote .source") + .find('a[href="' + testData[lang].authorLink + '"]') + .should("have.attr", "href", testData[lang].authorLink); + } + } else { + cy.get("#zitat-service").contains( + "Error: No quote found for given parameters" + ); } - } else { - cy.get("#zitat-service").contains( - "Error: No quote found for given parameters" - ); - } - }); + }); }); }); describe("set category option", () => { // category 'Ant' (id 305) has one quote in German it("prepare category test with choosing category 'Ant'", function () { - setOption({ "#jform_params_category": "305" }); + TestHelpers.setOption({ "#jform_params_category": "305" }); }); // expected results @@ -310,29 +220,28 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( // five tests in the five languages languages.forEach((lang) => { - it(`check ${ - testData[lang] ? "the presence of quote for category" : "error" - } in ${lang}`, () => { - myVisit(`/index.php/${lang}`); - cy.get("#zitat-service").should("exist"); - if (testData[lang]) { - cy.get("#zitat-service .quote").should("exist"); - cy.get(".quote .quotation") - .should("exist") - .contains(testData[lang].quotation); - } else { - cy.get("#zitat-service").contains( - "Error: No quote found for given parameters" - ); - } - }); + it(`check ${testData[lang] ? "the presence of quote for category" : "error" + } in ${lang}`, () => { + TestHelpers.myVisit(`/index.php/${lang}`); + cy.get("#zitat-service").should("exist"); + if (testData[lang]) { + cy.get("#zitat-service .quote").should("exist"); + cy.get(".quote .quotation") + .should("exist") + .contains(testData[lang].quotation); + } else { + cy.get("#zitat-service").contains( + "Error: No quote found for given parameters" + ); + } + }); }); }); describe("set all languages option", () => { // category 'Ant' (id 305) has one quote in German it("prepare category test with choosing category 'Ant' and language 'all'", function () { - setOption({ + TestHelpers.setOption({ "#jform_params_category": "305", "#jform_params_language": "all", }); @@ -345,7 +254,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( // five tests in the five languages languages.forEach((lang) => { it(`check the presence of quote in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get("#zitat-service").should("exist"); cy.get("#zitat-service .quote").should("exist"); cy.get(".quote .quotation").should("exist").contains(quote); @@ -356,7 +265,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("set one language 'de' option", () => { // category 'Ant' (id 305) has one quote in German it("prepare category test with choosing category 'Ant' and language 'de'", function () { - setOption({ + TestHelpers.setOption({ "#jform_params_category": "305", "#jform_params_language": "de", }); @@ -369,7 +278,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( // five tests in the five languages languages.forEach((lang) => { it(`check the presence of quote in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get("#zitat-service").should("exist"); cy.get("#zitat-service .quote").should("exist"); cy.get(".quote .quotation").should("exist").contains(quote); @@ -381,13 +290,13 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("JavaScript-based and no target for all links", () => { it("prepare reset to all defaults", function () { - setOption({}); + TestHelpers.setOption({}); }); // five tests in the five languages languages.forEach((lang) => { it(`check there is no target in any link for ${lang} in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get(".quote a").each(($el) => { // for each link found inside a .quote div, check that the target attribute is 'quoteCypressTest' cy.wrap($el).should("not.have.attr", "target", "quoteCypressTest"); @@ -398,13 +307,13 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("JavaScript-based and set target for all links", () => { it("prepare with target for HTML links", function () { - setOption({}, { "#jform_params_target": target }); + TestHelpers.setOption({}, { "#jform_params_target": target }); }); // five tests in the five languages languages.forEach((lang) => { it(`check target is set for all links in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get(".quote a").each(($el) => { // for each link found inside a .quote div, check that the target attribute is 'quoteCypressTest' cy.wrap($el).should("have.attr", "target", "quoteCypressTest"); @@ -415,7 +324,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("Joomla-based and no target for all links", () => { it("prepare query method 'from Joomla'", function () { - setOption( + TestHelpers.setOption( {}, { 'input[type="radio"][name="jform[params][script]"][value="0"]': @@ -427,7 +336,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( // five tests in the five languages languages.forEach((lang) => { it(`check there is no target in any link in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get(".quote a").each(($el) => { // for each link found inside a .quote div, check that the target attribute is 'quoteCypressTest' cy.wrap($el).should("not.have.attr", "target", "quoteCypressTest"); @@ -438,7 +347,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("Joomla-based and set target for all links", () => { it("prepare query method 'from Joomla' and set target for all links", function () { - setOption( + TestHelpers.setOption( {}, { "#jform_params_target": target, @@ -451,7 +360,7 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( // five tests in the five languages languages.forEach((lang) => { it(`check target is set for all links in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get(".quote a").each(($el) => { // for each link found inside a .quote div, check that the target attribute is 'quoteCypressTest' cy.wrap($el).should("have.attr", "target", "quoteCypressTest"); @@ -463,13 +372,13 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( describe("set advanced option min-height", () => { const minHeight = "234px"; it("prepare min-height test with setting height", function () { - setOption({}, { "#jform_params_height": minHeight }); + TestHelpers.setOption({}, { "#jform_params_height": minHeight }); }); // five tests in the five languages languages.forEach((lang) => { it(`check min-height in ${lang}`, () => { - myVisit(`/index.php/${lang}`); + TestHelpers.myVisit(`/index.php/${lang}`); cy.get(".quote a").each(($el) => { cy.get("#zitat-service").should(($div) => { const style = window.getComputedStyle($div[0]); @@ -479,4 +388,21 @@ describe(`Test module zitat-service.de for Joomla ${Cypress.env( }); }); }); + + // describe("Backend I18N translation", () => { + // it("prepare reset to all defaults", function () { + // TestHelpers.setOption({}); + // }); + + // // five tests in the five languages + // languages.forEach((lang) => { + // it(`check ${lang}`, () => { + // TestHelpers.myVisit(`/index.php/${lang}`); + // cy.get(".quote a").each(($el) => { + // // for each link found inside a .quote div, check that the target attribute is 'quoteCypressTest' + // cy.wrap($el).should("not.have.attr", "target", "quoteCypressTest"); + // }); + // }); + // }); + // }); }); diff --git a/test/cypress/e2e/testHelper.ts b/test/cypress/e2e/testHelper.ts new file mode 100644 index 0000000..49678d4 --- /dev/null +++ b/test/cypress/e2e/testHelper.ts @@ -0,0 +1,130 @@ +/// +/* + * MIT License, Copyright (c) 2023 Heiko Lübbe + * https://github.com/muhme/quote_wordpress + * + * test_helper.js - utility methods used in the tests + */ +import "joomla-cypress"; + +/** + * Do backend login as admin. + */ +function doLogin() { + + if (Cypress.env("joomla_version") === "3") { + // do admin login by own + cy.visit("/administrator/index.php"); + cy.get("#mod-login-username").type(Cypress.env("username")); + cy.get("#mod-login-password").type(Cypress.env("password")); + cy.get("button.btn.btn-primary.btn-block.btn-large.login-button").click(); + } else { + cy.doAdministratorLogin(Cypress.env("username"), Cypress.env("password")); + } +} +export { doLogin }; + +/** + * Open the module zitat-service.de. + */ +function openModule() { + + cy.visit("/administrator/index.php?option=com_modules"); + //cy.searchForItem("zitat-service.de") - don't use as not available for Joomla 3 + cy.contains("a", "zitat-service.de").should("be.visible").click(); +} +export { openModule }; + + /** + * Set module options with: + * 1. backend login as admin + * 2. open the module zitat-service.de + * 3. reset all four module options to the default values + * 4. set given module options with #id to value + * 5. reset all three advanced options to the default values + * 6. set given advanced options with #id to value + * 7. save module configuration + */ + function setOption(options, advanced = {}) { + // 1. backend login as admin + doLogin(); + + // 2. open the module zitat-service.de + openModule(); + + // 3. reset all four module options to the default values ('*', respective 'frontend' for language) + cy.get("#jform_params_user") + .invoke("val", "") + .trigger("change", { force: true }); + cy.get("#jform_params_author") + .invoke("val", "") + .trigger("change", { force: true }); + cy.get("#jform_params_category") + .invoke("val", "") + .trigger("change", { force: true }); + cy.get("#jform_params_language").select("", { force: true }); + + // 4. set given module options with #id to value + Object.entries(options).forEach(([id, value]) => { + cy.log(`Set module parameter "${id}" to "${value}"`); + cy.get(id).invoke("val", value).trigger("change", { force: true }); + }); + + // 5. reset all three advanced options to the default values (clear, respective 1 for the radio-button) + if (Cypress.env("joomla_version") === "3") { + // Joomla 3 uses the Bootstrap 2.x framework for its admin UI + cy.contains("li a", "Advanced").click(); + } else { + cy.get( + 'div[role="tablist"] button[aria-controls="attrib-advanced"]' + ).click(); + } + cy.get("#jform_params_target").clear(); + cy.get( + 'input[type="radio"][name="jform[params][script]"][value="1"]' + ).check(); + cy.get("#jform_params_height").clear({ force: true }); + + // 6. set given advanced options with #id to value + Object.entries(advanced).forEach(([id, value]) => { + if (value === "check") { + cy.log(`Check advanced parameter "${id}"`); + cy.get(id).check(); + cy.wait(3000); + } else { + cy.log(`Set advanced parameter "${id}" to "${value}"`); + cy.get(id).invoke("val", value).trigger("change", { force: true }); + } + }); + + + // 7. save module configuration + cy.get("button.button-save").contains("Save & Close").click(); + // Check for the success message (Joomla 3 w/o final dot) + cy.contains(".alert-message", /Module saved\.?/, { timeout: 30000 }).should( + "be.visible" + ); + + // ignore backend admin logout + } + export {setOption}; + + /** + * do cy.visit() and check for deprecated notice + * @param string path + */ + function myVisit(path) { + cy.visit(path); + // wait for the body element to be available + cy.get("body").should(($body) => { + // get the text of the body element + const text = $body.text(); + // assert that the 'Deprecated: ' string is not present + expect(text).not.to.include("Deprecated: "); + // assert that the 'Warning: ' string is not present + expect(text).not.to.include("Warning: "); + // assert that the 'Error: ' string is not present + expect(text).not.to.include("Error: "); + }); + } + export {myVisit}; diff --git a/test/cypress/joomla-cypress.d.ts b/test/cypress/joomla-cypress.d.ts new file mode 100644 index 0000000..65e9d0b --- /dev/null +++ b/test/cypress/joomla-cypress.d.ts @@ -0,0 +1,13 @@ + +/* + * MIT License, Copyright (c) 2023 Heiko Lübbe + * https://github.com/muhme/quote_wordpress + * + * joomla-cypress.d.ts - declare used methods + */ +declare namespace Cypress { + interface Chainable { + // only this that I use in testHelper.ts + doAdministratorLogin(username: string, password: string): Chainable; + } +} diff --git a/test/cypress/tsconfig.json b/test/cypress/tsconfig.json new file mode 100644 index 0000000..c1cf8e6 --- /dev/null +++ b/test/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["es5", "dom"], + "types": ["cypress", "node"] + }, + "include": ["**/*.ts", "e2e/install.cy.js", "joomla-cypress.d.ts"] +}