From 51548634f34ad92802c0e9c64ddfd68ded3b7657 Mon Sep 17 00:00:00 2001 From: splincode Date: Fri, 19 Jan 2024 17:34:17 +0300 Subject: [PATCH] ci: add component testing by cypress --- .github/workflows/e2e-cypress.yml | 21 ++ .gitignore | 2 + package-lock.json | 355 ++++++++---------- package.json | 3 +- .../tests/mobile-calendar.component.spec.ts | 205 ---------- projects/demo-cypress/cypress.config.ts | 172 +++------ .../demo-cypress/cypress/cypress.options.ts | 16 - .../cypress/fixtures/stubs/web-api.svg | 56 --- .../cypress/support/commands/basic.ts | 111 ------ .../cypress/support/commands/snapshot.ts | 14 - .../cypress/support/constants/index.ts | 1 - .../support/constants/real-events-support.ts | 11 - projects/demo-cypress/cypress/support/e2e.ts | 3 - .../cypress/support/helpers/click-outside.ts | 3 - .../support/helpers/example-id-utils.ts | 11 - .../cypress/support/helpers/focus.ts | 9 - .../cypress/support/helpers/hide.ts | 11 - .../support/helpers/scroll-into-view.ts | 13 - .../cypress/support/helpers/set-language.ts | 6 - .../cypress/support/helpers/set-night-mode.ts | 5 - .../cypress/support/helpers/show.ts | 11 - .../cypress/support/helpers/type-tab.ts | 83 ---- .../cypress/support/helpers/visit.ts | 178 --------- .../support/helpers/wait-before-screenshot.ts | 15 - .../support/helpers/wait-code-highlight.ts | 7 - .../support/helpers/wait-kit-dialog.ts | 7 - .../support/helpers/wait-requests.util.ts | 22 -- .../support/stubs/stub-external-icons.util.ts | 21 -- .../cypress/support/stubs/stub-metrics.ts | 3 - projects/demo-cypress/project.json | 23 +- .../src/support/component-index.html | 18 + .../demo-cypress/src/support/component.ts | 17 + .../src/tests/mobile-calendar.cy.ts | 157 ++++++++ projects/demo-cypress/tsconfig.json | 2 +- projects/demo/src/modules/app/app.style.less | 6 +- projects/demo/src/styles.less | 5 + .../cypress/assertions/be-in-viewport.ts | 36 -- projects/testing/cypress/assertions/index.ts | 1 - .../commands/wait-all-img-inside.command.ts | 81 ---- projects/testing/cypress/index.ts | 4 - projects/testing/cypress/ng-package.json | 5 - projects/testing/cypress/snapshot/command.ts | 62 --- projects/testing/cypress/snapshot/plugin.ts | 52 --- 43 files changed, 436 insertions(+), 1408 deletions(-) create mode 100644 .github/workflows/e2e-cypress.yml delete mode 100644 projects/addon-mobile/components/mobile-calendar/tests/mobile-calendar.component.spec.ts delete mode 100644 projects/demo-cypress/cypress/cypress.options.ts delete mode 100644 projects/demo-cypress/cypress/fixtures/stubs/web-api.svg delete mode 100644 projects/demo-cypress/cypress/support/commands/basic.ts delete mode 100644 projects/demo-cypress/cypress/support/commands/snapshot.ts delete mode 100644 projects/demo-cypress/cypress/support/constants/index.ts delete mode 100644 projects/demo-cypress/cypress/support/constants/real-events-support.ts delete mode 100644 projects/demo-cypress/cypress/support/e2e.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/click-outside.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/example-id-utils.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/focus.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/hide.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/scroll-into-view.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/set-language.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/set-night-mode.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/show.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/type-tab.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/visit.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/wait-before-screenshot.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/wait-code-highlight.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/wait-kit-dialog.ts delete mode 100644 projects/demo-cypress/cypress/support/helpers/wait-requests.util.ts delete mode 100644 projects/demo-cypress/cypress/support/stubs/stub-external-icons.util.ts delete mode 100644 projects/demo-cypress/cypress/support/stubs/stub-metrics.ts create mode 100644 projects/demo-cypress/src/support/component-index.html create mode 100644 projects/demo-cypress/src/support/component.ts create mode 100644 projects/demo-cypress/src/tests/mobile-calendar.cy.ts delete mode 100644 projects/testing/cypress/assertions/be-in-viewport.ts delete mode 100644 projects/testing/cypress/assertions/index.ts delete mode 100644 projects/testing/cypress/commands/wait-all-img-inside.command.ts delete mode 100644 projects/testing/cypress/index.ts delete mode 100644 projects/testing/cypress/ng-package.json delete mode 100644 projects/testing/cypress/snapshot/command.ts delete mode 100644 projects/testing/cypress/snapshot/plugin.ts diff --git a/.github/workflows/e2e-cypress.yml b/.github/workflows/e2e-cypress.yml new file mode 100644 index 0000000000000..81d051f94abbc --- /dev/null +++ b/.github/workflows/e2e-cypress.yml @@ -0,0 +1,21 @@ +name: ⚙️ Component testing +on: + pull_request: + push: + branches: + - main + +jobs: + test: + if: ${{ !contains(github.head_ref, 'release/') }} + runs-on: ubuntu-latest + name: cypress + steps: + - uses: taiga-family/ci/actions/setup/checkout@v1.50.8 + - uses: taiga-family/ci/actions/setup/variables@v1.50.8 + - uses: taiga-family/ci/actions/setup/node@v1.50.8 + - run: npx nx component-test demo-cypress + +concurrency: + group: e2e-cypress-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true diff --git a/.gitignore b/.gitignore index db25f4b9d5475..7fa4a416d370b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,8 @@ quality-check dist **/cypress/screenshots **/cypress/snapshots +**/cypress/logs +**/cypress/downloads .ssl RELEASE_BODY.md *tsbuildinfo diff --git a/package-lock.json b/package-lock.json index 730c6f11ff3dd..a2e622d66dd7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "@cypress/webpack-batteries-included-preprocessor": "3.0.2", "@cypress/webpack-preprocessor": "6.0.1", "@nx/angular": "17.2.8", + "@nx/cypress": "17.2.8", "@nx/jest": "17.2.8", "@nx/node": "17.2.8", "@nx/workspace": "17.2.8", @@ -1616,9 +1617,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", - "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.9.tgz", + "integrity": "sha512-B2L9neXTIyPQoXDm+NtovPvG6VOLWnaXu3BIeVDWwdKFgG30oNa6CqVGiJPDWQwIAK49t9gnQI9c6K6RzabiKw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -1756,13 +1757,13 @@ } }, "node_modules/@babel/helper-function-name/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -1972,40 +1973,40 @@ } }, "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz", - "integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -2025,9 +2026,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2138,12 +2139,12 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.7.tgz", - "integrity": "sha512-b1s5JyeMvqj7d9m9KhJNHKc18gEJiSyVzVX3bwbiPalQBQpuvfPh6lA9F7Kk/dWH0TIiXRpB9yicwijY6buPng==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.9.tgz", + "integrity": "sha512-hJhBCb0+NnTWybvWq2WpbCYDOcflSbx0t+BYP65e5R9GVnukiDTi+on5bFkk4p7QGuv190H6KfNiV9Knf/3cZA==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.23.7", + "@babel/helper-create-class-features-plugin": "^7.23.9", "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-decorators": "^7.23.3" }, @@ -2672,9 +2673,9 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", - "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -2832,14 +2833,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -3068,9 +3069,9 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", - "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", "dev": true, "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", @@ -3811,9 +3812,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", - "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -3821,8 +3822,8 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -3869,9 +3870,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -5013,9 +5014,9 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -5023,11 +5024,11 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -5112,16 +5113,16 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/@babel/plugin-transform-runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", - "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.9.tgz", + "integrity": "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "semver": "^6.3.1" }, "engines": { @@ -5141,9 +5142,9 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/@babel/preset-env": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", - "integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", "dev": true, "dependencies": { "@babel/compat-data": "^7.23.5", @@ -5173,7 +5174,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", @@ -5195,7 +5196,7 @@ "@babel/plugin-transform-member-expression-literals": "^7.23.3", "@babel/plugin-transform-modules-amd": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", "@babel/plugin-transform-modules-umd": "^7.23.3", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.23.3", @@ -5221,9 +5222,9 @@ "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -5258,9 +5259,9 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -5270,14 +5271,14 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -5336,29 +5337,13 @@ } }, "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -7919,9 +7904,9 @@ } }, "node_modules/@nx/js/node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -7929,11 +7914,11 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -8018,16 +8003,16 @@ } }, "node_modules/@nx/js/node_modules/@babel/plugin-transform-runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", - "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.9.tgz", + "integrity": "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "semver": "^6.3.1" }, "engines": { @@ -8047,9 +8032,9 @@ } }, "node_modules/@nx/js/node_modules/@babel/preset-env": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz", - "integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", "dev": true, "dependencies": { "@babel/compat-data": "^7.23.5", @@ -8079,7 +8064,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", @@ -8101,7 +8086,7 @@ "@babel/plugin-transform-member-expression-literals": "^7.23.3", "@babel/plugin-transform-modules-amd": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", "@babel/plugin-transform-modules-umd": "^7.23.3", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.23.3", @@ -8127,9 +8112,9 @@ "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -8164,9 +8149,9 @@ } }, "node_modules/@nx/js/node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -8176,14 +8161,14 @@ } }, "node_modules/@nx/js/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -8242,29 +8227,13 @@ } }, "node_modules/@nx/js/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@nx/js/node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -8344,9 +8313,9 @@ } }, "node_modules/@nx/js/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -8782,9 +8751,9 @@ } }, "node_modules/@nx/webpack/node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -8792,11 +8761,11 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -8836,14 +8805,14 @@ } }, "node_modules/@nx/webpack/node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -10389,9 +10358,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.41", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", - "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", + "version": "4.17.42", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.42.tgz", + "integrity": "sha512-ckM3jm2bf/MfB3+spLPWYPUH573plBFwpOhqQ2WottxYV85j1HQFlxmnTq57X1yHY9awZPig06hL/cLMgNWHIQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -13015,9 +12984,9 @@ } }, "node_modules/axios": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.6.tgz", - "integrity": "sha512-XZLZDFfXKM9U/Y/B4nNynfCRUqNyVZ4sBC/n9GDRCkq9vd2mIvKjKKsbIh1WPmHmNbg6ND7cTBY3Y2+u1G3/2Q==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dev": true, "dependencies": { "follow-redirects": "^1.15.4", @@ -18496,9 +18465,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.645", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.645.tgz", - "integrity": "sha512-EeS1oQDCmnYsRDRy2zTeC336a/4LZ6WKqvSaM1jLocEk5ZuyszkQtCpsqvuvaIXGOUjwtvF6LTcS8WueibXvSw==" + "version": "1.4.647", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.647.tgz", + "integrity": "sha512-Z/fTNGwc45WrYQhPaEcz5tAJuZZ8G7S/DBnhS6Kgp4BxnS40Z/HqlJ0hHg3Z79IGVzuVartIlTcjw/cQbPLgOw==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -19832,9 +19801,9 @@ } }, "node_modules/eslint-plugin-jsx-a11y/node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -23425,9 +23394,9 @@ } }, "node_modules/immutable": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", "dev": true }, "node_modules/import-fresh": { @@ -31036,9 +31005,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", - "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { "node": "14 || >=16.14" diff --git a/package.json b/package.json index 34188656d0e03..76c619c615bdd 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:ssr": "nx build demo && nx run demo:server:production", "prerender": "nx run demo:prerender", "test": "nx run-many --target test --all --output-style=stream --parallel=1", - "test:e2e": "nx e2e-ui demo-cypress", + "cy:open": "cypress open --project ./projects/demo-cypress/", "*** Workflow ***": "", "stylelint": "stylelint '**/*.{less,css}' --config package.json", "lint": "eslint .", @@ -124,6 +124,7 @@ "@cypress/webpack-batteries-included-preprocessor": "3.0.2", "@cypress/webpack-preprocessor": "6.0.1", "@nx/angular": "17.2.8", + "@nx/cypress": "17.2.8", "@nx/jest": "17.2.8", "@nx/node": "17.2.8", "@nx/workspace": "17.2.8", diff --git a/projects/addon-mobile/components/mobile-calendar/tests/mobile-calendar.component.spec.ts b/projects/addon-mobile/components/mobile-calendar/tests/mobile-calendar.component.spec.ts deleted file mode 100644 index 206bff62e54c7..0000000000000 --- a/projects/addon-mobile/components/mobile-calendar/tests/mobile-calendar.component.spec.ts +++ /dev/null @@ -1,205 +0,0 @@ -import {Component, ViewChild} from '@angular/core'; -import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; -import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import { - TuiMobileCalendarComponent, - TuiMobileCalendarModule, -} from '@taiga-ui/addon-mobile'; -import { - ALWAYS_FALSE_HANDLER, - TUI_FIRST_DAY, - TUI_LAST_DAY, - TuiDay, - TuiDayRange, -} from '@taiga-ui/cdk'; -import {TUI_CALENDAR_DATE_STREAM} from '@taiga-ui/kit'; -import {TuiPageObject} from '@taiga-ui/testing'; -import {of} from 'rxjs'; - -const today = TuiDay.currentLocal(); -const tomorrow = today.append({day: 1}); - -describe('MobileCalendar', () => { - @Component({ - template: ` - - `, - providers: [ - { - provide: TUI_CALENDAR_DATE_STREAM, - useValue: of(tomorrow), - }, - ], - }) - class TestComponent { - @ViewChild(TuiMobileCalendarComponent, {static: true}) - component!: TuiMobileCalendarComponent; - - min = TUI_FIRST_DAY; - max = TUI_LAST_DAY; - disabledItemHandler = ALWAYS_FALSE_HANDLER; - single = true; - onCancel = jest.fn(); - onConfirm = jest.fn(); - } - - let fixture: ComponentFixture; - let testComponent: TestComponent; - let pageObject: TuiPageObject; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [NoopAnimationsModule, TuiMobileCalendarModule], - declarations: [TestComponent], - }); - await TestBed.compileComponents(); - fixture = TestBed.createComponent(TestComponent); - pageObject = new TuiPageObject(fixture); - testComponent = fixture.componentInstance; - fixture.autoDetectChanges(); - }); - - function getToday(): HTMLElement { - return pageObject - .getAllByAutomationId('tui-primitive-calendar-mobile__cell') - .find(item => item.classes['t-cell_today'])?.nativeElement; - } - - it('the back button emits a cancel event', () => { - pageObject - .getByAutomationId('tui-mobile-calendar__cancel') - ?.nativeElement.click(); - - expect(testComponent.onCancel).toHaveBeenCalled(); - }); - - it('single === true', () => { - expect( - pageObject - .getByAutomationId('tui-mobile-calendar__label') - ?.nativeElement.textContent.trim(), - ).toBe('Choose day'); - }); - - it('single === false', fakeAsync(() => { - testComponent.single = false; - fixture.detectChanges(); - - tick(100); - - expect( - pageObject - .getByAutomationId('tui-mobile-calendar__label') - ?.nativeElement.textContent.trim(), - ).toBe('Choose range'); - })); - - describe('when the done button emits', () => { - // TODO: move to cypress - // TypeError: el.scrollTo is not a function - xit('confirm event with selected day', fakeAsync(() => { - fixture.detectChanges(); - getToday().click(); - pageObject - .getByAutomationId('tui-mobile-calendar__confirm') - ?.nativeElement.click(); - - const value = testComponent.onConfirm.mock.calls[0][0]; - - expect(value.daySame(today)).toBe(true); - })); - - xit('confirm event at selected interval', () => { - fixture.detectChanges(); - testComponent.single = false; - fixture.autoDetectChanges(); - getToday().click(); - pageObject - .getByAutomationId('tui-mobile-calendar__confirm')! - .nativeElement.click(); - - const value = testComponent.onConfirm.mock.calls[0][0]; - - expect(value instanceof TuiDayRange).toBe(true); - expect(value.from.daySame(today)).toBe(true); - expect(value.to.daySame(today)).toBe(true); - }); - - xit('confirm event with selected interval with different dates', fakeAsync(() => { - testComponent.single = false; - fixture.autoDetectChanges(); - tick(500); - - const days = pageObject.getAllByAutomationId( - 'tui-primitive-calendar-mobile__cell', - ); - - days[0].nativeElement.click(); - days[1].nativeElement.click(); - pageObject - .getByAutomationId('tui-mobile-calendar__confirm')! - .nativeElement.click(); - - const value = testComponent.onConfirm.mock.calls[0][0]; - - expect(value.isSingleDay).toBe(false); - })); - - xit('cancel event if null', fakeAsync(() => { - testComponent.component.value = null; - pageObject - .getByAutomationId('tui-mobile-calendar__confirm')! - .nativeElement.click(); - - expect(testComponent.onConfirm).not.toHaveBeenCalled(); - expect(testComponent.onCancel).toHaveBeenCalled(); - })); - }); - - /** - * TODO: - * TypeError: el.scrollTo is not a function - * at CdkVirtualScrollViewport.Object..CdkScrollable._applyScrollToOptions (../src/cdk/scrolling/scrollable.ts:133:10) - * at CdkVirtualScrollViewport.Object..CdkScrollable.scrollTo (../src/cdk/scrolling/scrollable.ts:126:10) - * at CdkVirtualScrollViewport.Object..CdkVirtualScrollViewport.scrollToOffset (../src/cdk/scrolling/virtual-scroll-viewport.ts:353:10) - * at FixedSizeVirtualScrollStrategy.Object..FixedSizeVirtualScrollStrategy.scrollToIndex (../src/cdk/scrolling/fixed-size-virtual-scroll.ts:107:22) - * at CdkVirtualScrollViewport.Object..CdkVirtualScrollViewport.scrollToIndex (../src/cdk/scrolling/virtual-scroll-viewport.ts:362:26) - * at TuiMobileCalendarComponent.scrollToActiveYear (projects/addon-mobile/components/mobile-calendar/mobile-calendar.component.ts:387:30) - * at TuiMobileCalendarComponent.setYear (projects/addon-mobile/components/mobile-calendar/mobile-calendar.component.ts:211:14) - * at projects/addon-mobile/components/mobile-calendar/tests/mobile-calendar.component.spec.ts:170:33 - * at _ZoneDelegate.Object.._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:409:30) - * at ProxyZoneSpec.Object..ProxyZoneSpec.onInvoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3830:43) - * at _ZoneDelegate.Object.._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56) - * at Zone.Object..Zone.run (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:169:47) - * at Object.wrappedFunc (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:4330:34) - */ - xit('Year selection scrolls through months', done => { - testComponent.component.setYear(1950); - fixture.detectChanges(); - - const waitCdkScrollToIndex = 300; - - setTimeout(() => { - pageObject - .getAllByAutomationId('tui-primitive-calendar-mobile__cell')[0] - .nativeElement.click(); - - pageObject - .getByAutomationId('tui-mobile-calendar__confirm') - ?.nativeElement.click(); - - const value = testComponent.onConfirm.mock.calls[0][0]; - - expect(value.year).toBeLessThanOrEqual(1950); - done(); - }, waitCdkScrollToIndex); - }); -}); diff --git a/projects/demo-cypress/cypress.config.ts b/projects/demo-cypress/cypress.config.ts index d7afe335c6b20..eac04016856c1 100644 --- a/projects/demo-cypress/cypress.config.ts +++ b/projects/demo-cypress/cypress.config.ts @@ -1,138 +1,50 @@ -/// -import {tuiAddSnapshotPlugin} from '@taiga-ui/testing/cypress/snapshot/plugin'; +import {nxComponentTestingPreset} from '@nx/angular/plugins/component-testing'; import {defineConfig} from 'cypress'; -import { - TUI_BLOCK_HOSTS as blockHosts, - TUI_CYPRESS_DESKTOP_VIEWPORT_HEIGHT, - TUI_CYPRESS_DESKTOP_VIEWPORT_HEIGHT as viewportHeight, - TUI_CYPRESS_DESKTOP_VIEWPORT_WIDTH, - TUI_CYPRESS_DESKTOP_VIEWPORT_WIDTH as viewportWidth, -} from './cypress/cypress.options'; +const preset = nxComponentTestingPreset(__filename); -export const TUI_CYPRESS_CONFIG: Cypress.ConfigOptions = { +export default defineConfig({ video: false, - blockHosts, - viewportWidth, - viewportHeight, - fixturesFolder: 'cypress/fixtures', - screenshotsFolder: 'cypress/screenshots', - - /** - * @description: - * Time, in milliseconds, to wait until most - * DOM based commands are considered timed out. - */ - defaultCommandTimeout: 4000, - - /** - * @description: - * Time, in milliseconds, to wait until a response - * in a cy.request(), cy.wait(), - */ - responseTimeout: 30_000, - - /** - * @description: - * Number of times to retry a failed test. - * If a number is set, tests will retry in both runMode and openMode. - */ - retries: { - runMode: 1, // Configure retry attempts for `cypress run` - openMode: 0, // Configure retry attempts for `cypress open` - }, - - /** - * @description: - * The number of tests for which snapshots and command data are kept in memory. - * Reduce this number if you are experiencing high memory - * consumption in your browser during a test run. - */ - numTestsKeptInMemory: 0, - - env: { - componentsExclusion: [ - ['components/select', [5]], - ['components/multi-select', [4]], - ['components/mobile-calendar', [2, 3]], // flaky test, need investigate - ['components/table', [4, 5]], // randomly generated data - ['components/preview', [1, 2, 3]], - ['components/progress-bar', [6]], // indeterminate progress bar - ], - waitBeforeScreenshot: 1000, - waitBeforeAction: 50, - fonts: { - '@tui-mobile-min': {width: 360, font: 'Manrope'}, - '@tui-mobile': {width: 767, font: 'Manrope'}, - '@tui-tablet': {width: 1024, font: 'Manrope'}, - '@tui-desktop': {width: 1280, font: 'Manrope'}, - }, - }, - - e2e: { - specPattern: 'cypress/tests/**/*.cy.ts', - supportFile: 'cypress/support/e2e.ts', - baseUrl: 'http://localhost:3333', - /** - * @description: - * We've imported your old cypress plugins here. - * You may want to clean this up later by importing these. - */ - async setupNodeEvents( - on: Cypress.PluginEvents, - config: Cypress.PluginConfigOptions, - ) { - await tuiAddSnapshotPlugin(on, config, { - newSnapshotMarkFn: oldFileName => `==new==${oldFileName}`, - newSnapshotMarkEnabled: config.baseUrl === 'http://localhost:3333/', - }); - - const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor'); - const webpackOptions = webpackPreprocessor.defaultOptions.webpackOptions; - - webpackOptions.module.rules.unshift({ - test: /[/\\]@angular[/\\].+\.m?js$/, - resolve: { - fullySpecified: false, - }, - use: { - loader: 'babel-loader', - options: { - plugins: ['@angular/compiler-cli/linker/babel'], - compact: false, - cacheDirectory: true, + fixturesFolder: 'src/fixtures', + viewportWidth: 500, + viewportHeight: 900, + responseTimeout: 60000, + pageLoadTimeout: 120000, + defaultCommandTimeout: 10000, + component: { + ...preset, + devServer: { + ...preset.devServer, + options: { + ...preset.devServer.options, + projectConfig: { + ...preset.devServer.options.projectConfig, + buildOptions: { + ...preset.devServer.options.projectConfig.buildOptions, + tsConfig: './tsconfig.json', + assets: [ + { + glob: '**/*', + input: 'projects/demo/src/assets/', + output: './assets/', + }, + { + glob: '**/*', + input: 'projects/icons/src', + output: 'assets/taiga-ui/icons', + }, + ], + baseHref: './', + styles: [ + 'projects/demo/src/normalize.less', + 'projects/demo/src/styles.less', + ], }, }, - }); - - on( - 'file:preprocessor', - webpackPreprocessor({ - webpackOptions, - typescript: require.resolve('typescript'), - }), - ); - - on('before:browser:launch', (browser, launchOptions) => { - if (browser.name === 'chrome') { - launchOptions.args.push( - '--font-render-hinting=none', // prevent inconsistent text rendering in headless mode - `--window-size=${TUI_CYPRESS_DESKTOP_VIEWPORT_WIDTH},${TUI_CYPRESS_DESKTOP_VIEWPORT_HEIGHT}`, - '--force-device-scale-factor=2', - '--high-dpi-support=1', - '--force-prefers-reduced-motion', - '--force-color-profile=srgb', - '--disable-dev-shm-usage', - '--disable-gpu', - '--incognito', - ); - } - - return launchOptions; - }); + }, }, + supportFile: 'src/support/component.ts', + indexHtmlFile: 'src/support/component-index.html', + specPattern: 'src/tests/**/*.cy.ts', }, -}; - -// noinspection JSUnusedGlobalSymbols -export default defineConfig(TUI_CYPRESS_CONFIG); +}); diff --git a/projects/demo-cypress/cypress/cypress.options.ts b/projects/demo-cypress/cypress/cypress.options.ts deleted file mode 100644 index 1a3f7b1b6d5af..0000000000000 --- a/projects/demo-cypress/cypress/cypress.options.ts +++ /dev/null @@ -1,16 +0,0 @@ -// cspell:disable -export const TUI_CYPRESS_MOBILE_USER_AGENT = - 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'; -// Samsung Galaxy Ace GT: -export const TUI_CYPRESS_MOBILE_VIEWPORT_WIDTH = 320; -export const TUI_CYPRESS_MOBILE_VIEWPORT_HEIGHT = 480; -// Full HD: -export const TUI_CYPRESS_DESKTOP_VIEWPORT_WIDTH = 1920; -export const TUI_CYPRESS_DESKTOP_VIEWPORT_HEIGHT = 1080; -// Related with proprietary repo, resources are not available under private VPN -export const TUI_BLOCK_HOSTS = [ - '*.google-analytics.com', - '*.doubleclick.net', - '*.ggpht.com', - '*.bcbits.com', -]; diff --git a/projects/demo-cypress/cypress/fixtures/stubs/web-api.svg b/projects/demo-cypress/cypress/fixtures/stubs/web-api.svg deleted file mode 100644 index 05e65fe678250..0000000000000 --- a/projects/demo-cypress/cypress/fixtures/stubs/web-api.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - diff --git a/projects/demo-cypress/cypress/support/commands/basic.ts b/projects/demo-cypress/cypress/support/commands/basic.ts deleted file mode 100644 index 9a396aded4a21..0000000000000 --- a/projects/demo-cypress/cypress/support/commands/basic.ts +++ /dev/null @@ -1,111 +0,0 @@ -import {tuiClickOutside} from '@demo-cypress/support/helpers/click-outside'; -import { - tuiFindDocExample, - tuiGetDocExample, -} from '@demo-cypress/support/helpers/example-id-utils'; -import {tuiFocus} from '@demo-cypress/support/helpers/focus'; -import {tuiHide} from '@demo-cypress/support/helpers/hide'; -import {tuiScrollIntoView} from '@demo-cypress/support/helpers/scroll-into-view'; -import {tuiSetLanguage} from '@demo-cypress/support/helpers/set-language'; -import {tuiSetNightMode} from '@demo-cypress/support/helpers/set-night-mode'; -import {tuiShow} from '@demo-cypress/support/helpers/show'; -import {tuiTab} from '@demo-cypress/support/helpers/type-tab'; -import {tuiVisit} from '@demo-cypress/support/helpers/visit'; -import { - tuiWaitBeforeAction, - tuiWaitBeforeScreenshot, -} from '@demo-cypress/support/helpers/wait-before-screenshot'; -import {tuiWaitCodeHighlight} from '@demo-cypress/support/helpers/wait-code-highlight'; -import {tuiWaitKitDialog} from '@demo-cypress/support/helpers/wait-kit-dialog'; -import {tuiBeInViewportAssertion, tuiWaitAllImgInside} from '@taiga-ui/testing/cypress'; - -declare global { - namespace Cypress { - interface Chainable { - findByAutomationId(automationId: string): Chainable; - - getByAutomationId(automationId: string): Chainable; - - tuiClickOutside: typeof tuiClickOutside; - tuiFindByExampleId(): Chainable; - tuiFocus(): Chainable; - tuiGetByExampleId(): Chainable; - tuiHide: typeof tuiHide; - tuiScrollIntoView(): Chainable; - tuiSetLanguage: typeof tuiSetLanguage; - tuiSetNightMode: typeof tuiSetNightMode; - - tuiShow: typeof tuiShow; - tuiTab(direction: 'backward' | 'forward'): Chainable; - tuiVisit: typeof tuiVisit; - tuiWaitAllImgInside(enabled?: boolean): Chainable; - tuiWaitBeforeAction(): Chainable; - tuiWaitBeforeScreenshot(): Chainable; - tuiWaitCodeHighlight: typeof tuiWaitCodeHighlight; - tuiWaitKitDialog: typeof tuiWaitKitDialog; - } - - interface Chainer { - (chainer: 'be.inViewport'): Chainable; - } - } -} - -Cypress.Commands.add('getByAutomationId', id => cy.get(`[automation-id=${id}]`)); -Cypress.Commands.add('tuiGetByExampleId', tuiGetDocExample); -Cypress.Commands.add( - 'findByAutomationId', - {prevSubject: true}, - (subject: S, id: string) => - /** - * `subject` is just `jQuery`-element which has method `.find()`. - * This method doesn't have {@link https://docs.cypress.io/guides/core-concepts/retry-ability retry-ability}! - * ___ - * `cy.wrap(subject)` is a `$Chainer`-element (cypress built-in implementation) which also has method `.find()`. - * This method has retry-ability! - */ - cy.wrap(subject, {log: false}).find(`[automation-id=${id}]`), -); -Cypress.Commands.add('tuiVisit', tuiVisit); -Cypress.Commands.add('tuiWaitKitDialog', tuiWaitKitDialog); -Cypress.Commands.add('tuiSetLanguage', tuiSetLanguage); -Cypress.Commands.add('tuiSetNightMode', tuiSetNightMode); -Cypress.Commands.add('tuiWaitCodeHighlight', tuiWaitCodeHighlight); -Cypress.Commands.add('tuiHide', tuiHide); -Cypress.Commands.add('tuiShow', tuiShow); -Cypress.Commands.add('tuiFindByExampleId', {prevSubject: true}, (subject: S) => - tuiFindDocExample(subject), -); -Cypress.Commands.add('tuiClickOutside', tuiClickOutside); -Cypress.Commands.add( - 'tuiWaitBeforeScreenshot', - {prevSubject: ['optional']}, - tuiWaitBeforeScreenshot, -); -Cypress.Commands.add( - 'tuiWaitBeforeAction', - {prevSubject: ['optional', 'element', 'window', 'document']}, - tuiWaitBeforeAction, -); -Cypress.Commands.add( - 'tuiTab', - {prevSubject: ['optional', 'element', 'window', 'document']}, - tuiTab, -); -Cypress.Commands.add( - 'tuiScrollIntoView', - {prevSubject: ['optional', 'element', 'window', 'document']}, - tuiScrollIntoView, -); -Cypress.Commands.add( - 'tuiFocus', - {prevSubject: ['optional', 'element', 'window', 'document']}, - tuiFocus, -); -Cypress.Commands.add( - 'tuiWaitAllImgInside', - {prevSubject: ['optional', 'element', 'window', 'document']}, - tuiWaitAllImgInside, -); - -chai.use(tuiBeInViewportAssertion); diff --git a/projects/demo-cypress/cypress/support/commands/snapshot.ts b/projects/demo-cypress/cypress/support/commands/snapshot.ts deleted file mode 100644 index f3aef30a72806..0000000000000 --- a/projects/demo-cypress/cypress/support/commands/snapshot.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {tuiAddMatchImageSnapshotCommand} from '@taiga-ui/testing/cypress'; - -tuiAddMatchImageSnapshotCommand({ - allowSizeMismatch: false, - runInProcess: false, - failureThreshold: 0.0004, - failureThresholdType: 'percent', - comparisonMethod: 'ssim', - diffDirection: 'horizontal', - customDiffConfig: { - ssim: 'fast', - windowSize: 24, - } as any, -}); diff --git a/projects/demo-cypress/cypress/support/constants/index.ts b/projects/demo-cypress/cypress/support/constants/index.ts deleted file mode 100644 index 561f84f34f48d..0000000000000 --- a/projects/demo-cypress/cypress/support/constants/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './real-events-support'; diff --git a/projects/demo-cypress/cypress/support/constants/real-events-support.ts b/projects/demo-cypress/cypress/support/constants/real-events-support.ts deleted file mode 100644 index 2d43dcda7a13b..0000000000000 --- a/projects/demo-cypress/cypress/support/constants/real-events-support.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Some tests use `cy.realPress([...])`, to simulate text selection. - * But this command is not supported by all browsers. - * ___ - * @see https://docs.cypress.io/guides/guides/cross-browser-testing#Running-Specific-Tests-by-Browser - * @see https://github.com/dmtrKovalenko/cypress-real-events#requirements - * @see https://github.com/cypress-io/cypress/issues/2839#issuecomment-867411151 - */ -export const BROWSER_SUPPORTS_REAL_EVENTS: Cypress.TestConfigOverrides = { - browser: '!firefox', -}; diff --git a/projects/demo-cypress/cypress/support/e2e.ts b/projects/demo-cypress/cypress/support/e2e.ts deleted file mode 100644 index 0a013bb98a0f6..0000000000000 --- a/projects/demo-cypress/cypress/support/e2e.ts +++ /dev/null @@ -1,3 +0,0 @@ -import 'cypress-real-events'; -import './commands/basic'; -import './commands/snapshot'; // @note: override in proprietary diff --git a/projects/demo-cypress/cypress/support/helpers/click-outside.ts b/projects/demo-cypress/cypress/support/helpers/click-outside.ts deleted file mode 100644 index 95675347ee7b9..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/click-outside.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function tuiClickOutside(): void { - cy.get('body').click(0, 0); -} diff --git a/projects/demo-cypress/cypress/support/helpers/example-id-utils.ts b/projects/demo-cypress/cypress/support/helpers/example-id-utils.ts deleted file mode 100644 index a0f9315c6bf0a..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/example-id-utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function tuiEnsureDocExample(): string { - return Cypress.env('EXAMPLE_ID') ?? 'tui-doc-example'; -} - -export function tuiGetDocExample(): Cypress.Chainable { - return cy.getByAutomationId(tuiEnsureDocExample()); -} - -export function tuiFindDocExample($subject: S): Cypress.Chainable { - return cy.wrap($subject, {log: false}).findByAutomationId(tuiEnsureDocExample()); -} diff --git a/projects/demo-cypress/cypress/support/helpers/focus.ts b/projects/demo-cypress/cypress/support/helpers/focus.ts deleted file mode 100644 index ebc8bd69e7d70..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/focus.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const tuiFocus = ( - $subject: Cypress.PrevSubjectMap[Cypress.PrevSubject], -): Cypress.Chainable => - cy - .wrap($subject, {log: false}) - .focus() - .should('be.focused') - .should('be.visible') - .tuiWaitBeforeAction(); diff --git a/projects/demo-cypress/cypress/support/helpers/hide.ts b/projects/demo-cypress/cypress/support/helpers/hide.ts deleted file mode 100644 index 2de3e51b46871..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/hide.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const tuiHide = (selector: string): void => { - cy.get('body', {log: false}).then($body => { - if ($body.find(selector).length > 0) { - cy.get(selector, {log: false}).invoke( - 'attr', - 'style', - 'opacity: 0; visibility: hidden; pointer-events: none', - ); - } - }); -}; diff --git a/projects/demo-cypress/cypress/support/helpers/scroll-into-view.ts b/projects/demo-cypress/cypress/support/helpers/scroll-into-view.ts deleted file mode 100644 index 8e4cc5b914bd1..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/scroll-into-view.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const tuiScrollIntoView = ( - $subject: Cypress.PrevSubjectMap[Cypress.PrevSubject], -): Cypress.Chainable => - cy - .wrap($subject, {log: false}) - .scrollIntoView({ - ensureScrollable: true, - easing: 'linear', - duration: 0, - }) - .should('be.inViewport') - .should('be.visible') - .tuiWaitBeforeAction(); diff --git a/projects/demo-cypress/cypress/support/helpers/set-language.ts b/projects/demo-cypress/cypress/support/helpers/set-language.ts deleted file mode 100644 index 5dafd28a787c5..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/set-language.ts +++ /dev/null @@ -1,6 +0,0 @@ -export function tuiSetLanguage(language: string): void { - cy.get('tui-language-switcher', {log: false}).click({log: false}); - cy.get('tui-dropdown [tuiOption]', {log: false}) - .contains(language, {matchCase: false, log: false}) - .click({force: true, log: false}); -} diff --git a/projects/demo-cypress/cypress/support/helpers/set-night-mode.ts b/projects/demo-cypress/cypress/support/helpers/set-night-mode.ts deleted file mode 100644 index b89a3dfe1c995..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/set-night-mode.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function tuiSetNightMode({enable}: {enable: boolean}): void { - cy.window().then((win: Window) => - win.localStorage.setItem('tuiNight', enable.toString()), - ); -} diff --git a/projects/demo-cypress/cypress/support/helpers/show.ts b/projects/demo-cypress/cypress/support/helpers/show.ts deleted file mode 100644 index 627524e47bd99..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/show.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const tuiShow = (selector: string): void => { - cy.get('body', {log: false}).then($body => { - if ($body.find(selector).length > 0) { - cy.get(selector, {log: false}).invoke( - 'attr', - 'style', - 'opacity: 1; visibility: visible; pointer-events: auto', - ); - } - }); -}; diff --git a/projects/demo-cypress/cypress/support/helpers/type-tab.ts b/projects/demo-cypress/cypress/support/helpers/type-tab.ts deleted file mode 100644 index 65d5d8532c47f..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/type-tab.ts +++ /dev/null @@ -1,83 +0,0 @@ -function nextTabbable($referenceElement: JQuery, direction = 'forward'): JQuery { - if (!(direction === 'forward' || direction === 'backward')) { - throw new Error('Expected direction to be forward or backward'); - } - - const stack = []; - let element; - - const siblingProp = - direction === 'forward' ? 'nextElementSibling' : 'previousElementSibling'; - - element = $referenceElement.get(0); - - while (element) { - let sibling = element[siblingProp]; - - while (sibling) { - stack.unshift(sibling); - sibling = sibling[siblingProp]; - } - - element = element.parentElement; - } - - while (stack.length > 0) { - element = stack.pop(); - - const $candidateElement = $referenceElement.constructor(element); - - if (isTabbable($candidateElement)) { - return $candidateElement; - } - - let children = Array.from(element?.children || []); - - if (direction === 'forward') { - children = children.reverse(); - } - - children.forEach(child => { - stack.push(child); - }); - } - - return $referenceElement.constructor(); -} - -function isTabbable($element: JQuery): boolean { - const tabIndex = $element.attr('tabindex'); - - return (!tabIndex || parseInt(tabIndex, 10) >= 0) && isFocusable($element); -} - -const DISABLEMENT_ELEMENTS = [ - 'input', - 'button', - 'select', - 'textarea', - 'button', - 'object', -]; - -function isFocusable($element: JQuery): boolean { - const nodeName = $element.prop('nodeName')?.toLowerCase() || ''; - - return ( - (nodeName === 'a' || - !!$element.attr('tabindex') || - (DISABLEMENT_ELEMENTS.includes(nodeName) && $element.is(':enabled'))) && - $element.is(':visible') - ); -} - -export function tuiTab( - $subject: Cypress.PrevSubjectMap[Cypress.PrevSubject], - direction: 'backward' | 'forward', -): Cypress.Chainable { - const thenable: Cypress.Chainable = $subject - ? cy.wrap($subject, {log: false}) - : cy.focused({log: false}); - - return thenable.then($el => nextTabbable($el, direction)).focus({log: false}); -} diff --git a/projects/demo-cypress/cypress/support/helpers/visit.ts b/projects/demo-cypress/cypress/support/helpers/visit.ts deleted file mode 100644 index e770c33597c63..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/visit.ts +++ /dev/null @@ -1,178 +0,0 @@ -import {waitAllRequests} from '@demo-cypress/support/helpers/wait-requests.util'; -import {stubExternalIcons} from '@demo-cypress/support/stubs/stub-external-icons.util'; -import {stubMetrics} from '@demo-cypress/support/stubs/stub-metrics'; - -const NEXT_URL_STORAGE_KEY = 'env'; -const REPEATED_SLASH_REG = /\/\//g; - -interface TuiVisitOptions { - clock?: Date | null; - enableNightMode?: boolean; - headers?: Record; - hideCursor?: boolean; - hideGetHelpLinks?: boolean; - hideHeader?: boolean; - hideLanguageSwitcher?: boolean; - hideNavigation?: boolean; - hideScrollbar?: boolean; - hideVersionManager?: boolean; - /** - * Cypress runs all tests within an iframe. - * Sometimes our app can behave differently if it runs under iframe or not (see util {@link isInsideIframe}). - * This parameter can help to falsify result of {@link isInsideIframe} for certain test run. - */ - inIframe?: boolean; - noSmoothScroll?: boolean; - /** - * WARNING: this flag does not provide fully emulation of touch mobile device. - * Cypress can't do it (https://docs.cypress.io/faq/questions/general-questions-faq#Do-you-support-native-mobile-apps). - * But you can control token `TUI_IS_MOBILE` by this flag. - */ - pseudoMobile?: boolean; - rootSelector?: string; - skipDecodingUrl?: boolean; - skipExpectUrl?: boolean; - waitAllIcons?: boolean; - waitRenderedFont?: RegExp; -} - -const setBeforeLoadOptions = ( - win: Window, - {inIframe}: Pick, 'inIframe'>, -): void => { - if (!inIframe) { - // @ts-ignore window.parent is readonly property - // eslint-disable-next-line @typescript-eslint/dot-notation - win['parent'] = win; - } -}; - -const MOBILE_USER_AGENT = - 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'; - -export function tuiVisit(path: string, options: TuiVisitOptions = {}): void { - const { - inIframe = true, - waitAllIcons = true, - enableNightMode = false, - hideCursor = true, - hideScrollbar = true, - hideHeader = true, - skipExpectUrl = false, - skipDecodingUrl = false, - hideNavigation = true, - hideVersionManager = true, - hideLanguageSwitcher = true, - hideGetHelpLinks = true, - headers = {}, - pseudoMobile = false, - waitRenderedFont, - clock = Date.UTC(2018, 10, 1), - rootSelector = 'app', - } = options; - - if (clock) { - cy.clock(clock, ['Date']); - } - - stubExternalIcons(); - stubMetrics(); - - const encodedPath = skipDecodingUrl - ? path - : encodeURI( - decodeURIComponent(path), // @note: prevent twice encoding - ); - - // eslint-disable-next-line no-restricted-syntax - Cypress.on('uncaught:exception', () => false); - - cy.visit('/', { - headers, - onBeforeLoad: window => { - if (headers['userAgent']) { - Object.defineProperty(window.navigator, 'userAgent', { - value: headers['userAgent'], - }); - } - - const baseHref = - window.document.baseURI.replace(`${window.location.origin}/`, '') ?? '/'; - const nextUrl = `/${baseHref}${encodedPath}`.replace(REPEATED_SLASH_REG, '/'); - - setBeforeLoadOptions(window, {inIframe}); - - window.localStorage.setItem(NEXT_URL_STORAGE_KEY, nextUrl); - window.localStorage.setItem('tuiNight', enableNightMode.toString()); - - if (pseudoMobile) { - Object.defineProperty(window.navigator, 'userAgent', { - value: MOBILE_USER_AGENT, - }); - } - }, - }).then(() => { - if (skipExpectUrl) { - cy.tuiWaitBeforeScreenshot(); - } else { - cy.url().should('include', encodedPath); - } - }); - - if (waitAllIcons) { - cy.intercept('*.svg').as('icons'); - } - - cy.window().should('have.property', 'Cypress'); - - cy.clearLocalStorage(NEXT_URL_STORAGE_KEY); - - cy.document().its('fonts.size').should('be.greaterThan', 0); - cy.document().its('fonts.status').should('equal', 'loaded'); - cy.document() - // https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready - // The promise will only resolve once the document has completed loading fonts, - // layout operations are completed, and no further font loads are needed. - .then(document => (document as any)?.fonts.ready) - .then(() => cy.log('Font loading completed')); - - if (waitRenderedFont) { - cy.get('body', {log: false}) - .should('have.css', 'font-family') - .and('match', waitRenderedFont); - } - - if (waitAllIcons) { - waitAllRequests('@icons'); - } - - if (hideCursor) { - cy.get('@app').invoke('addClass', '_hide-cursor'); - } - - if (hideScrollbar) { - cy.get('@app').invoke('addClass', '_hide-scrollbar'); - } - - cy.get(rootSelector).should('have.class', '_loaded'); - - if (hideHeader) { - cy.tuiHide('[tuidocheader]'); - } - - if (hideNavigation) { - cy.tuiHide('.tui-doc-navigation'); - } - - if (hideVersionManager) { - cy.tuiHide('version-manager'); - } - - if (hideLanguageSwitcher) { - cy.tuiHide('tui-language-switcher'); - } - - if (hideGetHelpLinks) { - cy.tuiHide('community-links'); - } -} diff --git a/projects/demo-cypress/cypress/support/helpers/wait-before-screenshot.ts b/projects/demo-cypress/cypress/support/helpers/wait-before-screenshot.ts deleted file mode 100644 index c14e19b1e5c80..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/wait-before-screenshot.ts +++ /dev/null @@ -1,15 +0,0 @@ -export function tuiWaitBeforeScreenshot( - $subject?: Cypress.PrevSubjectMap[Cypress.PrevSubject], -): Cypress.Chainable { - const timeout = Cypress.env('waitBeforeScreenshot') ?? 1000; - - return cy.wait(timeout, {log: false}).wrap($subject, {log: false}); -} - -export function tuiWaitBeforeAction( - $subject: Cypress.PrevSubjectMap[Cypress.PrevSubject], -): Cypress.Chainable { - const timeout = Cypress.env('waitBeforeAction') ?? 50; - - return cy.wait(timeout, {log: false}).wrap($subject, {log: false}); -} diff --git a/projects/demo-cypress/cypress/support/helpers/wait-code-highlight.ts b/projects/demo-cypress/cypress/support/helpers/wait-code-highlight.ts deleted file mode 100644 index bccdf74bc813b..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/wait-code-highlight.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function tuiWaitCodeHighlight(selector = 'code'): void { - cy.get(selector) - .should('has.class', 'hljs') - .find('.hljs-ln-numbers') - .should('exist') - .tuiWaitBeforeAction(); -} diff --git a/projects/demo-cypress/cypress/support/helpers/wait-kit-dialog.ts b/projects/demo-cypress/cypress/support/helpers/wait-kit-dialog.ts deleted file mode 100644 index 720fe47f7086f..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/wait-kit-dialog.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function tuiWaitKitDialog(selector = 'tui-dialog'): void { - cy.get(selector) - .last() - .should('be.visible') - .should('not.have.class', 'ng-animating') - .tuiWaitBeforeScreenshot(); -} diff --git a/projects/demo-cypress/cypress/support/helpers/wait-requests.util.ts b/projects/demo-cypress/cypress/support/helpers/wait-requests.util.ts deleted file mode 100644 index 01cc75a17a3d9..0000000000000 --- a/projects/demo-cypress/cypress/support/helpers/wait-requests.util.ts +++ /dev/null @@ -1,22 +0,0 @@ -const getNotLoadedRequests = (alias: string): Cypress.Chainable => - cy - .get>(`${alias}.all`, {log: false}) - .then(requests => requests.filter(req => req.state !== 'Complete')); - -export const waitAllRequests = (alias: string): void => { - getNotLoadedRequests(alias) - .then(requests => - requests.length ? cy.wait(alias, {log: false}) : cy.tuiWaitBeforeAction(), - ) - .then(() => getNotLoadedRequests(alias)) - .then(requests => - requests.length - ? waitAllRequests(alias) - : cy - .tuiWaitBeforeAction() - .then(() => getNotLoadedRequests(alias)) - .then(async request => - request.length ? waitAllRequests(alias) : Promise.resolve(), - ), - ); -}; diff --git a/projects/demo-cypress/cypress/support/stubs/stub-external-icons.util.ts b/projects/demo-cypress/cypress/support/stubs/stub-external-icons.util.ts deleted file mode 100644 index 1c54b8b18b3bb..0000000000000 --- a/projects/demo-cypress/cypress/support/stubs/stub-external-icons.util.ts +++ /dev/null @@ -1,21 +0,0 @@ -// not taiga ui icons -export const EXTERNAL_ICONS = [ - 'web-api.svg', - 'avatars.githubusercontent.com', - 'raw.githubusercontent.com', - '.*ng-polymorpheus.*logo.svg', - 'bf2e94ae58ee713717faf397958a8e3d.jpg', // filename - MD5 hash value of file content (waterplea avatar) - 'avatar.jpg', -]; - -export const stubExternalIcons = (icons: string[] = EXTERNAL_ICONS): void => { - icons.forEach(iconName => { - cy.intercept( - { - method: 'GET', - url: new RegExp(`.*${iconName}`), - }, - {fixture: 'stubs/web-api.svg'}, - ); - }); -}; diff --git a/projects/demo-cypress/cypress/support/stubs/stub-metrics.ts b/projects/demo-cypress/cypress/support/stubs/stub-metrics.ts deleted file mode 100644 index 3b130cdc6482c..0000000000000 --- a/projects/demo-cypress/cypress/support/stubs/stub-metrics.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const stubMetrics = (): void => { - cy.intercept({hostname: 'mc.yandex.ru'}, {}); -}; diff --git a/projects/demo-cypress/project.json b/projects/demo-cypress/project.json index 2729a151f54fe..d4acc3f447814 100644 --- a/projects/demo-cypress/project.json +++ b/projects/demo-cypress/project.json @@ -5,22 +5,15 @@ "projectType": "application", "prefix": "app", "targets": { - "e2e-ui": { - "executor": "nx:run-commands", + "component-test": { + "executor": "@nx/cypress:cypress", "options": { - "parallel": false, - "commands": [ - "npx wait-on http://localhost:3333 --timeout 1000", - "cypress open --browser chrome --project ./projects/demo-cypress" - ] - } - }, - "e2e": { - "executor": "nx:run-commands", - "outputs": ["{projectRoot}/cypress/snapshots"], - "options": { - "command": "npx cypress run --env ci=true --browser chrome --headless --project ./projects/demo-cypress --spec '**/{args.folder}/**/*.cy.ts'" + "cypressConfig": "projects/demo-cypress/cypress.config.ts", + "testingType": "component", + "skipServe": true, + "devServerTarget": "demo:build" } } - } + }, + "implicitDependencies": ["demo"] } diff --git a/projects/demo-cypress/src/support/component-index.html b/projects/demo-cypress/src/support/component-index.html new file mode 100644 index 0000000000000..39ca75702d5fb --- /dev/null +++ b/projects/demo-cypress/src/support/component-index.html @@ -0,0 +1,18 @@ + + + + + + + Components App + + +
+ + diff --git a/projects/demo-cypress/src/support/component.ts b/projects/demo-cypress/src/support/component.ts new file mode 100644 index 0000000000000..37e404638e4b7 --- /dev/null +++ b/projects/demo-cypress/src/support/component.ts @@ -0,0 +1,17 @@ +import {mount} from 'cypress/angular'; + +declare global { + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + mount: typeof mount; + } + } +} + +export const stableMount: typeof mount = (...mountArgs) => + mount(...mountArgs).then(async mountResponse => + mountResponse.fixture.whenStable().then(() => mountResponse), + ); + +Cypress.Commands.add('mount', stableMount); diff --git a/projects/demo-cypress/src/tests/mobile-calendar.cy.ts b/projects/demo-cypress/src/tests/mobile-calendar.cy.ts new file mode 100644 index 0000000000000..e1dee2091f036 --- /dev/null +++ b/projects/demo-cypress/src/tests/mobile-calendar.cy.ts @@ -0,0 +1,157 @@ +import {Component, EventEmitter, ViewChild} from '@angular/core'; +import { + TuiMobileCalendarComponent, + TuiMobileCalendarModule, +} from '@taiga-ui/addon-mobile'; +import { + ALWAYS_FALSE_HANDLER, + TUI_FIRST_DAY, + TUI_LAST_DAY, + TuiDay, + TuiDayRange, +} from '@taiga-ui/cdk'; +import {TuiRootModule} from '@taiga-ui/core'; +import {TUI_CALENDAR_DATE_STREAM} from '@taiga-ui/kit'; +import {createOutputSpy} from 'cypress/angular'; +import {of} from 'rxjs'; + +describe('Mobile calendar', () => { + const today = TuiDay.currentLocal(); + const tomorrow = today.append({day: 1}); + + @Component({ + template: ` + + + + `, + providers: [ + { + provide: TUI_CALENDAR_DATE_STREAM, + useValue: of(tomorrow), + }, + ], + }) + class TestComponent { + @ViewChild(TuiMobileCalendarComponent, {static: true}) + component!: TuiMobileCalendarComponent; + + single = true; + min = TUI_FIRST_DAY; + max = TUI_LAST_DAY; + disabledItemHandler = ALWAYS_FALSE_HANDLER; + onCancel = new EventEmitter(); + onConfirm = new EventEmitter(); + } + + it('the back button emits a cancel event', () => { + cy.mount(TestComponent, { + imports: [TuiRootModule, TuiMobileCalendarModule], + componentProperties: { + onCancel: createOutputSpy('onCancelSpy'), + }, + }); + + cy.get('[automation-id="tui-mobile-calendar__cancel"]').click(); + cy.get('@onCancelSpy').should('be.calledWith', true); + }); + + it('single === true', () => { + cy.mount(TestComponent, { + imports: [TuiRootModule, TuiMobileCalendarModule], + }); + + cy.get('[automation-id="tui-mobile-calendar__label"]').should( + 'contain.text', + 'Choose day', + ); + }); + + it('single === false', () => { + cy.mount(TestComponent, { + imports: [TuiRootModule, TuiMobileCalendarModule], + componentProperties: { + single: false, + }, + }); + + cy.get('[automation-id="tui-mobile-calendar__label"]').should( + 'contain.text', + 'Choose range', + ); + }); + + describe('when the done button emits', () => { + it('confirm event with selected day', () => { + cy.mount(TestComponent, { + imports: [TuiRootModule, TuiMobileCalendarModule], + componentProperties: { + onConfirm: createOutputSpy('onConfirmSpy'), + }, + }); + + cy.get( + '[automation-id="tui-primitive-calendar-mobile__cell"].t-cell_today', + ).click(); + cy.get('[automation-id="tui-mobile-calendar__confirm"]').click(); + cy.get('@onConfirmSpy').should('be.calledWith', today); + }); + + it('confirm event at selected interval', () => { + cy.mount(TestComponent, { + imports: [TuiRootModule, TuiMobileCalendarModule], + componentProperties: { + single: false, + onConfirm: createOutputSpy('onConfirmSpy'), + }, + }); + + cy.get( + '[automation-id="tui-primitive-calendar-mobile__cell"].t-cell_today', + ).click(); + cy.get('[automation-id="tui-mobile-calendar__confirm"]').click(); + cy.get('@onConfirmSpy').should( + 'be.calledWith', + new TuiDayRange(today, today), + ); + }); + + it('Year selection scrolls through months', () => { + cy.mount(TestComponent, { + imports: [TuiRootModule, TuiMobileCalendarModule], + componentProperties: { + onConfirm: createOutputSpy('onConfirmSpy'), + }, + }).then(wrapper => { + const testComponent = wrapper.component; + + testComponent.component.setYear(1950); + wrapper.fixture.detectChanges(); + + cy.wait(1000); // wait scroll + + cy.get('[automation-id="tui-primitive-calendar-mobile__cell"]:visible') + .eq(0) + .click(); + + cy.get('[automation-id="tui-mobile-calendar__confirm"]').click(); + }); + + cy.get('@onConfirmSpy') + .should('be.called') + .then(args => { + const spy = (args as any)?.getCalls()?.[0].args[0] as TuiDay; + + expect(spy.year).to.be.lessThan(1950); + }); + }); + }); +}); diff --git a/projects/demo-cypress/tsconfig.json b/projects/demo-cypress/tsconfig.json index 844ea99f0f938..08eff273ad888 100644 --- a/projects/demo-cypress/tsconfig.json +++ b/projects/demo-cypress/tsconfig.json @@ -4,6 +4,6 @@ "typeRoots": ["../../node_modules/@types", "../../node_modules/cypress/types"], "types": ["cypress", "node"] }, - "include": ["./cypress/**/*.ts"], + "include": ["**/*.ts", "**/*.d.ts"], "exclude": [] } diff --git a/projects/demo/src/modules/app/app.style.less b/projects/demo/src/modules/app/app.style.less index b30fbd373d603..0398d3b9bca5e 100644 --- a/projects/demo/src/modules/app/app.style.less +++ b/projects/demo/src/modules/app/app.style.less @@ -1,8 +1,4 @@ -@import '@taiga-ui/core/styles/taiga-ui-local.less'; -@import '@taiga-ui/core/styles/taiga-ui-theme.less'; -@import '@taiga-ui/core/styles/taiga-ui-fonts.less'; -@import '@taiga-ui/addon-mobile/styles/taiga-ui-mobile.less'; -@import '@taiga-ui/styles/taiga-ui-global.less'; +@import '@taiga-ui/core/styles/taiga-ui-local'; app { display: block; diff --git a/projects/demo/src/styles.less b/projects/demo/src/styles.less index 001f3e6eb9360..27319bb50e8ae 100644 --- a/projects/demo/src/styles.less +++ b/projects/demo/src/styles.less @@ -1,3 +1,8 @@ +@import '@taiga-ui/core/styles/taiga-ui-local.less'; +@import '@taiga-ui/core/styles/taiga-ui-theme.less'; +@import '@taiga-ui/core/styles/taiga-ui-fonts.less'; +@import '@taiga-ui/addon-mobile/styles/taiga-ui-mobile.less'; +@import '@taiga-ui/styles/taiga-ui-global.less'; @import '@taiga-ui/core/styles/taiga-ui-local'; html, diff --git a/projects/testing/cypress/assertions/be-in-viewport.ts b/projects/testing/cypress/assertions/be-in-viewport.ts deleted file mode 100644 index c5a8e2e5544d9..0000000000000 --- a/projects/testing/cypress/assertions/be-in-viewport.ts +++ /dev/null @@ -1,36 +0,0 @@ -/// -/// - -/** - * Check if element is inside viewport - * - * @note WARNING! `.should('be.visible')` doesn't not check if element is inside viewport - * @see https://github.com/cypress-io/cypress/issues/17483 - * @see https://github.com/cypress-io/cypress/issues/877#issuecomment-342187174 - * @see https://github.com/cypress-io/cypress/issues/877#issuecomment-657583222 - * @example - ```ts - cy.get('#test').should('be.inViewport'); - ``` - * */ -export const tuiBeInViewportAssertion: Chai.ChaiPlugin = _chai => { - chai.Assertion.addMethod('inViewport', function () { - const subject = this._obj; - const {top, bottom} = subject[0].getBoundingClientRect(); - - const viewportHeight: number = - // @ts-ignore TS2339: Property 'state' does not exist on type 'cy & CyEventEmitter'. - Cypress.$(cy.state('window')).height() || 0; - - const subjectOverlapsAllViewport = top < 0 && bottom > viewportHeight; - const topBorderIsVisible = top >= 0 && top < viewportHeight; - const bottomBorderIsVisible = bottom >= 0 && bottom < viewportHeight; - - this.assert( - subjectOverlapsAllViewport || topBorderIsVisible || bottomBorderIsVisible, - 'expected #{this} to be in viewport', - 'expected #{this} to not be in viewport', - subject, - ); - }); -}; diff --git a/projects/testing/cypress/assertions/index.ts b/projects/testing/cypress/assertions/index.ts deleted file mode 100644 index d3e9691fb83b5..0000000000000 --- a/projects/testing/cypress/assertions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './be-in-viewport'; diff --git a/projects/testing/cypress/commands/wait-all-img-inside.command.ts b/projects/testing/cypress/commands/wait-all-img-inside.command.ts deleted file mode 100644 index 4556beddb57c7..0000000000000 --- a/projects/testing/cypress/commands/wait-all-img-inside.command.ts +++ /dev/null @@ -1,81 +0,0 @@ -/// - -export const tuiWaitAllImgInside = ( - prevSubject: Cypress.PrevSubjectMap[Cypress.PrevSubject], - enabled: boolean = true, -): Cypress.Chainable> | Cypress.Chainable => { - const target = - prevSubject && Cypress.dom.isJquery(prevSubject) - ? cy.wrap(prevSubject, {log: false}) - : cy.get('body', {log: false}); - - target.then($target => { - const img = $target.find('img'); - - if (img.length && enabled) { - const log = Cypress.log({ - displayName: 'Wait all images', - message: 'naturalWidth greaterThan 0', - name: 'tuiWaitAllImgInside', - autoEnd: false, - consoleProps: () => ({ - prevSubject, - img, - }), - }); - - cy.wrap($target, {log: false}) - .get('img', {log: false}) - .each((img: JQuery) => { - const nativeImage = img.get(0); - const url = nativeImage?.src || nativeImage?.srcset; - - if (!url) { - return; - } - - const offsetParent = img.prop('offsetParent'); - - return cy.window({log: false}).then((win: Window) => { - const rect = nativeImage.getBoundingClientRect(); - const isInViewport = - offsetParent && - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= - (win.innerHeight || - win.document.documentElement.clientHeight) && - rect.right <= - (win.innerWidth || - win.document.documentElement.clientWidth); - - if (isInViewport) { - if (url.includes('base64')) { - (expect as any)( - nativeImage.naturalWidth, - ).to.be.greaterThan(0); - } else { - cy.request({ - url, - failOnStatusCode: false, - log: false, - }).then(resp => { - if (resp.status === 200) { - cy.get(img as any, {log: false}).should( - (el: JQuery) => - (expect as any)( - el[0].naturalWidth, - ).to.be.greaterThan(0), - ); - } - }); - } - } - }); - }) - .then(() => log.end()); - } - }); - - return target; -}; diff --git a/projects/testing/cypress/index.ts b/projects/testing/cypress/index.ts deleted file mode 100644 index c0088a022f12c..0000000000000 --- a/projects/testing/cypress/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './assertions'; -export * from './commands/wait-all-img-inside.command'; -export * from './snapshot/command'; -export * from './snapshot/plugin'; diff --git a/projects/testing/cypress/ng-package.json b/projects/testing/cypress/ng-package.json deleted file mode 100644 index bebf62dcb5e51..0000000000000 --- a/projects/testing/cypress/ng-package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "lib": { - "entryFile": "index.ts" - } -} diff --git a/projects/testing/cypress/snapshot/command.ts b/projects/testing/cypress/snapshot/command.ts deleted file mode 100644 index d1a96b4aaeecd..0000000000000 --- a/projects/testing/cypress/snapshot/command.ts +++ /dev/null @@ -1,62 +0,0 @@ -/// -// eslint-disable-next-line @taiga-ui/experience/no-deep-imports -import {tuiIsObject, tuiIsString} from '@taiga-ui/cdk/utils/miscellaneous'; -import {Options} from 'cypress-image-snapshot'; -import {matchImageSnapshotCommand} from 'cypress-image-snapshot/command'; - -import {tuiWaitAllImgInside} from '../commands/wait-all-img-inside.command'; - -declare module 'cypress-image-snapshot/command' { - function matchImageSnapshotCommand(options: Options): (...args: unknown[]) => void; -} - -interface TuiSnapshotCommandOptions { - waitAllImages?: boolean; -} - -declare global { - namespace Cypress { - interface Chainable { - matchImageSnapshot( - name: string, - options?: Options & TuiSnapshotCommandOptions, - ): void; - } - } -} - -function makeScreenshotName(name?: string): string { - return ( - name ?? - Cypress.currentTest.titlePath - .join('-') - .replace(/\s|-/g, '.') - .replace(/['[\]`()]/g, '') - .toLowerCase() - ); -} - -export function tuiAddMatchImageSnapshotCommand( - options: Options & TuiSnapshotCommandOptions, -): void { - const matchSnapshotFn = matchImageSnapshotCommand(options); - - Cypress.Commands.add( - 'matchImageSnapshot', - {prevSubject: ['optional', 'element', 'window', 'document']}, - ( - prevSubject, - nameOrOptions: string | (Options & TuiSnapshotCommandOptions), - options?: Options & TuiSnapshotCommandOptions, - ) => { - const name = tuiIsString(nameOrOptions) ? nameOrOptions : undefined; - const overloadedOptions = tuiIsObject(nameOrOptions) - ? nameOrOptions - : options; - - tuiWaitAllImgInside(prevSubject, overloadedOptions?.waitAllImages ?? true); - - matchSnapshotFn(prevSubject, makeScreenshotName(name), overloadedOptions); - }, - ); -} diff --git a/projects/testing/cypress/snapshot/plugin.ts b/projects/testing/cypress/snapshot/plugin.ts deleted file mode 100644 index c04aaaafa788d..0000000000000 --- a/projects/testing/cypress/snapshot/plugin.ts +++ /dev/null @@ -1,52 +0,0 @@ -/// -/// - -import fs from 'fs'; - -declare module 'cypress-image-snapshot/plugin' { - function matchImageSnapshotPlugin( - details: Cypress.ScreenshotDetails, - ): Cypress.AfterScreenshotReturnObject | void; -} - -export interface TuiSnapshotPluginOptions { - newSnapshotMarkEnabled: boolean; - newSnapshotMarkFn: (oldSnapshotFileName: string) => string; -} - -export async function tuiAddSnapshotPlugin( - on: Cypress.PluginEvents, - config: Cypress.PluginConfigOptions, - {newSnapshotMarkEnabled, newSnapshotMarkFn}: TuiSnapshotPluginOptions, -): Promise { - const {addMatchImageSnapshotPlugin, matchImageSnapshotPlugin} = await import( - 'cypress-image-snapshot/plugin' - ); - - addMatchImageSnapshotPlugin(on, config); - - on('after:screenshot', (details: Cypress.ScreenshotDetails) => { - const {name, path, testFailure} = details; - const possibleSnapshotPath = path - .replace('screenshots', 'snapshots') - .replace(/\.(\w+)$/g, '.snap.$1'); - const snapshotAlreadyExists = fs.existsSync(possibleSnapshotPath); - - if (newSnapshotMarkEnabled && !testFailure && !snapshotAlreadyExists) { - const newName = newSnapshotMarkFn(name); - const newPath = path.replace(name, newName); - - fs.renameSync(path, newPath); - - console.info( - '\x1B[32m%s\x1B[0m', - '\t[tuiAddSnapshotPlugin]:', - `${name} => ${newName}`, - ); - - return matchImageSnapshotPlugin({...details, path: newPath}); - } - - return matchImageSnapshotPlugin(details); - }); -}