diff --git a/package-lock.json b/package-lock.json index 918f68b39..59da71255 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@s3pweb/keycloak-admin-client-cjs": "^26.0.0", "@xmldom/xmldom": "^0.9.5", "csv-writer": "^1.6.0", + "dotenv": "^16.5.0", "fast-xml-parser": "^5.0.9", "gunzip-file": "^0.1.1", "jpeg-js": "^0.4.4", @@ -242,16 +243,20 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -335,9 +340,9 @@ } }, "node_modules/@faker-js/faker": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.6.0.tgz", - "integrity": "sha512-3vm4by+B5lvsFPSyep3ELWmZfE3kicDtmemVpuwl1yH7tqtnHdsA6hG8fbXedMVdkzgtvzWoRgjSB4Q+FHnZiw==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.8.0.tgz", + "integrity": "sha512-U9wpuSrJC93jZBxx/Qq2wPjCuYISBueyVUGK7qqdmj7r/nxaxwW8AQDCLeRO7wZnjj94sh3p246cAYjUKuqgfg==", "funding": [ { "type": "opencollective", @@ -456,9 +461,9 @@ } }, "node_modules/@keycloak/keycloak-admin-client": { - "version": "26.1.4", - "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-26.1.4.tgz", - "integrity": "sha512-zJJM7uhtzUUD0Uf6Q2xhFrUqT+qvfj5WhBqTwKtO8k4jbxu4uNmk5qRDa8fnkk0sHyPzlD+d875H2Jora/W2gw==", + "version": "26.2.4", + "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-26.2.4.tgz", + "integrity": "sha512-2N56jps2HEGJoslxT2LQudUNEKmVwXyfZushR77hkoQF05YQ2USFOvqeM0kxxFb/3S38ZwS4wZv0NiZKnAwhUw==", "license": "Apache-2.0", "dependencies": { "camelize-ts": "^3.0.0", @@ -525,12 +530,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.1.tgz", - "integrity": "sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.51.1" + "playwright": "1.52.0" }, "bin": { "playwright": "cli.js" @@ -546,12 +551,12 @@ "dev": true }, "node_modules/@s3pweb/keycloak-admin-client-cjs": { - "version": "26.1.4", - "resolved": "https://registry.npmjs.org/@s3pweb/keycloak-admin-client-cjs/-/keycloak-admin-client-cjs-26.1.4.tgz", - "integrity": "sha512-KZ+YYV5VcrFpkyHsVCPF/qRg40+Fu3ibIoISi9S1pZ1GytS+8cQW8oqrGm7biI7tSosiheWz1v6quRcViNAkCA==", + "version": "26.2.4", + "resolved": "https://registry.npmjs.org/@s3pweb/keycloak-admin-client-cjs/-/keycloak-admin-client-cjs-26.2.4.tgz", + "integrity": "sha512-NbYC6HlAZuUIVI8L6xYDrpSzzCppqGwddPUY+L0ePYNY2rlPZKHWmnyvFYAPvQRXodgSxD/wLpio3/2acP8Ekw==", "license": "MIT", "dependencies": { - "@keycloak/keycloak-admin-client": "26.1.4" + "@keycloak/keycloak-admin-client": "26.2.4" } }, "node_modules/@socket.io/component-emitter": { @@ -609,9 +614,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", - "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "version": "22.15.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz", + "integrity": "sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -631,21 +636,21 @@ "optional": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", - "integrity": "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", + "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.29.0", - "@typescript-eslint/type-utils": "8.29.0", - "@typescript-eslint/utils": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/type-utils": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -660,10 +665,20 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "license": "MIT", "engines": { @@ -674,16 +689,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.0.tgz", - "integrity": "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", + "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.29.0", - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/typescript-estree": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4" }, "engines": { @@ -699,14 +714,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", - "integrity": "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz", + "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0" + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -717,16 +732,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.0.tgz", - "integrity": "sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz", + "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.29.0", - "@typescript-eslint/utils": "8.29.0", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/utils": "8.32.1", "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -754,9 +769,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", - "integrity": "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz", + "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==", "dev": true, "license": "MIT", "engines": { @@ -768,20 +783,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.0.tgz", - "integrity": "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz", + "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -808,16 +823,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.0.tgz", - "integrity": "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz", + "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.29.0", - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/typescript-estree": "8.29.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -832,13 +847,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.0.tgz", - "integrity": "sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz", + "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/types": "8.32.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -1939,6 +1954,18 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2875,9 +2902,9 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.0.tgz", - "integrity": "sha512-Uw9+Mjt4SBRud1IcaYuW/O0lW8SKKdMl5g7g24HiIuyH5fQSD+AVLybSlJtqLYEbytVFjWQa5DMGcNgeksdRBg==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.3.tgz", + "integrity": "sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==", "funding": [ { "type": "github", @@ -2886,7 +2913,7 @@ ], "license": "MIT", "dependencies": { - "strnum": "^2.0.5" + "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" @@ -3171,6 +3198,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4670,12 +4710,12 @@ } }, "node_modules/playwright": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz", - "integrity": "sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.51.1" + "playwright-core": "1.52.0" }, "bin": { "playwright": "cli.js" @@ -4688,9 +4728,9 @@ } }, "node_modules/playwright-core": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz", - "integrity": "sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -4932,6 +4972,16 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -5042,9 +5092,9 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5478,9 +5528,9 @@ } }, "node_modules/strnum": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", - "integrity": "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.0.tgz", + "integrity": "sha512-w0S//9BqZZGw0L0Y8uLSelFGnDJgTyyNQLmSlPnVz43zPAiqu3w4t8J8sDqqANOGeZIZ/9jWuPguYcEnsoHv4A==", "funding": [ { "type": "github", @@ -5663,14 +5713,15 @@ } }, "node_modules/tsc-alias": { - "version": "1.8.13", - "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.13.tgz", - "integrity": "sha512-hpuglrm2DoHZE62L8ntYqRNiSQ7J8kvIxEsajzY/QfGOm7EcdhgG5asqoWYi2E2KX0SqUuhOTnV8Ry8D/TnsEA==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.16.tgz", + "integrity": "sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^3.5.3", "commander": "^9.0.0", + "get-tsconfig": "^4.10.0", "globby": "^11.0.4", "mylas": "^2.1.9", "normalize-path": "^3.0.0", @@ -6331,12 +6382,12 @@ } }, "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "requires": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" } }, "@eslint-community/regexpp": { @@ -6399,9 +6450,9 @@ "dev": true }, "@faker-js/faker": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.6.0.tgz", - "integrity": "sha512-3vm4by+B5lvsFPSyep3ELWmZfE3kicDtmemVpuwl1yH7tqtnHdsA6hG8fbXedMVdkzgtvzWoRgjSB4Q+FHnZiw==" + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.8.0.tgz", + "integrity": "sha512-U9wpuSrJC93jZBxx/Qq2wPjCuYISBueyVUGK7qqdmj7r/nxaxwW8AQDCLeRO7wZnjj94sh3p246cAYjUKuqgfg==" }, "@humanwhocodes/config-array": { "version": "0.13.0", @@ -6487,9 +6538,9 @@ } }, "@keycloak/keycloak-admin-client": { - "version": "26.1.4", - "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-26.1.4.tgz", - "integrity": "sha512-zJJM7uhtzUUD0Uf6Q2xhFrUqT+qvfj5WhBqTwKtO8k4jbxu4uNmk5qRDa8fnkk0sHyPzlD+d875H2Jora/W2gw==", + "version": "26.2.4", + "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-26.2.4.tgz", + "integrity": "sha512-2N56jps2HEGJoslxT2LQudUNEKmVwXyfZushR77hkoQF05YQ2USFOvqeM0kxxFb/3S38ZwS4wZv0NiZKnAwhUw==", "requires": { "camelize-ts": "^3.0.0", "url-join": "^5.0.0", @@ -6540,11 +6591,11 @@ } }, "@playwright/test": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.1.tgz", - "integrity": "sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", "requires": { - "playwright": "1.51.1" + "playwright": "1.52.0" } }, "@rtsao/scc": { @@ -6554,11 +6605,11 @@ "dev": true }, "@s3pweb/keycloak-admin-client-cjs": { - "version": "26.1.4", - "resolved": "https://registry.npmjs.org/@s3pweb/keycloak-admin-client-cjs/-/keycloak-admin-client-cjs-26.1.4.tgz", - "integrity": "sha512-KZ+YYV5VcrFpkyHsVCPF/qRg40+Fu3ibIoISi9S1pZ1GytS+8cQW8oqrGm7biI7tSosiheWz1v6quRcViNAkCA==", + "version": "26.2.4", + "resolved": "https://registry.npmjs.org/@s3pweb/keycloak-admin-client-cjs/-/keycloak-admin-client-cjs-26.2.4.tgz", + "integrity": "sha512-NbYC6HlAZuUIVI8L6xYDrpSzzCppqGwddPUY+L0ePYNY2rlPZKHWmnyvFYAPvQRXodgSxD/wLpio3/2acP8Ekw==", "requires": { - "@keycloak/keycloak-admin-client": "26.1.4" + "@keycloak/keycloak-admin-client": "26.2.4" } }, "@socket.io/component-emitter": { @@ -6616,9 +6667,9 @@ "dev": true }, "@types/node": { - "version": "22.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", - "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "version": "22.15.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz", + "integrity": "sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==", "requires": { "undici-types": "~6.21.0" } @@ -6636,64 +6687,70 @@ "optional": true }, "@typescript-eslint/eslint-plugin": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", - "integrity": "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", + "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.29.0", - "@typescript-eslint/type-utils": "8.29.0", - "@typescript-eslint/utils": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/type-utils": "8.32.1", + "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "dependencies": { + "ignore": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", + "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "dev": true + }, "ts-api-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "requires": {} } } }, "@typescript-eslint/parser": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.0.tgz", - "integrity": "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", + "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "8.29.0", - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/typescript-estree": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", - "integrity": "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz", + "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==", "dev": true, "requires": { - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0" + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1" } }, "@typescript-eslint/type-utils": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.0.tgz", - "integrity": "sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz", + "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "8.29.0", - "@typescript-eslint/utils": "8.29.0", + "@typescript-eslint/typescript-estree": "8.32.1", + "@typescript-eslint/utils": "8.32.1", "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "dependencies": { "ts-api-utils": { @@ -6706,25 +6763,25 @@ } }, "@typescript-eslint/types": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", - "integrity": "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz", + "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.0.tgz", - "integrity": "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz", + "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==", "dev": true, "requires": { - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/visitor-keys": "8.29.0", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/visitor-keys": "8.32.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.1.0" }, "dependencies": { "ts-api-utils": { @@ -6737,24 +6794,24 @@ } }, "@typescript-eslint/utils": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.0.tgz", - "integrity": "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz", + "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==", "dev": true, "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.29.0", - "@typescript-eslint/types": "8.29.0", - "@typescript-eslint/typescript-estree": "8.29.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.32.1", + "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/typescript-estree": "8.32.1" } }, "@typescript-eslint/visitor-keys": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.0.tgz", - "integrity": "sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==", + "version": "8.32.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz", + "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==", "dev": true, "requires": { - "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/types": "8.32.1", "eslint-visitor-keys": "^4.2.0" }, "dependencies": { @@ -7554,6 +7611,11 @@ "domhandler": "^5.0.3" } }, + "dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==" + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8257,11 +8319,11 @@ "dev": true }, "fast-xml-parser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.0.tgz", - "integrity": "sha512-Uw9+Mjt4SBRud1IcaYuW/O0lW8SKKdMl5g7g24HiIuyH5fQSD+AVLybSlJtqLYEbytVFjWQa5DMGcNgeksdRBg==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.3.tgz", + "integrity": "sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==", "requires": { - "strnum": "^2.0.5" + "strnum": "^2.1.0" } }, "fastq": { @@ -8476,6 +8538,15 @@ "get-intrinsic": "^1.2.4" } }, + "get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -9544,18 +9615,18 @@ "dev": true }, "playwright": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz", - "integrity": "sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", "requires": { "fsevents": "2.3.2", - "playwright-core": "1.51.1" + "playwright-core": "1.52.0" } }, "playwright-core": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz", - "integrity": "sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==" }, "plimit-lit": { "version": "1.6.1", @@ -9715,6 +9786,12 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -9786,9 +9863,9 @@ } }, "semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==" }, "send": { "version": "0.19.0", @@ -10099,9 +10176,9 @@ "dev": true }, "strnum": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", - "integrity": "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.0.tgz", + "integrity": "sha512-w0S//9BqZZGw0L0Y8uLSelFGnDJgTyyNQLmSlPnVz43zPAiqu3w4t8J8sDqqANOGeZIZ/9jWuPguYcEnsoHv4A==" }, "supports-color": { "version": "5.5.0", @@ -10222,13 +10299,14 @@ } }, "tsc-alias": { - "version": "1.8.13", - "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.13.tgz", - "integrity": "sha512-hpuglrm2DoHZE62L8ntYqRNiSQ7J8kvIxEsajzY/QfGOm7EcdhgG5asqoWYi2E2KX0SqUuhOTnV8Ry8D/TnsEA==", + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.16.tgz", + "integrity": "sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==", "dev": true, "requires": { "chokidar": "^3.5.3", "commander": "^9.0.0", + "get-tsconfig": "^4.10.0", "globby": "^11.0.4", "mylas": "^2.1.9", "normalize-path": "^3.0.0", diff --git a/package.json b/package.json index 2d6071402..ec1c80d1d 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@s3pweb/keycloak-admin-client-cjs": "^26.0.0", "@xmldom/xmldom": "^0.9.5", "csv-writer": "^1.6.0", + "dotenv": "^16.5.0", "fast-xml-parser": "^5.0.9", "gunzip-file": "^0.1.1", "jpeg-js": "^0.4.4", diff --git a/src/data/demo/countries.ts b/src/data/demo/countries.ts index 6e0375377..f41579215 100644 --- a/src/data/demo/countries.ts +++ b/src/data/demo/countries.ts @@ -48,6 +48,7 @@ export default { callPrefix: '1', zone: 'North America', active: false, + containsStates: true, }), canada: new FakerCountry({ id: 4, @@ -56,5 +57,6 @@ export default { callPrefix: '1', zone: 'North America', active: false, + containsStates: true, }), }; diff --git a/src/data/demo/states.ts b/src/data/demo/states.ts index 91c88f8ad..e11744a16 100644 --- a/src/data/demo/states.ts +++ b/src/data/demo/states.ts @@ -1,6 +1,15 @@ import FakerState from '@data/faker/state'; +import {fakerFR as faker} from '@faker-js/faker'; -export default { +const states = { + alaska: new FakerState({ + id: 5, + name: 'Alaska', + isoCode: 'AK', + country: 'United States', + zone: 'North America', + status: true, + }), california: new FakerState({ id: 8, name: 'California', @@ -25,4 +34,33 @@ export default { zone: 'Asia', status: true, }), + ontario: new FakerState({ + id: 89, + name: 'Ontario', + isoCode: 'ON', + country: 'Canada', + zone: 'North America', + status: true, + }), + quebec: new FakerState({ + id: 89, + name: 'Quebec', + isoCode: 'QC', + country: 'Canada', + zone: 'North America', + status: true, + }), }; +export default states; + +export function getRandomStateNameByCountryName(countryName: string): string|null { + const countryStatesNames = Object.values(states) + .filter((state: FakerState) => state.country === countryName) + .map((state: FakerState) => state.name); + + if (countryStatesNames.length) { + return faker.helpers.arrayElement(countryStatesNames); + } + + return null; +} diff --git a/src/data/faker/brandAddress.ts b/src/data/faker/brandAddress.ts index d15540f64..997d8c762 100644 --- a/src/data/faker/brandAddress.ts +++ b/src/data/faker/brandAddress.ts @@ -1,6 +1,7 @@ import type BrandAddressCreator from '@data/types/brandAddress'; import dataCountries from '@data/demo/countries'; import type FakerCountry from '@data/faker/country'; +import {getRandomStateNameByCountryName} from '@data/demo/states'; import {fakerFR as faker} from '@faker-js/faker'; @@ -29,6 +30,8 @@ export default class BrandAddressData { public readonly country: string; + public readonly state: string|null = null; + public readonly homePhone: string; public readonly mobilePhone: string; @@ -67,6 +70,9 @@ export default class BrandAddressData { /** @type {string} Address country name */ this.country = brandAddressToCreate.country || faker.helpers.arrayElement(countriesNames); + /** @type {string} Address state name */ + this.state = brandAddressToCreate.state || getRandomStateNameByCountryName(this.country); + /** @type {string} Home phone number linked to the address */ this.homePhone = brandAddressToCreate.homePhone || faker.phone.number(); diff --git a/src/data/faker/supplier.ts b/src/data/faker/supplier.ts index 04862586a..b545b4a2c 100644 --- a/src/data/faker/supplier.ts +++ b/src/data/faker/supplier.ts @@ -1,6 +1,8 @@ import dataCountries from '@data/demo/countries'; import type FakerCountry from '@data/faker/country'; import SupplierCreator from '@data/types/supplier'; +import {getRandomStateNameByCountryName} from '@data/demo/states'; + import {fakerFR as faker} from '@faker-js/faker'; const countriesNames: string[] = Object.values(dataCountries).map((country: FakerCountry) => country.name); @@ -32,6 +34,8 @@ export default class FakerSupplier { public country: string; + public state: string|null = null; + public logo: string; public metaTitle: string; @@ -88,6 +92,9 @@ export default class FakerSupplier { /** @type {string} Country for the address of the supplier */ this.country = supplierToCreate.country || faker.helpers.arrayElement(countriesNames); + /** @type {string} Address state name */ + this.state = supplierToCreate.state || getRandomStateNameByCountryName(this.country); + /** @type {string} Logo name/path of the supplier */ this.logo = supplierToCreate.logo || `${this.name.replace(/[^\w\s]/gi, '')}.png`; diff --git a/src/data/import/addresses.ts b/src/data/import/addresses.ts new file mode 100644 index 000000000..868ec17ed --- /dev/null +++ b/src/data/import/addresses.ts @@ -0,0 +1,68 @@ +import dataCountries from '@data/demo/countries'; +import dataCustomers from '@data/demo/customers'; +import type FakerCountry from '@data/faker/country'; +import FakerImport from '@data/faker/import'; +import type {ImportAddress} from '@data/types/import'; +import {fakerFR as faker} from '@faker-js/faker'; + +const countriesNames = Object.values(dataCountries).map((country: FakerCountry) => country.name); + +const records: ImportAddress[] = []; + +function createRecord(): ImportAddress[] { + for (let i: number = 0; i < 10; i++) { + records.push({ + id: i + 3, + alias: faker.location.streetAddress().substring(0, 30), + active: faker.number.int({min: 0, max: 1}), + email: dataCustomers.johnDoe.email, + customerID: dataCustomers.johnDoe.id, + manufacturer: '', + supplier: '', + company: faker.company.name(), + lastname: 'test', + firstname: faker.person.firstName(), + address1: faker.location.streetAddress(), + address2: faker.location.secondaryAddress(), + zipCode: faker.location.zipCode('#####'), + city: faker.location.city(), + country: faker.helpers.arrayElement(countriesNames), + state: '', + other: '', + phone: faker.phone.number(), + mobilePhone: faker.phone.number(), + vatNumber: '', + dni: '', + }); + } + + return records; +} + +export default new FakerImport({ + entity: 'Addresses', + header: [ + {id: 'id', title: 'Address ID'}, + {id: 'alias', title: 'Alias*'}, + {id: 'active', title: 'Active (0/1)'}, + {id: 'email', title: 'Customer e-mail*'}, + {id: 'customerID', title: 'Customer ID*'}, + {id: 'manufacturer', title: 'Manufacturer'}, + {id: 'supplier', title: 'Supplier'}, + {id: 'company', title: 'Company'}, + {id: 'lastname', title: 'Lastname*'}, + {id: 'firstname', title: 'Firstname*'}, + {id: 'address1', title: 'Address 1*'}, + {id: 'address2', title: 'Address 2'}, + {id: 'zipCode', title: 'Zipcode*'}, + {id: 'city', title: 'City*'}, + {id: 'country', title: 'Country*'}, + {id: 'state', title: 'State'}, + {id: 'other', title: 'Other'}, + {id: 'phone', title: 'Phone'}, + {id: 'mobilePhone', title: 'Mobile Phone'}, + {id: 'vatNumber', title: 'VAT number'}, + {id: 'dni', title: 'DNI'}, + ], + records: createRecord(), +}); diff --git a/src/data/import/brands.ts b/src/data/import/brands.ts new file mode 100644 index 000000000..42ba5fc83 --- /dev/null +++ b/src/data/import/brands.ts @@ -0,0 +1,40 @@ +import FakerImport from '@data/faker/import'; +import type {ImportBrand} from '@data/types/import'; +import {faker} from '@faker-js/faker'; + +const records: ImportBrand[] = []; + +function createRecord(): ImportBrand[] { + for (let i: number = 0; i < 10; i++) { + const name = `todelete ${faker.company.name()}`; + records.push({ + id: i + 2, + active: faker.number.int({min: 0, max: 1}), + name, + description: faker.lorem.sentence(), + shortDescription: faker.lorem.sentence(), + metaTitle: name, + metaKeywords: [], + metaDescription: faker.lorem.sentence(), + imageURL: '', + }); + } + + return records; +} + +export default new FakerImport({ + entity: 'Brands', + header: [ + {id: 'id', title: 'ID'}, + {id: 'active', title: 'Active (0/1)'}, + {id: 'name', title: 'Name *'}, + {id: 'description', title: 'Description'}, + {id: 'shortDescription', title: 'Short description'}, + {id: 'metaTitle', title: 'Meta title'}, + {id: 'metaKeywords', title: 'Meta keywords'}, + {id: 'metaDescription', title: 'Meta description'}, + {id: 'imageURL', title: 'Image URL'}, + ], + records: createRecord(), +}); diff --git a/src/data/import/categories.ts b/src/data/import/categories.ts new file mode 100644 index 000000000..2fc5da042 --- /dev/null +++ b/src/data/import/categories.ts @@ -0,0 +1,106 @@ +import FakerImport from '@data/faker/import'; +import {type ImportCategory} from '@data/types/import'; + +const records: ImportCategory[] = [ + { + id: 10, + active: 1, + name: 'category_1', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 1', + }, + { + id: 11, + active: 1, + name: 'category_2', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 2', + }, + { + id: 12, + active: 1, + name: 'category_3', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 3', + }, + { + id: 13, + active: 1, + name: 'category_4', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 4', + }, + { + id: 14, + active: 1, + name: 'category_5', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 5', + }, + { + id: 15, + active: 1, + name: 'category_6', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 6', + }, + { + id: 16, + active: 1, + name: 'category_7', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 7', + }, + { + id: 17, + active: 1, + name: 'category_8', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 8', + }, + { + id: 18, + active: 1, + name: 'category_9', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 9', + }, + { + id: 19, + active: 1, + name: 'category_10', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 10', + }, + { + id: 20, + active: 1, + name: 'category_11', + parent_category: 'Home', + root_category: '0', + description: 'Description for the category 11', + }, +]; + +export default new FakerImport({ + entity: 'Categories', + header: [ + {id: 'id', title: 'Category ID'}, + {id: 'active', title: 'Active (0/1)'}, + {id: 'name', title: 'Name *'}, + {id: 'parent_category', title: 'Parent category'}, + {id: 'root_category', title: 'Root category (0/1)'}, + {id: 'description', title: 'Description'}, + ], + records, +}); diff --git a/src/data/import/combinations.ts b/src/data/import/combinations.ts new file mode 100644 index 000000000..3b1646503 --- /dev/null +++ b/src/data/import/combinations.ts @@ -0,0 +1,82 @@ +import FakerImport from '@data/faker/import'; +import type {ImportCombination} from '@data/types/import'; + +const records: ImportCombination[] = [ + { + id: 20, + reference: 'reference_1', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 21, + reference: 'reference_2', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 22, + reference: 'reference_3', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 23, + reference: 'reference_4', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 24, + reference: 'reference_5', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 25, + reference: 'reference_6', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 26, + reference: 'reference_7', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 27, + reference: 'reference_8', + attribute: 'Color:color:0', + value: 'Home', + }, + { + id: 28, + reference: 'reference_9', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 29, + reference: 'reference_10', + attribute: 'Color:color:0', + value: 'Blue:0', + }, + { + id: 30, + reference: 'reference_11', + attribute: 'Color:color:0', + value: 'Blue:0', + }, +]; + +export default new FakerImport({ + entity: 'Combinations', + header: [ + {id: 'id', title: 'Product ID*'}, + {id: 'reference', title: 'Product_Reference'}, + {id: 'attribute', title: 'Attribute (Name:Type:Position)*'}, + {id: 'value', title: 'Value (Value:Position)*'}, + ], + records, +}); diff --git a/src/data/import/customers.ts b/src/data/import/customers.ts new file mode 100644 index 000000000..664a328fd --- /dev/null +++ b/src/data/import/customers.ts @@ -0,0 +1,52 @@ +import dataGroups from '@data/demo/groups'; +import type FakerGroup from '@data/faker/group'; +import FakerImport from '@data/faker/import'; +import type {ImportCustomer} from '@data/types/import'; +import {faker} from '@faker-js/faker'; + +const groups: string[] = Object.values(dataGroups).map((group: FakerGroup) => group.name); + +const records: ImportCustomer[] = []; + +function createRecord(): ImportCustomer[] { + for (let i: number = 0; i < 10; i++) { + const lastName = faker.person.lastName(); + records.push({ + id: i + 3, + active: faker.number.int({min: 0, max: 1}), + title: faker.number.int({min: 1, max: 2}), + email: `test.${lastName}@prestashop.com`, + password: faker.internet.password(), + birthdate: faker.date.between({from: '1950-01-01', to: '2000-12-31'}).toISOString().slice(0, 10), + lastName, + firstName: faker.person.firstName(), + newsletter: faker.number.int({min: 0, max: 1}), + optIn: faker.number.int({min: 0, max: 1}), + registrationDate: faker.date.past({years: 2}).toISOString().slice(0, 10), + groups: faker.helpers.arrayElement(groups), + defaultGroup: faker.helpers.arrayElement(groups), + }); + } + + return records; +} + +export default new FakerImport({ + entity: 'Customers', + header: [ + {id: 'id', title: 'Customer ID'}, + {id: 'active', title: 'Active (0/1)'}, + {id: 'title', title: 'Titles ID (Mr = 1, Ms = 2, else 0)'}, + {id: 'email', title: 'Email*'}, + {id: 'password', title: 'Password*'}, + {id: 'birthdate', title: 'Birthday (yyyy-mm-dd)'}, + {id: 'lastName', title: 'Last Name*'}, + {id: 'firstName', title: 'First Name*'}, + {id: 'newsletter', title: 'Newsletter (0/1)'}, + {id: 'optIn', title: 'Opt-in (0/1)'}, + {id: 'registrationDate', title: 'Registration date (yyyy-mm-dd)'}, + {id: 'groups', title: 'Groups(x,y,z...)'}, + {id: 'defaultGroup', title: 'Default group ID'}, + ], + records: createRecord(), +}); diff --git a/src/data/import/products/disabled.ts b/src/data/import/products/disabled.ts new file mode 100644 index 000000000..a9799ad52 --- /dev/null +++ b/src/data/import/products/disabled.ts @@ -0,0 +1,358 @@ +import FakerImport from '@data/faker/import'; +import type {ImportProduct} from '@data/types/import'; + +const records: ImportProduct[] = [ + { + id: 20, + active: 0, + name: 'todelete_1', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_1', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 21, + active: 0, + name: 'todelete_2', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_2', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 22, + active: 0, + name: 'todelete_3', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_3', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 23, + active: 0, + name: 'todelete_4', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_4', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 24, + active: 0, + name: 'todelete_5', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_5', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 25, + active: 0, + name: 'todelete_6', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_6', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 26, + active: 0, + name: 'todelete_7', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_7', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 27, + active: 0, + name: 'todelete_8', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_8', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 28, + active: 0, + name: 'todelete_9', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_9', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 29, + active: 0, + name: 'todelete_10', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_10', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, + { + id: 30, + active: 0, + name: 'todelete_11', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_11', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 1, + }, +]; + +export default new FakerImport({ + entity: 'Products', + header: [ + {id: 'id', title: 'Product ID*'}, + {id: 'active', title: 'Active (0/1)'}, + {id: 'name', title: 'Name *'}, + {id: 'categories', title: 'Categories (x,y,z...)'}, + {id: 'price_TEXC', title: 'price tax excluded'}, + {id: 'tax_rule_id', title: 'Tax ruleID'}, + {id: 'cost_price', title: 'Cost Price'}, + {id: 'on_sale', title: 'On sale'}, + {id: 'discount_amount', title: 'Discount amount'}, + {id: 'discount_percent', title: 'Discount Percent'}, + {id: 'discount_from', title: 'Discount from'}, + {id: 'discount_to', title: 'Discount to'}, + {id: 'reference', title: 'Reference'}, + {id: 'supplier_reference', title: 'Supplier reference'}, + {id: 'supplier', title: 'Supplier'}, + {id: 'brand', title: 'Brand'}, + {id: 'ean13', title: 'EAN13'}, + {id: 'upc', title: 'UPC'}, + {id: 'value', title: 'MPN'}, + {id: 'mpn', title: 'Ecotax'}, + {id: 'width', title: 'Width'}, + {id: 'height', title: 'Height'}, + {id: 'depth', title: 'Depth'}, + {id: 'weight', title: 'Weight'}, + {id: 'delivery_time_in_stock', title: 'Delivery time of in-stock product'}, + {id: 'delivery_time_out_of_stock', title: 'Delivery time of out-of-stock products with allowed orders'}, + {id: 'quantity', title: 'Quantity'}, + ], + records, +}); diff --git a/src/data/import/products/withoutQuantities.ts b/src/data/import/products/withoutQuantities.ts new file mode 100644 index 000000000..a75e5024b --- /dev/null +++ b/src/data/import/products/withoutQuantities.ts @@ -0,0 +1,358 @@ +import FakerImport from '@data/faker/import'; +import type {ImportProduct} from '@data/types/import'; + +const records: ImportProduct[] = [ + { + id: 20, + active: 1, + name: 'todelete_1', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_1', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 21, + active: 1, + name: 'todelete_2', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_2', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 22, + active: 1, + name: 'todelete_3', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_3', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 23, + active: 1, + name: 'todelete_4', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_4', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 24, + active: 1, + name: 'todelete_5', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_5', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 25, + active: 1, + name: 'todelete_6', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_6', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 26, + active: 1, + name: 'todelete_7', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_7', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 27, + active: 1, + name: 'todelete_8', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_8', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 28, + active: 1, + name: 'todelete_9', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_9', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 29, + active: 1, + name: 'todelete_10', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_10', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, + { + id: 30, + active: 1, + name: 'todelete_11', + categories: 'Home', + price_TEXC: '', + tax_rule_id: '', + cost_price: '', + on_sale: '', + discount_amount: '', + discount_percent: '', + discount_from: '', + discount_to: '', + reference: 'reference_11', + supplier_reference: '', + supplier: '', + brand: '', + ean13: '', + upc: '', + value: '', + mpn: '', + width: '', + height: '', + depth: '', + weight: '', + delivery_time_in_stock: '', + delivery_time_out_of_stock: '', + quantity: 0, + }, +]; + +export default new FakerImport({ + entity: 'Products', + header: [ + {id: 'id', title: 'Product ID*'}, + {id: 'active', title: 'Active (0/1)'}, + {id: 'name', title: 'Name *'}, + {id: 'categories', title: 'Categories (x,y,z...)'}, + {id: 'price_TEXC', title: 'price tax excluded'}, + {id: 'tax_rule_id', title: 'Tax ruleID'}, + {id: 'cost_price', title: 'Cost Price'}, + {id: 'on_sale', title: 'On sale'}, + {id: 'discount_amount', title: 'Discount amount'}, + {id: 'discount_percent', title: 'Discount Percent'}, + {id: 'discount_from', title: 'Discount from'}, + {id: 'discount_to', title: 'Discount to'}, + {id: 'reference', title: 'Reference'}, + {id: 'supplier_reference', title: 'Supplier reference'}, + {id: 'supplier', title: 'Supplier'}, + {id: 'brand', title: 'Brand'}, + {id: 'ean13', title: 'EAN13'}, + {id: 'upc', title: 'UPC'}, + {id: 'value', title: 'MPN'}, + {id: 'mpn', title: 'Ecotax'}, + {id: 'width', title: 'Width'}, + {id: 'height', title: 'Height'}, + {id: 'depth', title: 'Depth'}, + {id: 'weight', title: 'Weight'}, + {id: 'delivery_time_in_stock', title: 'Delivery time of in-stock product'}, + {id: 'delivery_time_out_of_stock', title: 'Delivery time of out-of-stock products with allowed orders'}, + {id: 'quantity', title: 'Quantity'}, + ], + records, +}); diff --git a/src/data/types/brandAddress.ts b/src/data/types/brandAddress.ts index 1999309c6..18466cd4c 100644 --- a/src/data/types/brandAddress.ts +++ b/src/data/types/brandAddress.ts @@ -8,6 +8,7 @@ type BrandAddressCreator = { postalCode?: string; city?: string; country?: string; + state?: string; homePhone?: string; mobilePhone?: string; other?: string; diff --git a/src/data/types/globals.ts b/src/data/types/globals.ts index 38edc8ecd..d702ee67c 100644 --- a/src/data/types/globals.ts +++ b/src/data/types/globals.ts @@ -15,6 +15,10 @@ type GlobalFO = { URL: string } +type GlobalAPI = { + URL: string +} + type GlobalBO = { URL: string EMAIL: string @@ -70,7 +74,8 @@ type GlobalBrowserErrors = { type GlobalScreenshot = { FOLDER: string - AFTER_FAIL: any + AFTER_FAIL: boolean + EACH_STEP: boolean } type GlobalMaildevConfig = { @@ -85,11 +90,13 @@ type GlobalKeycloakConfig = { keycloakAdminUser: string keycloakAdminPass: string keycloakClientId: string + keycloakClientSecret: string } export type { GlobalInstall, GlobalFO, + GlobalAPI, GlobalBO, GlobalBrowser, GlobalBrowserConfig, diff --git a/src/data/types/module.ts b/src/data/types/module.ts index 62e5f346c..fd0d9dac2 100644 --- a/src/data/types/module.ts +++ b/src/data/types/module.ts @@ -6,6 +6,15 @@ type FakerModuleCreator = { releaseZip?: string } +type ModuleApiInfo = { + moduleId: number + technicalName: string + moduleVersion: string + installedVersion: string|null + enabled: boolean + installed: boolean +} + type ModuleInfo = { moduleId: number technicalName: string @@ -16,5 +25,6 @@ type ModuleInfo = { export type { FakerModuleCreator, + ModuleApiInfo, ModuleInfo, }; diff --git a/src/data/types/supplier.ts b/src/data/types/supplier.ts index 1f3aeba01..79e016483 100644 --- a/src/data/types/supplier.ts +++ b/src/data/types/supplier.ts @@ -10,6 +10,7 @@ type SupplierCreator = { postalCode?: string city?: string country?: string + state?: string logo?: string metaTitle?: string metaTitleFr?: string diff --git a/src/index.ts b/src/index.ts index 06712d310..91705a65e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,8 @@ +// StartUp : Load .env in global +import utilsConf from '@utils/conf'; + +utilsConf.loadEnv(); + // Export data export type { CarrierCreator, @@ -14,6 +19,7 @@ export type {default as DashboardTrafficSource} from '@data/types/dashboard'; export type {EmployeePermission} from '@data/types/employee'; export type { GlobalInstall, + GlobalAPI, GlobalFO, GlobalBO, GlobalBrowser, @@ -37,7 +43,10 @@ export type { export type {default as ImportContent} from '@data/types/localization'; export type {LinkWidgetPage} from '@data/types/linkWidget'; export type {default as MailDevEmail} from '@data/types/maildevEmail'; -export type {ModuleInfo} from '@data/types/module'; +export type { + ModuleApiInfo, + ModuleInfo, +} from '@data/types/module'; export type { OrderCreator, OrderHistory, @@ -120,6 +129,14 @@ export {default as dataTaxRuleBehaviours} from '@data/demo/taxRuleBehaviour'; export {default as dataTitles} from '@data/demo/titles'; export {default as dataZones} from '@data/demo/zones'; +export {default as dataImportAddresses} from '@data/import/addresses'; +export {default as dataImportBrands} from '@data/import/brands'; +export {default as dataImportCategories} from '@data/import/categories'; +export {default as dataImportCombinations} from '@data/import/combinations'; +export {default as dataImportCustomers} from '@data/import/customers'; +export {default as dataImportProductsDisabled} from '@data/import/products/disabled'; +export {default as dataImportProductsWithoutQuantities} from '@data/import/products/withoutQuantities'; + export {default as FakerAddress} from '@data/faker/address'; export {default as FakerAPIClient} from '@data/faker/apiClient'; export {default as FakerAttribute} from '@data/faker/attribute'; @@ -242,6 +259,7 @@ export {default as boEmailPage} from '@pages/BO/advancedParameters/email'; export {default as boEmployeesPage} from '@pages/BO/advancedParameters/team/employees'; export {default as boEmployeesCreatePage} from '@pages/BO/advancedParameters/team/employees/create'; export {default as boEmployeeSessionsPage} from '@pages/BO/advancedParameters/security/employeeSessions'; +export {default as boErrorPage} from '@pages/BO/error'; export {default as boFeatureFlagPage} from '@pages/BO/advancedParameters/featureFlag'; export {default as boFeaturesPage} from '@pages/BO/catalog/features'; export {default as boFeaturesCreatePage} from '@pages/BO/catalog/features/create'; @@ -375,6 +393,7 @@ export {default as foClassicContactUsPage} from '@pages/FO/classic/contactUs'; export {default as foClassicCreateAccountPage} from '@pages/FO/classic/myAccount/create'; export {default as foClassicDeliveryPage} from '@pages/FO/classic/delivery'; export {default as foClassicEmailSubscriptionPage} from '@pages/FO/classic/emailSubscription'; +export {default as foClassicGuestOrderTrackingPage} from '@pages/FO/classic/guestOrderTracking'; export {default as foClassicHomePage} from '@pages/FO/classic/home'; export {default as foClassicLegalNoticePage} from '@pages/FO/classic/legalNotice'; export {default as foClassicLoginPage} from '@pages/FO/classic/login'; @@ -385,21 +404,27 @@ export {default as foClassicMyAccountPage} from '@pages/FO/classic/myAccount'; export {default as foClassicMyAddressesPage} from '@pages/FO/classic/myAccount/addresses'; export {default as foClassicMyAddressesCreatePage} from '@pages/FO/classic/myAccount/addresses/create'; export {default as foClassicMyCreditSlipsPage} from '@pages/FO/classic/myAccount/creditSlips'; +export {default as foClassicMyGDPRPersonalDataPage} from '@pages/FO/classic/myAccount/gdprPersonalData'; export {default as foClassicMyInformationsPage} from '@pages/FO/classic/myAccount/informations'; export {default as foClassicMyMerchandiseReturnsPage} from '@pages/FO/classic/myAccount/merchandiseReturns'; export {default as foClassicMyOrderDetailsPage} from '@pages/FO/classic/myAccount/orderDetails'; export {default as foClassicMyOrderHistoryPage} from '@pages/FO/classic/myAccount/orderHistory'; +export {default as foClassicMyReturnDetailsPage} from '@pages/FO/classic/myAccount/returnDetails'; export {default as foClassicMyVouchersPage} from '@pages/FO/classic/myAccount/vouchers'; export {default as foClassicMyWishlistsPage} from '@pages/FO/classic/myAccount/myWishlists'; export {default as foClassicMyWishlistsViewPage} from '@pages/FO/classic/myAccount/myWishlists/view'; +export {default as foClassicNewProductsPage} from '@pages/FO/classic/newProducts'; export {default as foClassicPasswordReminderPage} from '@pages/FO/classic/passwordReminder'; +export {default as foClassicPricesDropPage} from '@pages/FO/classic/pricesDrop'; export {default as foClassicProductPage} from '@pages/FO/classic/product'; export {default as foClassicSearchResultsPage} from '@pages/FO/classic/searchResults'; +export {default as foClassicSecurePaymentPage} from '@pages/FO/classic/securePayment'; export {default as foClassicSitemapPage} from '@pages/FO/classic/sitemap'; export {default as foClassicStoresPage} from '@pages/FO/classic/stores'; +export {default as foClassicTermsAndConditionsOfUsePage} from '@pages/FO/classic/termsAndConditionsOfUse'; // Export Pages FO/Hummingbird export {default as foHummingbirdAboutUsPage} from '@pages/FO/hummingbird/aboutUs'; -export {default as foHummingbirdBestSalesPage} from '@pages/FO/classic/bestSales'; +export {default as foHummingbirdBestSalesPage} from '@pages/FO/hummingbird/bestSales'; export {default as foHummingbirdCartPage} from '@pages/FO/hummingbird/cart'; export {default as foHummingbirdCategoryPage} from '@pages/FO/hummingbird/category'; export {default as foHummingbirdCheckoutPage} from '@pages/FO/hummingbird/checkout'; @@ -409,6 +434,7 @@ export {default as foHummingbirdContactUsPage} from '@pages/FO/hummingbird/conta export {default as foHummingbirdCreateAccountPage} from '@pages/FO/hummingbird/myAccount/create'; export {default as foHummingbirdMyCreditSlipsPage} from '@pages/FO/hummingbird/myAccount/creditSlips'; export {default as foHummingbirdDeliveryPage} from '@pages/FO/hummingbird/delivery'; +export {default as foHummingbirdGuestOrderTrackingPage} from '@pages/FO/hummingbird/guestOrderTracking'; export {default as foHummingbirdHomePage} from '@pages/FO/hummingbird/home'; export {default as foHummingbirdLegalNoticePage} from '@pages/FO/hummingbird/legalNotice'; export {default as foHummingbirdLoginPage} from '@pages/FO/hummingbird/login'; @@ -417,18 +443,24 @@ export {default as foHummingbirdModalQuickViewPage} from '@pages/FO/hummingbird/ export {default as foHummingbirdMyAccountPage} from '@pages/FO/hummingbird/myAccount'; export {default as foHummingbirdMyAddressesPage} from '@pages/FO/hummingbird/myAccount/addresses'; export {default as foHummingbirdMyAddressesCreatePage} from '@pages/FO/hummingbird/myAccount/addresses/create'; +export {default as foHummingbirdMyGDPRPersonalDataPage} from '@pages/FO/hummingbird/myAccount/gdprPersonalData'; export {default as foHummingbirdMyInformationsPage} from '@pages/FO/hummingbird/myAccount/informations'; export {default as foHummingbirdMyMerchandiseReturnsPage} from '@pages/FO/hummingbird/myAccount/merchandiseReturns'; export {default as foHummingbirdMyOrderDetailsPage} from '@pages/FO/hummingbird/myAccount/orderDetails'; export {default as foHummingbirdMyOrderHistoryPage} from '@pages/FO/hummingbird/myAccount/orderHistory'; +export {default as foHummingbirdMyReturnDetailsPage} from '@pages/FO/hummingbird/myAccount/returnDetails'; export {default as foHummingbirdMyVouchersPage} from '@pages/FO/hummingbird/myAccount/vouchers'; export {default as foHummingbirdMyWishlistsPage} from '@pages/FO/hummingbird/myAccount/myWishlists'; export {default as foHummingbirdMyWishlistsViewPage} from '@pages/FO/hummingbird/myAccount/myWishlists/view'; +export {default as foHummingbirdNewProductsPage} from '@pages/FO/hummingbird/newProducts'; export {default as foHummingbirdPasswordReminderPage} from '@pages/FO/hummingbird/passwordReminder'; +export {default as foHummingbirdPricesDropPage} from '@pages/FO/hummingbird/pricesDrop'; export {default as foHummingbirdProductPage} from '@pages/FO/hummingbird/product'; export {default as foHummingbirdSearchResultsPage} from '@pages/FO/hummingbird/searchResults'; +export {default as foHummingbirdSecurePaymentPage} from '@pages/FO/hummingbird/securePayment'; export {default as foHummingbirdSitemapPage} from '@pages/FO/hummingbird/sitemap'; export {default as foHummingbirdStoresPage} from '@pages/FO/hummingbird/stores'; +export {default as foHummingbirdTermsAndConditionsOfUsePage} from '@pages/FO/hummingbird/termsAndConditionsOfUse'; // Export Modules export {default as modAutoupgradeBoMain} from '@pages/BO/modules/autoupgrade'; @@ -452,9 +484,13 @@ export {default as modPsNewProductsBoMain} from '@pages/BO/modules/ps_newproduct export {default as modPsSupplierListBoMain} from '@pages/BO/modules/ps_supplierlist'; export {default as modPsWirepaymentBoMain} from '@pages/BO/modules/ps_wirepayment'; +// Export install +export {default as installPage} from '@pages/install'; + // Export utils export {default as utilsAPI} from '@utils/api'; export {default as utilsCore} from '@utils/core'; +export {default as utilsConf} from '@utils/conf'; export {default as utilsDate} from '@utils/date'; export {default as utilsFile} from '@utils/file'; export {default as utilsKeycloak} from '@utils/keycloak'; diff --git a/src/interfaces/BO/error.ts b/src/interfaces/BO/error.ts new file mode 100644 index 000000000..97b3bb04c --- /dev/null +++ b/src/interfaces/BO/error.ts @@ -0,0 +1,5 @@ +import {BOBasePagePageInterface} from '@interfaces/BO'; + +export interface BOErrorPageInterface extends BOBasePagePageInterface { + readonly notFoundTitle: string; +} diff --git a/src/interfaces/BO/index.ts b/src/interfaces/BO/index.ts index 7c17b0f97..26463180e 100644 --- a/src/interfaces/BO/index.ts +++ b/src/interfaces/BO/index.ts @@ -47,6 +47,7 @@ export interface BOBasePagePageInterface extends CommonPageInterface { readonly ordersLink: string; readonly ordersParentLink: string; readonly outstandingLink: string; + readonly pageNotFoundMessage: string; readonly statsLink: string readonly pagesLink: string; readonly paymentMethodsLink: string; diff --git a/src/interfaces/FO/guestOrderTracking.ts b/src/interfaces/FO/guestOrderTracking.ts new file mode 100644 index 000000000..a5d6f0ea6 --- /dev/null +++ b/src/interfaces/FO/guestOrderTracking.ts @@ -0,0 +1,5 @@ +import {type FOBasePagePageInterface} from '@interfaces/FO'; + +export interface FOGuestOrderTrackingPageInterface extends FOBasePagePageInterface { + readonly pageTitle: string; +} diff --git a/src/interfaces/FO/modal/blockCart.ts b/src/interfaces/FO/modal/blockCart.ts index c01c1fa4c..e7f81b2f4 100644 --- a/src/interfaces/FO/modal/blockCart.ts +++ b/src/interfaces/FO/modal/blockCart.ts @@ -4,6 +4,8 @@ import {FOBasePagePageInterface} from '@interfaces/FO'; import type {Page} from '@playwright/test'; export interface FoModalBlockCartPageInterface extends FOBasePagePageInterface { + readonly blockCartModalDiv: string; + getBlockCartModalTitle(page: Page): Promise; isBlockCartModalVisible(page: Page): Promise; getProductDetailsFromBlockCartModal(page: Page): Promise; diff --git a/src/interfaces/FO/myAccount/gdprPersonalData.ts b/src/interfaces/FO/myAccount/gdprPersonalData.ts new file mode 100644 index 000000000..8341cc410 --- /dev/null +++ b/src/interfaces/FO/myAccount/gdprPersonalData.ts @@ -0,0 +1,10 @@ +import {FOBasePagePageInterface} from '@interfaces/FO'; +import {type Page} from '@playwright/test'; + +export interface FOMyGDPRPersonalDataPageInterface extends FOBasePagePageInterface { + readonly pageTitle: string; + + exportDataToCSV(page: Page): Promise; + exportDataToPDF(page: Page): Promise; + goToContactUsPage(page: Page): Promise; +} diff --git a/src/interfaces/FO/myAccount/returnDetails.ts b/src/interfaces/FO/myAccount/returnDetails.ts new file mode 100644 index 000000000..5a165b961 --- /dev/null +++ b/src/interfaces/FO/myAccount/returnDetails.ts @@ -0,0 +1,12 @@ +import {FOBasePagePageInterface} from '@interfaces/FO'; +import {type Page} from '@playwright/test'; + +export interface FOMyReturnDetailsPageInterface extends FOBasePagePageInterface { + readonly errorMessage: string; + orderReturnCardBlock: string; + readonly pageTitle: string; + + getAlertWarning(page: Page): Promise; + getOrderReturnInfo(page: Page): Promise; + isAlertWarningVisible(page: Page): Promise; +} diff --git a/src/interfaces/FO/newProducts.ts b/src/interfaces/FO/newProducts.ts new file mode 100644 index 000000000..099d2aeca --- /dev/null +++ b/src/interfaces/FO/newProducts.ts @@ -0,0 +1,5 @@ +import {type FOBasePagePageInterface} from '@interfaces/FO'; + +export interface FONewProductsPageInterface extends FOBasePagePageInterface { + readonly pageTitle: string; +} diff --git a/src/interfaces/FO/pricesDrop.ts b/src/interfaces/FO/pricesDrop.ts new file mode 100644 index 000000000..94a2ae198 --- /dev/null +++ b/src/interfaces/FO/pricesDrop.ts @@ -0,0 +1,5 @@ +import {type FOBasePagePageInterface} from '@interfaces/FO'; + +export interface FOPricesDropPageInterface extends FOBasePagePageInterface { + readonly pageTitle: string; +} diff --git a/src/interfaces/FO/securePayment.ts b/src/interfaces/FO/securePayment.ts new file mode 100644 index 000000000..ae43e055c --- /dev/null +++ b/src/interfaces/FO/securePayment.ts @@ -0,0 +1,5 @@ +import {type FOBasePagePageInterface} from '@interfaces/FO'; + +export interface FOSecurePaymentPageInterface extends FOBasePagePageInterface { + readonly pageTitle: string; +} diff --git a/src/interfaces/FO/termsAndConditionsOfUse.ts b/src/interfaces/FO/termsAndConditionsOfUse.ts new file mode 100644 index 000000000..5739a8ee1 --- /dev/null +++ b/src/interfaces/FO/termsAndConditionsOfUse.ts @@ -0,0 +1,5 @@ +import {type FOBasePagePageInterface} from '@interfaces/FO'; + +export interface FOTermsAndConditionsOfUsePageInterface extends FOBasePagePageInterface { + readonly pageTitle: string; +} diff --git a/src/interfaces/install.ts b/src/interfaces/install.ts new file mode 100644 index 000000000..8364beebd --- /dev/null +++ b/src/interfaces/install.ts @@ -0,0 +1,28 @@ +import {type CommonPageInterface} from '@interfaces/index'; +import {type Page} from '@playwright/test'; + +export interface InstallPageInterface extends CommonPageInterface { + readonly fifthStepEnTitle: string; + readonly finalStepEnTitle: string; + readonly firstStepEnTitle: string; + readonly firstStepFrTitle: string; + readonly fourthStepEnTitle: string; + readonly secondStepEnTitle: string; + readonly sixthStepEnTitle: string; + readonly thirdStepEnTitle: string; + + agreeToTermsAndConditions(page: Page):Promise; + fillDatabaseForm(page: Page): Promise; + fillInformationForm(page: Page): Promise; + getStepTitle(page : Page, step: string): Promise; + goToFOAfterInstall(page: Page): Promise; + isDatabaseConnected(page: Page): Promise; + isInstallationInProgress(page: Page): Promise; + isInstallationStepFinished(page: Page, step: string, timeout?: number): Promise; + isInstallationSuccessful(page: Page): Promise; + isThirdStepVisible(page: Page): Promise; + nextStep(page: Page): Promise; + setInstallLanguage(page: Page): Promise; + waitForFinishedFifthStep(page: Page): Promise; + waitForFinishedForthStep(page: Page): Promise; +} diff --git a/src/pages/BO/BOBasePage.ts b/src/pages/BO/BOBasePage.ts index b7754d00d..7571c8810 100644 --- a/src/pages/BO/BOBasePage.ts +++ b/src/pages/BO/BOBasePage.ts @@ -759,6 +759,9 @@ export default class BOBasePage extends CommonPage implements BOBasePagePageInte if (semver.gte(shopVersion, '7.8.0')) { linkActiveClass = 'link-active'; } + if (semver.lte(shopVersion, '7.7.0')) { + linkActiveClass = '-active'; + } if (await this.isSidebarCollapsed(page)) { await this.waitForHiddenSelector(page, `${linkSelector}.${linkActiveClass}`); diff --git a/src/pages/BO/catalog/products/create/index.ts b/src/pages/BO/catalog/products/create/index.ts index eebb7adaa..a8d3add99 100644 --- a/src/pages/BO/catalog/products/create/index.ts +++ b/src/pages/BO/catalog/products/create/index.ts @@ -15,6 +15,9 @@ function requirePage(): BOProductsCreatePageInterface { if (semver.lt(psVersion, '7.6.0')) { return require('@versions/1.7.5/pages/BO/catalog/products/create').boProductsCreatePage; } + if (semver.lt(psVersion, '8.0.0')) { + return require('@versions/1.7.8/pages/BO/catalog/products/create').boProductsCreatePage; + } if (semver.lt(psVersion, '8.1.0')) { return require('@versions/8.0/pages/BO/catalog/products/create').boProductsCreatePage; } diff --git a/src/pages/BO/error.ts b/src/pages/BO/error.ts new file mode 100644 index 000000000..d69a56093 --- /dev/null +++ b/src/pages/BO/error.ts @@ -0,0 +1,9 @@ +import type {BOErrorPageInterface} from '@interfaces/BO/error'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): BOErrorPageInterface { + return require('@versions/develop/pages/BO/error'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/BO/orders/view/viewOrderBasePage.ts b/src/pages/BO/orders/view/viewOrderBasePage.ts index a3833de03..72bca32f6 100644 --- a/src/pages/BO/orders/view/viewOrderBasePage.ts +++ b/src/pages/BO/orders/view/viewOrderBasePage.ts @@ -11,6 +11,9 @@ function requirePage(): BOViewOrderBasePageInterface { if (semver.lt(psVersion, '7.7.0')) { return require('@versions/1.7.6/pages/BO/orders/view/viewOrderBasePage').viewOrderBasePage; } + if (semver.lt(psVersion, '9.0.0')) { + return require('@versions/8.2/pages/BO/orders/view/viewOrderBasePage').viewOrderBasePage; + } return require('@versions/develop/pages/BO/orders/view/viewOrderBasePage').viewOrderBasePage; } diff --git a/src/pages/FO/FOBasePage.ts b/src/pages/FO/FOBasePage.ts index 3a8a2f9f3..b9c825c18 100644 --- a/src/pages/FO/FOBasePage.ts +++ b/src/pages/FO/FOBasePage.ts @@ -169,9 +169,9 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte this.cartLink = '#_desktop_cart a'; this.userInfoLink = '#_desktop_user_info'; this.accountLink = `${this.userInfoLink} .user-info a[href*="my-account"]`; - this.logoutLink = `${this.userInfoLink} .user-info a[href*="?mylogout="]`; + this.logoutLink = `${this.userInfoLink} .user-info a[href*="/?mylogout="]`; this.contactLink = '#contact-link'; - this.categoryMenu = (id) => `#category-${id} > a`; + this.categoryMenu = (id) => `#top-menu #category-${id} > a`; this.languageSelectorDiv = '#_desktop_language_selector'; this.defaultLanguageSpan = `${this.languageSelectorDiv} button span`; this.languageSelectorExpandIcon = `${this.languageSelectorDiv} i.expand-more`; @@ -308,7 +308,7 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte const currentUrl: string = page.url(); await page.locator(this.breadCrumbLink(link === '/' ? '$' : '*', link)).first().click(); - await page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}); + await page.waitForURL((url: URL): boolean => url.toString() !== currentUrl); } /** @@ -472,7 +472,7 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte await Promise.all([ this.selectByVisibleText(page, this.currencySelect, currency, true), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); } @@ -530,7 +530,7 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte async goToSubCategory(page: Page, categoryID: number, subCategoryID: number): Promise { await Promise.all([ page.locator(this.categoryMenu(categoryID)).first().hover(), - this.clickAndWaitForURL(page, this.categoryMenu(subCategoryID)), + page.locator(this.categoryMenu(subCategoryID)).click(), ]); } @@ -641,7 +641,7 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte await this.setValue(page, this.theme === 'hummingbird' ? this.hSearchInput : this.searchInput, productName); await page.keyboard.press('Enter'); - await page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}); + await page.waitForURL((url: URL): boolean => url.toString() !== currentUrl); } /** diff --git a/src/pages/FO/classic/guestOrderTracking.ts b/src/pages/FO/classic/guestOrderTracking.ts new file mode 100644 index 000000000..1fa5157b2 --- /dev/null +++ b/src/pages/FO/classic/guestOrderTracking.ts @@ -0,0 +1,9 @@ +import type {FOGuestOrderTrackingPageInterface} from '@interfaces/FO/guestOrderTracking'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOGuestOrderTrackingPageInterface { + return require('@versions/develop/pages/FO/classic/guestOrderTracking').foGuestOrderTrackingPage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/classic/modal/quickView.ts b/src/pages/FO/classic/modal/quickView.ts index b4162cce3..9e251c1ec 100644 --- a/src/pages/FO/classic/modal/quickView.ts +++ b/src/pages/FO/classic/modal/quickView.ts @@ -2,7 +2,7 @@ import type {FoModalQuickViewPageInterface} from '@interfaces/FO/modal/quickView /* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ function requirePage(): FoModalQuickViewPageInterface { - return require('@versions/develop/pages/FO/classic/modal/quickView').quickViewModal; + return require('@versions/develop/pages/FO/classic/modal/quickView').foModalQuickViewPage; } /* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ diff --git a/src/pages/FO/classic/myAccount/gdprPersonalData.ts b/src/pages/FO/classic/myAccount/gdprPersonalData.ts new file mode 100644 index 000000000..bc486260e --- /dev/null +++ b/src/pages/FO/classic/myAccount/gdprPersonalData.ts @@ -0,0 +1,9 @@ +import {type FOMyGDPRPersonalDataPageInterface} from '@interfaces/FO/myAccount/gdprPersonalData'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports */ +function requirePage(): FOMyGDPRPersonalDataPageInterface { + return require('@versions/develop/pages/FO/classic/myAccount/gdprPersonalData').foMyGDPRPersonalDataPage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports */ + +export default requirePage(); diff --git a/src/pages/FO/classic/myAccount/returnDetails.ts b/src/pages/FO/classic/myAccount/returnDetails.ts new file mode 100644 index 000000000..dd4d6c356 --- /dev/null +++ b/src/pages/FO/classic/myAccount/returnDetails.ts @@ -0,0 +1,9 @@ +import type {FOMyReturnDetailsPageInterface} from '@interfaces/FO/myAccount/returnDetails'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOMyReturnDetailsPageInterface { + return require('@versions/develop/pages/FO/classic/myAccount/returnDetails').foMyReturnDetailsPage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/classic/newProducts.ts b/src/pages/FO/classic/newProducts.ts new file mode 100644 index 000000000..902400911 --- /dev/null +++ b/src/pages/FO/classic/newProducts.ts @@ -0,0 +1,9 @@ +import type {FONewProductsPageInterface} from '@interfaces/FO/newProducts'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FONewProductsPageInterface { + return require('@versions/develop/pages/FO/classic/newProducts').foNewProductsPage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/classic/pricesDrop.ts b/src/pages/FO/classic/pricesDrop.ts new file mode 100644 index 000000000..c8189bed0 --- /dev/null +++ b/src/pages/FO/classic/pricesDrop.ts @@ -0,0 +1,9 @@ +import type {FOPricesDropPageInterface} from '@interfaces/FO/pricesDrop'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOPricesDropPageInterface { + return require('@versions/develop/pages/FO/classic/pricesDrop').foPricesDropPage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/classic/securePayment.ts b/src/pages/FO/classic/securePayment.ts new file mode 100644 index 000000000..b5207aa61 --- /dev/null +++ b/src/pages/FO/classic/securePayment.ts @@ -0,0 +1,9 @@ +import type {FOSecurePaymentPageInterface} from '@interfaces/FO/securePayment'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOSecurePaymentPageInterface { + return require('@versions/develop/pages/FO/classic/securePayment').foSecurePaymentPage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/classic/termsAndConditionsOfUse.ts b/src/pages/FO/classic/termsAndConditionsOfUse.ts new file mode 100644 index 000000000..b4276cc0a --- /dev/null +++ b/src/pages/FO/classic/termsAndConditionsOfUse.ts @@ -0,0 +1,9 @@ +import type {FOTermsAndConditionsOfUsePageInterface} from '@interfaces/FO/termsAndConditionsOfUse'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOTermsAndConditionsOfUsePageInterface { + return require('@versions/develop/pages/FO/classic/termsAndConditionsOfUse').foTermsAndConditionsOfUsePage; +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/guestOrderTracking.ts b/src/pages/FO/hummingbird/guestOrderTracking.ts new file mode 100644 index 000000000..18f40db1b --- /dev/null +++ b/src/pages/FO/hummingbird/guestOrderTracking.ts @@ -0,0 +1,9 @@ +import type {FOGuestOrderTrackingPageInterface} from '@interfaces/FO/guestOrderTracking'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOGuestOrderTrackingPageInterface { + return require('@versions/develop/pages/FO/hummingbird/guestOrderTracking'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/myAccount/gdprPersonalData.ts b/src/pages/FO/hummingbird/myAccount/gdprPersonalData.ts new file mode 100644 index 000000000..f69386ee2 --- /dev/null +++ b/src/pages/FO/hummingbird/myAccount/gdprPersonalData.ts @@ -0,0 +1,9 @@ +import {type FOMyGDPRPersonalDataPageInterface} from '@interfaces/FO/myAccount/gdprPersonalData'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports */ +function requirePage(): FOMyGDPRPersonalDataPageInterface { + return require('@versions/develop/pages/FO/hummingbird/myAccount/gdprPersonalData'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/myAccount/returnDetails.ts b/src/pages/FO/hummingbird/myAccount/returnDetails.ts new file mode 100644 index 000000000..ed5bc5d1c --- /dev/null +++ b/src/pages/FO/hummingbird/myAccount/returnDetails.ts @@ -0,0 +1,9 @@ +import type {FOMyReturnDetailsPageInterface} from '@interfaces/FO/myAccount/returnDetails'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports */ +function requirePage(): FOMyReturnDetailsPageInterface { + return require('@versions/develop/pages/FO/hummingbird/myAccount/returnDetails'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/newProducts.ts b/src/pages/FO/hummingbird/newProducts.ts new file mode 100644 index 000000000..b438d4a77 --- /dev/null +++ b/src/pages/FO/hummingbird/newProducts.ts @@ -0,0 +1,9 @@ +import type {FONewProductsPageInterface} from '@interfaces/FO/newProducts'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FONewProductsPageInterface { + return require('@versions/develop/pages/FO/hummingbird/newProducts'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/pricesDrop.ts b/src/pages/FO/hummingbird/pricesDrop.ts new file mode 100644 index 000000000..14e707ee8 --- /dev/null +++ b/src/pages/FO/hummingbird/pricesDrop.ts @@ -0,0 +1,9 @@ +import type {FOPricesDropPageInterface} from '@interfaces/FO/pricesDrop'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOPricesDropPageInterface { + return require('@versions/develop/pages/FO/hummingbird/pricesDrop'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/securePayment.ts b/src/pages/FO/hummingbird/securePayment.ts new file mode 100644 index 000000000..a4ea3d0e1 --- /dev/null +++ b/src/pages/FO/hummingbird/securePayment.ts @@ -0,0 +1,9 @@ +import type {FOSecurePaymentPageInterface} from '@interfaces/FO/securePayment'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOSecurePaymentPageInterface { + return require('@versions/develop/pages/FO/hummingbird/securePayment'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/hummingbird/termsAndConditionsOfUse.ts b/src/pages/FO/hummingbird/termsAndConditionsOfUse.ts new file mode 100644 index 000000000..66ed80b00 --- /dev/null +++ b/src/pages/FO/hummingbird/termsAndConditionsOfUse.ts @@ -0,0 +1,9 @@ +import type {FOTermsAndConditionsOfUsePageInterface} from '@interfaces/FO/termsAndConditionsOfUse'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): FOTermsAndConditionsOfUsePageInterface { + return require('@versions/develop/pages/FO/hummingbird/termsAndConditionsOfUse'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/commonPage.ts b/src/pages/commonPage.ts index b57f55f16..d586650b6 100644 --- a/src/pages/commonPage.ts +++ b/src/pages/commonPage.ts @@ -214,7 +214,7 @@ export default class CommonPage implements CommonPageInterface { page: Page, selector: string, newPageSelector: string = 'body .logo', - state: 'load' | 'domcontentloaded' | 'networkidle' = 'networkidle', + state: 'load' | 'domcontentloaded' | 'networkidle' = 'load', waitForVisible: boolean = true, ): Promise { const [newPage] = await Promise.all([ @@ -259,6 +259,17 @@ export default class CommonPage implements CommonPageInterface { * @return {Promise} */ async setValue(page: Frame | Page, selector: string, value: string | number): Promise { + await page.locator(selector).fill(value.toString()); + } + + /** + * Delete the existing text from input then set a value + * @param page {Frame|Page} Browser tab + * @param selector {string} String to locate the input to set its value + * @param value {?string|number} Value to set on the input + * @return {Promise} + */ + async setValueSequentially(page: Frame | Page, selector: string, value: string | number): Promise { await this.clearInput(page, selector); if (value !== null) { @@ -421,17 +432,19 @@ export default class CommonPage implements CommonPageInterface { * @param selector {string} String to locate the element * @param state {'load'|'domcontentloaded'|'networkidle'} The event to wait after click * @param timeout {number} Time to wait for navigation + * @param clickOptions {any} Click options * @return {Promise} */ async clickAndWaitForLoadState( page: Frame | Page, selector: string, - state: 'load' | 'domcontentloaded' | 'networkidle' = 'networkidle', + state: 'load' | 'domcontentloaded' | 'networkidle' = 'load', timeout: number = 30000, + clickOptions: any = {}, ): Promise { await Promise.all([ page.waitForLoadState(state, {timeout}), - page.locator(selector).click(), + page.locator(selector).click(clickOptions), ]); } @@ -441,19 +454,21 @@ export default class CommonPage implements CommonPageInterface { * @param selector {string} String to locate the element * @param waitUntil {WaitForNavigationWaitUntil} The event to wait after click * @param timeout {number} Time to wait for navigation + * @param clickOptions {any} Click options * @return {Promise} */ async clickAndWaitForURL( page: Frame | Page, selector: string, - waitUntil: WaitForNavigationWaitUntil = 'networkidle', + waitUntil: WaitForNavigationWaitUntil = 'load', timeout: number = 30000, + clickOptions: any = {}, ): Promise { const currentUrl: string = page.url(); await Promise.all([ page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil, timeout}), - page.locator(selector).first().click(), + page.locator(selector).click(clickOptions), ]); } diff --git a/src/pages/install.ts b/src/pages/install.ts new file mode 100644 index 000000000..90a566fb5 --- /dev/null +++ b/src/pages/install.ts @@ -0,0 +1,9 @@ +import type {InstallPageInterface} from '@interfaces/install'; + +/* eslint-disable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ +function requirePage(): InstallPageInterface { + return require('@versions/develop/pages/install'); +} +/* eslint-enable global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts index 54f42cbdb..26bf28625 100644 --- a/src/types/globals.d.ts +++ b/src/types/globals.d.ts @@ -1,10 +1,13 @@ /* eslint-disable vars-on-top, no-var */ +import {GlobalBO} from '@data/types/globals'; + declare global { var INSTALL: GlobalInstall; var URLHasPort: boolean; var FO: GlobalFO; var BO: GlobalBO; + var API: GlobalAPI; var PSConfig: GlobalPSConfig; var BROWSER: GlobalBrowser; var GENERATE_FAILED_STEPS: any; diff --git a/src/utils/conf.ts b/src/utils/conf.ts new file mode 100644 index 000000000..01b0bbdb6 --- /dev/null +++ b/src/utils/conf.ts @@ -0,0 +1,89 @@ +import path from 'path'; +import {config} from 'dotenv'; +import utilsFile from '@utils/file'; + +export default { + loadEnv(): void { + config(); + + global.FO = { + URL: process.env.URL_FO || 'http://localhost/prestashop/', + }; + + // Linked to the issue #22581 + global.URLHasPort = (global.FO.URL).match(/:\d+.+/) !== null; + + global.BO = { + URL: process.env.URL_BO || `${global.FO.URL}admin-dev/`, + EMAIL: process.env.LOGIN || 'demo@prestashop.com', + PASSWD: process.env.PASSWD || 'Correct Horse Battery Staple', + FIRSTNAME: process.env.FIRSTNAME || 'Marc', + LASTNAME: process.env.LASTNAME || 'Beier', + }; + + global.API = { + URL: process.env.URL_API || `${global.FO.URL}admin-api/`, + }; + + global.PSConfig = { + parametersFile: process.env.PS_PARAMETERS_FILE || path.resolve(utilsFile.getRootPath(), 'app/config/parameters.php'), + }; + + global.INSTALL = { + URL: process.env.URL_INSTALL || `${global.FO.URL}install-dev/`, + LANGUAGE: process.env.INSTALL_LANGUAGE || 'en', + COUNTRY: process.env.INSTALL_COUNTRY || 'France', + ENABLE_SSL: process.env.ENABLE_SSL === 'true', + DB_SERVER: process.env.DB_SERVER || '127.0.0.1', + DB_NAME: process.env.DB_NAME || 'prestashopdb', + DB_USER: process.env.DB_USER || 'root', + DB_PASSWD: process.env.DB_PASSWD || '', + DB_PREFIX: process.env.DB_PREFIX || 'tst_', + SHOP_NAME: process.env.SHOP_NAME || 'PrestaShop', + }; + + global.BROWSER = { + name: process.env.BROWSER || 'chromium', + lang: process.env.BROWSER_LANG || 'en-GB', + width: process.env.BROWSER_WIDTH ? parseInt(process.env.BROWSER_WIDTH, 10) : 1680, + height: process.env.BROWSER_HEIGHT ? parseInt(process.env.BROWSER_HEIGHT, 10) : 900, + sandboxArgs: ['--no-sandbox', '--disable-setuid-sandbox'], + acceptDownloads: true, + config: { + headless: process.env.HEADLESS ? JSON.parse(process.env.HEADLESS) : true, + timeout: 0, + slowMo: process.env.SLOW_MO ? parseInt(process.env.SLOW_MO, 10) : 5, + }, + captureErrors: process.env.INTERCEPT_ERRORS ? JSON.parse(process.env.INTERCEPT_ERRORS) : false, + }; + + global.GENERATE_FAILED_STEPS = process.env.GENERATE_FAILED_STEPS ? JSON.parse(process.env.GENERATE_FAILED_STEPS) : false; + + global.SCREENSHOT = { + FOLDER: process.env.SCREENSHOT_FOLDER || './screenshots', + AFTER_FAIL: process.env.TAKE_SCREENSHOT_AFTER_FAIL ? JSON.parse(process.env.TAKE_SCREENSHOT_AFTER_FAIL) : false, + EACH_STEP: process.env.TAKE_SCREENSHOT_AFTER_EACH_STEP ? JSON.parse(process.env.TAKE_SCREENSHOT_AFTER_EACH_STEP) : false, + }; + + global.maildevConfig = { + smtpPort: parseInt(process.env.SMTP_PORT ?? '1026', 10), + smtpServer: process.env.SMTP_SERVER || 'localhost', + silent: true, + }; + + global.keycloakConfig = { + keycloakExternalUrl: process.env.KEYCLOAK_URL_EXTERNAL || 'http://localhost:8003', + keycloakInternalUrl: process.env.KEYCLOAK_URL_INTERNAL || 'http://keycloak:8080', + keycloakAdminUser: process.env.KEYCLOAK_ADMIN_USER || 'admin', + keycloakAdminPass: process.env.KEYCLOAK_ADMIN_PASS || 'admin', + keycloakClientId: process.env.KEYCLOAK_CLIENT_ID || 'prestashop-keycloak', + keycloakClientSecret: process.env.KEYCLOAK_CLIENT_SECRET || 'O2kKN0fprCK2HWP6PS6reVbZThWf5LFw', + }; + + global.browserErrors = { + responses: [], + js: [], + console: [], + }; + }, +}; diff --git a/src/versions/1.7.3/pages/BO/catalog/products/index.ts b/src/versions/1.7.3/pages/BO/catalog/products/index.ts index aef454b79..9ee4e3968 100644 --- a/src/versions/1.7.3/pages/BO/catalog/products/index.ts +++ b/src/versions/1.7.3/pages/BO/catalog/products/index.ts @@ -82,7 +82,7 @@ class BOProductsVersion extends ProductsPage implements BOProductsPageInterface } // click on search await page.mouse.click(100, 100); - await this.clickAndWaitForLoadState(page, this.filterSearchButton, 'networkidle', 10000); + await this.clickAndWaitForLoadState(page, this.filterSearchButton, 'load', 10000); } } diff --git a/src/versions/1.7.5/pages/BO/catalog/products/create/index.ts b/src/versions/1.7.5/pages/BO/catalog/products/create/index.ts index fa010c09a..93340eb6a 100644 --- a/src/versions/1.7.5/pages/BO/catalog/products/create/index.ts +++ b/src/versions/1.7.5/pages/BO/catalog/products/create/index.ts @@ -1,6 +1,6 @@ // Import pages import type {BOProductsCreatePageInterface} from '@interfaces/BO/catalog/products/create'; -import {BOProductsCreatePage} from '@versions/8.0/pages/BO/catalog/products/create'; +import {BOProductsCreatePage} from '@versions/1.7.8/pages/BO/catalog/products/create'; /** * Bo create product page, contains functions that can be used on the page diff --git a/src/versions/1.7.6/pages/BO/orders/view/viewOrderBasePage.ts b/src/versions/1.7.6/pages/BO/orders/view/viewOrderBasePage.ts index 3d4ad018f..47363ea87 100644 --- a/src/versions/1.7.6/pages/BO/orders/view/viewOrderBasePage.ts +++ b/src/versions/1.7.6/pages/BO/orders/view/viewOrderBasePage.ts @@ -1,6 +1,6 @@ // Import pages import type {BOViewOrderBasePageInterface} from '@interfaces/BO/orders/view/viewOrderBasePage'; -import {ViewOrderBasePage} from '@versions/develop/pages/BO/orders/view/viewOrderBasePage'; +import {ViewOrderBasePage} from '@versions/8.2/pages/BO/orders/view/viewOrderBasePage'; import type {Page} from 'playwright-core'; /** diff --git a/src/versions/1.7.8/pages/BO/catalog/products/create/index.ts b/src/versions/1.7.8/pages/BO/catalog/products/create/index.ts new file mode 100644 index 000000000..4c69fa8dc --- /dev/null +++ b/src/versions/1.7.8/pages/BO/catalog/products/create/index.ts @@ -0,0 +1,38 @@ +// Import pages +import type {BOProductsCreatePageInterface} from '@interfaces/BO/catalog/products/create'; +import {BOProductsCreatePage} from '@versions/8.0/pages/BO/catalog/products/create'; + +import type {Page} from 'playwright'; + +/** + * Bo create product page, contains functions that can be used on the page + * @class + * @extends BOProductsCreatePage + */ +class BOProductsCreatePageVersion extends BOProductsCreatePage implements BOProductsCreatePageInterface { + /** + * @constructs + * Setting up texts and selectors to use on create product page + */ + constructor() { + super(); + + this.saveProductButton = '.product-footer #submit'; + } + + /** + * Save product + * @param page {Page} Browser tab + * @returns {Promise} + */ + async saveProduct(page: Page): Promise { + await page.click(this.saveProductButton); + const growlTextMessage = await this.getGrowlMessageContent(page, 30000); + //await this.closeGrowlMessage(page); + + return growlTextMessage ?? ''; + } +} + +const boProductsCreatePage = new BOProductsCreatePageVersion(); +export {boProductsCreatePage, BOProductsCreatePageVersion as BOProductsCreatePage}; diff --git a/src/versions/8.0/pages/BO/catalog/products/create/index.ts b/src/versions/8.0/pages/BO/catalog/products/create/index.ts index 87659df94..fc0cf8128 100644 --- a/src/versions/8.0/pages/BO/catalog/products/create/index.ts +++ b/src/versions/8.0/pages/BO/catalog/products/create/index.ts @@ -56,6 +56,7 @@ class BOProductsCreatePageVersion extends BOProductsCreatePage implements BOProd async setProductName(page: Page, name: string, locale: string = 'en'): Promise { await this.selectByVisibleText(page, this.productNameLanguageButton, locale); await this.setValue(page, this.productNameInput(locale), name); + await page.locator(this.productNameInput(locale)).fill(name); } /** diff --git a/src/versions/8.0/pages/BO/catalog/products/create/tabStocks.ts b/src/versions/8.0/pages/BO/catalog/products/create/tabStocks.ts index 64a77fef0..4944fcbb0 100644 --- a/src/versions/8.0/pages/BO/catalog/products/create/tabStocks.ts +++ b/src/versions/8.0/pages/BO/catalog/products/create/tabStocks.ts @@ -29,8 +29,8 @@ class BOProductTabStocksVersion extends StocksTab implements BOProductsCreateTab this.denyOrderRadioButton = '#form_step3_out_of_stock_0'; this.allowOrderRadioButton = '#form_step3_out_of_stock_1'; this.useDefaultBehaviourRadioButton = '#form_step3_out_of_stock_2'; - this.labelWhenInStockInput = '#form_step3_available_now_1'; - this.labelWhenOutOfStock = '#form_step3_available_later_1'; + this.labelWhenInStockInput = '#form_step3_available_now_2'; + this.labelWhenOutOfStock = '#form_step3_available_later_2'; } /** diff --git a/src/versions/8.2/pages/BO/orders/view/viewOrderBasePage.ts b/src/versions/8.2/pages/BO/orders/view/viewOrderBasePage.ts new file mode 100644 index 000000000..b075ff279 --- /dev/null +++ b/src/versions/8.2/pages/BO/orders/view/viewOrderBasePage.ts @@ -0,0 +1,33 @@ +// Import pages +import type {BOViewOrderBasePageInterface} from '@interfaces/BO/orders/view/viewOrderBasePage'; +import {ViewOrderBasePage} from '@versions/develop/pages/BO/orders/view/viewOrderBasePage'; +import type {Page} from 'playwright-core'; + +/** + * View orders page, contains functions that can be used in the page + * @class + * @extends OrdersPage + */ +class ViewOrderBasePageVersion extends ViewOrderBasePage implements BOViewOrderBasePageInterface { + /** + * Modify the order status + * @param page {Page} Browser tab + * @param status {string} Status to edit + * @returns {Promise} + */ + async modifyOrderStatus(page: Page, status: string): Promise { + const actualStatus = await this.getOrderStatus(page); + + if (status !== actualStatus) { + await this.selectByVisibleText(page, this.orderStatusesSelect, status); + await page.locator(this.updateStatusButton).click(); + await page.waitForLoadState(); + return this.getOrderStatus(page); + } + + return actualStatus; + } +} + +const viewOrderBasePage = new ViewOrderBasePageVersion(); +export {viewOrderBasePage, ViewOrderBasePageVersion as ViewOrderBasePage}; diff --git a/src/versions/8.2/pages/BO/shipping/carriers/index.ts b/src/versions/8.2/pages/BO/shipping/carriers/index.ts index c818fbec3..36d2625a5 100644 --- a/src/versions/8.2/pages/BO/shipping/carriers/index.ts +++ b/src/versions/8.2/pages/BO/shipping/carriers/index.ts @@ -212,7 +212,7 @@ class BOCarriersPage extends BOCarriersPageVersion implements BOCarriersPageInte case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value === '1' ? 'Yes' : 'No'), ]); break; diff --git a/src/versions/develop/pages/BO/advancedParameters/database/dbBackup/index.ts b/src/versions/develop/pages/BO/advancedParameters/database/dbBackup/index.ts index c5a42a77d..f734f770e 100644 --- a/src/versions/develop/pages/BO/advancedParameters/database/dbBackup/index.ts +++ b/src/versions/develop/pages/BO/advancedParameters/database/dbBackup/index.ts @@ -229,7 +229,7 @@ class BODbBackupPage extends BOBasePage implements BODbBackupPageInterface { const currentUrl: string = page.url(); await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/advancedParameters/database/sqlManager/index.ts b/src/versions/develop/pages/BO/advancedParameters/database/sqlManager/index.ts index e7cf438a5..ea510417c 100644 --- a/src/versions/develop/pages/BO/advancedParameters/database/sqlManager/index.ts +++ b/src/versions/develop/pages/BO/advancedParameters/database/sqlManager/index.ts @@ -340,7 +340,7 @@ class BOSQLManagerPage extends BOBasePage implements BOSQLManagerPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/advancedParameters/logs.ts b/src/versions/develop/pages/BO/advancedParameters/logs.ts index 62c2240d1..84f52608a 100644 --- a/src/versions/develop/pages/BO/advancedParameters/logs.ts +++ b/src/versions/develop/pages/BO/advancedParameters/logs.ts @@ -257,7 +257,7 @@ class BOLogsPage extends BOBasePage implements BOLogsPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/advancedParameters/multistore/create.ts b/src/versions/develop/pages/BO/advancedParameters/multistore/create.ts index 25a86417d..34876d5cf 100644 --- a/src/versions/develop/pages/BO/advancedParameters/multistore/create.ts +++ b/src/versions/develop/pages/BO/advancedParameters/multistore/create.ts @@ -64,7 +64,7 @@ class BOMultistoreGroupCreatePage extends BOBasePage implements BOMultistoreGrou ); await this.setChecked(page, this.statusToggleLabel(shopGroupData.status ? 'on' : 'off')); - await this.clickAndWaitForURL(page, this.saveButton, 'networkidle', 60000); + await this.clickAndWaitForURL(page, this.saveButton, 'load', 60000); return this.getAlertSuccessBlockContent(page); } } diff --git a/src/versions/develop/pages/BO/advancedParameters/multistore/shop/create.ts b/src/versions/develop/pages/BO/advancedParameters/multistore/shop/create.ts index bdcf84ca8..f72ab8720 100644 --- a/src/versions/develop/pages/BO/advancedParameters/multistore/shop/create.ts +++ b/src/versions/develop/pages/BO/advancedParameters/multistore/shop/create.ts @@ -71,7 +71,7 @@ class BOMultistoreShopCreatePage extends BOBasePage implements BOMultistoreShopC await Promise.all([ page.locator(this.saveButton).evaluate((el: HTMLElement) => el.click()), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle', timeout: 30000}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {timeout: 30000}), ]); return this.getTextContent(page, this.alertSuccessBlock); diff --git a/src/versions/develop/pages/BO/advancedParameters/multistore/url/create.ts b/src/versions/develop/pages/BO/advancedParameters/multistore/url/create.ts index 181d26e22..0e670d00e 100644 --- a/src/versions/develop/pages/BO/advancedParameters/multistore/url/create.ts +++ b/src/versions/develop/pages/BO/advancedParameters/multistore/url/create.ts @@ -60,7 +60,7 @@ class BOMultistoreShopUrlCreatePage extends BOBasePage implements BOMultistoreSh async setVirtualUrl(page: Page, url: string): Promise { await this.setValue(page, this.virtualUrlInput, url); - await this.clickAndWaitForURL(page, this.saveButton, 'networkidle', 60000); + await this.clickAndWaitForURL(page, this.saveButton, 'load', 60000); return this.getTextContent(page, this.alertSuccessBlock); } diff --git a/src/versions/develop/pages/BO/advancedParameters/multistore/url/index.ts b/src/versions/develop/pages/BO/advancedParameters/multistore/url/index.ts index a2a0c74a5..8ed75c35d 100644 --- a/src/versions/develop/pages/BO/advancedParameters/multistore/url/index.ts +++ b/src/versions/develop/pages/BO/advancedParameters/multistore/url/index.ts @@ -227,7 +227,7 @@ class BOMultistoreShopUrlPage extends BOBasePage implements BOMultistoreShopUrlP case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value ? 'Yes' : 'No'), ]); break; diff --git a/src/versions/develop/pages/BO/advancedParameters/performance/index.ts b/src/versions/develop/pages/BO/advancedParameters/performance/index.ts index 15d54706c..50fe00290 100644 --- a/src/versions/develop/pages/BO/advancedParameters/performance/index.ts +++ b/src/versions/develop/pages/BO/advancedParameters/performance/index.ts @@ -93,7 +93,7 @@ class PerformancePage extends BOBasePage implements BOPerformancePageInterface { * @returns {Promise} */ async isDebugModeToggleVisible(page: Page): Promise { - return this.elementVisible(page, this.debugModeToolbar, 1000); + return this.elementVisible(page, this.debugModeToolbar, 3000); } /** diff --git a/src/versions/develop/pages/BO/advancedParameters/webservices/index.ts b/src/versions/develop/pages/BO/advancedParameters/webservices/index.ts index 330f97468..aa8ca820f 100644 --- a/src/versions/develop/pages/BO/advancedParameters/webservices/index.ts +++ b/src/versions/develop/pages/BO/advancedParameters/webservices/index.ts @@ -419,7 +419,7 @@ class BOWebservicesPage extends BOBasePage implements BOWebservicesPageInterface await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/catalog/attributes/index.ts b/src/versions/develop/pages/BO/catalog/attributes/index.ts index f0344079c..cefd41344 100644 --- a/src/versions/develop/pages/BO/catalog/attributes/index.ts +++ b/src/versions/develop/pages/BO/catalog/attributes/index.ts @@ -387,7 +387,7 @@ class BOAttributesPage extends BOBasePage implements BOAttributesPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/catalog/attributes/view.ts b/src/versions/develop/pages/BO/catalog/attributes/view.ts index 4bac77e3e..b60b7e506 100644 --- a/src/versions/develop/pages/BO/catalog/attributes/view.ts +++ b/src/versions/develop/pages/BO/catalog/attributes/view.ts @@ -351,7 +351,7 @@ class BOAttributesViewPage extends BOBasePage implements BOAttributesViewPageInt await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/catalog/brands/addresses/create.ts b/src/versions/develop/pages/BO/catalog/brands/addresses/create.ts index 31435812c..475022e1e 100644 --- a/src/versions/develop/pages/BO/catalog/brands/addresses/create.ts +++ b/src/versions/develop/pages/BO/catalog/brands/addresses/create.ts @@ -27,6 +27,8 @@ class BOBrandAdressesCreatePage extends BOBasePage implements BOBrandAdressesCre private readonly countrySelect: string; + private readonly stateSelect: string; + private readonly homePhoneInput: string; private readonly mobilePhoneInput: string; @@ -53,6 +55,7 @@ class BOBrandAdressesCreatePage extends BOBasePage implements BOBrandAdressesCre this.postalCodeInput = 'input#manufacturer_address_post_code'; this.cityInput = 'input#manufacturer_address_city'; this.countrySelect = 'select#manufacturer_address_id_country'; + this.stateSelect = 'select#manufacturer_address_id_state'; this.homePhoneInput = 'input#manufacturer_address_home_phone'; this.mobilePhoneInput = 'input#manufacturer_address_mobile_phone'; this.otherInput = 'input#manufacturer_address_other'; @@ -77,14 +80,26 @@ class BOBrandAdressesCreatePage extends BOBasePage implements BOBrandAdressesCre await this.setValue(page, this.secondaryAddressInput, brandAddressData.secondaryAddress); await this.setValue(page, this.postalCodeInput, brandAddressData.postalCode); await this.setValue(page, this.cityInput, brandAddressData.city); - await this.selectByVisibleText(page, this.countrySelect, brandAddressData.country); - await page.locator(this.homePhoneInput).click(); + + // Select country + await Promise.all([ + page.waitForResponse((response) => response.url().includes('states/country-states'), {timeout: 1000}), + this.selectByVisibleText(page, this.countrySelect, brandAddressData.country), + ]); + + // Select state + if (brandAddressData.state) { + await this.selectByVisibleText(page, this.stateSelect, brandAddressData.state); + } else { + await this.elementNotVisible(page, this.stateSelect); + } + await this.setValue(page, this.homePhoneInput, brandAddressData.homePhone); await this.setValue(page, this.mobilePhoneInput, brandAddressData.mobilePhone); await this.setValue(page, this.otherInput, brandAddressData.other); - // Click on Save button and successful message - await this.clickAndWaitForURL(page, this.saveButton); + // Click on Save button and successful message (the delay makes it more stable when state selector is switched) + await this.clickAndWaitForURL(page, this.saveButton, 'load', 30000, {delay: 500}); return this.getAlertSuccessBlockParagraphContent(page); } } diff --git a/src/versions/develop/pages/BO/catalog/brands/index.ts b/src/versions/develop/pages/BO/catalog/brands/index.ts index 5fddc4aea..291cdd48d 100644 --- a/src/versions/develop/pages/BO/catalog/brands/index.ts +++ b/src/versions/develop/pages/BO/catalog/brands/index.ts @@ -194,7 +194,9 @@ class BOBrandsPage extends BOBasePage implements BOBrandsPageInterface { */ async resetFilter(page: Page, tableName: string): Promise { if (await this.elementVisible(page, this.filterResetButton(tableName), 2000)) { - await this.clickAndWaitForLoadState(page, this.filterResetButton(tableName)); + // Wait for URL update instead of load state, because with two grids on the same page the load + // event was not stable enough + await this.clickAndWaitForURL(page, this.filterResetButton(tableName)); await this.elementNotVisible(page, this.filterResetButton(tableName), 2000); } } @@ -240,8 +242,10 @@ class BOBrandsPage extends BOBasePage implements BOBrandsPageInterface { default: throw new Error(`Filter ${filterBy} was not found`); } - // click on search - await this.clickAndWaitForLoadState(page, this.filterSearchButton(tableName)); + // Click on search + // Wait for URL update instead of load state, because with two grids on the same page the load + // event was not stable enough + await this.clickAndWaitForURL(page, this.filterSearchButton(tableName)); } /** diff --git a/src/versions/develop/pages/BO/catalog/categories/index.ts b/src/versions/develop/pages/BO/catalog/categories/index.ts index 549ce8446..812a5f8f8 100644 --- a/src/versions/develop/pages/BO/catalog/categories/index.ts +++ b/src/versions/develop/pages/BO/catalog/categories/index.ts @@ -543,7 +543,7 @@ class BOCategoriesPage extends BOBasePage implements BOCategoriesPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/catalog/discounts/catalogPriceRules/index.ts b/src/versions/develop/pages/BO/catalog/discounts/catalogPriceRules/index.ts index 5299e14bf..0549d2d8c 100644 --- a/src/versions/develop/pages/BO/catalog/discounts/catalogPriceRules/index.ts +++ b/src/versions/develop/pages/BO/catalog/discounts/catalogPriceRules/index.ts @@ -229,7 +229,7 @@ class BOCatalogPriceRulesPage extends BOBasePage implements BOCatalogPriceRulesP case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value), ]); break; diff --git a/src/versions/develop/pages/BO/catalog/discounts/index.ts b/src/versions/develop/pages/BO/catalog/discounts/index.ts index f76c6da50..3a324abec 100644 --- a/src/versions/develop/pages/BO/catalog/discounts/index.ts +++ b/src/versions/develop/pages/BO/catalog/discounts/index.ts @@ -372,7 +372,7 @@ class BOCartRulesPage extends BOBasePage implements BOCartRulesPageInterface { case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value === '1' ? 'Yes' : 'No'), ]); break; diff --git a/src/versions/develop/pages/BO/catalog/monitoring.ts b/src/versions/develop/pages/BO/catalog/monitoring.ts index e4a8955f7..bbe57b79f 100644 --- a/src/versions/develop/pages/BO/catalog/monitoring.ts +++ b/src/versions/develop/pages/BO/catalog/monitoring.ts @@ -388,7 +388,7 @@ class BOMonitoringPage extends BOBasePage implements BOMonitoringPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect(tableName), number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page, tableName); diff --git a/src/versions/develop/pages/BO/catalog/outstanding.ts b/src/versions/develop/pages/BO/catalog/outstanding.ts index 6d9108c98..8b27a3a2b 100644 --- a/src/versions/develop/pages/BO/catalog/outstanding.ts +++ b/src/versions/develop/pages/BO/catalog/outstanding.ts @@ -157,7 +157,7 @@ class BOOutstandingPage extends BOBasePage implements BOOutstandingPageInterface await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/catalog/products/create/index.ts b/src/versions/develop/pages/BO/catalog/products/create/index.ts index 77e9bbdbf..a0938df41 100644 --- a/src/versions/develop/pages/BO/catalog/products/create/index.ts +++ b/src/versions/develop/pages/BO/catalog/products/create/index.ts @@ -116,7 +116,7 @@ class BOProductsCreatePage extends BOBasePage implements BOProductsCreatePageInt constructor() { super(); - this.pageTitle = 'Products'; + this.pageTitle = 'Product'; this.saveAndPublishButtonName = 'Save and publish'; this.successfulDuplicateMessage = 'Successful duplication'; this.errorMessage = 'Unable to update settings.'; @@ -517,7 +517,7 @@ class BOProductsCreatePage extends BOBasePage implements BOProductsCreatePageInt await boProductsPage.selectProductType(page, productType); await boProductsPage.clickOnAddNewProduct(page); - await page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}); + await page.waitForURL((url: URL): boolean => url.toString() !== currentUrl); } /** diff --git a/src/versions/develop/pages/BO/catalog/products/create/tabCombinations.ts b/src/versions/develop/pages/BO/catalog/products/create/tabCombinations.ts index 37a068c96..f50505b86 100644 --- a/src/versions/develop/pages/BO/catalog/products/create/tabCombinations.ts +++ b/src/versions/develop/pages/BO/catalog/products/create/tabCombinations.ts @@ -363,7 +363,7 @@ class CombinationsTab extends BOBasePage implements BOProductsCreateTabCombinati async clickOnLearnMoreButton(page: Page): Promise { await this.waitForSelectorAndClick(page, this.combinationsTabLink); - return this.openLinkWithTargetBlank(page, this.learnMoreButton, 'body', 'domcontentloaded'); + return this.openLinkWithTargetBlank(page, this.learnMoreButton, 'body'); } /** diff --git a/src/versions/develop/pages/BO/catalog/products/create/tabDescription.ts b/src/versions/develop/pages/BO/catalog/products/create/tabDescription.ts index d23f8725b..ace27c2dd 100644 --- a/src/versions/develop/pages/BO/catalog/products/create/tabDescription.ts +++ b/src/versions/develop/pages/BO/catalog/products/create/tabDescription.ts @@ -18,6 +18,8 @@ class DescriptionTab extends BOBasePage implements BOProductsCreateTabDescriptio private readonly productImageDropZoneDiv: string; + private readonly imageLoading: string; + private readonly imagePreviewBlock: string; private readonly imageDefaultBlock: string; @@ -114,6 +116,7 @@ class DescriptionTab extends BOBasePage implements BOProductsCreateTabDescriptio this.descriptionTabLink = '#product_description-tab-nav'; // Image selectors this.productImageDropZoneDiv = '#product-images-dropzone'; + this.imageLoading = `${this.productImageDropZoneDiv} div.dropzone-loading`; this.imagePreviewBlock = `${this.productImageDropZoneDiv} div.dz-preview.openfilemanager`; this.imageDefaultBlock = `${this.productImageDropZoneDiv} div.dz-default.openfilemanager`; this.imagePreviewCover = `${this.productImageDropZoneDiv} div.dz-preview.is-cover`; @@ -179,6 +182,12 @@ class DescriptionTab extends BOBasePage implements BOProductsCreateTabDescriptio * @returns {Promise} */ async getNumberOfImages(page: Page): Promise { + // Wait for the dropzone element to be initialized + await this.elementVisible(page, this.productImageDropZoneDiv, 3000); + + // But wait for the loading to be over before counting + await this.elementNotVisible(page, this.imageLoading, 1000); + return page.locator(this.productImage).count(); } diff --git a/src/versions/develop/pages/BO/catalog/products/create/tabPricing.ts b/src/versions/develop/pages/BO/catalog/products/create/tabPricing.ts index 018e429a9..3e3c10761 100644 --- a/src/versions/develop/pages/BO/catalog/products/create/tabPricing.ts +++ b/src/versions/develop/pages/BO/catalog/products/create/tabPricing.ts @@ -220,7 +220,7 @@ class PricingTab extends BOBasePage implements BOProductsCreateTabPricingPageInt * @returns {Promise} */ async setRetailPrice(page: Page, isTaxExcluded: boolean, price: number): Promise { - await this.setValue( + await this.setValueSequentially( page, isTaxExcluded ? this.retailPriceInputTaxExcl : this.retailPriceInputTaxIncl, price, diff --git a/src/versions/develop/pages/BO/catalog/products/index.ts b/src/versions/develop/pages/BO/catalog/products/index.ts index 6b372d573..a88e7f946 100644 --- a/src/versions/develop/pages/BO/catalog/products/index.ts +++ b/src/versions/develop/pages/BO/catalog/products/index.ts @@ -464,7 +464,6 @@ class ProductsPage extends BOBasePage implements BOProductsPageInterface { await page.waitForURL((url: URL): boolean => url.toString().includes('/sell/catalog/products') && url.toString().includes('/edit'), { - waitUntil: 'domcontentloaded', timeout: 30000, }); } @@ -585,7 +584,7 @@ class ProductsPage extends BOBasePage implements BOProductsPageInterface { (action === 'enable' || action === 'disable') ? `${action}_selection` : `bulk_${action}`, ); await this.waitForSelectorAndClick(page, modalBulkActionsProductsCloseButton); - await page.waitForLoadState('networkidle'); + await page.waitForLoadState(); return this.elementNotVisible(page, modalBulkActionsProductsProgress, 1000); } @@ -766,7 +765,7 @@ class ProductsPage extends BOBasePage implements BOProductsPageInterface { // Do nothing } // click on search - await this.clickAndWaitForLoadState(page, this.filterSearchButton, 'networkidle', 10000); + await this.clickAndWaitForLoadState(page, this.filterSearchButton, 'load', 10000); } /** diff --git a/src/versions/develop/pages/BO/catalog/suppliers/create.ts b/src/versions/develop/pages/BO/catalog/suppliers/create.ts index 6080de7ab..00f9b90b3 100644 --- a/src/versions/develop/pages/BO/catalog/suppliers/create.ts +++ b/src/versions/develop/pages/BO/catalog/suppliers/create.ts @@ -125,10 +125,19 @@ class BOSuppliersCreatePage extends BOBasePage implements BOSuppliersCreatePageI await this.setValue(page, this.secondaryAddressInput, supplierData.secondaryAddress); await this.setValue(page, this.postalCodeInput, supplierData.postalCode); await this.setValue(page, this.cityInput, supplierData.city); + // Select country - await page.locator(this.selectCountryList).click(); - await this.setValue(page, this.searchCountryInput, supplierData.country); - await this.waitForSelectorAndClick(page, this.countrySearchResult); + await Promise.all([ + page.waitForResponse((response) => response.url().includes('states/country-states'), {timeout: 1000}), + this.selectByVisibleText(page, this.countryInput, supplierData.country), + ]); + + // Select state + if (supplierData.state) { + await this.selectByVisibleText(page, this.stateInput, supplierData.state); + } else { + await this.elementNotVisible(page, this.stateInput); + } // Add logo await this.uploadFile(page, this.logoFileInput, supplierData.logo); diff --git a/src/versions/develop/pages/BO/customerService/customerService/index.ts b/src/versions/develop/pages/BO/customerService/customerService/index.ts index e92de3a95..02b5c7c9c 100644 --- a/src/versions/develop/pages/BO/customerService/customerService/index.ts +++ b/src/versions/develop/pages/BO/customerService/customerService/index.ts @@ -188,7 +188,7 @@ class BOCustomerServicePage extends BOBasePage implements BOCustomerServicePageI case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value ? 'Yes' : 'No'), ]); break; diff --git a/src/versions/develop/pages/BO/customers/index.ts b/src/versions/develop/pages/BO/customers/index.ts index e15f4372e..5d467ac24 100644 --- a/src/versions/develop/pages/BO/customers/index.ts +++ b/src/versions/develop/pages/BO/customers/index.ts @@ -633,7 +633,7 @@ class BOCustomersPage extends BOBasePage implements BOCustomersPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); } diff --git a/src/versions/develop/pages/BO/dashboard/index.ts b/src/versions/develop/pages/BO/dashboard/index.ts index c5ea467d9..1bcce8cb3 100644 --- a/src/versions/develop/pages/BO/dashboard/index.ts +++ b/src/versions/develop/pages/BO/dashboard/index.ts @@ -377,7 +377,7 @@ class Dashboard extends BOBasePage implements DashboardPageInterface { * @returns {Promise} */ async getOutOfStockProducts(page: Page): Promise { - return this.getNumberFromText(page, this.outOfStockProductsNumber); + return this.getNumberFromText(page, this.outOfStockProductsNumber, 1000); } /** @@ -512,6 +512,9 @@ class Dashboard extends BOBasePage implements DashboardPageInterface { * @returns {Promise} */ async getTrafficSources(page: Page): Promise { + // Wait for elements to be loaded before counting them + await this.elementVisible(page, this.dashboardTrafficSourceItem, 1000); + const nbItems = await page.locator(this.dashboardTrafficSourceItem).count(); const sources: DashboardTrafficSource[] = []; diff --git a/src/versions/develop/pages/BO/design/imageSettings/index.ts b/src/versions/develop/pages/BO/design/imageSettings/index.ts index a6264fb3b..8650078a0 100644 --- a/src/versions/develop/pages/BO/design/imageSettings/index.ts +++ b/src/versions/develop/pages/BO/design/imageSettings/index.ts @@ -420,7 +420,7 @@ class BOImageSettingsPage extends BOBasePage implements BOImageSettingsPageInter await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/error.ts b/src/versions/develop/pages/BO/error.ts new file mode 100644 index 000000000..148421591 --- /dev/null +++ b/src/versions/develop/pages/BO/error.ts @@ -0,0 +1,26 @@ +import {type BOErrorPageInterface} from '@interfaces/BO/error'; +import BOBasePage from '@pages/BO/BOBasePage'; + +/** + * Error page, contains selectors and functions for the error pages + * @class + * @extends BOBasePage + */ +class BOErrorPage extends BOBasePage implements BOErrorPageInterface { + public readonly notFoundTitle: string; + + /** + * @constructs + * Setting up titles and selectors to use on error pages + */ + constructor() { + super(); + + // Selectors + this.alertDangerBlockParagraph = '.alert-danger'; + + this.notFoundTitle = 'Page not found'; + } +} + +module.exports = new BOErrorPage(); diff --git a/src/versions/develop/pages/BO/international/languages/index.ts b/src/versions/develop/pages/BO/international/languages/index.ts index a044b842b..99bf6b775 100644 --- a/src/versions/develop/pages/BO/international/languages/index.ts +++ b/src/versions/develop/pages/BO/international/languages/index.ts @@ -425,7 +425,7 @@ class BOLanguagesPage extends BOBasePage implements BOLanguagesPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/international/localization/currencies/index.ts b/src/versions/develop/pages/BO/international/localization/currencies/index.ts index 0dd3ce6f8..8917a4af1 100644 --- a/src/versions/develop/pages/BO/international/localization/currencies/index.ts +++ b/src/versions/develop/pages/BO/international/localization/currencies/index.ts @@ -422,7 +422,7 @@ class BOCurrenciesPage extends BOLocalizationBasePage implements BOCurrenciesPag await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/international/localization/index.ts b/src/versions/develop/pages/BO/international/localization/index.ts index 6515c542e..8b37bc116 100644 --- a/src/versions/develop/pages/BO/international/localization/index.ts +++ b/src/versions/develop/pages/BO/international/localization/index.ts @@ -109,7 +109,7 @@ class BOLocalizationPage extends BOLocalizationBasePage implements BOLocalizatio // Import the pack await page.locator(this.importButton).click(); - return this.getAlertSuccessBlockParagraphContent(page); + return this.getAlertSuccessBlockParagraphContent(page, 20000); } /** diff --git a/src/versions/develop/pages/BO/international/locations/countries/index.ts b/src/versions/develop/pages/BO/international/locations/countries/index.ts index 08bd639af..231bdea7d 100644 --- a/src/versions/develop/pages/BO/international/locations/countries/index.ts +++ b/src/versions/develop/pages/BO/international/locations/countries/index.ts @@ -280,7 +280,7 @@ class BOCountriesPage extends BOBasePage implements BOCountriesPageInterface { } await Promise.all([ this.selectByVisibleText(page, this.filterColumn(filterBy), textValue), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); break; diff --git a/src/versions/develop/pages/BO/international/translations/index.ts b/src/versions/develop/pages/BO/international/translations/index.ts index 1cc082e58..43ce9f8e7 100644 --- a/src/versions/develop/pages/BO/international/translations/index.ts +++ b/src/versions/develop/pages/BO/international/translations/index.ts @@ -209,7 +209,7 @@ class BOTranslationsPage extends BOBasePage implements BOTranslationsPageInterfa await this.waitForSelectorAndClick(page, this.searchLanguageResult); await page.locator(this.addUpdateLanguageButton).click(); - return this.getAlertSuccessBlockParagraphContent(page); + return this.getAlertSuccessBlockParagraphContent(page, 20000); } /** diff --git a/src/versions/develop/pages/BO/login/index.ts b/src/versions/develop/pages/BO/login/index.ts index 8b07cd704..b60aa699e 100644 --- a/src/versions/develop/pages/BO/login/index.ts +++ b/src/versions/develop/pages/BO/login/index.ts @@ -176,7 +176,7 @@ class LoginPage extends BOBasePage implements LoginPageInterface { async clickOnLoginButton(page: Page, waitForNavigation: boolean): Promise { // Wait for navigation if the login is successful if (waitForNavigation) { - await this.clickAndWaitForURL(page, this.submitLoginButton, 'load'); + await this.clickAndWaitForURL(page, this.submitLoginButton); await this.isNavbarVisible(page); } else { await page.locator(this.submitLoginButton).click(); diff --git a/src/versions/develop/pages/BO/modules/autoupgrade/index.ts b/src/versions/develop/pages/BO/modules/autoupgrade/index.ts index cc06943da..50b2cf920 100644 --- a/src/versions/develop/pages/BO/modules/autoupgrade/index.ts +++ b/src/versions/develop/pages/BO/modules/autoupgrade/index.ts @@ -71,7 +71,7 @@ class Autoupgrade extends ModuleConfigurationPage implements ModuleAutoupgradeMa this.pageTitle = `Update assistant > Update assistant • ${global.INSTALL.SHOP_NAME}`; this.checkRequirementSuccessMessage = 'The requirements check is complete, you can update your store to this ' + 'version of PrestaShop.'; - this.updateSuccessMessage = 'Your store is up to date'; + this.updateSuccessMessage = 'Your store has been updated to PrestaShop version '; // Selectors // First page : Welcome to PrestaShop Update Assistant diff --git a/src/versions/develop/pages/BO/modules/ps_facetedsearch/index.ts b/src/versions/develop/pages/BO/modules/ps_facetedsearch/index.ts index 836c1c815..c8cb185d7 100644 --- a/src/versions/develop/pages/BO/modules/ps_facetedsearch/index.ts +++ b/src/versions/develop/pages/BO/modules/ps_facetedsearch/index.ts @@ -64,7 +64,7 @@ class PsFacetedSearch extends ModuleConfigurationPage implements ModulePsFaceted super(); // Override - this.alertTextBlock = 'div.alert'; + this.alertTextBlock = '#content > div.alert'; this.pageSubTitle = 'Faceted search'; this.msgSuccessfulCreation = (name: string) => `Your filter "${name}" was added successfully.`; @@ -167,7 +167,7 @@ class PsFacetedSearch extends ModuleConfigurationPage implements ModulePsFaceted */ async setShowProductsOnlyFromDefaultCategoryValue(page: Page, value: boolean): Promise { await this.setChecked(page, this.showProductsOnlyFromDefaultCategoryCheckbox(value ? 'on' : 'off'), true); - await page.locator(this.btnConfigurationSave).click(); + await this.clickAndWaitForLoadState(page, this.btnConfigurationSave); return this.getAlertBlockContent(page); } diff --git a/src/versions/develop/pages/BO/modules/ps_newproducts/index.ts b/src/versions/develop/pages/BO/modules/ps_newproducts/index.ts index fd3b24b1d..f517c6439 100644 --- a/src/versions/develop/pages/BO/modules/ps_newproducts/index.ts +++ b/src/versions/develop/pages/BO/modules/ps_newproducts/index.ts @@ -31,7 +31,7 @@ class PsNewProducts extends ModuleConfigurationPage implements ModulePsNewProduc super(); // Override - this.alertTextBlock = 'div.alert'; + this.alertTextBlock = 'div.alert[class^="module_"]'; this.pageSubTitle = 'New products block'; this.updateSettingsSuccessMessage = 'The settings have been updated.'; diff --git a/src/versions/develop/pages/BO/orders/creditSlips.ts b/src/versions/develop/pages/BO/orders/creditSlips.ts index 7e1ed5fef..6d5b1b1d6 100644 --- a/src/versions/develop/pages/BO/orders/creditSlips.ts +++ b/src/versions/develop/pages/BO/orders/creditSlips.ts @@ -340,7 +340,7 @@ class BOCreditSlipsPage extends BOBasePage implements BOCreditSlipsPageInterface await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/orders/index.ts b/src/versions/develop/pages/BO/orders/index.ts index 16812b348..05cf696b5 100644 --- a/src/versions/develop/pages/BO/orders/index.ts +++ b/src/versions/develop/pages/BO/orders/index.ts @@ -248,7 +248,7 @@ class OrdersPage extends BOBasePage implements BOOrdersPageInterface { } // click on search await page.locator(this.filterSearchButton).click(); - await page.waitForURL(`**/?order**filters**${filterBy}**`, {waitUntil: 'domcontentloaded'}); + await page.waitForURL(`**/?order**filters**${filterBy}**`); } /** @@ -609,7 +609,7 @@ class OrdersPage extends BOBasePage implements BOOrdersPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'domcontentloaded'}), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/orders/shoppingCarts/index.ts b/src/versions/develop/pages/BO/orders/shoppingCarts/index.ts index c88aa63a9..196e70708 100644 --- a/src/versions/develop/pages/BO/orders/shoppingCarts/index.ts +++ b/src/versions/develop/pages/BO/orders/shoppingCarts/index.ts @@ -410,7 +410,7 @@ class BOShoppingCarts extends BOBasePage implements BOShoppingCartsPageInterface const currentUrl: string = page.url(); await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/orders/view/viewOrderBasePage.ts b/src/versions/develop/pages/BO/orders/view/viewOrderBasePage.ts index 181f16f40..c84de4340 100644 --- a/src/versions/develop/pages/BO/orders/view/viewOrderBasePage.ts +++ b/src/versions/develop/pages/BO/orders/view/viewOrderBasePage.ts @@ -46,11 +46,11 @@ class ViewOrderBasePage extends BOBasePage implements BOViewOrderBasePageInterfa private readonly orderReference: string; - private readonly orderStatusesSelect: string; + protected readonly orderStatusesSelect: string; private readonly orderStatusesOptionSelect: string; - private readonly updateStatusButton: string; + protected readonly updateStatusButton: string; private readonly viewInvoiceButton: string; diff --git a/src/versions/develop/pages/BO/quickAccess/index.ts b/src/versions/develop/pages/BO/quickAccess/index.ts index 51c6ca878..0bd20a8ad 100644 --- a/src/versions/develop/pages/BO/quickAccess/index.ts +++ b/src/versions/develop/pages/BO/quickAccess/index.ts @@ -164,7 +164,7 @@ class BOQuickAccess extends BOBasePage implements BOQuickAccessInterface { case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value ? 'Yes' : 'No'), ]); break; diff --git a/src/versions/develop/pages/BO/shipping/carriers/index.ts b/src/versions/develop/pages/BO/shipping/carriers/index.ts index 60afa6096..cc0d3261e 100644 --- a/src/versions/develop/pages/BO/shipping/carriers/index.ts +++ b/src/versions/develop/pages/BO/shipping/carriers/index.ts @@ -425,7 +425,7 @@ class BOCarriersPage extends BOBasePage implements BOCarriersPageInterface { const currentUrl: string = page.url(); await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/shopParameters/customerSettings/groups/index.ts b/src/versions/develop/pages/BO/shopParameters/customerSettings/groups/index.ts index 056f70d12..aac8ee406 100644 --- a/src/versions/develop/pages/BO/shopParameters/customerSettings/groups/index.ts +++ b/src/versions/develop/pages/BO/shopParameters/customerSettings/groups/index.ts @@ -220,7 +220,7 @@ class BOGroupsPage extends BOBasePage implements BOCustomerGroupsPageInterface { case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value ? 'Yes' : 'No'), ]); break; diff --git a/src/versions/develop/pages/BO/shopParameters/customerSettings/titles/index.ts b/src/versions/develop/pages/BO/shopParameters/customerSettings/titles/index.ts index 32f44be00..cd520c2c4 100644 --- a/src/versions/develop/pages/BO/shopParameters/customerSettings/titles/index.ts +++ b/src/versions/develop/pages/BO/shopParameters/customerSettings/titles/index.ts @@ -371,7 +371,7 @@ class BOTitlesPage extends BOBasePage implements BOTitlesPageInterface { await Promise.all([ this.selectByVisibleText(page, this.paginationLimitSelect, number), - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), ]); return this.getPaginationLabel(page); diff --git a/src/versions/develop/pages/BO/shopParameters/stores/index.ts b/src/versions/develop/pages/BO/shopParameters/stores/index.ts index 5b62111d1..ff7242ae8 100644 --- a/src/versions/develop/pages/BO/shopParameters/stores/index.ts +++ b/src/versions/develop/pages/BO/shopParameters/stores/index.ts @@ -283,7 +283,7 @@ class BOStoresPage extends BOBasePage implements BOStoresPageInterface { case 'select': await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), this.selectByVisibleText(page, this.filterColumn(filterBy), value === '1' ? 'Yes' : 'No'), ]); break; @@ -400,7 +400,8 @@ class BOStoresPage extends BOBasePage implements BOStoresPageInterface { * @return {Promise} */ async gotoEditStorePage(page: Page, row: number): Promise { - await this.clickAndWaitForURL(page, this.tableColumnActionsEditLink(row)); + // Special case where we wait for networkidle because the list of states in the select is loaded by ajax + await this.clickAndWaitForURL(page, this.tableColumnActionsEditLink(row), 'networkidle'); } /** diff --git a/src/versions/develop/pages/FO/classic/category/index.ts b/src/versions/develop/pages/FO/classic/category/index.ts index 561ce1661..59282a9c9 100644 --- a/src/versions/develop/pages/FO/classic/category/index.ts +++ b/src/versions/develop/pages/FO/classic/category/index.ts @@ -1,7 +1,7 @@ // Import pages import type {FoCategoryPageInterface} from '@interfaces/FO/category'; import FOBasePage from '@pages/FO/FOBasePage'; -import quickViewModal from '@pages/FO/classic/modal/quickView'; +import foModalQuickViewPage from '@pages/FO/classic/modal/quickView'; import type {Page} from 'playwright'; @@ -389,7 +389,7 @@ class CategoryPage extends FOBasePage implements FoCategoryPageInterface { } /* eslint-enable no-await-in-loop */ await Promise.all([ - this.waitForVisibleSelector(page, quickViewModal.quickViewModalDiv), + this.waitForVisibleSelector(page, foModalQuickViewPage.quickViewModalDiv), page.locator(this.productQuickViewLink(id)).evaluate((el: HTMLElement) => el.click()), ]); } diff --git a/src/versions/develop/pages/FO/classic/guestOrderTracking.ts b/src/versions/develop/pages/FO/classic/guestOrderTracking.ts new file mode 100644 index 000000000..b9d9f74fb --- /dev/null +++ b/src/versions/develop/pages/FO/classic/guestOrderTracking.ts @@ -0,0 +1,26 @@ +import {type FOGuestOrderTrackingPageInterface} from '@interfaces/FO/guestOrderTracking'; +import FOBasePage from '@pages/FO/FOBasePage'; + +/** + * Guest order tracking page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FOGuestOrderTrackingPage extends FOBasePage implements FOGuestOrderTrackingPageInterface { + public readonly pageTitle: string; + + /** + * @constructs + * Setting up texts and selectors to use on Guest order tracking page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'Guest tracking'; + + // Selectors for the page + } +} + +const foGuestOrderTrackingPage = new FOGuestOrderTrackingPage(); +export {foGuestOrderTrackingPage, FOGuestOrderTrackingPage}; diff --git a/src/versions/develop/pages/FO/classic/home/index.ts b/src/versions/develop/pages/FO/classic/home/index.ts index 7eff3d229..d666b2c44 100644 --- a/src/versions/develop/pages/FO/classic/home/index.ts +++ b/src/versions/develop/pages/FO/classic/home/index.ts @@ -1,7 +1,7 @@ import {FoHomePageInterface} from '@interfaces/FO/home'; import FOBasePage from '@pages/FO/FOBasePage'; import {type Page} from '@playwright/test'; -import {quickViewModal as foClassicModalQuickViewPage} from '@versions/develop/pages/FO/classic/modal/quickView'; +import {foModalQuickViewPage as foClassicModalQuickViewPage} from '@versions/develop/pages/FO/classic/modal/quickView'; /** * Home page, contains functions that can be used on the page diff --git a/src/versions/develop/pages/FO/classic/modal/blockCart.ts b/src/versions/develop/pages/FO/classic/modal/blockCart.ts index a632afe83..d3dd46d66 100644 --- a/src/versions/develop/pages/FO/classic/modal/blockCart.ts +++ b/src/versions/develop/pages/FO/classic/modal/blockCart.ts @@ -16,7 +16,7 @@ import type {Page} from 'playwright'; class FoModalBlockCartPage extends FOBasePage implements FoModalBlockCartPageInterface { private readonly blockCartLabel: string; - protected readonly blockCartModalDiv: string; + public readonly blockCartModalDiv: string; protected blockCartModalCloseButton: string; diff --git a/src/versions/develop/pages/FO/classic/modal/quickView.ts b/src/versions/develop/pages/FO/classic/modal/quickView.ts index b496702dc..ae3aadabc 100644 --- a/src/versions/develop/pages/FO/classic/modal/quickView.ts +++ b/src/versions/develop/pages/FO/classic/modal/quickView.ts @@ -1,18 +1,15 @@ -// Import pages +import type {ProductAttribute, ProductDetails, ProductDetailsWithDiscount} from '@data/types/product'; import type {FoModalQuickViewPageInterface} from '@interfaces/FO/modal/quickView'; +import foClassicModalBlockCartPage from '@pages/FO/classic/modal/blockCart'; import FOBasePage from '@pages/FO/FOBasePage'; - -// Import data -import type {ProductAttribute, ProductDetails, ProductDetailsWithDiscount} from '@data/types/product'; - -import type {Page} from 'playwright'; +import type {Page} from '@playwright/test'; /** * Quick view modal, contains functions that can be used on the modal * @class * @extends FOBasePage */ -class QuickViewModal extends FOBasePage implements FoModalQuickViewPageInterface { +class FoModalQuickViewPage extends FOBasePage implements FoModalQuickViewPageInterface { public quickViewModalDiv: string; protected quickViewCloseButton: string; @@ -51,7 +48,7 @@ class QuickViewModal extends FOBasePage implements FoModalQuickViewPageInterface private readonly quickViewPinterestSocialSharing: string; - private readonly addToCartButton: string; + protected readonly addToCartButton: string; protected quickViewModalProductImageCover: string; @@ -145,12 +142,16 @@ class QuickViewModal extends FOBasePage implements FoModalQuickViewPageInterface } /** - * Click on add to cart button from quick view modal - * @param page {Page} Browser tab - * @returns {Promise} - */ - async addToCartByQuickView(page: Page): Promise { + * Click on add to cart button from quick view modal + * @param page {Page} Browser tab + * @returns {Promise} + */ + async addToCartByQuickView(page: Page, isHidden: boolean = true): Promise { await this.waitForSelectorAndClick(page, this.addToCartButton); + if (isHidden) { + await this.waitForHiddenSelector(page, this.quickViewModalDiv); + await this.waitForVisibleSelector(page, foClassicModalBlockCartPage.blockCartModalDiv); + } } /** @@ -161,7 +162,7 @@ class QuickViewModal extends FOBasePage implements FoModalQuickViewPageInterface */ async setQuantityAndAddToCart(page: Page, quantityWanted: number | string = 1): Promise { await this.setQuantity(page, quantityWanted); - await this.addToCartByQuickView(page); + await this.addToCartByQuickView(page, typeof quantityWanted === 'number'); } /** @@ -440,5 +441,5 @@ class QuickViewModal extends FOBasePage implements FoModalQuickViewPageInterface } } -const quickViewModal = new QuickViewModal(); -export {quickViewModal, QuickViewModal}; +const foModalQuickViewPage = new FoModalQuickViewPage(); +export {foModalQuickViewPage, FoModalQuickViewPage}; diff --git a/src/versions/develop/pages/FO/classic/myAccount/addresses.ts b/src/versions/develop/pages/FO/classic/myAccount/addresses.ts index 7eca1b899..671dd9511 100644 --- a/src/versions/develop/pages/FO/classic/myAccount/addresses.ts +++ b/src/versions/develop/pages/FO/classic/myAccount/addresses.ts @@ -92,7 +92,7 @@ class FoMyAddressesPage extends FOBasePage implements FoMyAddressesPageInterface const currentUrl: string = page.url(); await Promise.all([ - page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil: 'networkidle'}), + page.waitForURL((url: URL): boolean => url.toString() !== currentUrl), editButtonsLocators.nth(positionEditButtons).click(), ]); } diff --git a/src/versions/develop/pages/FO/classic/myAccount/gdprPersonalData.ts b/src/versions/develop/pages/FO/classic/myAccount/gdprPersonalData.ts new file mode 100644 index 000000000..be91755e8 --- /dev/null +++ b/src/versions/develop/pages/FO/classic/myAccount/gdprPersonalData.ts @@ -0,0 +1,79 @@ +import {type FOMyGDPRPersonalDataPageInterface} from '@interfaces/FO/myAccount/gdprPersonalData'; +import FOBasePage from '@pages/FO/FOBasePage'; +import {type Page} from '@playwright/test'; + +/** + * GDPR personal data page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FOMyGDPRPersonalDataPage extends FOBasePage implements FOMyGDPRPersonalDataPageInterface { + public readonly pageTitle: string; + + private readonly headerTitle: string; + + private readonly exportDataToPDFButton: string; + + protected contactUsHyperLink: string; + + private readonly exportDataToCSVButton: string; + + /** + * @constructs + * Setting up texts and selectors to use on gdpr personal data page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'GDPR - Personal data'; + + // Selectors + this.headerTitle = '#content-wrapper h1'; + this.exportDataToPDFButton = '#exportDataToPdf'; + this.contactUsHyperLink = '#content section.page_content a[href*=\'contact-us\']'; + this.exportDataToCSVButton = '#exportDataToCsv'; + } + + /* + Methods + */ + /** + * @override + * Get the page title from the main section + * @param page {Page} Browser tab + * @returns {Promise} + */ + async getPageTitle(page: Page): Promise { + return this.getTextContent(page, this.headerTitle); + } + + /** + * Export data to PDF + * @param page {Page} Browser tab + * @returns {Promise} + */ + async exportDataToPDF(page: Page): Promise { + return this.clickAndWaitForDownload(page, this.exportDataToPDFButton); + } + + /** + * Go to contact us page + * @param page {Page} Browser tab + * @returns {Promise} + */ + async goToContactUsPage(page: Page): Promise { + await this.clickAndWaitForURL(page, this.contactUsHyperLink); + } + + /** + * Export data to CSV + * @param page {Page} Browser tab + * @returns {Promise} + */ + async exportDataToCSV(page: Page): Promise { + return this.clickAndWaitForDownload(page, this.exportDataToCSVButton); + } +} + +const foMyGDPRPersonalDataPage = new FOMyGDPRPersonalDataPage(); +export {foMyGDPRPersonalDataPage, FOMyGDPRPersonalDataPage}; diff --git a/src/versions/develop/pages/FO/classic/myAccount/index.ts b/src/versions/develop/pages/FO/classic/myAccount/index.ts index b3d148935..d9aff2c49 100644 --- a/src/versions/develop/pages/FO/classic/myAccount/index.ts +++ b/src/versions/develop/pages/FO/classic/myAccount/index.ts @@ -57,8 +57,8 @@ class MyAccountPage extends FOBasePage implements FoMyAccountPageInterface { this.orderSlipsLink = '#order-slips-link'; this.successMessageAlert = '#notifications article.alert-success'; this.logoutFooterLink = '#main footer a[href*="mylogout"]'; - this.myWishlistsLink = '#wishlist-link'; - this.psgdprLink = '#psgdpr-link'; + this.myWishlistsLink = '#content #wishlist-link'; + this.psgdprLink = '#content #psgdpr-link'; } /* @@ -164,7 +164,7 @@ class MyAccountPage extends FOBasePage implements FoMyAccountPageInterface { * @returns {Promise} */ async goToMyWishlistsPage(page: Page): Promise { - await this.clickAndWaitForURL(page, this.myWishlistsLink, 'networkidle'); + await this.clickAndWaitForURL(page, this.myWishlistsLink); await this.elementVisible(page, foClassicMyWishlistsPage.wishlistListItemNthTitle(1), 5000); } } diff --git a/src/versions/develop/pages/FO/classic/myAccount/returnDetails.ts b/src/versions/develop/pages/FO/classic/myAccount/returnDetails.ts new file mode 100644 index 000000000..4bb108549 --- /dev/null +++ b/src/versions/develop/pages/FO/classic/myAccount/returnDetails.ts @@ -0,0 +1,83 @@ +import {type FOMyReturnDetailsPageInterface} from '@interfaces/FO/myAccount/returnDetails'; +import FOBasePage from '@pages/FO/FOBasePage'; +import {type Page} from '@playwright/test'; + +/** + * Return details page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FOMyReturnDetailsPage extends FOBasePage implements FOMyReturnDetailsPageInterface { + public readonly pageTitle: string; + + public readonly errorMessage: string; + + public orderReturnCardBlock: string; + + protected pageTitleHeader: string; + + protected alertWarning: string; + + private readonly orderReturnInfo: string; + + /** + * @constructs + * Setting up texts and selectors to use on return details page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'Return Details'; + this.errorMessage = 'You must wait for confirmation before returning any merchandise.'; + this.orderReturnCardBlock = 'We have logged your return request. Your package must be returned to us within 14 days' + + ' of receiving your order. The current status of your merchandise return is:'; + + // Selectors + this.pageTitleHeader = '#main header h1.h1'; + this.alertWarning = '#notifications .notifications-container article.alert-warning'; + this.orderReturnInfo = '#order-return-infos'; + } + + /* + Methods + */ + + /** + * Get page title + * @param page {Page} Browser tab + * @returns {Promise} + */ + async getPageTitle(page: Page): Promise { + return this.getTextContent(page, this.pageTitleHeader); + } + + /** + * get return notifications + * @param page {Page} Browser tab + * @returns {Promise} + */ + async getAlertWarning(page: Page): Promise { + return this.getTextContent(page, this.alertWarning); + } + + /** + * Is alert warning visible + * @param page {Page} Browser tab + * @returns {Promise} + */ + async isAlertWarningVisible(page: Page): Promise { + return this.elementVisible(page, this.alertWarning); + } + + /** + * Get order return info + * @param page {Page} Browser tab + * @returns {Promise} + */ + async getOrderReturnInfo(page: Page): Promise { + return this.getTextContent(page, this.orderReturnInfo); + } +} + +const foMyReturnDetailsPage = new FOMyReturnDetailsPage(); +export {foMyReturnDetailsPage, FOMyReturnDetailsPage}; diff --git a/src/versions/develop/pages/FO/classic/newProducts.ts b/src/versions/develop/pages/FO/classic/newProducts.ts new file mode 100644 index 000000000..dd3e5e1d1 --- /dev/null +++ b/src/versions/develop/pages/FO/classic/newProducts.ts @@ -0,0 +1,24 @@ +import {type FONewProductsPageInterface} from '@interfaces/FO/newProducts'; +import FOBasePage from '@pages/FO/FOBasePage'; + +/** + * New products page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FONewProductsPage extends FOBasePage implements FONewProductsPageInterface { + public readonly pageTitle: string; + + /** + * @constructs + * Setting up texts and selectors to use on new products page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'New products'; + } +} + +const foNewProductsPage = new FONewProductsPage(); +export {foNewProductsPage, FONewProductsPage}; diff --git a/src/versions/develop/pages/FO/classic/pricesDrop.ts b/src/versions/develop/pages/FO/classic/pricesDrop.ts new file mode 100644 index 000000000..1cecaf192 --- /dev/null +++ b/src/versions/develop/pages/FO/classic/pricesDrop.ts @@ -0,0 +1,24 @@ +import {type FOPricesDropPageInterface} from '@interfaces/FO/pricesDrop'; +import FOBasePage from '@pages/FO/FOBasePage'; + +/** + * Prices drop page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FOPricesDropPage extends FOBasePage implements FOPricesDropPageInterface { + public readonly pageTitle: string; + + /** + * @constructs + * Setting up texts and selectors to use on prices drop page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'Prices drop'; + } +} + +const foPricesDropPage = new FOPricesDropPage(); +export {foPricesDropPage, FOPricesDropPage}; diff --git a/src/versions/develop/pages/FO/classic/product/index.ts b/src/versions/develop/pages/FO/classic/product/index.ts index 693bb4183..367272f94 100644 --- a/src/versions/develop/pages/FO/classic/product/index.ts +++ b/src/versions/develop/pages/FO/classic/product/index.ts @@ -983,7 +983,7 @@ class ProductPage extends FOBasePage implements FoProductPageInterface { throw new Error(`${socialSharing} was not found`); } - return this.openLinkWithTargetBlank(page, selector, 'body', 'networkidle', false); + return this.openLinkWithTargetBlank(page, selector, 'body', 'load', false); } /** diff --git a/src/versions/develop/pages/FO/classic/securePayment.ts b/src/versions/develop/pages/FO/classic/securePayment.ts new file mode 100644 index 000000000..6d949c136 --- /dev/null +++ b/src/versions/develop/pages/FO/classic/securePayment.ts @@ -0,0 +1,24 @@ +import {type FOSecurePaymentPageInterface} from '@interfaces/FO/securePayment'; +import FOBasePage from '@pages/FO/FOBasePage'; + +/** + * Secure payment page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FOSecurePaymentPage extends FOBasePage implements FOSecurePaymentPageInterface { + public readonly pageTitle: string; + + /** + * @constructs + * Setting up texts and selectors to use on secure payment page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'Secure payment'; + } +} + +const foSecurePaymentPage = new FOSecurePaymentPage(); +export {foSecurePaymentPage, FOSecurePaymentPage}; diff --git a/src/versions/develop/pages/FO/classic/termsAndConditionsOfUse.ts b/src/versions/develop/pages/FO/classic/termsAndConditionsOfUse.ts new file mode 100644 index 000000000..e3c5ac087 --- /dev/null +++ b/src/versions/develop/pages/FO/classic/termsAndConditionsOfUse.ts @@ -0,0 +1,24 @@ +import {type FOTermsAndConditionsOfUsePageInterface} from '@interfaces/FO/termsAndConditionsOfUse'; +import FOBasePage from '@pages/FO/FOBasePage'; + +/** + * Terms and conditions of use page, contains functions that can be used on the page + * @class + * @extends FOBasePage + */ +class FOTermsAndConditionsOfUsePage extends FOBasePage implements FOTermsAndConditionsOfUsePageInterface { + public readonly pageTitle: string; + + /** + * @constructs + * Setting up texts and selectors to use on terms and conditions of use page + */ + constructor(theme: string = 'classic') { + super(theme); + + this.pageTitle = 'Terms and conditions of use'; + } +} + +const foTermsAndConditionsOfUsePage = new FOTermsAndConditionsOfUsePage(); +export {foTermsAndConditionsOfUsePage, FOTermsAndConditionsOfUsePage}; diff --git a/src/versions/develop/pages/FO/hummingbird/guestOrderTracking.ts b/src/versions/develop/pages/FO/hummingbird/guestOrderTracking.ts new file mode 100644 index 000000000..1c1792170 --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/guestOrderTracking.ts @@ -0,0 +1,17 @@ +import {type FOGuestOrderTrackingPageInterface} from '@interfaces/FO/guestOrderTracking'; +import {FOGuestOrderTrackingPage as FOGuestOrderTrackingPageClassic} from '@versions/develop/pages/FO/classic/guestOrderTracking'; + +/** + * @class + * @extends FOBasePage + */ +class FOGuestOrderTrackingPage extends FOGuestOrderTrackingPageClassic implements FOGuestOrderTrackingPageInterface { + /** + * @constructs + */ + constructor() { + super('hummingbird'); + } +} + +module.exports = new FOGuestOrderTrackingPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/modal/quickView.ts b/src/versions/develop/pages/FO/hummingbird/modal/quickView.ts index 152fcdccf..d1a69b6b5 100644 --- a/src/versions/develop/pages/FO/hummingbird/modal/quickView.ts +++ b/src/versions/develop/pages/FO/hummingbird/modal/quickView.ts @@ -1,14 +1,15 @@ import {type ProductAttribute, type ProductDetails} from '@data/types/product'; import {type FoModalQuickViewPageInterface} from '@interfaces/FO/modal/quickView'; +import foHummingbirdModalBlockCartPage from '@pages/FO/hummingbird/modal/blockCart'; import {type Page} from '@playwright/test'; -import {QuickViewModal as QuickViewModalClassic} from '@versions/develop/pages/FO/classic/modal/quickView'; +import {FoModalQuickViewPage as FoModalQuickViewPageClassic} from '@versions/develop/pages/FO/classic/modal/quickView'; /** * Quick view modal, contains functions that can be used on the page * @class - * @extends QuickViewModal + * @extends FoModalQuickViewPageClassic */ -class QuickViewModal extends QuickViewModalClassic implements FoModalQuickViewPageInterface { +class FoModalQuickViewPage extends FoModalQuickViewPageClassic implements FoModalQuickViewPageInterface { /** * @constructs * Setting up texts and selectors to use on home page @@ -32,6 +33,19 @@ class QuickViewModal extends QuickViewModalClassic implements FoModalQuickViewPa this.quickViewCloseButton = `${this.quickViewModalDiv} button.btn-close`; } + /** + * Click on add to cart button from quick view modal + * @param page {Page} Browser tab + * @returns {Promise} + */ + async addToCartByQuickView(page: Page, isHidden: boolean = true): Promise { + await this.waitForSelectorAndClick(page, this.addToCartButton); + if (isHidden) { + await this.waitForHiddenSelector(page, this.quickViewModalDiv); + await this.waitForVisibleSelector(page, foHummingbirdModalBlockCartPage.blockCartModalDiv); + } + } + /** * Get product details from quick view modal * @param page {Page} Browser tab @@ -102,4 +116,4 @@ class QuickViewModal extends QuickViewModalClassic implements FoModalQuickViewPa } } -module.exports = new QuickViewModal(); +module.exports = new FoModalQuickViewPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/myAccount/gdprPersonalData.ts b/src/versions/develop/pages/FO/hummingbird/myAccount/gdprPersonalData.ts new file mode 100644 index 000000000..8a163fca7 --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/myAccount/gdprPersonalData.ts @@ -0,0 +1,23 @@ +import {type FOMyGDPRPersonalDataPageInterface} from '@interfaces/FO/myAccount/gdprPersonalData'; +import { + FOMyGDPRPersonalDataPage as FOMyGDPRPersonalDataPageClassic, +} from '@versions/develop/pages/FO/classic/myAccount/gdprPersonalData'; + +/** + * @class + * @extends FOBasePage + */ +class FOMyGDPRPersonalDataPage extends FOMyGDPRPersonalDataPageClassic implements FOMyGDPRPersonalDataPageInterface { + /** + * @constructs + * Setting up texts and selectors to use on GDPR personal data page + */ + constructor() { + super('hummingbird'); + + // Selectors + this.contactUsHyperLink = 'section.page-content a[href*=\'contact-us\']'; + } +} + +module.exports = new FOMyGDPRPersonalDataPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/myAccount/returnDetails.ts b/src/versions/develop/pages/FO/hummingbird/myAccount/returnDetails.ts new file mode 100644 index 000000000..e347c0354 --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/myAccount/returnDetails.ts @@ -0,0 +1,23 @@ +import {type FOMyReturnDetailsPageInterface} from '@interfaces/FO/myAccount/returnDetails'; +import {FOMyReturnDetailsPage as FOMyReturnDetailsPageClassic} from '@versions/develop/pages/FO/classic/myAccount/returnDetails'; + +/** + * @class + * @extends FOBasePage + */ +class FOMyReturnDetailsPage extends FOMyReturnDetailsPageClassic implements FOMyReturnDetailsPageInterface { + /** + * @constructs + * Setting up texts and selectors to use + */ + constructor() { + super('hummingbird'); + + this.orderReturnCardBlock = 'We have logged your return request. List of items to be returned:'; + + this.pageTitleHeader = '#content-wrapper h1'; + this.alertWarning = '#notifications article.alert-warning'; + } +} + +module.exports = new FOMyReturnDetailsPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/newProducts.ts b/src/versions/develop/pages/FO/hummingbird/newProducts.ts new file mode 100644 index 000000000..efdcd02f6 --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/newProducts.ts @@ -0,0 +1,17 @@ +import {type FONewProductsPageInterface} from '@interfaces/FO/newProducts'; +import {FONewProductsPage as FONewProductsPageClassic} from '@versions/develop/pages/FO/classic/newProducts'; + +/** + * @class + * @extends FOBasePage + */ +class FONewProductsPage extends FONewProductsPageClassic implements FONewProductsPageInterface { + /** + * @constructs + */ + constructor() { + super('hummingbird'); + } +} + +module.exports = new FONewProductsPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/pricesDrop.ts b/src/versions/develop/pages/FO/hummingbird/pricesDrop.ts new file mode 100644 index 000000000..c97377830 --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/pricesDrop.ts @@ -0,0 +1,17 @@ +import {type FOPricesDropPageInterface} from '@interfaces/FO/pricesDrop'; +import {FOPricesDropPage as FOPricesDropPageClassic} from '@versions/develop/pages/FO/classic/pricesDrop'; + +/** + * @class + * @extends FOBasePage + */ +class FOPricesDropPage extends FOPricesDropPageClassic implements FOPricesDropPageInterface { + /** + * @constructs + */ + constructor() { + super('hummingbird'); + } +} + +module.exports = new FOPricesDropPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/securePayment.ts b/src/versions/develop/pages/FO/hummingbird/securePayment.ts new file mode 100644 index 000000000..84f9fb8d5 --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/securePayment.ts @@ -0,0 +1,17 @@ +import {type FOSecurePaymentPageInterface} from '@interfaces/FO/securePayment'; +import {FOSecurePaymentPage as FOSecurePaymentPageClassic} from '@versions/develop/pages/FO/classic/securePayment'; + +/** + * @class + * @extends FOBasePage + */ +class FOSecurePaymentPage extends FOSecurePaymentPageClassic implements FOSecurePaymentPageInterface { + /** + * @constructs + */ + constructor() { + super('hummingbird'); + } +} + +module.exports = new FOSecurePaymentPage(); diff --git a/src/versions/develop/pages/FO/hummingbird/termsAndConditionsOfUse.ts b/src/versions/develop/pages/FO/hummingbird/termsAndConditionsOfUse.ts new file mode 100644 index 000000000..c19c6bc9e --- /dev/null +++ b/src/versions/develop/pages/FO/hummingbird/termsAndConditionsOfUse.ts @@ -0,0 +1,20 @@ +import {type FOTermsAndConditionsOfUsePageInterface} from '@interfaces/FO/termsAndConditionsOfUse'; +import { + FOTermsAndConditionsOfUsePage as FOTermsAndConditionsOfUsePageClassic, +} from '@versions/develop/pages/FO/classic/termsAndConditionsOfUse'; + +/** + * @class + * @extends FOBasePage + */ +class FOTermsAndConditionsOfUsePage extends FOTermsAndConditionsOfUsePageClassic + implements FOTermsAndConditionsOfUsePageInterface { + /** + * @constructs + */ + constructor() { + super('hummingbird'); + } +} + +module.exports = new FOTermsAndConditionsOfUsePage(); diff --git a/src/versions/develop/pages/install.ts b/src/versions/develop/pages/install.ts new file mode 100644 index 000000000..e7c32d35d --- /dev/null +++ b/src/versions/develop/pages/install.ts @@ -0,0 +1,417 @@ +import {type InstallPageInterface} from '@interfaces/install'; +import CommonPage from '@pages/commonPage'; +import {type Page} from '@playwright/test'; + +/** + * Install page, contains functions used in different steps of the installation + * @class + * @extends CommonPage + */ +class InstallPage extends CommonPage implements InstallPageInterface { + // Titles + public readonly firstStepFrTitle: string; + + public readonly firstStepEnTitle: string; + + public readonly secondStepEnTitle: string; + + public readonly thirdStepEnTitle: string; + + public readonly fourthStepEnTitle: string; + + public readonly fifthStepEnTitle: string; + + public readonly sixthStepEnTitle: string; + + public readonly finalStepEnTitle: string; + + // Selectors + private readonly nextStepButton: string; + + private readonly chooseLanguageStepPageTitle: string; + + private readonly languageSelect: string; + + private readonly licenseAgreementsStepPageTitle: string; + + private readonly termsConditionsCheckbox: string; + + private readonly systemCompatibilityStepPageTitle: string; + + private readonly thirdStepFinishedListItem: string; + + private readonly fourthStepFinishedListItem: string; + + private readonly storeInformationStepPageTitle: string; + + private readonly shopNameInput: string; + + private readonly countryChosenSelect: string; + + private readonly countryChosenSearchInput: string; + + private readonly enableSslRadio: (value: number) => string; + + private readonly firstNameInput: string; + + private readonly lastNameInput: string; + + private readonly emailInput: string; + + private readonly passwordInput: string; + + private readonly repeatPasswordInput: string; + + private readonly contentInformationStepPageTitle: string; + + private readonly fifthStepFinishedListItem: string; + + private readonly systemConfigurationStepPageTitle: string; + + private readonly dbServerInput: string; + + private readonly dbLoginInput: string; + + private readonly dbNameInput: string; + + private readonly dbPasswordInput: string; + + private readonly dbPrefixInput: string; + + private readonly testDbConnectionButton: string; + + private readonly createDbButton: string; + + private readonly dbResultCheckOkBlock: string; + + private readonly installationProgressBar: string; + + private readonly generateSettingsFileStep: string; + + private readonly installDatabaseStep: string; + + private readonly installDefaultDataStep: string; + + private readonly populateDatabaseStep: string; + + private readonly configureShopStep: string; + + private readonly installModulesStep: string; + + private readonly installThemeStep: string; + + private readonly installFixturesStep: string; + + private readonly installPostInstall: string; + + private readonly installationFinishedStepPageTitle: string; + + private readonly discoverFoButton: string; + + /** + * @constructs + * Setting up titles and selectors to use on installation page + */ + constructor() { + super(); + + // Define Step Titles + this.firstStepFrTitle = 'Bienvenue sur l\'installateur de PrestaShop'; + this.firstStepEnTitle = 'Welcome to the PrestaShop'; + this.secondStepEnTitle = 'License Agreements'; + this.thirdStepEnTitle = 'We are currently checking PrestaShop compatibility with your system environment'; + this.fourthStepEnTitle = 'Information about your Store'; + this.fifthStepEnTitle = 'Content of your store'; + this.sixthStepEnTitle = 'Configure your database by filling out the following fields'; + this.finalStepEnTitle = 'Your installation is finished!'; + + // Selectors for all steps + this.nextStepButton = '#btNext'; + + // Selectors for step 1 + this.chooseLanguageStepPageTitle = 'h2'; + this.languageSelect = '#langList'; + + // Selectors for step 2 + this.licenseAgreementsStepPageTitle = 'h2#licenses-agreement'; + this.termsConditionsCheckbox = '#set_license'; + + // Selectors for step 3 + this.systemCompatibilityStepPageTitle = '#sheet_system h2'; + this.thirdStepFinishedListItem = '#leftpannel #tabs li.finished:nth-child(3)'; + + // Selectors for step 4 + this.fourthStepFinishedListItem = '#leftpannel #tabs li.finished:nth-child(4)'; + this.storeInformationStepPageTitle = '#infosShopBlock h2'; + this.shopNameInput = '#infosShop'; + this.countryChosenSelect = '#infosCountry_chosen'; + this.countryChosenSearchInput = `${this.countryChosenSelect} .chosen-search input`; + this.enableSslRadio = (value: number) => `input[name="enable_ssl"][value="${value}"]`; + this.firstNameInput = '#infosFirstname'; + this.lastNameInput = '#infosName'; + this.emailInput = '#infosEmail'; + this.passwordInput = '#infosPassword'; + this.repeatPasswordInput = '#infosPasswordRepeat'; + + // Selectors for step 5 + this.contentInformationStepPageTitle = '#contentInfosBlock h2'; + this.fifthStepFinishedListItem = '#leftpannel #tabs li.finished:nth-child(5)'; + + // Selectors for step 6 + this.systemConfigurationStepPageTitle = '#dbPart h2'; + this.dbServerInput = '#dbServer'; + this.dbLoginInput = '#dbLogin'; + this.dbNameInput = '#dbName'; + this.dbPasswordInput = '#dbPassword'; + this.dbPrefixInput = '#db_prefix'; + this.testDbConnectionButton = '#btTestDB'; + this.createDbButton = '#btCreateDB'; + this.dbResultCheckOkBlock = '#dbResultCheck.okBlock'; + + // Selectors for Final step + this.installationProgressBar = '#install_process_form #progress_bar .installing'; + this.generateSettingsFileStep = '#process_step_generateSettingsFile'; + this.installDatabaseStep = '#process_step_installDatabase'; + this.installDefaultDataStep = '#process_step_installDefaultData'; + this.populateDatabaseStep = '#process_step_populateDatabase'; + this.configureShopStep = '#process_step_configureShop'; + this.installModulesStep = '#process_step_installModules'; + this.installThemeStep = '#process_step_installTheme'; + this.installFixturesStep = '#process_step_installFixtures'; + this.installPostInstall = '#process_step_postInstall'; + this.installationFinishedStepPageTitle = '#install_process_success h2'; + this.discoverFoButton = '#foBlock'; + } + + /** + * Get step title + * @param page {Page} Browser tab + * @param step {string} Step to get title from + * @returns {Promise} + */ + async getStepTitle(page : Page, step: string): Promise { + let selector; + + switch (step) { + case 'Choose your language': + selector = this.chooseLanguageStepPageTitle; + break; + + case 'License agreements': + selector = this.licenseAgreementsStepPageTitle; + break; + + case 'System compatibility': + selector = this.systemCompatibilityStepPageTitle; + break; + + case 'Store information': + selector = this.storeInformationStepPageTitle; + break; + + case 'Content of your store': + selector = this.contentInformationStepPageTitle; + break; + + case 'System configuration': + selector = this.systemConfigurationStepPageTitle; + break; + + case 'Installation finished': + selector = this.installationFinishedStepPageTitle; + break; + + default: + throw new Error(`'${step}' was not found on the installation process`); + } + + return this.getTextContent(page, selector); + } + + /** + * Change install language in step 1 + * @param page {Page} Browser tab + * @return {Promise} + */ + async setInstallLanguage(page: Page): Promise { + await this.selectByValue(page, this.languageSelect, global.INSTALL.LANGUAGE); + } + + /** + * Go to next step + * @param page {Page} Browser tab + * @return {Promise} + */ + async nextStep(page: Page): Promise { + await this.waitForVisibleSelector(page, this.nextStepButton); + await page.locator(this.nextStepButton).click(); + } + + /** + * Click on checkbox to agree on terms and conditions if it's not checked already in step 2 + * @param page {Page} Browser tab + * @return {Promise} + */ + async agreeToTermsAndConditions(page: Page):Promise { + await this.setChecked(page, this.termsConditionsCheckbox); + } + + /** + * Return the visibility of the third step + * @param page {Page} Browser Tab + */ + async isThirdStepVisible(page: Page): Promise { + return this.elementVisible(page, this.thirdStepFinishedListItem, 500); + } + + /** + * Wait for Fourth step to be visible + * @param page {Page} Browser Tab + */ + async waitForFinishedForthStep(page: Page): Promise { + await this.waitForVisibleSelector(page, this.fourthStepFinishedListItem, 500); + } + + /** + * Wait for Fifth step to be visible + * @param page {Page} Browser Tab + */ + async waitForFinishedFifthStep(page: Page): Promise { + await this.waitForVisibleSelector(page, this.fifthStepFinishedListItem, 500); + } + + /** + * Fill Information and Account Forms in step 4 + * @param page {Page} Browser tab + * @return {Promise} + */ + async fillInformationForm(page: Page): Promise { + await page.locator(this.shopNameInput).fill(global.INSTALL.SHOP_NAME); + + // Choosing country + await page.locator(this.countryChosenSelect).click(); + await page.locator(this.countryChosenSearchInput).pressSequentially(global.INSTALL.COUNTRY); + await page.keyboard.press('Enter'); + await page.locator(this.enableSslRadio(global.INSTALL.ENABLE_SSL ? 1 : 0)).click(); + + await page.locator(this.firstNameInput).fill(global.BO.FIRSTNAME); + await page.locator(this.lastNameInput).fill(global.BO.LASTNAME); + await page.locator(this.emailInput).fill(global.BO.EMAIL); + await page.locator(this.passwordInput).fill(global.BO.PASSWD); + await page.locator(this.repeatPasswordInput).fill(global.BO.PASSWD); + } + + /** + * Fill Database Form in step 5 + * @param page {Page} Browser tab + * @return {Promise} + */ + async fillDatabaseForm(page: Page): Promise { + await this.setValue(page, this.dbServerInput, global.INSTALL.DB_SERVER); + await this.setValue(page, this.dbNameInput, global.INSTALL.DB_NAME); + await this.setValue(page, this.dbLoginInput, global.INSTALL.DB_USER); + await this.setValue(page, this.dbPasswordInput, global.INSTALL.DB_PASSWD); + await this.setValue(page, this.dbPrefixInput, global.INSTALL.DB_PREFIX); + } + + /** + * Check if database exist (if not, it will be created) + * and check if all set properly to submit form + * @param page {Page} Browser tab + * @return {Promise} + */ + async isDatabaseConnected(page: Page): Promise { + await page.locator(this.testDbConnectionButton).click(); + + // Create database 'prestashop' if not exist + if (await this.elementVisible(page, this.createDbButton, 3000)) { + await page.locator(this.createDbButton).click(); + } + + return this.elementVisible(page, this.dbResultCheckOkBlock, 3000); + } + + /** + * Check if progress bar is visible + * @param page {Page} Browser tab + * @returns {Promise} + */ + async isInstallationInProgress(page: Page): Promise { + return this.elementVisible(page, this.installationProgressBar, 30000); + } + + /** + * Check if step installation is finished + * @param page {Page} Browser tab + * @param step {string} The installation step + * @param timeout {number} Time to wait for step to finish + * @returns {Promise} + */ + async isInstallationStepFinished(page: Page, step: string, timeout: number = 30000): Promise { + let selector; + + switch (step) { + case 'Generate Setting file': + selector = this.generateSettingsFileStep; + break; + + case 'Install database': + selector = this.installDatabaseStep; + break; + + case 'Default data': + selector = this.installDefaultDataStep; + break; + + case 'Populate database': + selector = this.populateDatabaseStep; + break; + + case 'Shop configuration': + selector = this.configureShopStep; + break; + + case 'Install modules': + selector = this.installModulesStep; + break; + + case 'Install theme': + selector = this.installThemeStep; + break; + + case 'Install fixtures': + selector = this.installFixturesStep; + break; + + case 'Post installation scripts': + selector = this.installPostInstall; + break; + + default: + throw new Error(`${step} was not found as an option`); + } + + return this.elementVisible(page, `${selector}.success`, timeout); + } + + /** + * Check if prestashop is installed properly + * @param page {Page} Browser tab + * @return {Promise} + */ + async isInstallationSuccessful(page: Page): Promise { + return this.elementVisible(page, this.installationFinishedStepPageTitle, 30000); + } + + /** + * Go to FO after Installation and check that Prestashop logo exist + * @param page {Page} Browser tab + * @return {Promise} + */ + async goToFOAfterInstall(page: Page): Promise { + await this.waitForVisibleSelector(page, this.discoverFoButton); + return this.openLinkWithTargetBlank(page, this.discoverFoButton); + } +} + +module.exports = new InstallPage();