From 3e607fe77c7c700808b966337c7114da364ec8b6 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Wed, 23 Mar 2022 12:12:59 -0300 Subject: [PATCH 01/35] chore: playwright config and start the first test --- .gitignore | 1 + package-lock.json | 1318 ++++++++++++++++++++++- package.json | 4 + playwright.config.ts | 18 + tests/e2e/00-login.spec.ts | 8 + tests/e2e/utils/globalcommands/login.ts | 5 + 6 files changed, 1351 insertions(+), 3 deletions(-) create mode 100644 playwright.config.ts create mode 100644 tests/e2e/00-login.spec.ts create mode 100644 tests/e2e/utils/globalcommands/login.ts diff --git a/.gitignore b/.gitignore index 1443aac7da70..c7d55c27baad 100644 --- a/.gitignore +++ b/.gitignore @@ -81,5 +81,6 @@ tests/end-to-end/temporary_staged_test /storybook-static /tests/cypress/screenshots /tests/cypress/videos +/tests/e2e/test-failures coverage .nyc_output diff --git a/package-lock.json b/package-lock.json index 9536ad20a496..b48de3fb3707 100644 --- a/package-lock.json +++ b/package-lock.json @@ -822,6 +822,33 @@ } } }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + } + } + }, "@babel/helper-explode-assignable-expression": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz", @@ -5146,6 +5173,657 @@ } } }, + "@playwright/test": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.20.0.tgz", + "integrity": "sha512-UpI5HTcgNLckR0kqXqwNvbcIXtRaDxk+hnO0OBwPSjfbBjRfRgAJ2ClA/b30C5E3UW5dJa17zhsy2qrk66l5cg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.16.7", + "@babel/core": "7.16.12", + "@babel/helper-plugin-utils": "7.16.7", + "@babel/plugin-proposal-class-properties": "7.16.7", + "@babel/plugin-proposal-dynamic-import": "7.16.7", + "@babel/plugin-proposal-export-namespace-from": "7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.7", + "@babel/plugin-proposal-numeric-separator": "7.16.7", + "@babel/plugin-proposal-optional-chaining": "7.16.7", + "@babel/plugin-proposal-private-methods": "7.16.11", + "@babel/plugin-proposal-private-property-in-object": "7.16.7", + "@babel/plugin-syntax-async-generators": "7.8.4", + "@babel/plugin-syntax-json-strings": "7.8.3", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "7.8.3", + "@babel/plugin-transform-modules-commonjs": "7.16.8", + "@babel/preset-typescript": "7.16.7", + "colors": "1.4.0", + "commander": "8.3.0", + "debug": "4.3.3", + "expect": "27.2.5", + "jest-matcher-utils": "27.2.5", + "json5": "2.2.0", + "mime": "3.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "open": "8.4.0", + "pirates": "4.0.4", + "playwright-core": "1.20.0", + "rimraf": "3.0.2", + "source-map-support": "0.4.18", + "stack-utils": "2.0.5", + "yazl": "2.5.1" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", + "dev": true + }, + "@babel/core": { + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.12", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", + "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.8.tgz", + "integrity": "sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.8.tgz", + "integrity": "sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==", + "dev": true + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-typescript": "^7.16.7" + } + }, + "@babel/preset-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz", + "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-transform-typescript": "^7.16.7" + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "browserslist": { + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001319", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz", + "integrity": "sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.4.90", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.90.tgz", + "integrity": "sha512-ZwKgSA0mQMyEhz+NR0F8dRzkrCLeHLzLkjx/CWf16+zV85hQ6meXPQbKanvhnpkYb7b2uJNj+enQJ/N877ND4Q==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "pirates": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", + "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "dev": true + }, + "playwright-core": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.20.0.tgz", + "integrity": "sha512-d25IRcdooS278Cijlp8J8A5fLQZ+/aY3dKRJvgX5yjXA69N0huIUdnh3xXSgn+LsQ9DCNmB7Ngof3eY630jgdA==", + "dev": true, + "requires": { + "colors": "1.4.0", + "commander": "8.3.0", + "debug": "4.3.3", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.0", + "jpeg-js": "0.4.3", + "mime": "3.0.0", + "pixelmatch": "5.2.1", + "pngjs": "6.0.0", + "progress": "2.0.3", + "proper-lockfile": "4.1.2", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "socks-proxy-agent": "6.1.1", + "stack-utils": "2.0.5", + "ws": "8.4.2", + "yauzl": "2.10.0", + "yazl": "2.5.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "ws": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz", + "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==", + "dev": true + } + } + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz", @@ -10408,6 +11086,12 @@ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, "@types/stream-buffers": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.3.tgz", @@ -15547,8 +16231,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true + "dev": true }, "combined-stream": { "version": "1.0.7", @@ -16985,6 +17668,12 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -17128,6 +17817,12 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -18973,6 +19668,101 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, + "expect": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.5.tgz", + "integrity": "sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-regex-util": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -23729,6 +24519,100 @@ "iterate-iterator": "^1.0.1" } }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, "jest-haste-map": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", @@ -23815,6 +24699,292 @@ } } }, + "jest-matcher-utils": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz", + "integrity": "sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.2.5", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, "jest-regex-util": { "version": "26.0.0", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", @@ -23992,6 +25162,12 @@ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", "dev": true }, + "jpeg-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", + "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==", + "dev": true + }, "jquery": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", @@ -24544,7 +25720,7 @@ "dev": true }, "lamejs": { - "version": "git+https://github.com/zhuker/lamejs.git#582bbba6a12f981b984d8fb9e1874499fed85675", + "version": "git+https://github.com/zhuker/lamejs.git#564612b5b57336238a5920ba4c301b49f7cb2bab", "from": "git+https://github.com/zhuker/lamejs.git", "requires": { "use-strict": "1.0.1" @@ -29232,6 +30408,23 @@ "node-modules-regexp": "^1.0.0" } }, + "pixelmatch": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.2.1.tgz", + "integrity": "sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==", + "dev": true, + "requires": { + "pngjs": "^4.0.1" + }, + "dependencies": { + "pngjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-4.0.1.tgz", + "integrity": "sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==", + "dev": true + } + } + }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -29300,6 +30493,12 @@ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" }, + "pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true + }, "pnp-webpack-plugin": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", @@ -31069,6 +32268,25 @@ "react-is": "^16.8.1" } }, + "proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + } + } + }, "property-information": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", @@ -31121,6 +32339,12 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -33434,6 +34658,12 @@ "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=" }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, "snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -33577,6 +34807,53 @@ } } }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "sodium-native": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.2.1.tgz", @@ -33637,6 +34914,15 @@ "urix": "^0.1.0" } }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -33781,6 +35067,23 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "stackframe": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", @@ -38412,6 +39715,15 @@ "fd-slicer": "~1.1.0" } }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 26d6de7bb25a..6057ced66c02 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,9 @@ "testunit-definition": "mocha --config ./.mocharc.definition.js", "testunit-watch": "mocha --watch --config ./.mocharc.js", "test": "npm run testapi && npm run testui", + "test:playwright": "playwright test", + "test:playwright:watch": "PWDEBUG=1 playwright test", + "test:playwright:headed": "playwright test --headed", "translation-diff": "node .scripts/translationDiff.js", "translation-check": "node .scripts/check-i18n.js", "translation-fix-order": "node .scripts/fix-i18n.js", @@ -62,6 +65,7 @@ "@babel/preset-env": "^7.14.7", "@babel/preset-react": "^7.14.5", "@babel/register": "^7.14.5", + "@playwright/test": "^1.20.0", "@rocket.chat/eslint-config": "^0.4.0", "@rocket.chat/livechat": "^1.12.1", "@settlin/spacebars-loader": "^1.0.9", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 000000000000..a671c785224e --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,18 @@ +import { PlaywrightTestConfig } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + outputDir: 'tests/e2e/test-failures', + reporter: [['line']], + timeout: 10000, + use: { + baseURL: process.env.BASE_URL || 'http://localhost:3000/', + headless: false, + viewport: { width: 1200, height: 720 }, + ignoreHTTPSErrors: true, + video: 'retain-on-failure', + screenshot: 'only-on-failure', + trace: 'retain-on-failure', + }, + testDir: 'tests/e2e', +}; +export default config; diff --git a/tests/e2e/00-login.spec.ts b/tests/e2e/00-login.spec.ts new file mode 100644 index 000000000000..99b4aec8a616 --- /dev/null +++ b/tests/e2e/00-login.spec.ts @@ -0,0 +1,8 @@ +import { test, expect } from '@playwright/test'; + +test('basic test', async ({ page, baseURL }) => { + await page.goto('https://playwright.dev/'); + console.log(baseURL); + const title = page.locator('.navbar__inner .navbar__title'); + await expect(title).toHaveText('Playwright'); +}); diff --git a/tests/e2e/utils/globalcommands/login.ts b/tests/e2e/utils/globalcommands/login.ts new file mode 100644 index 000000000000..db7de8d209b6 --- /dev/null +++ b/tests/e2e/utils/globalcommands/login.ts @@ -0,0 +1,5 @@ +import { Page } from '@playwright/test'; + +const makeLogin = (page: Page): Page => { + return page.locator(''); +}; From 67f8a427220e78f7420b4f974221f557aeac532b Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Thu, 24 Mar 2022 17:43:19 -0300 Subject: [PATCH 02/35] chore: configuration of files to run playwright --- app.json | 41 +++++++++++++++++++++++------------------ package.json | 3 ++- playwright.config.ts | 9 +++++---- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/app.json b/app.json index 1513ba1382a8..d079803f58a0 100644 --- a/app.json +++ b/app.json @@ -1,20 +1,25 @@ { - "name": "Rocket.Chat", - "description": "Have your own open-source Slack-like online chat platform.", - "repository": "https://github.com/RocketChat/Rocket.Chat", - "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", - "keywords": ["meteor", "social", "community", "chat"], - "website": "https://rocket.chat", - "env": { - "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", - "HEROKU_APP_NAME": { - "description": "Please re-enter your App Name from the top.", - "required": true - }, - "DEPLOY_PLATFORM": "heroku" - }, - "addons": [ - "mongolab", - "logentries" - ] + "name": "Rocket.Chat", + "description": "Have your own open-source Slack-like online chat platform.", + "repository": "https://github.com/RocketChat/Rocket.Chat", + "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", + "keywords": [ + "meteor", + "social", + "community", + "chat" + ], + "website": "https://rocket.chat", + "env": { + "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", + "HEROKU_APP_NAME": { + "description": "Please re-enter your App Name from the top.", + "required": true + }, + "DEPLOY_PLATFORM": "heroku" + }, + "addons": [ + "mongolab", + "logentries" + ] } diff --git a/package.json b/package.json index 6057ced66c02..dafdd91c9fc7 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ ], "scripts": { "prepare": "husky install", - "start": "meteor", + "start": "TEST_MODE=true meteor", + "dev": "meteor reset && npm start", "ha": "meteor npm run ha:start", "ha:start": "ts-node .scripts/run-ha.ts main", "ha:add": "ts-node .scripts/run-ha.ts instance", diff --git a/playwright.config.ts b/playwright.config.ts index a671c785224e..ffbb6551a6a5 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,11 +2,12 @@ import { PlaywrightTestConfig } from '@playwright/test'; const config: PlaywrightTestConfig = { outputDir: 'tests/e2e/test-failures', - reporter: [['line']], - timeout: 10000, + reporter: [['list']], + workers: 3, + globalSetup: require.resolve('./tests/e2e/globalsetup/globalSetup'), use: { - baseURL: process.env.BASE_URL || 'http://localhost:3000/', - headless: false, + baseURL: process.env.BASE_URL || 'http://localhost:3000', + headless: true, viewport: { width: 1200, height: 720 }, ignoreHTTPSErrors: true, video: 'retain-on-failure', From 0d9291ae5b96ef6b61f44fbe8007ff9c52261707 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Thu, 24 Mar 2022 17:44:08 -0300 Subject: [PATCH 03/35] test: ensure all flow of unlloged area is work --- tests/e2e/00-login.spec.ts | 8 -- tests/e2e/00-register.spec.ts | 119 +++++++++++++++++++ tests/e2e/01-login.spec.ts | 28 +++++ tests/e2e/02-forgot-password.spec.ts | 45 +++++++ tests/e2e/globalsetup/globalSetup.ts | 5 + tests/e2e/utils/globalcommands/login.ts | 5 - tests/e2e/utils/interfaces/Login.ts | 10 ++ tests/e2e/utils/mocks/userAndPasswordMock.ts | 23 ++++ tests/e2e/utils/pageobjects/Pages.ts | 24 ++++ tests/e2e/utils/pageobjects/login.page.ts | 114 ++++++++++++++++++ 10 files changed, 368 insertions(+), 13 deletions(-) delete mode 100644 tests/e2e/00-login.spec.ts create mode 100644 tests/e2e/00-register.spec.ts create mode 100644 tests/e2e/01-login.spec.ts create mode 100644 tests/e2e/02-forgot-password.spec.ts create mode 100644 tests/e2e/globalsetup/globalSetup.ts delete mode 100644 tests/e2e/utils/globalcommands/login.ts create mode 100644 tests/e2e/utils/interfaces/Login.ts create mode 100644 tests/e2e/utils/mocks/userAndPasswordMock.ts create mode 100644 tests/e2e/utils/pageobjects/Pages.ts create mode 100644 tests/e2e/utils/pageobjects/login.page.ts diff --git a/tests/e2e/00-login.spec.ts b/tests/e2e/00-login.spec.ts deleted file mode 100644 index 99b4aec8a616..000000000000 --- a/tests/e2e/00-login.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { test, expect } from '@playwright/test'; - -test('basic test', async ({ page, baseURL }) => { - await page.goto('https://playwright.dev/'); - console.log(baseURL); - const title = page.locator('.navbar__inner .navbar__title'); - await expect(title).toHaveText('Playwright'); -}); diff --git a/tests/e2e/00-register.spec.ts b/tests/e2e/00-register.spec.ts new file mode 100644 index 000000000000..f0f7ad620ad0 --- /dev/null +++ b/tests/e2e/00-register.spec.ts @@ -0,0 +1,119 @@ +import { test, expect } from '@playwright/test'; + +import { incorrectUser, registerUser } from './utils/mocks/userAndPasswordMock'; +import LoginPage from './utils/pageobjects/login.page'; + +// test.describe('[Wizard]', () => { +// let loginPage: LoginPage; +// test.beforeAll(async ({ browser, baseURL }) => { +// loginPage = new LoginPage(browser, baseURL as string); +// await loginPage.open(); +// }); +// }); +test.describe.configure({ mode: 'parallel' }); +test.describe('[Register]', () => { + let loginPage: LoginPage; + test.beforeAll(async ({ browser, baseURL }) => { + loginPage = new LoginPage(browser, baseURL as string); + await loginPage.open(); + }); + test.beforeEach(async () => { + await loginPage.goto(''); + }); + test('expect login is failed', async () => { + await loginPage.login(incorrectUser); + const toastError = loginPage.getToastError(); + expect(toastError).toBeVisible(); + expect(toastError).toHaveText('User not found or incorrect password'); + }); + // TODO verify register flow + test('expect new user is created', async () => { + await loginPage.gotToRegister(); + await loginPage.registerNewUser(registerUser); + + const submitButton = loginPage.registerNextButton(); + await submitButton.click(); + await expect(loginPage.getHomeMessage()).toContainText('Home'); + }); + + test('expect when user dont inform user and password error message is showed', async () => { + await loginPage.submit(); + await expect(loginPage.emailOrUsernameInvalidText()).toHaveText('The email entered is invalid'); + await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); + }); + + test('expect when user dont inform password error message is showed', async () => { + const emailErrorInput = loginPage.emailOrUsernameField(); + await emailErrorInput.type('any_email@email.com'); + await loginPage.submit(); + expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); + }); + + test('expect when user dont inform user error message is showed', async () => { + const passwordErrorInput = loginPage.passwordField(); + await passwordErrorInput.type('any_password'); + await loginPage.submit(); + await expect(loginPage.emailOrUsernameInvalidText()).toHaveText('The email entered is invalid'); + }); + + test('expect user click in register button without data', async () => { + await loginPage.gotToRegister(); + await loginPage.submit(); + + await expect(loginPage.nameInvalidText()).toHaveText('The name must not be empty'); + await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); + await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); + }); + + test('expect user click in register button email and password', async () => { + await loginPage.gotToRegister(); + + const inputName = loginPage.nameField(); + await inputName.type('any_name'); + await loginPage.submit(); + await expect(loginPage.nameInvalidText()).not.toBeVisible(); + await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); + await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); + }); + + test('expect user click in register button withoud name and password', async () => { + await loginPage.gotToRegister(); + + const inputEmail = loginPage.emailField(); + await inputEmail.type('any_mail@email.com'); + await loginPage.submit(); + await expect(loginPage.emailInvalidText()).not.toBeVisible(); + await expect(loginPage.nameInvalidText()).toHaveText('The name must not be empty'); + await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); + }); + + test('expect user click in register button withoud name and email', async () => { + await loginPage.gotToRegister(); + + const passwordFiled = loginPage.passwordField(); + await passwordFiled.type('any_mail@email.com'); + await loginPage.submit(); + await expect(loginPage.passwordInvalidText()).not.toBeVisible(); + await expect(loginPage.nameInvalidText()).toHaveText('The name must not be empty'); + await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); + }); + + test('expect user click in register button with diferent password', async () => { + await loginPage.gotToRegister(); + + const passwordField = loginPage.passwordField(); + await passwordField.type('any_mail@email.com'); + + const inputEmail = loginPage.emailField(); + await inputEmail.type('any_mail@email.com'); + + const inputName = loginPage.nameField(); + await inputName.type('any_name'); + + await loginPage.confirmPasswordField().type('any_passwor'); + + await loginPage.submit(); + await expect(loginPage.confirmPasswordInvalidText()).toBeVisible(); + await expect(loginPage.confirmPasswordInvalidText()).toHaveText('The password confirmation does not match password'); + }); +}); diff --git a/tests/e2e/01-login.spec.ts b/tests/e2e/01-login.spec.ts new file mode 100644 index 000000000000..8b657a5a0b64 --- /dev/null +++ b/tests/e2e/01-login.spec.ts @@ -0,0 +1,28 @@ +import { test, expect } from '@playwright/test'; + +import { validUser } from './utils/mocks/userAndPasswordMock'; +import LoginPage from './utils/pageobjects/login.page'; + +test.describe('[Login]', () => { + let loginPage: LoginPage; + test.beforeEach(async ({ browser, baseURL }) => { + loginPage = new LoginPage(browser, baseURL as string); + await loginPage.open(); + }); + + test('expect user make login', async () => { + await loginPage.login(validUser); + await expect(loginPage.getHomeMessage()).toContainText('Home'); + }); + + test('expect user write a password incorrectely', async () => { + const invalidUserPassword = { + email: validUser.email, + password: 'any_password1', + }; + await loginPage.login(invalidUserPassword); + const toastError = loginPage.getToastError(); + await expect(toastError).toBeVisible(); + await expect(toastError).toHaveText('User not found or incorrect password'); + }); +}); diff --git a/tests/e2e/02-forgot-password.spec.ts b/tests/e2e/02-forgot-password.spec.ts new file mode 100644 index 000000000000..7ec0e3f92d5a --- /dev/null +++ b/tests/e2e/02-forgot-password.spec.ts @@ -0,0 +1,45 @@ +import { test, expect } from '@playwright/test'; + +import LoginPage from './utils/pageobjects/login.page'; + +test.describe('recoverPassword', () => { + let loginPage: LoginPage; + test.beforeAll(async ({ browser, baseURL }) => { + loginPage = new LoginPage(browser, baseURL as string); + await loginPage.open(); + }); + + test.beforeEach(async () => { + await loginPage.goto(''); + await loginPage.gotToForgotPassword(); + }); + + test('it should be required', async () => { + loginPage.submit(); + // loginPage.emailField.should('have.class', 'error'); + await expect(loginPage.emailInvalidText()).toBeVisible(); + }); + + test('it should be invalid for email without domain', async () => { + const emailField = loginPage.emailField(); + await emailField.type('invalidmail'); + await loginPage.submit(); + // loginPage.emailField.should('have.class', 'error'); + await expect(loginPage.emailInvalidText()).toBeVisible(); + }); + + test('it should be invalid for email with invalid domain', async () => { + const emailField = loginPage.emailField(); + await emailField.type('email@mail'); + await loginPage.submit(); + await expect(loginPage.emailInvalidText()).toBeVisible(); + }); + + test('expect user type a valçid email', async () => { + const emailField = loginPage.emailField(); + await emailField.type('any_user@gmail.com'); + await loginPage.submit(); + const toastMessageSuccess = loginPage.getToastMessageSuccess(); + await expect(toastMessageSuccess).toBeVisible(); + }); +}); diff --git a/tests/e2e/globalsetup/globalSetup.ts b/tests/e2e/globalsetup/globalSetup.ts new file mode 100644 index 000000000000..f24aa11d88ad --- /dev/null +++ b/tests/e2e/globalsetup/globalSetup.ts @@ -0,0 +1,5 @@ +const globalSetup = (): void => { + console.log(process.env.TEST_MODE); +}; + +export default globalSetup; diff --git a/tests/e2e/utils/globalcommands/login.ts b/tests/e2e/utils/globalcommands/login.ts deleted file mode 100644 index db7de8d209b6..000000000000 --- a/tests/e2e/utils/globalcommands/login.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Page } from '@playwright/test'; - -const makeLogin = (page: Page): Page => { - return page.locator(''); -}; diff --git a/tests/e2e/utils/interfaces/Login.ts b/tests/e2e/utils/interfaces/Login.ts new file mode 100644 index 000000000000..fdba700a1851 --- /dev/null +++ b/tests/e2e/utils/interfaces/Login.ts @@ -0,0 +1,10 @@ +export interface ILogin { + email: string; + password: string; +} + +export interface IRegister { + email: string; + password: string; + name: string; +} diff --git a/tests/e2e/utils/mocks/userAndPasswordMock.ts b/tests/e2e/utils/mocks/userAndPasswordMock.ts new file mode 100644 index 000000000000..023e05739410 --- /dev/null +++ b/tests/e2e/utils/mocks/userAndPasswordMock.ts @@ -0,0 +1,23 @@ +import { v4 } from 'uuid'; + +import { ILogin, IRegister } from '../interfaces/Login'; + +export const username = 'user.test'; +export const email = `${username}@rocket.chat`; +export const password = 'rocket.chat'; + +export const registerUser: IRegister = { + email: `${v4()}@email.com`, + password: 'any_password', + name: `any_name${v4()}`, +}; + +export const validUser: ILogin = { + email: 'rocketchat.internal.admin.test@rocket.chat', + password: 'rocketchat.internal.admin.test', +}; + +export const incorrectUser: ILogin = { + email: `${v4()}@email.com`, + password: 'any_password', +}; diff --git a/tests/e2e/utils/pageobjects/Pages.ts b/tests/e2e/utils/pageobjects/Pages.ts new file mode 100644 index 000000000000..44bb4eb15394 --- /dev/null +++ b/tests/e2e/utils/pageobjects/Pages.ts @@ -0,0 +1,24 @@ +import { Browser, Page } from '@playwright/test'; + +class Pages { + protected page: Page; + + constructor(protected readonly browser: Browser, protected readonly baseURL: string) {} + + public async open(path: string): Promise { + const context = await this.browser.newContext(); + this.page = await context.newPage(); + this.page.setDefaultNavigationTimeout(50000); + await this.goto(path); + } + + // TODO remover + public async pause(): Promise { + await this.page.pause(); + } + + public async goto(path: string): Promise { + await this.page.goto(`${this.baseURL}/${path}`); + } +} +export default Pages; diff --git a/tests/e2e/utils/pageobjects/login.page.ts b/tests/e2e/utils/pageobjects/login.page.ts new file mode 100644 index 000000000000..86b9652a344f --- /dev/null +++ b/tests/e2e/utils/pageobjects/login.page.ts @@ -0,0 +1,114 @@ +import { FrameLocator, Locator } from '@playwright/test'; + +import { ILogin, IRegister } from '../interfaces/Login'; +import Pages from './Pages'; + +class LoginPage extends Pages { + private registerButton(): Locator { + return this.page.locator('button.register'); + } + + get forgotPasswordButton(): FrameLocator { + return this.page.locator('.forgot-password'); + } + + public submitButton(): Locator { + return this.page.locator('.login'); + } + + public registerNextButton(): Locator { + return this.page.locator('button[data-loading-text=" Please_wait ..."]'); + } + + public registerMessage(): Locator { + return this.page.locator('//form[@id["login-card"]]//header//p'); + } + + public emailOrUsernameField(): Locator { + return this.page.locator('[name=emailOrUsername]'); + } + + public nameField(): Locator { + return this.page.locator('[name=name]'); + } + + public emailField(): Locator { + return this.page.locator('[name=email]'); + } + + public passwordField(): Locator { + return this.page.locator('[name=pass]'); + } + + public userNameField(): Locator { + return this.page.locator('[name=username]'); + } + + public confirmPasswordField(): Locator { + return this.page.locator('[name=confirm-pass]'); + } + + public getToastError(): Locator { + return this.page.locator('.toast'); + } + + public getToastMessageSuccess(): Locator { + return this.page.locator('.toast-message'); + } + + public emailOrUsernameInvalidText(): Locator { + return this.page.locator('[name=emailOrUsername]~.input-error'); + } + + public nameInvalidText(): Locator { + return this.page.locator('[name=name]~.input-error'); + } + + public emailInvalidText(): Locator { + return this.page.locator('[name=email]~.input-error'); + } + + public passwordInvalidText(): Locator { + return this.page.locator('[name=pass]~.input-error'); + } + + public confirmPasswordInvalidText(): Locator { + return this.page.locator('[name=confirm-pass]~.input-error'); + } + + public getHomeMessage(): Locator { + return this.page.locator('//span[@class="rc-header__block"]'); + } + + public async open(): Promise { + await super.open(''); + } + + public async gotToRegister(): Promise { + await this.registerButton().click(); + } + + public async gotToForgotPassword(): Promise { + await this.forgotPasswordButton.click(); + } + + public async registerNewUser({ name, email, password }: IRegister): Promise { + await this.nameField().type(name); + await this.emailField().type(email); + await this.passwordField().type(password); + await this.confirmPasswordField().type(password); + await this.submit(); + } + + public async login({ email, password }: ILogin): Promise { + await this.emailOrUsernameField().type(email); + await this.passwordField().type(password); + await this.submitButton().click(); + } + + public async submit(): Promise { + await this.submitButton().click(); + } +} + +export default LoginPage; From 3c1c421c776ef52f2d617c9d4298e9d954c7b813 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Fri, 25 Mar 2022 12:21:58 -0300 Subject: [PATCH 04/35] test: wizard page --- tests/e2e/0-wizard.spec.ts | 35 +++++++ tests/e2e/utils/mocks/userAndPasswordMock.ts | 4 + tests/e2e/utils/pageobjects/login.page.ts | 6 +- tests/e2e/utils/pageobjects/wizzard.page.ts | 102 +++++++++++++++++++ 4 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/0-wizard.spec.ts create mode 100644 tests/e2e/utils/pageobjects/wizzard.page.ts diff --git a/tests/e2e/0-wizard.spec.ts b/tests/e2e/0-wizard.spec.ts new file mode 100644 index 000000000000..f2e616d15c3a --- /dev/null +++ b/tests/e2e/0-wizard.spec.ts @@ -0,0 +1,35 @@ +import { test, expect } from '@playwright/test'; + +import SetupWizzard from './utils/pageobjects/wizzard.page'; +import { adminUsername, adminEmail, adminPassword } from './utils/mocks/userAndPasswordMock'; + +test.describe('[Wizzard]', () => { + let setupWizard: SetupWizzard; + + test.beforeAll(async ({ browser, baseURL }) => { + setupWizard = new SetupWizzard(browser, baseURL); + await setupWizard.open(''); + }); + + test.describe('[Step 1]', () => { + test('expect required field alert showed when user dont inform data', async () => { + await setupWizard.goNext(); + + await expect(setupWizard.fullNameIvalidtext()).toBeVisible(); + await expect(setupWizard.userNameInvalidText()).toBeVisible(); + await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); + await expect(setupWizard.passwordInvalidText()).toBeVisible(); + }); + }); + + test('expect alert showed when email provided is invalid', async () => { + await setupWizard.fullName().type('Any admin Name'); + await setupWizard.userName().type(adminUsername); + await setupWizard.companyEmail().type('useremail'); + await setupWizard.password().type(adminPassword); + + await setupWizard.goNext(); + + await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); + }); +}); diff --git a/tests/e2e/utils/mocks/userAndPasswordMock.ts b/tests/e2e/utils/mocks/userAndPasswordMock.ts index 023e05739410..6d589b44d8b3 100644 --- a/tests/e2e/utils/mocks/userAndPasswordMock.ts +++ b/tests/e2e/utils/mocks/userAndPasswordMock.ts @@ -5,6 +5,10 @@ import { ILogin, IRegister } from '../interfaces/Login'; export const username = 'user.test'; export const email = `${username}@rocket.chat`; export const password = 'rocket.chat'; +export const reason = 'rocket.chat.reason'; +export const adminUsername = 'rocketchat.internal.admin.test'; +export const adminEmail = `${adminUsername}@rocket.chat`; +export const adminPassword = adminUsername; export const registerUser: IRegister = { email: `${v4()}@email.com`, diff --git a/tests/e2e/utils/pageobjects/login.page.ts b/tests/e2e/utils/pageobjects/login.page.ts index 86b9652a344f..5ec88873fea6 100644 --- a/tests/e2e/utils/pageobjects/login.page.ts +++ b/tests/e2e/utils/pageobjects/login.page.ts @@ -1,4 +1,4 @@ -import { FrameLocator, Locator } from '@playwright/test'; +import { Locator } from '@playwright/test'; import { ILogin, IRegister } from '../interfaces/Login'; import Pages from './Pages'; @@ -8,7 +8,7 @@ class LoginPage extends Pages { return this.page.locator('button.register'); } - get forgotPasswordButton(): FrameLocator { + private forgotPasswordButton(): Locator { return this.page.locator('.forgot-password'); } @@ -89,7 +89,7 @@ class LoginPage extends Pages { } public async gotToForgotPassword(): Promise { - await this.forgotPasswordButton.click(); + await this.forgotPasswordButton().click(); } public async registerNewUser({ name, email, password }: IRegister): Promise { diff --git a/tests/e2e/utils/pageobjects/wizzard.page.ts b/tests/e2e/utils/pageobjects/wizzard.page.ts new file mode 100644 index 000000000000..1c3120a642f4 --- /dev/null +++ b/tests/e2e/utils/pageobjects/wizzard.page.ts @@ -0,0 +1,102 @@ +import { Locator } from '@playwright/test'; + +import Pages from './Pages'; +import LoginPage from './login.page'; +import { adminEmail, adminPassword } from '../mocks/userAndPasswordMock'; + +class SetupWizard extends Pages { + private nextStep(): Locator { + return this.page.locator('//button[contains(text(), "Next")]'); + } + + public fullName(): Locator { + return this.page.locator('[name="fullname"]'); + } + + public userName(): Locator { + return this.page.locator('[name="username"]'); + } + + public companyEmail(): Locator { + return this.page.locator('[name="companyEmail"]'); + } + + public password(): Locator { + return this.page.locator('[name="password"]'); + } + + public goToWorkspace(): Locator { + return this.page.locator('//button[contains(text(), "Confirm")]'); + } + + public organizationType(): Locator { + return this.page.locator('[name="organizationType"]'); + } + + public organizationName(): Locator { + return this.page.locator('[name="organizationName"]'); + } + + public industry(): Locator { + return this.page.locator('[name="organizationIndustry"]'); + } + + public size(): Locator { + return this.page.locator('[name="organizationSize"]'); + } + + public country(): Locator { + return this.page.locator('[name="country"]'); + } + + public registeredServer(): Locator { + return this.page.locator('input[name=email]'); + } + + public registerButton(): Locator { + return this.page.locator('button:contains("Register")'); + } + + // public agreementField(): Locator { + // return this.page.locator('input[name=agreement]').closest('.rcx-check-box'); + // } + + public standaloneServer(): Locator { + return this.page.locator('button:contains("Continue as standalone")'); + } + + public standaloneConfirmText(): Locator { + return this.page.locator('.rcx-box:contains("Standalone Server Confirmation")'); + } + + public fullNameIvalidtext(): Locator { + return this.page.locator('//input[@name="fullname"]/../following-sibling::span'); + } + + public userNameInvalidText(): Locator { + return this.page.locator('//input[@name="username"]/../following-sibling::span'); + } + + public companyEmailInvalidText(): Locator { + return this.page.locator('//input[@name="companyEmail"]/../following-sibling::span'); + } + + public passwordInvalidText(): Locator { + return this.page.locator('//input[@name="password"]/../../../span[contains(@class, "rcx-field__error")]'); + } + + public async login(): Promise { + const loginObj = new LoginPage(this.browser, this.baseURL); + await loginObj.login({ email: adminEmail, password: adminPassword }); + } + + public async goNext(): Promise { + await this.nextStep().click(); + } + + // goToHome() { + // this.goToWorkspace.click(); + // } +} + +export default SetupWizard; From 63d2370f27f2523af934378329addb5e762c485c Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Mon, 28 Mar 2022 12:20:47 -0300 Subject: [PATCH 05/35] test: implements wizard on playwright --- tests/e2e/0-wizard.spec.ts | 113 +++++++++++-- tests/e2e/utils/pageobjects/Pages.ts | 4 + tests/e2e/utils/pageobjects/wizard.page.ts | 172 ++++++++++++++++++++ tests/e2e/utils/pageobjects/wizzard.page.ts | 102 ------------ 4 files changed, 277 insertions(+), 114 deletions(-) create mode 100644 tests/e2e/utils/pageobjects/wizard.page.ts delete mode 100644 tests/e2e/utils/pageobjects/wizzard.page.ts diff --git a/tests/e2e/0-wizard.spec.ts b/tests/e2e/0-wizard.spec.ts index f2e616d15c3a..d726dd80e4cc 100644 --- a/tests/e2e/0-wizard.spec.ts +++ b/tests/e2e/0-wizard.spec.ts @@ -1,17 +1,21 @@ import { test, expect } from '@playwright/test'; -import SetupWizzard from './utils/pageobjects/wizzard.page'; -import { adminUsername, adminEmail, adminPassword } from './utils/mocks/userAndPasswordMock'; +import SetupWizard from './utils/pageobjects/wizard.page'; +import { adminUsername, adminPassword } from './utils/mocks/userAndPasswordMock'; -test.describe('[Wizzard]', () => { - let setupWizard: SetupWizzard; +test.describe('[Wizard]', () => { + let setupWizard: SetupWizard; test.beforeAll(async ({ browser, baseURL }) => { - setupWizard = new SetupWizzard(browser, baseURL); + setupWizard = new SetupWizard(browser, baseURL as string); await setupWizard.open(''); }); test.describe('[Step 1]', () => { + test.beforeEach(async () => { + await setupWizard.goto(''); + }); + test('expect required field alert showed when user dont inform data', async () => { await setupWizard.goNext(); @@ -20,16 +24,101 @@ test.describe('[Wizzard]', () => { await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); await expect(setupWizard.passwordInvalidText()).toBeVisible(); }); + + test('expect alert showed when email provided is invalid', async () => { + await setupWizard.fullName().type('Any admin Name'); + await setupWizard.userName().type(adminUsername); + await setupWizard.companyEmail().type('useremail'); + await setupWizard.password().type(adminPassword); + + await setupWizard.goNext(); + + await expect(setupWizard.companyEmail()).toBeFocused(); + }); + + test('expect go to Step 2 successfully', async () => { + await setupWizard.stepOneSucess(); + + await expect(setupWizard.getPage()).toHaveURL(/.*\/setup-wizard\/2/); + }); }); - test('expect alert showed when email provided is invalid', async () => { - await setupWizard.fullName().type('Any admin Name'); - await setupWizard.userName().type(adminUsername); - await setupWizard.companyEmail().type('useremail'); - await setupWizard.password().type(adminPassword); + test.describe('[Step 2]', async () => { + test.beforeEach(async () => { + await setupWizard.goto(''); + await setupWizard.stepOneSucess(); + }); + + test('expect required field alert showed when user dont inform data', async () => { + await setupWizard.goNext(); + + await expect(setupWizard.organizationName()).toBeVisible(); + await expect(setupWizard.industryInvalidSelect()).toBeVisible(); + await expect(setupWizard.sizeInvalidSelect()).toBeVisible(); + await expect(setupWizard.countryInvalidSelect()).toBeVisible(); + }); - await setupWizard.goNext(); + test('expect go to Step 3 successfully', async () => { + await setupWizard.stepTwoSucess(); + await expect(setupWizard.getPage()).toHaveURL(/.*\/setup-wizard\/3/); + }); + }); + + test.describe.only('[Step 3]', async () => { + test.beforeEach(async () => { + await setupWizard.goto(''); + await setupWizard.stepOneSucess(); + await setupWizard.stepTwoSucess(); + }); - await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); + test('expect have email field to register the server', async () => { + await expect(setupWizard.registeredServer()).toBeVisible(); + }); + + test('expect start wtesth "Register" button disabled', async () => { + await expect(setupWizard.registerButton()).toBeDisabled(); + }); + + test('expect show an error on invalid email', async () => { + await setupWizard.registeredServer().type('a'); + await setupWizard.registeredServer().click({ clickCount: 3 }); + await setupWizard.getPage().keyboard.press('Backspace'); + + await expect( + setupWizard.getPage().locator('//input[@name="email"]/../../span[contains(text(), "This field is required")]'), + ).toBeVisible(); + }); + + test('expect enable "Register" button when email is valid and terms checked', async () => { + await setupWizard.registeredServer().type('email@email.com'); + await setupWizard.agreementField().click(); + await expect(setupWizard.registerButton()).toBeEnabled(); + }); + + test('expect have option for standalone server', async () => { + await expect(setupWizard.standaloneServer()).toBeVisible(); + }); + + test('expect continue when clicking on "Continue as standalone"', async () => { + await setupWizard.standaloneServer().click(); + }); + }); + + test.describe('[Final Step]', async () => { + test.beforeEach(async () => { + await setupWizard.goto(''); + await setupWizard.stepOneSucess(); + await setupWizard.stepTwoSucess(); + await setupWizard.stepThreeSucess(); + }); + + test('expect confirm the standalone option', async () => { + await expect(setupWizard.goToWorkspace()).toBeVisible(); + await expect(setupWizard.standaloneConfirmText()).toBeVisible(); + }); + + test('expect confirm standalone', async () => { + await setupWizard.goToWorkspace().click(); + }); }); }); diff --git a/tests/e2e/utils/pageobjects/Pages.ts b/tests/e2e/utils/pageobjects/Pages.ts index 44bb4eb15394..d11423b62704 100644 --- a/tests/e2e/utils/pageobjects/Pages.ts +++ b/tests/e2e/utils/pageobjects/Pages.ts @@ -20,5 +20,9 @@ class Pages { public async goto(path: string): Promise { await this.page.goto(`${this.baseURL}/${path}`); } + + public getPage(): Page { + return this.page; + } } export default Pages; diff --git a/tests/e2e/utils/pageobjects/wizard.page.ts b/tests/e2e/utils/pageobjects/wizard.page.ts new file mode 100644 index 000000000000..81120173d208 --- /dev/null +++ b/tests/e2e/utils/pageobjects/wizard.page.ts @@ -0,0 +1,172 @@ +import { expect, Locator } from '@playwright/test'; + +import Pages from './Pages'; +import LoginPage from './login.page'; +import { adminUsername, adminEmail, adminPassword, reason } from '../mocks/userAndPasswordMock'; + +class SetupWizard extends Pages { + private nextStep(): Locator { + return this.page.locator('//button[contains(text(), "Next")]'); + } + + public fullName(): Locator { + return this.page.locator('[name="fullname"]'); + } + + public userName(): Locator { + return this.page.locator('[name="username"]'); + } + + public companyEmail(): Locator { + return this.page.locator('[name="companyEmail"]'); + } + + public password(): Locator { + return this.page.locator('[name="password"]'); + } + + public goToWorkspace(): Locator { + return this.page.locator('//button[contains(text(), "Confirm")]'); + } + + public organizationType(): Locator { + return this.page.locator('[name="organizationType"]'); + } + + public organizationTypeSelect(): Locator { + return this.page.locator('.rcx-options .rcx-option:first-child'); + } + + public organizationName(): Locator { + return this.page.locator('[name="organizationName"]'); + } + + public industry(): Locator { + return this.page.locator('[name="organizationIndustry"]'); + } + + public industrySelect(): Locator { + return this.page.locator('.rcx-options .rcx-option:first-child'); + } + + public size(): Locator { + return this.page.locator('[name="organizationSize"]'); + } + + public sizeSelect(): Locator { + return this.page.locator('.rcx-options .rcx-option:first-child'); + } + + public country(): Locator { + return this.page.locator('[name="country"]'); + } + + public countrySelect(): Locator { + return this.page.locator('.rcx-options .rcx-option:first-child'); + } + + public registeredServer(): Locator { + return this.page.locator('input[name=email]'); + } + + public registerButton(): Locator { + return this.page.locator('//button[contains(text(), "Register")]'); + } + + public agreementField(): Locator { + return this.page.locator('//input[@name="agreement"]/../i[contains(@class, "rcx-check-box")]'); + } + + public standaloneServer(): Locator { + return this.page.locator('//button[contains(text(), "Continue as standalone")]'); + } + + public standaloneConfirmText(): Locator { + return this.page.locator('//*[contains(text(), "Standalone Server Confirmation")]'); + } + + public fullNameIvalidtext(): Locator { + return this.page.locator('//input[@name="fullname"]/../following-sibling::span'); + } + + public userNameInvalidText(): Locator { + return this.page.locator('//input[@name="username"]/../following-sibling::span'); + } + + public companyEmailInvalidText(): Locator { + return this.page.locator('//input[@name="companyEmail"]/../following-sibling::span'); + } + + public organizationNameInvalidText(): Locator { + return this.page.locator('//input[@name="organizationName"]/../following-sibling::span'); + } + + public passwordInvalidText(): Locator { + return this.page.locator('//input[@name="password"]/../../../span[contains(@class, "rcx-field__error")]'); + } + + public industryInvalidSelect(): Locator { + return this.page.locator('//div[@name="organizationIndustry"]/../following-sibling::span'); + } + + public sizeInvalidSelect(): Locator { + return this.page.locator('//div[@name="organizationSize"]/../following-sibling::span'); + } + + public countryInvalidSelect(): Locator { + return this.page.locator('//div[@name="country"]/../following-sibling::span'); + } + + public invalidInputEmail(): Locator { + return this.page.locator('$$("input:invalid")'); + } + + public async login(): Promise { + const loginObj = new LoginPage(this.browser, this.baseURL); + await loginObj.login({ email: adminEmail, password: adminPassword }); + } + + public async goNext(): Promise { + await this.nextStep().click(); + } + + public async stepOneSucess(): Promise { + await this.fullName().type('Any admin Name'); + await this.userName().type(adminUsername); + await this.companyEmail().type(adminEmail); + await this.password().type(adminPassword); + + await this.goNext(); + } + + public async stepTwoSucess(): Promise { + await this.organizationName().type(reason); + + await this.organizationType().click(); + await this.organizationTypeSelect().click(); + await expect(this.getPage().locator('.rcx-options')).toHaveCount(0); + + await this.industry().click(); + await this.industrySelect().click(); + await expect(this.getPage().locator('.rcx-options')).toHaveCount(0); + + await this.size().click(); + await this.sizeSelect().click(); + await expect(this.getPage().locator('.rcx-options')).toHaveCount(0); + + await this.country().click(); + await this.countrySelect().click(); + + await this.goNext(); + } + + public async stepThreeSucess(): Promise { + await this.standaloneServer().click(); + } + + // goToHome() { + // this.goToWorkspace.click(); + // } +} + +export default SetupWizard; diff --git a/tests/e2e/utils/pageobjects/wizzard.page.ts b/tests/e2e/utils/pageobjects/wizzard.page.ts deleted file mode 100644 index 1c3120a642f4..000000000000 --- a/tests/e2e/utils/pageobjects/wizzard.page.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Locator } from '@playwright/test'; - -import Pages from './Pages'; -import LoginPage from './login.page'; -import { adminEmail, adminPassword } from '../mocks/userAndPasswordMock'; - -class SetupWizard extends Pages { - private nextStep(): Locator { - return this.page.locator('//button[contains(text(), "Next")]'); - } - - public fullName(): Locator { - return this.page.locator('[name="fullname"]'); - } - - public userName(): Locator { - return this.page.locator('[name="username"]'); - } - - public companyEmail(): Locator { - return this.page.locator('[name="companyEmail"]'); - } - - public password(): Locator { - return this.page.locator('[name="password"]'); - } - - public goToWorkspace(): Locator { - return this.page.locator('//button[contains(text(), "Confirm")]'); - } - - public organizationType(): Locator { - return this.page.locator('[name="organizationType"]'); - } - - public organizationName(): Locator { - return this.page.locator('[name="organizationName"]'); - } - - public industry(): Locator { - return this.page.locator('[name="organizationIndustry"]'); - } - - public size(): Locator { - return this.page.locator('[name="organizationSize"]'); - } - - public country(): Locator { - return this.page.locator('[name="country"]'); - } - - public registeredServer(): Locator { - return this.page.locator('input[name=email]'); - } - - public registerButton(): Locator { - return this.page.locator('button:contains("Register")'); - } - - // public agreementField(): Locator { - // return this.page.locator('input[name=agreement]').closest('.rcx-check-box'); - // } - - public standaloneServer(): Locator { - return this.page.locator('button:contains("Continue as standalone")'); - } - - public standaloneConfirmText(): Locator { - return this.page.locator('.rcx-box:contains("Standalone Server Confirmation")'); - } - - public fullNameIvalidtext(): Locator { - return this.page.locator('//input[@name="fullname"]/../following-sibling::span'); - } - - public userNameInvalidText(): Locator { - return this.page.locator('//input[@name="username"]/../following-sibling::span'); - } - - public companyEmailInvalidText(): Locator { - return this.page.locator('//input[@name="companyEmail"]/../following-sibling::span'); - } - - public passwordInvalidText(): Locator { - return this.page.locator('//input[@name="password"]/../../../span[contains(@class, "rcx-field__error")]'); - } - - public async login(): Promise { - const loginObj = new LoginPage(this.browser, this.baseURL); - await loginObj.login({ email: adminEmail, password: adminPassword }); - } - - public async goNext(): Promise { - await this.nextStep().click(); - } - - // goToHome() { - // this.goToWorkspace.click(); - // } -} - -export default SetupWizard; From fd4d726cc4dafc6157725eaceb7e34dc63e24b3e Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Mon, 28 Mar 2022 16:05:24 -0300 Subject: [PATCH 06/35] test: pageObject patter global --- package.json | 4 +- playwright.config.ts | 1 - tests/e2e/0-wizard.spec.ts | 48 ++++++++++--------- tests/e2e/02-forgot-password.spec.ts | 8 ++-- tests/e2e/globalSetup.ts | 0 tests/e2e/globalsetup/globalSetup.ts | 5 -- .../e2e/utils/pageobjects/GlobalSelectors.ts | 30 ++++++++++++ tests/e2e/utils/pageobjects/Pages.ts | 21 +++++++- 8 files changed, 82 insertions(+), 35 deletions(-) create mode 100644 tests/e2e/globalSetup.ts delete mode 100644 tests/e2e/globalsetup/globalSetup.ts create mode 100644 tests/e2e/utils/pageobjects/GlobalSelectors.ts diff --git a/package.json b/package.json index dafdd91c9fc7..53efddc575d9 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ ], "scripts": { "prepare": "husky install", - "start": "TEST_MODE=true meteor", + "start": "meteor", "dev": "meteor reset && npm start", "ha": "meteor npm run ha:start", "ha:start": "ts-node .scripts/run-ha.ts main", @@ -359,4 +359,4 @@ "node": "14.18.2", "npm": "6.14.15" } -} +} \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts index ffbb6551a6a5..57cab1b9bb7e 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -4,7 +4,6 @@ const config: PlaywrightTestConfig = { outputDir: 'tests/e2e/test-failures', reporter: [['list']], workers: 3, - globalSetup: require.resolve('./tests/e2e/globalsetup/globalSetup'), use: { baseURL: process.env.BASE_URL || 'http://localhost:3000', headless: true, diff --git a/tests/e2e/0-wizard.spec.ts b/tests/e2e/0-wizard.spec.ts index f2e616d15c3a..5e287604548e 100644 --- a/tests/e2e/0-wizard.spec.ts +++ b/tests/e2e/0-wizard.spec.ts @@ -3,33 +3,37 @@ import { test, expect } from '@playwright/test'; import SetupWizzard from './utils/pageobjects/wizzard.page'; import { adminUsername, adminEmail, adminPassword } from './utils/mocks/userAndPasswordMock'; -test.describe('[Wizzard]', () => { - let setupWizard: SetupWizzard; +const executeFunction = (): void => { + test.describe('[Wizzard]', () => { + let setupWizard: SetupWizzard; - test.beforeAll(async ({ browser, baseURL }) => { - setupWizard = new SetupWizzard(browser, baseURL); - await setupWizard.open(''); - }); + test.beforeAll(async ({ browser, baseURL }) => { + setupWizard = new SetupWizzard(browser, baseURL); + await setupWizard.open(''); + }); - test.describe('[Step 1]', () => { - test('expect required field alert showed when user dont inform data', async () => { - await setupWizard.goNext(); + test.describe('[Step 1]', () => { + test('expect required field alert showed when user dont inform data', async () => { + await setupWizard.goNext(); - await expect(setupWizard.fullNameIvalidtext()).toBeVisible(); - await expect(setupWizard.userNameInvalidText()).toBeVisible(); - await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); - await expect(setupWizard.passwordInvalidText()).toBeVisible(); + await expect(setupWizard.fullNameIvalidtext()).toBeVisible(); + await expect(setupWizard.userNameInvalidText()).toBeVisible(); + await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); + await expect(setupWizard.passwordInvalidText()).toBeVisible(); + }); }); - }); - test('expect alert showed when email provided is invalid', async () => { - await setupWizard.fullName().type('Any admin Name'); - await setupWizard.userName().type(adminUsername); - await setupWizard.companyEmail().type('useremail'); - await setupWizard.password().type(adminPassword); + test('expect alert showed when email provided is invalid', async () => { + await setupWizard.fullName().type('Any admin Name'); + await setupWizard.userName().type(adminUsername); + await setupWizard.companyEmail().type('useremail'); + await setupWizard.password().type(adminPassword); - await setupWizard.goNext(); + await setupWizard.goNext(); - await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); + await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); + }); }); -}); +}; + +export default executeFunction; diff --git a/tests/e2e/02-forgot-password.spec.ts b/tests/e2e/02-forgot-password.spec.ts index 7ec0e3f92d5a..b7acf9fcdadb 100644 --- a/tests/e2e/02-forgot-password.spec.ts +++ b/tests/e2e/02-forgot-password.spec.ts @@ -14,13 +14,13 @@ test.describe('recoverPassword', () => { await loginPage.gotToForgotPassword(); }); - test('it should be required', async () => { + test('expect be required', async () => { loginPage.submit(); // loginPage.emailField.should('have.class', 'error'); await expect(loginPage.emailInvalidText()).toBeVisible(); }); - test('it should be invalid for email without domain', async () => { + test('expect invalid for email without domain', async () => { const emailField = loginPage.emailField(); await emailField.type('invalidmail'); await loginPage.submit(); @@ -28,14 +28,14 @@ test.describe('recoverPassword', () => { await expect(loginPage.emailInvalidText()).toBeVisible(); }); - test('it should be invalid for email with invalid domain', async () => { + test('expect be invalid for email with invalid domain', async () => { const emailField = loginPage.emailField(); await emailField.type('email@mail'); await loginPage.submit(); await expect(loginPage.emailInvalidText()).toBeVisible(); }); - test('expect user type a valçid email', async () => { + test('expect user type a valçid email', async ({ page }) => { const emailField = loginPage.emailField(); await emailField.type('any_user@gmail.com'); await loginPage.submit(); diff --git a/tests/e2e/globalSetup.ts b/tests/e2e/globalSetup.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/e2e/globalsetup/globalSetup.ts b/tests/e2e/globalsetup/globalSetup.ts deleted file mode 100644 index f24aa11d88ad..000000000000 --- a/tests/e2e/globalsetup/globalSetup.ts +++ /dev/null @@ -1,5 +0,0 @@ -const globalSetup = (): void => { - console.log(process.env.TEST_MODE); -}; - -export default globalSetup; diff --git a/tests/e2e/utils/pageobjects/GlobalSelectors.ts b/tests/e2e/utils/pageobjects/GlobalSelectors.ts new file mode 100644 index 000000000000..b0ffd005f269 --- /dev/null +++ b/tests/e2e/utils/pageobjects/GlobalSelectors.ts @@ -0,0 +1,30 @@ +import Pages from './Pages'; + +export default class GlobalSelectors extends Pages { + public async setText(selector: string, text: string): Promise { + await this.getPage().type(selector, text); + } + + public async open(url = ''): Promise { + await super.open(url); + } + + public async click(selector: string): Promise { + await this.getPage().click(selector); + } + + public async clearInput(selector: string): Promise { + await this.getPage().click(selector, { clickCount: 3 }); + await this.getPage().keyboard.press('Backspace'); + } + + public async clearAllInputs(selectors: string[]): Promise { + const listOfActions = []; + + for (const selector of selectors) { + listOfActions.push(this.clearInput(selector)); + } + + await Promise.all(listOfActions); + } +} diff --git a/tests/e2e/utils/pageobjects/Pages.ts b/tests/e2e/utils/pageobjects/Pages.ts index 44bb4eb15394..e396b435c479 100644 --- a/tests/e2e/utils/pageobjects/Pages.ts +++ b/tests/e2e/utils/pageobjects/Pages.ts @@ -1,9 +1,18 @@ +import { resolve } from 'path'; + import { Browser, Page } from '@playwright/test'; class Pages { protected page: Page; - constructor(protected readonly browser: Browser, protected readonly baseURL: string) {} + protected browser: Browser; + + protected baseURL: string; + + constructor(browser: Browser, baseURL = '') { + this.browser = browser; + this.baseURL = baseURL; + } public async open(path: string): Promise { const context = await this.browser.newContext(); @@ -20,5 +29,15 @@ class Pages { public async goto(path: string): Promise { await this.page.goto(`${this.baseURL}/${path}`); } + + protected getPage(): Page { + return this.page; + } + + public async isSetUpWizzard(): Promise { + await this.page.waitForURL('**/setup-wizard'); + + return !!this.page.url().match(/.*\/setup-wizard/); + } } export default Pages; From b7e7726d2dd131c7d96bf9696534af15e218de32 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Mon, 28 Mar 2022 16:24:25 -0300 Subject: [PATCH 07/35] chore: remove unused variables --- tests/e2e/02-forgot-password.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/02-forgot-password.spec.ts b/tests/e2e/02-forgot-password.spec.ts index b7acf9fcdadb..9ff3860e1d40 100644 --- a/tests/e2e/02-forgot-password.spec.ts +++ b/tests/e2e/02-forgot-password.spec.ts @@ -35,7 +35,7 @@ test.describe('recoverPassword', () => { await expect(loginPage.emailInvalidText()).toBeVisible(); }); - test('expect user type a valçid email', async ({ page }) => { + test('expect user type a valçid email', async () => { const emailField = loginPage.emailField(); await emailField.type('any_user@gmail.com'); await loginPage.submit(); From 4aac14bc74a700c75f4f3f56278b56b72bafb4b4 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Mon, 28 Mar 2022 17:21:32 -0300 Subject: [PATCH 08/35] fix: add function --- .gitignore | 1 + tests/e2e/{0-wizard.spec.ts => 00-wizard.spec.ts} | 9 ++++----- tests/e2e/{00-register.spec.ts => 02-register.spec.ts} | 0 tests/e2e/{01-login.spec.ts => 03-login.spec.ts} | 0 tests/e2e/utils/mocks/userAndPasswordMock.ts | 4 ++-- tests/e2e/utils/pageobjects/wizard.page.ts | 1 - 6 files changed, 7 insertions(+), 8 deletions(-) rename tests/e2e/{0-wizard.spec.ts => 00-wizard.spec.ts} (96%) rename tests/e2e/{00-register.spec.ts => 02-register.spec.ts} (100%) rename tests/e2e/{01-login.spec.ts => 03-login.spec.ts} (100%) diff --git a/.gitignore b/.gitignore index c7d55c27baad..9e56afe03f66 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,4 @@ tests/end-to-end/temporary_staged_test /tests/e2e/test-failures coverage .nyc_output +data diff --git a/tests/e2e/0-wizard.spec.ts b/tests/e2e/00-wizard.spec.ts similarity index 96% rename from tests/e2e/0-wizard.spec.ts rename to tests/e2e/00-wizard.spec.ts index ff36a4112508..7ce73408f88b 100644 --- a/tests/e2e/0-wizard.spec.ts +++ b/tests/e2e/00-wizard.spec.ts @@ -8,12 +8,11 @@ test.describe('[Wizard]', () => { test.beforeAll(async ({ browser, baseURL }) => { setupWizard = new SetupWizard(browser, baseURL as string); - await setupWizard.open(''); }); test.describe('[Step 1]', () => { test.beforeEach(async () => { - await setupWizard.goto(''); + await setupWizard.open(''); }); test('expect required field alert showed when user dont inform data', async () => { @@ -45,7 +44,7 @@ test.describe('[Wizard]', () => { test.describe('[Step 2]', async () => { test.beforeEach(async () => { - await setupWizard.goto(''); + await setupWizard.open(''); await setupWizard.stepOneSucess(); }); @@ -66,7 +65,7 @@ test.describe('[Wizard]', () => { test.describe('[Step 3]', async () => { test.beforeEach(async () => { - await setupWizard.goto(''); + await setupWizard.open(''); await setupWizard.stepOneSucess(); await setupWizard.stepTwoSucess(); }); @@ -106,7 +105,7 @@ test.describe('[Wizard]', () => { test.describe('[Final Step]', async () => { test.beforeEach(async () => { - await setupWizard.goto(''); + await setupWizard.open(''); await setupWizard.stepOneSucess(); await setupWizard.stepTwoSucess(); await setupWizard.stepThreeSucess(); diff --git a/tests/e2e/00-register.spec.ts b/tests/e2e/02-register.spec.ts similarity index 100% rename from tests/e2e/00-register.spec.ts rename to tests/e2e/02-register.spec.ts diff --git a/tests/e2e/01-login.spec.ts b/tests/e2e/03-login.spec.ts similarity index 100% rename from tests/e2e/01-login.spec.ts rename to tests/e2e/03-login.spec.ts diff --git a/tests/e2e/utils/mocks/userAndPasswordMock.ts b/tests/e2e/utils/mocks/userAndPasswordMock.ts index 6d589b44d8b3..b39897576afd 100644 --- a/tests/e2e/utils/mocks/userAndPasswordMock.ts +++ b/tests/e2e/utils/mocks/userAndPasswordMock.ts @@ -17,8 +17,8 @@ export const registerUser: IRegister = { }; export const validUser: ILogin = { - email: 'rocketchat.internal.admin.test@rocket.chat', - password: 'rocketchat.internal.admin.test', + email: adminEmail, + password: adminPassword, }; export const incorrectUser: ILogin = { diff --git a/tests/e2e/utils/pageobjects/wizard.page.ts b/tests/e2e/utils/pageobjects/wizard.page.ts index 81120173d208..0ca4a719882c 100644 --- a/tests/e2e/utils/pageobjects/wizard.page.ts +++ b/tests/e2e/utils/pageobjects/wizard.page.ts @@ -135,7 +135,6 @@ class SetupWizard extends Pages { await this.userName().type(adminUsername); await this.companyEmail().type(adminEmail); await this.password().type(adminPassword); - await this.goNext(); } From 2617fda6cfeb76c82b8123bb472368d09cfc818c Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Mon, 28 Mar 2022 17:47:23 -0300 Subject: [PATCH 09/35] fix: remove unexpected test --- tests/e2e/00-wizard.spec.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/e2e/00-wizard.spec.ts b/tests/e2e/00-wizard.spec.ts index 7ce73408f88b..68eff24cacc9 100644 --- a/tests/e2e/00-wizard.spec.ts +++ b/tests/e2e/00-wizard.spec.ts @@ -8,11 +8,12 @@ test.describe('[Wizard]', () => { test.beforeAll(async ({ browser, baseURL }) => { setupWizard = new SetupWizard(browser, baseURL as string); + await setupWizard.open(''); }); test.describe('[Step 1]', () => { test.beforeEach(async () => { - await setupWizard.open(''); + await setupWizard.goto(''); }); test('expect required field alert showed when user dont inform data', async () => { @@ -44,7 +45,7 @@ test.describe('[Wizard]', () => { test.describe('[Step 2]', async () => { test.beforeEach(async () => { - await setupWizard.open(''); + await setupWizard.goto(''); await setupWizard.stepOneSucess(); }); @@ -63,9 +64,9 @@ test.describe('[Wizard]', () => { }); }); - test.describe('[Step 3]', async () => { + test.describe.only('[Step 3]', async () => { test.beforeEach(async () => { - await setupWizard.open(''); + await setupWizard.goto(''); await setupWizard.stepOneSucess(); await setupWizard.stepTwoSucess(); }); @@ -97,15 +98,11 @@ test.describe('[Wizard]', () => { test('expect have option for standalone server', async () => { await expect(setupWizard.standaloneServer()).toBeVisible(); }); - - test('expect continue when clicking on "Continue as standalone"', async () => { - await setupWizard.standaloneServer().click(); - }); }); - test.describe('[Final Step]', async () => { + test.describe.only('[Final Step]', async () => { test.beforeEach(async () => { - await setupWizard.open(''); + await setupWizard.goto(''); await setupWizard.stepOneSucess(); await setupWizard.stepTwoSucess(); await setupWizard.stepThreeSucess(); From b5f12ed7deb47e009cf69646ebb7977b386b9314 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Tue, 29 Mar 2022 09:04:01 -0300 Subject: [PATCH 10/35] fix: final step test setup wizard --- tests/e2e/00-wizard.spec.ts | 5 +++-- tests/e2e/utils/pageobjects/wizard.page.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/e2e/00-wizard.spec.ts b/tests/e2e/00-wizard.spec.ts index 68eff24cacc9..51bf28b06600 100644 --- a/tests/e2e/00-wizard.spec.ts +++ b/tests/e2e/00-wizard.spec.ts @@ -64,7 +64,7 @@ test.describe('[Wizard]', () => { }); }); - test.describe.only('[Step 3]', async () => { + test.describe('[Step 3]', async () => { test.beforeEach(async () => { await setupWizard.goto(''); await setupWizard.stepOneSucess(); @@ -100,7 +100,7 @@ test.describe('[Wizard]', () => { }); }); - test.describe.only('[Final Step]', async () => { + test.describe('[Final Step]', async () => { test.beforeEach(async () => { await setupWizard.goto(''); await setupWizard.stepOneSucess(); @@ -115,6 +115,7 @@ test.describe('[Wizard]', () => { test('expect confirm standalone', async () => { await setupWizard.goToWorkspace().click(); + await setupWizard.getPage().waitForSelector('//span[@class="rc-header__block"]'); }); }); }); diff --git a/tests/e2e/utils/pageobjects/wizard.page.ts b/tests/e2e/utils/pageobjects/wizard.page.ts index 0ca4a719882c..803cbba0f8bf 100644 --- a/tests/e2e/utils/pageobjects/wizard.page.ts +++ b/tests/e2e/utils/pageobjects/wizard.page.ts @@ -131,7 +131,7 @@ class SetupWizard extends Pages { } public async stepOneSucess(): Promise { - await this.fullName().type('Any admin Name'); + await this.fullName().type(adminUsername); await this.userName().type(adminUsername); await this.companyEmail().type(adminEmail); await this.password().type(adminPassword); From 2163fa2486bd031a2be8c21e86639022b76e2a7d Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Tue, 29 Mar 2022 09:21:17 -0300 Subject: [PATCH 11/35] chore: rename files --- .../{02-forgot-password.spec.ts => 01-forgot-password.spec.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/e2e/{02-forgot-password.spec.ts => 01-forgot-password.spec.ts} (100%) diff --git a/tests/e2e/02-forgot-password.spec.ts b/tests/e2e/01-forgot-password.spec.ts similarity index 100% rename from tests/e2e/02-forgot-password.spec.ts rename to tests/e2e/01-forgot-password.spec.ts From 795052b2406b6bcf3dbdcb313b5a3114dc32c437 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Tue, 29 Mar 2022 10:20:37 -0300 Subject: [PATCH 12/35] fix: spell check descriptions tests --- tests/e2e/01-forgot-password.spec.ts | 2 +- tests/e2e/02-register.spec.ts | 11 ++++++----- tests/e2e/03-login.spec.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/e2e/01-forgot-password.spec.ts b/tests/e2e/01-forgot-password.spec.ts index 9ff3860e1d40..0daad8d1b3fe 100644 --- a/tests/e2e/01-forgot-password.spec.ts +++ b/tests/e2e/01-forgot-password.spec.ts @@ -35,7 +35,7 @@ test.describe('recoverPassword', () => { await expect(loginPage.emailInvalidText()).toBeVisible(); }); - test('expect user type a valçid email', async () => { + test('expect user type a valid email', async () => { const emailField = loginPage.emailField(); await emailField.type('any_user@gmail.com'); await loginPage.submit(); diff --git a/tests/e2e/02-register.spec.ts b/tests/e2e/02-register.spec.ts index f0f7ad620ad0..0799ae1c9814 100644 --- a/tests/e2e/02-register.spec.ts +++ b/tests/e2e/02-register.spec.ts @@ -26,14 +26,15 @@ test.describe('[Register]', () => { expect(toastError).toBeVisible(); expect(toastError).toHaveText('User not found or incorrect password'); }); - // TODO verify register flow + test('expect new user is created', async () => { await loginPage.gotToRegister(); await loginPage.registerNewUser(registerUser); const submitButton = loginPage.registerNextButton(); + await loginPage.getPage().waitForSelector('//button[contains(text(), "Use this username")]'); await submitButton.click(); - await expect(loginPage.getHomeMessage()).toContainText('Home'); + await loginPage.getPage().waitForSelector('//span[@class="rc-header__block"]'); }); test('expect when user dont inform user and password error message is showed', async () => { @@ -76,7 +77,7 @@ test.describe('[Register]', () => { await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); }); - test('expect user click in register button withoud name and password', async () => { + test('expect user click in register button without name and password', async () => { await loginPage.gotToRegister(); const inputEmail = loginPage.emailField(); @@ -87,7 +88,7 @@ test.describe('[Register]', () => { await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); }); - test('expect user click in register button withoud name and email', async () => { + test('expect user click in register button without name and email', async () => { await loginPage.gotToRegister(); const passwordFiled = loginPage.passwordField(); @@ -98,7 +99,7 @@ test.describe('[Register]', () => { await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); }); - test('expect user click in register button with diferent password', async () => { + test('expect user click in register button with different password', async () => { await loginPage.gotToRegister(); const passwordField = loginPage.passwordField(); diff --git a/tests/e2e/03-login.spec.ts b/tests/e2e/03-login.spec.ts index 8b657a5a0b64..b153fb2b85fd 100644 --- a/tests/e2e/03-login.spec.ts +++ b/tests/e2e/03-login.spec.ts @@ -15,7 +15,7 @@ test.describe('[Login]', () => { await expect(loginPage.getHomeMessage()).toContainText('Home'); }); - test('expect user write a password incorrectely', async () => { + test('expect user write a password incorrectly', async () => { const invalidUserPassword = { email: validUser.email, password: 'any_password1', From 95baaa1a9103a3aa2254591093a113dfc6e7d019 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Tue, 29 Mar 2022 16:44:41 -0300 Subject: [PATCH 13/35] test: ensure channel is working --- tests/e2e/05-channel.spec.ts | 32 +++++++++++++++++++ tests/e2e/utils/pageobjects/Channel.ts | 43 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/e2e/05-channel.spec.ts create mode 100644 tests/e2e/utils/pageobjects/Channel.ts diff --git a/tests/e2e/05-channel.spec.ts b/tests/e2e/05-channel.spec.ts new file mode 100644 index 000000000000..5c476de41f1f --- /dev/null +++ b/tests/e2e/05-channel.spec.ts @@ -0,0 +1,32 @@ +import { test } from '@playwright/test'; +import { v4 } from 'uuid'; + +import ChannelCreation from './utils/pageobjects/ChannelCreation'; +import LoginPage from './utils/pageobjects/login.page'; + +test.describe.parallel('[Channel]', async () => { + let channelCreation: ChannelCreation; + let loginPage: LoginPage; + let channelName: string; + test.beforeAll(async ({ browser, baseURL }) => { + loginPage = new LoginPage(browser, baseURL as string); + await loginPage.open(); + await loginPage.login({ email: 'weslleydrum@hotmail.com', password: 'Weslley901@@' }); + + channelCreation = new ChannelCreation(loginPage.getPage()); + }); + + test.beforeEach(async () => { + channelName = v4(); + }); + // Cenário negativo + // Cenário positivo + + test('expect create privateChannel channel', async () => { + await channelCreation.createPrivateChannel(channelName, true); + }); + + test('expect create public channel', async () => { + await channelCreation.createPrivateChannel(channelName, false); + }); +}); diff --git a/tests/e2e/utils/pageobjects/Channel.ts b/tests/e2e/utils/pageobjects/Channel.ts new file mode 100644 index 000000000000..e8a63b2697d1 --- /dev/null +++ b/tests/e2e/utils/pageobjects/Channel.ts @@ -0,0 +1,43 @@ +import { Page, Locator, expect } from '@playwright/test'; + +export default class ChannelCreation { + private inputChannelName: Locator; + + private buttonCreateChannel: Locator; + + private buttonCreate: Locator; + + private inputChannelDescription: Locator; + + private page: Page; + + private channelName: Locator; + + private buttonConfirmCreation: Locator; + + private privateChannel: Locator; + + constructor(page: Page) { + this.page = page; + this.buttonCreate = page.locator('[data-qa="sidebar-create"]'); + this.inputChannelName = page.locator('[placeholder="Channel Name"]'); + this.inputChannelDescription = page.locator('[placeholder="What is this channel about?"]'); + this.buttonCreateChannel = page.locator('//ul[@class="rc-popover__list"]//li[@class="rcx-option"][1]'); + this.channelName = page.locator('//header//div//div//div//div[2]'); + this.buttonConfirmCreation = page.locator('//button[contains(text(), "Create" )]'); + this.privateChannel = page.locator('//label[contains(text(),"Private")]/../following-sibling::label/i'); + } + + public async createPrivateChannel(name: string, isPrivate: boolean): Promise { + await this.buttonCreate.click(); + await this.buttonCreateChannel.click(); + await this.inputChannelName.type(name); + await this.inputChannelDescription.type('any_description'); + if (!isPrivate) { + await this.privateChannel.click(); + } + await this.buttonConfirmCreation.click(); + + await expect(this.channelName).toHaveText(name); + } +} From 33a7c514023f7a306e762ba20bf8c2ed4da60671 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Tue, 29 Mar 2022 17:43:46 -0300 Subject: [PATCH 14/35] test: creating chats and send message to a channel --- docker-compose.yml | 1 + playwright.config.ts | 4 ++-- ...el.spec.ts => 05-channel-creation.spec.ts} | 14 ++++++++----- tests/e2e/utils/mocks/userAndPasswordMock.ts | 6 +++--- .../{Channel.ts => ChannelCreation.ts} | 21 ++++++++++++++++++- 5 files changed, 35 insertions(+), 11 deletions(-) rename tests/e2e/{05-channel.spec.ts => 05-channel-creation.spec.ts} (66%) rename tests/e2e/utils/pageobjects/{Channel.ts => ChannelCreation.ts} (64%) diff --git a/docker-compose.yml b/docker-compose.yml index 76a663537960..e73b670b22f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,6 +20,7 @@ services: - MONGO_URL=mongodb://mongo:27017/rocketchat - MONGO_OPLOG_URL=mongodb://mongo:27017/local - REG_TOKEN=${REG_TOKEN} + - TEST_MODE=true # - MAIL_URL=smtp://smtp.email # - HTTP_PROXY=http://proxy.domain.com # - HTTPS_PROXY=http://proxy.domain.com diff --git a/playwright.config.ts b/playwright.config.ts index 57cab1b9bb7e..335158ca4134 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -6,8 +6,8 @@ const config: PlaywrightTestConfig = { workers: 3, use: { baseURL: process.env.BASE_URL || 'http://localhost:3000', - headless: true, - viewport: { width: 1200, height: 720 }, + headless: false, + viewport: { width: 1368, height: 768 }, ignoreHTTPSErrors: true, video: 'retain-on-failure', screenshot: 'only-on-failure', diff --git a/tests/e2e/05-channel.spec.ts b/tests/e2e/05-channel-creation.spec.ts similarity index 66% rename from tests/e2e/05-channel.spec.ts rename to tests/e2e/05-channel-creation.spec.ts index 5c476de41f1f..2d9c2b55321b 100644 --- a/tests/e2e/05-channel.spec.ts +++ b/tests/e2e/05-channel-creation.spec.ts @@ -3,7 +3,9 @@ import { v4 } from 'uuid'; import ChannelCreation from './utils/pageobjects/ChannelCreation'; import LoginPage from './utils/pageobjects/login.page'; +import { validUser } from './utils/mocks/userAndPasswordMock'; +const targetUser = 'rocket.cat'; test.describe.parallel('[Channel]', async () => { let channelCreation: ChannelCreation; let loginPage: LoginPage; @@ -11,7 +13,7 @@ test.describe.parallel('[Channel]', async () => { test.beforeAll(async ({ browser, baseURL }) => { loginPage = new LoginPage(browser, baseURL as string); await loginPage.open(); - await loginPage.login({ email: 'weslleydrum@hotmail.com', password: 'Weslley901@@' }); + await loginPage.login(validUser); channelCreation = new ChannelCreation(loginPage.getPage()); }); @@ -19,14 +21,16 @@ test.describe.parallel('[Channel]', async () => { test.beforeEach(async () => { channelName = v4(); }); - // Cenário negativo - // Cenário positivo test('expect create privateChannel channel', async () => { - await channelCreation.createPrivateChannel(channelName, true); + await channelCreation.createChannel(channelName, true); }); test('expect create public channel', async () => { - await channelCreation.createPrivateChannel(channelName, false); + await channelCreation.createChannel(channelName, false); + }); + + test.only('expect send to channel created', async () => { + await channelCreation.sendMessage(targetUser); }); }); diff --git a/tests/e2e/utils/mocks/userAndPasswordMock.ts b/tests/e2e/utils/mocks/userAndPasswordMock.ts index b39897576afd..1688ba79acea 100644 --- a/tests/e2e/utils/mocks/userAndPasswordMock.ts +++ b/tests/e2e/utils/mocks/userAndPasswordMock.ts @@ -11,14 +11,14 @@ export const adminEmail = `${adminUsername}@rocket.chat`; export const adminPassword = adminUsername; export const registerUser: IRegister = { - email: `${v4()}@email.com`, + email: `any_user@email.com`, password: 'any_password', name: `any_name${v4()}`, }; export const validUser: ILogin = { - email: adminEmail, - password: adminPassword, + email: 'any_user@email.com', + password: 'any_password', }; export const incorrectUser: ILogin = { diff --git a/tests/e2e/utils/pageobjects/Channel.ts b/tests/e2e/utils/pageobjects/ChannelCreation.ts similarity index 64% rename from tests/e2e/utils/pageobjects/Channel.ts rename to tests/e2e/utils/pageobjects/ChannelCreation.ts index e8a63b2697d1..598cc8c2d896 100644 --- a/tests/e2e/utils/pageobjects/Channel.ts +++ b/tests/e2e/utils/pageobjects/ChannelCreation.ts @@ -17,6 +17,10 @@ export default class ChannelCreation { private privateChannel: Locator; + private searchChannel: Locator; + + private searchChannelInput: Locator; + constructor(page: Page) { this.page = page; this.buttonCreate = page.locator('[data-qa="sidebar-create"]'); @@ -26,9 +30,11 @@ export default class ChannelCreation { this.channelName = page.locator('//header//div//div//div//div[2]'); this.buttonConfirmCreation = page.locator('//button[contains(text(), "Create" )]'); this.privateChannel = page.locator('//label[contains(text(),"Private")]/../following-sibling::label/i'); + this.searchChannel = page.locator('[data-qa="sidebar-search"]'); + this.searchChannelInput = page.locator('[data-qa="sidebar-search-input"]'); } - public async createPrivateChannel(name: string, isPrivate: boolean): Promise { + public async createChannel(name: string, isPrivate: boolean): Promise { await this.buttonCreate.click(); await this.buttonCreateChannel.click(); await this.inputChannelName.type(name); @@ -40,4 +46,17 @@ export default class ChannelCreation { await expect(this.channelName).toHaveText(name); } + + public async sendMessage(targetUser: string): Promise { + await this.searchChannel.click(); + await this.searchChannelInput.type(targetUser); + await this.page.keyboard.press('Enter'); + + await this.page.type('.rc-message-box__textarea', 'Hello'); + await this.page.keyboard.press('Enter'); + const message = this.page.locator('.message:last-child .body'); + + await expect(message).toBeVisible(); + await expect(message).toHaveText('Hello'); + } } From 06a3ab648076523e97109cd1d56b2890459bbba5 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Wed, 30 Mar 2022 15:21:17 -0300 Subject: [PATCH 15/35] refactor: add mocks and adjust in test suites --- tests/e2e/00-wizard.spec.ts | 70 +++---- tests/e2e/01-forgot-password.spec.ts | 29 ++- tests/e2e/02-register.spec.ts | 116 ++---------- tests/e2e/03-login.spec.ts | 16 +- tests/e2e/05-channel-creation.spec.ts | 40 ++-- tests/e2e/06-messaging.spec.ts | 5 + tests/e2e/utils/mocks/keyboardKeyMock.ts | 2 + tests/e2e/utils/mocks/urlMock.ts | 7 + tests/e2e/utils/mocks/userAndPasswordMock.ts | 23 ++- tests/e2e/utils/mocks/waitSelectorsMock.ts | 2 + tests/e2e/utils/pageobjects/BasePage.ts | 26 +++ .../e2e/utils/pageobjects/ChannelCreation.ts | 91 +++++---- tests/e2e/utils/pageobjects/Pages.ts | 35 ---- tests/e2e/utils/pageobjects/login.page.ts | 74 +++++--- tests/e2e/utils/pageobjects/wizard.page.ts | 173 +++++++++++------- 15 files changed, 346 insertions(+), 363 deletions(-) create mode 100644 tests/e2e/06-messaging.spec.ts create mode 100644 tests/e2e/utils/mocks/keyboardKeyMock.ts create mode 100644 tests/e2e/utils/mocks/urlMock.ts create mode 100644 tests/e2e/utils/mocks/waitSelectorsMock.ts create mode 100644 tests/e2e/utils/pageobjects/BasePage.ts delete mode 100644 tests/e2e/utils/pageobjects/Pages.ts diff --git a/tests/e2e/00-wizard.spec.ts b/tests/e2e/00-wizard.spec.ts index 51bf28b06600..ead1a357e0af 100644 --- a/tests/e2e/00-wizard.spec.ts +++ b/tests/e2e/00-wizard.spec.ts @@ -1,73 +1,57 @@ import { test, expect } from '@playwright/test'; import SetupWizard from './utils/pageobjects/wizard.page'; -import { adminUsername, adminPassword } from './utils/mocks/userAndPasswordMock'; +import { adminRegister, VALID_EMAIL } from './utils/mocks/userAndPasswordMock'; +import { LOCALHOST, setupWizardStepRegex } from './utils/mocks/urlMock'; +import { HOME_SELECTOR } from './utils/mocks/waitSelectorsMock'; test.describe('[Wizard]', () => { let setupWizard: SetupWizard; - - test.beforeAll(async ({ browser, baseURL }) => { - setupWizard = new SetupWizard(browser, baseURL as string); - await setupWizard.open(''); + test.beforeEach(async ({ page }) => { + setupWizard = new SetupWizard(page); }); - test.describe('[Step 1]', () => { - test.beforeEach(async () => { - await setupWizard.goto(''); + test.beforeEach(async ({ baseURL }) => { + const baseUrl = baseURL || LOCALHOST; + await setupWizard.goto(baseUrl); }); test('expect required field alert showed when user dont inform data', async () => { - await setupWizard.goNext(); - - await expect(setupWizard.fullNameIvalidtext()).toBeVisible(); - await expect(setupWizard.userNameInvalidText()).toBeVisible(); - await expect(setupWizard.companyEmailInvalidText()).toBeVisible(); - await expect(setupWizard.passwordInvalidText()).toBeVisible(); + await setupWizard.stepOneFailedBlankFields(); }); test('expect alert showed when email provided is invalid', async () => { - await setupWizard.fullName().type('Any admin Name'); - await setupWizard.userName().type(adminUsername); - await setupWizard.companyEmail().type('useremail'); - await setupWizard.password().type(adminPassword); - - await setupWizard.goNext(); - - await expect(setupWizard.companyEmail()).toBeFocused(); + await setupWizard.stepOneFailedWithInvalidEmail(adminRegister); }); test('expect go to Step 2 successfully', async () => { - await setupWizard.stepOneSucess(); + await setupWizard.stepOneSucess(adminRegister); - await expect(setupWizard.getPage()).toHaveURL(/.*\/setup-wizard\/2/); + await expect(setupWizard.getPage()).toHaveURL(setupWizardStepRegex._2); }); }); test.describe('[Step 2]', async () => { - test.beforeEach(async () => { - await setupWizard.goto(''); - await setupWizard.stepOneSucess(); + test.beforeEach(async ({ baseURL }) => { + const baseUrl = baseURL || LOCALHOST; + await setupWizard.goto(baseUrl); + await setupWizard.stepOneSucess(adminRegister); }); test('expect required field alert showed when user dont inform data', async () => { - await setupWizard.goNext(); - - await expect(setupWizard.organizationName()).toBeVisible(); - await expect(setupWizard.industryInvalidSelect()).toBeVisible(); - await expect(setupWizard.sizeInvalidSelect()).toBeVisible(); - await expect(setupWizard.countryInvalidSelect()).toBeVisible(); + await setupWizard.stepTwoFailedWithBlankFields(); }); test('expect go to Step 3 successfully', async () => { await setupWizard.stepTwoSucess(); - await expect(setupWizard.getPage()).toHaveURL(/.*\/setup-wizard\/3/); + await expect(setupWizard.getPage()).toHaveURL(setupWizardStepRegex._3); }); }); test.describe('[Step 3]', async () => { test.beforeEach(async () => { await setupWizard.goto(''); - await setupWizard.stepOneSucess(); + await setupWizard.stepOneSucess(adminRegister); await setupWizard.stepTwoSucess(); }); @@ -75,22 +59,16 @@ test.describe('[Wizard]', () => { await expect(setupWizard.registeredServer()).toBeVisible(); }); - test('expect start wtesth "Register" button disabled', async () => { + test('expect start "Register" button disabled', async () => { await expect(setupWizard.registerButton()).toBeDisabled(); }); test('expect show an error on invalid email', async () => { - await setupWizard.registeredServer().type('a'); - await setupWizard.registeredServer().click({ clickCount: 3 }); - await setupWizard.getPage().keyboard.press('Backspace'); - - await expect( - setupWizard.getPage().locator('//input[@name="email"]/../../span[contains(text(), "This field is required")]'), - ).toBeVisible(); + await setupWizard.stepThreeFailedWithInvalidField(); }); test('expect enable "Register" button when email is valid and terms checked', async () => { - await setupWizard.registeredServer().type('email@email.com'); + await setupWizard.registeredServer().type(VALID_EMAIL); await setupWizard.agreementField().click(); await expect(setupWizard.registerButton()).toBeEnabled(); }); @@ -103,7 +81,7 @@ test.describe('[Wizard]', () => { test.describe('[Final Step]', async () => { test.beforeEach(async () => { await setupWizard.goto(''); - await setupWizard.stepOneSucess(); + await setupWizard.stepOneSucess(adminRegister); await setupWizard.stepTwoSucess(); await setupWizard.stepThreeSucess(); }); @@ -115,7 +93,7 @@ test.describe('[Wizard]', () => { test('expect confirm standalone', async () => { await setupWizard.goToWorkspace().click(); - await setupWizard.getPage().waitForSelector('//span[@class="rc-header__block"]'); + await setupWizard.waitForSelector(HOME_SELECTOR); }); }); }); diff --git a/tests/e2e/01-forgot-password.spec.ts b/tests/e2e/01-forgot-password.spec.ts index 0daad8d1b3fe..0ba155b302a4 100644 --- a/tests/e2e/01-forgot-password.spec.ts +++ b/tests/e2e/01-forgot-password.spec.ts @@ -1,45 +1,40 @@ import { test, expect } from '@playwright/test'; import LoginPage from './utils/pageobjects/login.page'; +import { LOCALHOST } from './utils/mocks/urlMock'; +import { VALID_EMAIL, INVALID_EMAIL, INVALID_EMAIL_WITHOUT_MAIL_PROVIDER } from './utils/mocks/userAndPasswordMock'; -test.describe('recoverPassword', () => { +test.describe('[Forgot Password]', () => { let loginPage: LoginPage; - test.beforeAll(async ({ browser, baseURL }) => { - loginPage = new LoginPage(browser, baseURL as string); - await loginPage.open(); - }); - test.beforeEach(async () => { - await loginPage.goto(''); + test.beforeEach(async ({ page, baseURL }) => { + loginPage = new LoginPage(page); + const baseUrl = baseURL || LOCALHOST; + await loginPage.goto(baseUrl); await loginPage.gotToForgotPassword(); }); test('expect be required', async () => { loginPage.submit(); - // loginPage.emailField.should('have.class', 'error'); + await expect(loginPage.emailInvalidText()).toBeVisible(); }); test('expect invalid for email without domain', async () => { - const emailField = loginPage.emailField(); - await emailField.type('invalidmail'); + await loginPage.emailField().type(INVALID_EMAIL_WITHOUT_MAIL_PROVIDER); await loginPage.submit(); - // loginPage.emailField.should('have.class', 'error'); await expect(loginPage.emailInvalidText()).toBeVisible(); }); test('expect be invalid for email with invalid domain', async () => { - const emailField = loginPage.emailField(); - await emailField.type('email@mail'); + await loginPage.emailField().type(INVALID_EMAIL); await loginPage.submit(); await expect(loginPage.emailInvalidText()).toBeVisible(); }); test('expect user type a valid email', async () => { - const emailField = loginPage.emailField(); - await emailField.type('any_user@gmail.com'); + await loginPage.emailField().type(VALID_EMAIL); await loginPage.submit(); - const toastMessageSuccess = loginPage.getToastMessageSuccess(); - await expect(toastMessageSuccess).toBeVisible(); + await expect(loginPage.getToastMessageSuccess()).toBeVisible(); }); }); diff --git a/tests/e2e/02-register.spec.ts b/tests/e2e/02-register.spec.ts index 0799ae1c9814..fb34fd2738b7 100644 --- a/tests/e2e/02-register.spec.ts +++ b/tests/e2e/02-register.spec.ts @@ -1,120 +1,28 @@ -import { test, expect } from '@playwright/test'; +import { test } from '@playwright/test'; -import { incorrectUser, registerUser } from './utils/mocks/userAndPasswordMock'; +import { registerUser, WRONG_PASSWORD } from './utils/mocks/userAndPasswordMock'; import LoginPage from './utils/pageobjects/login.page'; +import { LOCALHOST } from './utils/mocks/urlMock'; -// test.describe('[Wizard]', () => { -// let loginPage: LoginPage; -// test.beforeAll(async ({ browser, baseURL }) => { -// loginPage = new LoginPage(browser, baseURL as string); -// await loginPage.open(); -// }); -// }); -test.describe.configure({ mode: 'parallel' }); test.describe('[Register]', () => { let loginPage: LoginPage; - test.beforeAll(async ({ browser, baseURL }) => { - loginPage = new LoginPage(browser, baseURL as string); - await loginPage.open(); - }); - test.beforeEach(async () => { - await loginPage.goto(''); - }); - test('expect login is failed', async () => { - await loginPage.login(incorrectUser); - const toastError = loginPage.getToastError(); - expect(toastError).toBeVisible(); - expect(toastError).toHaveText('User not found or incorrect password'); - }); - - test('expect new user is created', async () => { - await loginPage.gotToRegister(); - await loginPage.registerNewUser(registerUser); - - const submitButton = loginPage.registerNextButton(); - await loginPage.getPage().waitForSelector('//button[contains(text(), "Use this username")]'); - await submitButton.click(); - await loginPage.getPage().waitForSelector('//span[@class="rc-header__block"]'); - }); - test('expect when user dont inform user and password error message is showed', async () => { - await loginPage.submit(); - await expect(loginPage.emailOrUsernameInvalidText()).toHaveText('The email entered is invalid'); - await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); - }); - - test('expect when user dont inform password error message is showed', async () => { - const emailErrorInput = loginPage.emailOrUsernameField(); - await emailErrorInput.type('any_email@email.com'); - await loginPage.submit(); - expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); - }); - - test('expect when user dont inform user error message is showed', async () => { - const passwordErrorInput = loginPage.passwordField(); - await passwordErrorInput.type('any_password'); - await loginPage.submit(); - await expect(loginPage.emailOrUsernameInvalidText()).toHaveText('The email entered is invalid'); + test.beforeEach(async ({ page, baseURL }) => { + const URL = baseURL || LOCALHOST; + loginPage = new LoginPage(page); + await loginPage.goto(URL); }); test('expect user click in register button without data', async () => { - await loginPage.gotToRegister(); - await loginPage.submit(); - - await expect(loginPage.nameInvalidText()).toHaveText('The name must not be empty'); - await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); - await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); - }); - - test('expect user click in register button email and password', async () => { - await loginPage.gotToRegister(); - - const inputName = loginPage.nameField(); - await inputName.type('any_name'); - await loginPage.submit(); - await expect(loginPage.nameInvalidText()).not.toBeVisible(); - await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); - await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); + await loginPage.registerFail(); }); - test('expect user click in register button without name and password', async () => { - await loginPage.gotToRegister(); - - const inputEmail = loginPage.emailField(); - await inputEmail.type('any_mail@email.com'); - await loginPage.submit(); - await expect(loginPage.emailInvalidText()).not.toBeVisible(); - await expect(loginPage.nameInvalidText()).toHaveText('The name must not be empty'); - await expect(loginPage.passwordInvalidText()).toHaveText('The password must not be empty'); - }); - - test('expect user click in register button without name and email', async () => { - await loginPage.gotToRegister(); - - const passwordFiled = loginPage.passwordField(); - await passwordFiled.type('any_mail@email.com'); - await loginPage.submit(); - await expect(loginPage.passwordInvalidText()).not.toBeVisible(); - await expect(loginPage.nameInvalidText()).toHaveText('The name must not be empty'); - await expect(loginPage.emailInvalidText()).toHaveText('The email entered is invalid'); + test('expect user click in register button with different password', async () => { + await loginPage.registerFailWithDifentPassword(registerUser, WRONG_PASSWORD); }); - test('expect user click in register button with different password', async () => { + test('expect new user is created', async () => { await loginPage.gotToRegister(); - - const passwordField = loginPage.passwordField(); - await passwordField.type('any_mail@email.com'); - - const inputEmail = loginPage.emailField(); - await inputEmail.type('any_mail@email.com'); - - const inputName = loginPage.nameField(); - await inputName.type('any_name'); - - await loginPage.confirmPasswordField().type('any_passwor'); - - await loginPage.submit(); - await expect(loginPage.confirmPasswordInvalidText()).toBeVisible(); - await expect(loginPage.confirmPasswordInvalidText()).toHaveText('The password confirmation does not match password'); + await loginPage.registerNewUser(registerUser); }); }); diff --git a/tests/e2e/03-login.spec.ts b/tests/e2e/03-login.spec.ts index b153fb2b85fd..b46ef768b948 100644 --- a/tests/e2e/03-login.spec.ts +++ b/tests/e2e/03-login.spec.ts @@ -2,17 +2,21 @@ import { test, expect } from '@playwright/test'; import { validUser } from './utils/mocks/userAndPasswordMock'; import LoginPage from './utils/pageobjects/login.page'; +import { LOCALHOST } from './utils/mocks/urlMock'; +import { HOME_SELECTOR } from './utils/mocks/waitSelectorsMock'; test.describe('[Login]', () => { let loginPage: LoginPage; - test.beforeEach(async ({ browser, baseURL }) => { - loginPage = new LoginPage(browser, baseURL as string); - await loginPage.open(); + + test.beforeEach(async ({ page, baseURL }) => { + const baseUrl = baseURL || LOCALHOST; + loginPage = new LoginPage(page); + await loginPage.goto(baseUrl); }); test('expect user make login', async () => { await loginPage.login(validUser); - await expect(loginPage.getHomeMessage()).toContainText('Home'); + await loginPage.waitForSelector(HOME_SELECTOR); }); test('expect user write a password incorrectly', async () => { @@ -21,8 +25,6 @@ test.describe('[Login]', () => { password: 'any_password1', }; await loginPage.login(invalidUserPassword); - const toastError = loginPage.getToastError(); - await expect(toastError).toBeVisible(); - await expect(toastError).toHaveText('User not found or incorrect password'); + await expect(loginPage.getToastError()).toBeVisible(); }); }); diff --git a/tests/e2e/05-channel-creation.spec.ts b/tests/e2e/05-channel-creation.spec.ts index 2d9c2b55321b..22ec6edff958 100644 --- a/tests/e2e/05-channel-creation.spec.ts +++ b/tests/e2e/05-channel-creation.spec.ts @@ -3,34 +3,40 @@ import { v4 } from 'uuid'; import ChannelCreation from './utils/pageobjects/ChannelCreation'; import LoginPage from './utils/pageobjects/login.page'; -import { validUser } from './utils/mocks/userAndPasswordMock'; +import { validUser, ROCKET_CAT } from './utils/mocks/userAndPasswordMock'; +import { LOCALHOST } from './utils/mocks/urlMock'; -const targetUser = 'rocket.cat'; test.describe.parallel('[Channel]', async () => { let channelCreation: ChannelCreation; let loginPage: LoginPage; - let channelName: string; - test.beforeAll(async ({ browser, baseURL }) => { - loginPage = new LoginPage(browser, baseURL as string); - await loginPage.open(); + + const HELLO = 'Hello'; + + test.beforeEach(async ({ page, baseURL }) => { + const baseUrl = baseURL || LOCALHOST; + loginPage = new LoginPage(page); + await loginPage.goto(baseUrl); await loginPage.login(validUser); - channelCreation = new ChannelCreation(loginPage.getPage()); + channelCreation = new ChannelCreation(page); }); - test.beforeEach(async () => { - channelName = v4(); - }); + test.describe('[Public and private channel creation]', () => { + let channelName: string; + test.beforeEach(async () => { + channelName = v4(); + }); - test('expect create privateChannel channel', async () => { - await channelCreation.createChannel(channelName, true); - }); + test('expect create privateChannel channel', async () => { + await channelCreation.createChannel(channelName, true); + }); - test('expect create public channel', async () => { - await channelCreation.createChannel(channelName, false); + test('expect create public channel', async () => { + await channelCreation.createChannel(channelName, false); + }); }); - test.only('expect send to channel created', async () => { - await channelCreation.sendMessage(targetUser); + test('expect send to channel created', async () => { + await channelCreation.sendMessage(ROCKET_CAT, HELLO); }); }); diff --git a/tests/e2e/06-messaging.spec.ts b/tests/e2e/06-messaging.spec.ts new file mode 100644 index 000000000000..0cbe5bd67855 --- /dev/null +++ b/tests/e2e/06-messaging.spec.ts @@ -0,0 +1,5 @@ +import { test, expect } from '@playwright/test'; + +test.describe('[Messaging]', () => { + test.beforeAll(async ({ page }) => {}); +}); diff --git a/tests/e2e/utils/mocks/keyboardKeyMock.ts b/tests/e2e/utils/mocks/keyboardKeyMock.ts new file mode 100644 index 000000000000..035611d3ee70 --- /dev/null +++ b/tests/e2e/utils/mocks/keyboardKeyMock.ts @@ -0,0 +1,2 @@ +export const ENTER = 'Enter'; +export const BACKSPACE = 'Backspace'; diff --git a/tests/e2e/utils/mocks/urlMock.ts b/tests/e2e/utils/mocks/urlMock.ts new file mode 100644 index 000000000000..e23a083833d2 --- /dev/null +++ b/tests/e2e/utils/mocks/urlMock.ts @@ -0,0 +1,7 @@ +export const LOCALHOST = 'localhost:3000'; + +export const setupWizardStepRegex = { + _1: /.*\/setup-wizard\/1/, + _2: /.*\/setup-wizard\/2/, + _3: /.*\/setup-wizard\/3/, +}; diff --git a/tests/e2e/utils/mocks/userAndPasswordMock.ts b/tests/e2e/utils/mocks/userAndPasswordMock.ts index 1688ba79acea..e477564fc2fb 100644 --- a/tests/e2e/utils/mocks/userAndPasswordMock.ts +++ b/tests/e2e/utils/mocks/userAndPasswordMock.ts @@ -2,13 +2,18 @@ import { v4 } from 'uuid'; import { ILogin, IRegister } from '../interfaces/Login'; -export const username = 'user.test'; -export const email = `${username}@rocket.chat`; -export const password = 'rocket.chat'; export const reason = 'rocket.chat.reason'; -export const adminUsername = 'rocketchat.internal.admin.test'; -export const adminEmail = `${adminUsername}@rocket.chat`; -export const adminPassword = adminUsername; + +export const adminRegister: IRegister = { + name: 'rocketchat.internal.admin.test', + email: 'rocketchat.internal.admin.test@rocket.chat', + password: 'rocketchat.internal.admin.test', +}; + +export const adminLogin: ILogin = { + email: 'rocketchat.internal.admin.test@rocket.chat', + password: 'rocketchat.internal.admin.test', +}; export const registerUser: IRegister = { email: `any_user@email.com`, @@ -25,3 +30,9 @@ export const incorrectUser: ILogin = { email: `${v4()}@email.com`, password: 'any_password', }; + +export const VALID_EMAIL = 'email@email.com'; +export const INVALID_EMAIL = 'mail@mail'; +export const INVALID_EMAIL_WITHOUT_MAIL_PROVIDER = 'email'; +export const ROCKET_CAT = 'rocket.cat'; +export const WRONG_PASSWORD = 'passwo1'; diff --git a/tests/e2e/utils/mocks/waitSelectorsMock.ts b/tests/e2e/utils/mocks/waitSelectorsMock.ts new file mode 100644 index 000000000000..a7acce309050 --- /dev/null +++ b/tests/e2e/utils/mocks/waitSelectorsMock.ts @@ -0,0 +1,2 @@ +export const HOME_SELECTOR = '//span[@class="rc-header__block"]'; +export const REGISTER_STEP2_BUTTON = '//button[contains(text(), "Use this username")]'; diff --git a/tests/e2e/utils/pageobjects/BasePage.ts b/tests/e2e/utils/pageobjects/BasePage.ts new file mode 100644 index 000000000000..e3a45d9ebe2c --- /dev/null +++ b/tests/e2e/utils/pageobjects/BasePage.ts @@ -0,0 +1,26 @@ +import { Page } from '@playwright/test'; + +class BasePage { + private page: Page; + + constructor(page: Page) { + this.page = page; + } + + public getPage(): Page { + return this.page; + } + + public async goto(path: string): Promise { + await this.page.goto(path); + } + + public async waitForSelector(selector: string): Promise { + await this.page.waitForSelector(selector); + } + + protected async keyboardPress(key: string): Promise { + await this.page.keyboard.press(key); + } +} +export default BasePage; diff --git a/tests/e2e/utils/pageobjects/ChannelCreation.ts b/tests/e2e/utils/pageobjects/ChannelCreation.ts index 598cc8c2d896..d5f63d48cc9c 100644 --- a/tests/e2e/utils/pageobjects/ChannelCreation.ts +++ b/tests/e2e/utils/pageobjects/ChannelCreation.ts @@ -1,62 +1,75 @@ -import { Page, Locator, expect } from '@playwright/test'; +import { Locator, expect } from '@playwright/test'; -export default class ChannelCreation { - private inputChannelName: Locator; +import BasePage from './BasePage'; +import { ENTER } from '../mocks/keyboardKeyMock'; - private buttonCreateChannel: Locator; +export default class ChannelCreation extends BasePage { + private buttonCreate(): Locator { + return this.getPage().locator('[data-qa="sidebar-create"]'); + } - private buttonCreate: Locator; + private inputChannelName(): Locator { + return this.getPage().locator('[placeholder="Channel Name"]'); + } - private inputChannelDescription: Locator; + private inputChannelDescription(): Locator { + return this.getPage().locator('[placeholder="What is this channel about?"]'); + } - private page: Page; + private buttonCreateChannel(): Locator { + return this.getPage().locator('//ul[@class="rc-popover__list"]//li[@class="rcx-option"][1]'); + } - private channelName: Locator; + private channelName(): Locator { + return this.getPage().locator('//header//div//div//div//div[2]'); + } - private buttonConfirmCreation: Locator; + private buttonConfirmCreation(): Locator { + return this.getPage().locator('//button[contains(text(), "Create" )]'); + } - private privateChannel: Locator; + private privateChannel(): Locator { + return this.getPage().locator('//label[contains(text(),"Private")]/../following-sibling::label/i'); + } - private searchChannel: Locator; + private searchChannel(): Locator { + return this.getPage().locator('[data-qa="sidebar-search"]'); + } - private searchChannelInput: Locator; + private searchChannelInput(): Locator { + return this.getPage().locator('[data-qa="sidebar-search-input"]'); + } + + private textArea(): Locator { + return this.getPage().locator('.rc-message-box__textarea'); + } - constructor(page: Page) { - this.page = page; - this.buttonCreate = page.locator('[data-qa="sidebar-create"]'); - this.inputChannelName = page.locator('[placeholder="Channel Name"]'); - this.inputChannelDescription = page.locator('[placeholder="What is this channel about?"]'); - this.buttonCreateChannel = page.locator('//ul[@class="rc-popover__list"]//li[@class="rcx-option"][1]'); - this.channelName = page.locator('//header//div//div//div//div[2]'); - this.buttonConfirmCreation = page.locator('//button[contains(text(), "Create" )]'); - this.privateChannel = page.locator('//label[contains(text(),"Private")]/../following-sibling::label/i'); - this.searchChannel = page.locator('[data-qa="sidebar-search"]'); - this.searchChannelInput = page.locator('[data-qa="sidebar-search-input"]'); + private lastMessage(): Locator { + return this.getPage().locator('.message:last-child .body'); } public async createChannel(name: string, isPrivate: boolean): Promise { - await this.buttonCreate.click(); - await this.buttonCreateChannel.click(); - await this.inputChannelName.type(name); - await this.inputChannelDescription.type('any_description'); + await this.buttonCreate().click(); + await this.buttonCreateChannel().click(); + await this.inputChannelName().type(name); + await this.inputChannelDescription().type('any_description'); if (!isPrivate) { - await this.privateChannel.click(); + await this.privateChannel().click(); } - await this.buttonConfirmCreation.click(); + await this.buttonConfirmCreation().click(); - await expect(this.channelName).toHaveText(name); + await expect(this.channelName()).toHaveText(name); } - public async sendMessage(targetUser: string): Promise { - await this.searchChannel.click(); - await this.searchChannelInput.type(targetUser); - await this.page.keyboard.press('Enter'); + public async sendMessage(targetUser: string, message: string): Promise { + await this.searchChannel().click(); + await this.searchChannelInput().type(targetUser); + await this.keyboardPress(ENTER); - await this.page.type('.rc-message-box__textarea', 'Hello'); - await this.page.keyboard.press('Enter'); - const message = this.page.locator('.message:last-child .body'); + await this.textArea().type(message); + await this.keyboardPress(ENTER); - await expect(message).toBeVisible(); - await expect(message).toHaveText('Hello'); + await expect(this.lastMessage()).toBeVisible(); + await expect(this.lastMessage()).toHaveText(message); } } diff --git a/tests/e2e/utils/pageobjects/Pages.ts b/tests/e2e/utils/pageobjects/Pages.ts deleted file mode 100644 index b4b8c16fb67e..000000000000 --- a/tests/e2e/utils/pageobjects/Pages.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Browser, Page } from '@playwright/test'; - -class Pages { - protected page: Page; - - protected browser: Browser; - - protected baseURL: string; - - constructor(browser: Browser, baseURL = '') { - this.browser = browser; - this.baseURL = baseURL; - } - - public async open(path: string): Promise { - const context = await this.browser.newContext(); - this.page = await context.newPage(); - this.page.setDefaultNavigationTimeout(50000); - await this.goto(path); - } - - // TODO remover - public async pause(): Promise { - await this.page.pause(); - } - - public async goto(path: string): Promise { - await this.page.goto(`${this.baseURL}/${path}`); - } - - public getPage(): Page { - return this.page; - } -} -export default Pages; diff --git a/tests/e2e/utils/pageobjects/login.page.ts b/tests/e2e/utils/pageobjects/login.page.ts index 5ec88873fea6..11f7228e12b0 100644 --- a/tests/e2e/utils/pageobjects/login.page.ts +++ b/tests/e2e/utils/pageobjects/login.page.ts @@ -1,87 +1,88 @@ -import { Locator } from '@playwright/test'; +import { Locator, expect } from '@playwright/test'; import { ILogin, IRegister } from '../interfaces/Login'; -import Pages from './Pages'; +import BasePage from './BasePage'; +import { HOME_SELECTOR, REGISTER_STEP2_BUTTON } from '../mocks/waitSelectorsMock'; -class LoginPage extends Pages { +class LoginPage extends BasePage { private registerButton(): Locator { - return this.page.locator('button.register'); + return this.getPage().locator('button.register'); } private forgotPasswordButton(): Locator { - return this.page.locator('.forgot-password'); + return this.getPage().locator('.forgot-password'); } public submitButton(): Locator { - return this.page.locator('.login'); + return this.getPage().locator('.login'); } public registerNextButton(): Locator { - return this.page.locator('button[data-loading-text=" Please_wait ..."]'); + return this.getPage().locator('button[data-loading-text=" Please_wait ..."]'); } public registerMessage(): Locator { - return this.page.locator('//form[@id["login-card"]]//header//p'); + return this.getPage().locator('//form[@id["login-card"]]//header//p'); } public emailOrUsernameField(): Locator { - return this.page.locator('[name=emailOrUsername]'); + return this.getPage().locator('[name=emailOrUsername]'); } public nameField(): Locator { - return this.page.locator('[name=name]'); + return this.getPage().locator('[name=name]'); } public emailField(): Locator { - return this.page.locator('[name=email]'); + return this.getPage().locator('[name=email]'); } public passwordField(): Locator { - return this.page.locator('[name=pass]'); + return this.getPage().locator('[name=pass]'); } public userNameField(): Locator { - return this.page.locator('[name=username]'); + return this.getPage().locator('[name=username]'); } public confirmPasswordField(): Locator { - return this.page.locator('[name=confirm-pass]'); + return this.getPage().locator('[name=confirm-pass]'); } public getToastError(): Locator { - return this.page.locator('.toast'); + return this.getPage().locator('.toast'); } public getToastMessageSuccess(): Locator { - return this.page.locator('.toast-message'); + return this.getPage().locator('.toast-message'); } public emailOrUsernameInvalidText(): Locator { - return this.page.locator('[name=emailOrUsername]~.input-error'); + return this.getPage().locator('[name=emailOrUsername]~.input-error'); } public nameInvalidText(): Locator { - return this.page.locator('[name=name]~.input-error'); + return this.getPage().locator('[name=name]~.input-error'); } public emailInvalidText(): Locator { - return this.page.locator('[name=email]~.input-error'); + return this.getPage().locator('[name=email]~.input-error'); } public passwordInvalidText(): Locator { - return this.page.locator('[name=pass]~.input-error'); + return this.getPage().locator('[name=pass]~.input-error'); } public confirmPasswordInvalidText(): Locator { - return this.page.locator('[name=confirm-pass]~.input-error'); + return this.getPage().locator('[name=confirm-pass]~.input-error'); } public getHomeMessage(): Locator { - return this.page.locator('//span[@class="rc-header__block"]'); + return this.getPage().locator('//span[@class="rc-header__block"]'); } - public async open(): Promise { - await super.open(''); + public async open(path: string): Promise { + await super.goto(path); } public async gotToRegister(): Promise { @@ -98,6 +99,10 @@ class LoginPage extends Pages { await this.passwordField().type(password); await this.confirmPasswordField().type(password); await this.submit(); + + await this.waitForSelector(REGISTER_STEP2_BUTTON); + await this.registerNextButton().click(); + await this.waitForSelector(HOME_SELECTOR); } public async login({ email, password }: ILogin): Promise { @@ -109,6 +114,27 @@ class LoginPage extends Pages { public async submit(): Promise { await this.submitButton().click(); } + + public async registerFail(): Promise { + await this.gotToRegister(); + await this.submit(); + + await expect(this.nameInvalidText()).toBeVisible(); + await expect(this.emailInvalidText()).toBeVisible(); + await expect(this.passwordInvalidText()).toBeVisible(); + } + + public async registerFailWithDifentPassword({ name, email, password }: IRegister, invalidPassword: string): Promise { + await this.gotToRegister(); + await this.passwordField().type(password); + await this.emailField().type(email); + await this.nameField().type(name); + await this.confirmPasswordField().type(invalidPassword); + + await this.submit(); + await expect(this.confirmPasswordInvalidText()).toBeVisible(); + await expect(this.confirmPasswordInvalidText()).toHaveText('The password confirmation does not match password'); + } } export default LoginPage; diff --git a/tests/e2e/utils/pageobjects/wizard.page.ts b/tests/e2e/utils/pageobjects/wizard.page.ts index 803cbba0f8bf..03a164b47547 100644 --- a/tests/e2e/utils/pageobjects/wizard.page.ts +++ b/tests/e2e/utils/pageobjects/wizard.page.ts @@ -1,140 +1,140 @@ import { expect, Locator } from '@playwright/test'; -import Pages from './Pages'; -import LoginPage from './login.page'; -import { adminUsername, adminEmail, adminPassword, reason } from '../mocks/userAndPasswordMock'; +import BasePage from './BasePage'; +import { reason, INVALID_EMAIL_WITHOUT_MAIL_PROVIDER } from '../mocks/userAndPasswordMock'; +import { IRegister } from '../interfaces/Login'; +import { BACKSPACE } from '../mocks/keyboardKeyMock'; -class SetupWizard extends Pages { +class SetupWizard extends BasePage { private nextStep(): Locator { - return this.page.locator('//button[contains(text(), "Next")]'); + return this.getPage().locator('//button[contains(text(), "Next")]'); } - public fullName(): Locator { - return this.page.locator('[name="fullname"]'); + private fullName(): Locator { + return this.getPage().locator('[name="fullname"]'); } - public userName(): Locator { - return this.page.locator('[name="username"]'); + private userName(): Locator { + return this.getPage().locator('[name="username"]'); } - public companyEmail(): Locator { - return this.page.locator('[name="companyEmail"]'); + private companyEmail(): Locator { + return this.getPage().locator('[name="companyEmail"]'); } - public password(): Locator { - return this.page.locator('[name="password"]'); + private password(): Locator { + return this.getPage().locator('[name="password"]'); } public goToWorkspace(): Locator { - return this.page.locator('//button[contains(text(), "Confirm")]'); + return this.getPage().locator('//button[contains(text(), "Confirm")]'); } - public organizationType(): Locator { - return this.page.locator('[name="organizationType"]'); + private organizationType(): Locator { + return this.getPage().locator('[name="organizationType"]'); } - public organizationTypeSelect(): Locator { - return this.page.locator('.rcx-options .rcx-option:first-child'); + private organizationTypeSelect(): Locator { + return this.getPage().locator('.rcx-options .rcx-option:first-child'); } - public organizationName(): Locator { - return this.page.locator('[name="organizationName"]'); + private organizationName(): Locator { + return this.getPage().locator('[name="organizationName"]'); } - public industry(): Locator { - return this.page.locator('[name="organizationIndustry"]'); + private industry(): Locator { + return this.getPage().locator('[name="organizationIndustry"]'); } - public industrySelect(): Locator { - return this.page.locator('.rcx-options .rcx-option:first-child'); + private industrySelect(): Locator { + return this.getPage().locator('.rcx-options .rcx-option:first-child'); } - public size(): Locator { - return this.page.locator('[name="organizationSize"]'); + private size(): Locator { + return this.getPage().locator('[name="organizationSize"]'); } - public sizeSelect(): Locator { - return this.page.locator('.rcx-options .rcx-option:first-child'); + private sizeSelect(): Locator { + return this.getPage().locator('.rcx-options .rcx-option:first-child'); } - public country(): Locator { - return this.page.locator('[name="country"]'); + private country(): Locator { + return this.getPage().locator('[name="country"]'); } - public countrySelect(): Locator { - return this.page.locator('.rcx-options .rcx-option:first-child'); + private countrySelect(): Locator { + return this.getPage().locator('.rcx-options .rcx-option:first-child'); } public registeredServer(): Locator { - return this.page.locator('input[name=email]'); + return this.getPage().locator('input[name=email]'); } public registerButton(): Locator { - return this.page.locator('//button[contains(text(), "Register")]'); + return this.getPage().locator('//button[contains(text(), "Register")]'); } public agreementField(): Locator { - return this.page.locator('//input[@name="agreement"]/../i[contains(@class, "rcx-check-box")]'); + return this.getPage().locator('//input[@name="agreement"]/../i[contains(@class, "rcx-check-box")]'); } public standaloneServer(): Locator { - return this.page.locator('//button[contains(text(), "Continue as standalone")]'); + return this.getPage().locator('//button[contains(text(), "Continue as standalone")]'); } public standaloneConfirmText(): Locator { - return this.page.locator('//*[contains(text(), "Standalone Server Confirmation")]'); + return this.getPage().locator('//*[contains(text(), "Standalone Server Confirmation")]'); } - public fullNameIvalidtext(): Locator { - return this.page.locator('//input[@name="fullname"]/../following-sibling::span'); + private fullNameIvalidtext(): Locator { + return this.getPage().locator('//input[@name="fullname"]/../following-sibling::span'); } - public userNameInvalidText(): Locator { - return this.page.locator('//input[@name="username"]/../following-sibling::span'); + private userNameInvalidText(): Locator { + return this.getPage().locator('//input[@name="username"]/../following-sibling::span'); } - public companyEmailInvalidText(): Locator { - return this.page.locator('//input[@name="companyEmail"]/../following-sibling::span'); + private companyEmailInvalidText(): Locator { + return this.getPage().locator('//input[@name="companyEmail"]/../following-sibling::span'); } - public organizationNameInvalidText(): Locator { - return this.page.locator('//input[@name="organizationName"]/../following-sibling::span'); + private organizationNameInvalidText(): Locator { + return this.getPage().locator('//input[@name="organizationName"]/../following-sibling::span'); } - public passwordInvalidText(): Locator { - return this.page.locator('//input[@name="password"]/../../../span[contains(@class, "rcx-field__error")]'); + private passwordInvalidText(): Locator { + return this.getPage().locator('//input[@name="password"]/../../../span[contains(@class, "rcx-field__error")]'); } - public industryInvalidSelect(): Locator { - return this.page.locator('//div[@name="organizationIndustry"]/../following-sibling::span'); + private industryInvalidSelect(): Locator { + return this.getPage().locator('//div[@name="organizationIndustry"]/../following-sibling::span'); } - public sizeInvalidSelect(): Locator { - return this.page.locator('//div[@name="organizationSize"]/../following-sibling::span'); + private sizeInvalidSelect(): Locator { + return this.getPage().locator('//div[@name="organizationSize"]/../following-sibling::span'); } - public countryInvalidSelect(): Locator { - return this.page.locator('//div[@name="country"]/../following-sibling::span'); + private countryInvalidSelect(): Locator { + return this.getPage().locator('//div[@name="country"]/../following-sibling::span'); } - public invalidInputEmail(): Locator { - return this.page.locator('$$("input:invalid")'); - } - - public async login(): Promise { - const loginObj = new LoginPage(this.browser, this.baseURL); - await loginObj.login({ email: adminEmail, password: adminPassword }); + private invalidInputEmail(): Locator { + return this.getPage().locator('$$("input:invalid")'); } public async goNext(): Promise { await this.nextStep().click(); } - public async stepOneSucess(): Promise { - await this.fullName().type(adminUsername); - await this.userName().type(adminUsername); - await this.companyEmail().type(adminEmail); - await this.password().type(adminPassword); + private stepThreeInputInvalidMail(): Locator { + return this.getPage().locator('//input[@name="email"]/../../span[contains(text(), "This field is required")]'); + } + + public async stepOneSucess(adminCredential: IRegister): Promise { + await this.fullName().type(adminCredential.name); + await this.userName().type(adminCredential.name); + await this.companyEmail().type(adminCredential.email); + await this.password().type(adminCredential.password); await this.goNext(); } @@ -163,9 +163,46 @@ class SetupWizard extends Pages { await this.standaloneServer().click(); } - // goToHome() { - // this.goToWorkspace.click(); - // } + public async stepOneFailedBlankFields(): Promise { + await this.goNext(); + + await expect(this.fullNameIvalidtext()).toBeVisible(); + await expect(this.userNameInvalidText()).toBeVisible(); + await expect(this.companyEmailInvalidText()).toBeVisible(); + await expect(this.passwordInvalidText()).toBeVisible(); + } + + public async stepOneFailedWithInvalidEmail(adminCredentials: IRegister): Promise { + await this.fullName().type(adminCredentials.name); + await this.userName().type(adminCredentials.name); + await this.companyEmail().type(INVALID_EMAIL_WITHOUT_MAIL_PROVIDER); + await this.password().type(adminCredentials.password); + + await this.goNext(); + + await expect(this.companyEmail()).toBeFocused(); + } + + public async stepTwoFailedWithBlankFields(): Promise { + await this.goNext(); + + await expect(this.organizationName()).toBeVisible(); + await expect(this.industryInvalidSelect()).toBeVisible(); + await expect(this.sizeInvalidSelect()).toBeVisible(); + await expect(this.countryInvalidSelect()).toBeVisible(); + } + + public async stepThreeFailedWithInvalidField(): Promise { + await this.registeredServer().type(INVALID_EMAIL_WITHOUT_MAIL_PROVIDER); + await this.registeredServer().click({ clickCount: 3 }); + await this.keyboardPress(BACKSPACE); + + await expect(this.stepThreeInputInvalidMail()).toBeVisible(); + } + + async goToHome(): Promise { + await this.goToWorkspace().click(); + } } export default SetupWizard; From 20281c4ca61ea0fb7ccd5059dec877f14e362a88 Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Wed, 30 Mar 2022 15:29:51 -0300 Subject: [PATCH 16/35] chore: remove unused class --- .../e2e/utils/pageobjects/GlobalSelectors.ts | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 tests/e2e/utils/pageobjects/GlobalSelectors.ts diff --git a/tests/e2e/utils/pageobjects/GlobalSelectors.ts b/tests/e2e/utils/pageobjects/GlobalSelectors.ts deleted file mode 100644 index b0ffd005f269..000000000000 --- a/tests/e2e/utils/pageobjects/GlobalSelectors.ts +++ /dev/null @@ -1,30 +0,0 @@ -import Pages from './Pages'; - -export default class GlobalSelectors extends Pages { - public async setText(selector: string, text: string): Promise { - await this.getPage().type(selector, text); - } - - public async open(url = ''): Promise { - await super.open(url); - } - - public async click(selector: string): Promise { - await this.getPage().click(selector); - } - - public async clearInput(selector: string): Promise { - await this.getPage().click(selector, { clickCount: 3 }); - await this.getPage().keyboard.press('Backspace'); - } - - public async clearAllInputs(selectors: string[]): Promise { - const listOfActions = []; - - for (const selector of selectors) { - listOfActions.push(this.clearInput(selector)); - } - - await Promise.all(listOfActions); - } -} From 429c4016676dc81bd793a0a51261802fc951447c Mon Sep 17 00:00:00 2001 From: Weslley de Campos Date: Wed, 30 Mar 2022 15:34:35 -0300 Subject: [PATCH 17/35] lint --- tests/e2e/06-messaging.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/e2e/06-messaging.spec.ts b/tests/e2e/06-messaging.spec.ts index 0cbe5bd67855..8f87d46ba64c 100644 --- a/tests/e2e/06-messaging.spec.ts +++ b/tests/e2e/06-messaging.spec.ts @@ -1,5 +1,7 @@ -import { test, expect } from '@playwright/test'; +import { test } from '@playwright/test'; test.describe('[Messaging]', () => { - test.beforeAll(async ({ page }) => {}); + test.beforeAll(async () => { + expect(1).toBe(1); + }); }); From f8af23b08194d27d20fcc0b649fce8912b20441f Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Wed, 30 Mar 2022 09:08:34 -0300 Subject: [PATCH 18/35] test: create flas-tab, main-content and side-nav --- tests/e2e/utils/pageobjects/flex-tab.page.ts | 372 ++++++++++++++++++ .../utils/pageobjects/main-content.page.ts | 260 ++++++++++++ tests/e2e/utils/pageobjects/side-nav.page.ts | 225 +++++++++++ 3 files changed, 857 insertions(+) create mode 100644 tests/e2e/utils/pageobjects/flex-tab.page.ts create mode 100644 tests/e2e/utils/pageobjects/main-content.page.ts create mode 100644 tests/e2e/utils/pageobjects/side-nav.page.ts diff --git a/tests/e2e/utils/pageobjects/flex-tab.page.ts b/tests/e2e/utils/pageobjects/flex-tab.page.ts new file mode 100644 index 000000000000..93e590a78b2f --- /dev/null +++ b/tests/e2e/utils/pageobjects/flex-tab.page.ts @@ -0,0 +1,372 @@ +import { Locator } from '@playwright/test'; + +import Pages from './Pages'; +// import Global from './global'; + +class FlexTab extends Pages { + public headerMoreActions(): Locator { + return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); + } + + public moreActions(): Locator { + return this.page.locator('.rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); + } + + public sendBtn(): Locator { + return this.page.locator('.rcx-vertical-bar .rc-message-box__icon.js-send'); + } + + public messageInput(): Locator { + return this.page.locator('.rcx-vertical-bar .js-input-message'); + } + + public threadTab(): Locator { + return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-thread'); + } + + // Channel Info Tab + public channelTab(): Locator { + return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-info-circled'); + } + + public channelSettings(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-info-circled'); + } + + public channelSettingName(): Locator { + return this.page.locator('.channel-settings .rc-user-info__name'); + } + + public archiveBtn(): Locator { + return this.page.locator('.clearfix:last-child .icon-pencil'); + } + + public archiveRadio(): Locator { + return this.page.locator('.editing'); + } + + public archiveSave(): Locator { + return this.page.locator('.save'); + } + + public editNameBtn(): Locator { + return this.page.locator('[data-edit="name"]'); + } + + public editTopicBtn(): Locator { + return this.page.locator('[data-edit="topic"]'); + } + + public editAnnouncementBtn(): Locator { + return this.page.locator('[data-edit="announcement"]'); + } + + public editDescriptionBtn(): Locator { + return this.page.locator('[data-edit="description"]'); + } + + public editNotificationBtn(): Locator { + return this.page.locator('[data-edit="desktopNotifications"]'); + } + + public editMobilePushBtn(): Locator { + return this.page.locator('[data-edit="mobilePushNotifications"]'); + } + + public editEmailNotificationBtn(): Locator { + return this.page.locator('[data-edit="emailNotifications"]'); + } + + public editUnreadAlertBtn(): Locator { + return this.page.locator('[data-edit="unreadAlert"]'); + } + + public editNameTextInput(): Locator { + return this.page.locator('.channel-settings input[name="name"]'); + } + + public editTopicTextInput(): Locator { + return this.page.locator('.channel-settings input[name="topic"]'); + } + + public editAnnouncementTextInput(): Locator { + return this.page.locator('.channel-settings input[name="announcement"]'); + } + + public editDescriptionTextInput(): Locator { + return this.page.locator('.channel-settings input[name="description"]'); + } + + public editNameSave(): Locator { + return this.page.locator('.channel-settings .save'); + } + + public deleteBtn(): Locator { + return this.page.locator('.channel-settings .js-delete'); + } + + // Members Tab + public membersTab(): Locator { + return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-members'); + } + + public membersTabContent(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-members'); + } + + public userSearchBar(): Locator { + return this.page.locator('#user-add-search'); + } + + public removeUserBtn(): Locator { + return this.page.locator('.remove-user'); + } + + public setOwnerBtn(): Locator { + return this.page.locator('.set-owner'); + } + + public setModeratorBtn(): Locator { + return this.page.locator('.set-moderator'); + } + + public muteUserBtn(): Locator { + return this.page.locator('.mute-user'); + } + + public viewAllBtn(): Locator { + return this.page.locator('.button.back'); + } + + public startVideoCall(): Locator { + return this.page.locator('.start-video-call'); + } + + public startAudioCall(): Locator { + return this.page.locator('.start-audio-call'); + } + + public showAll(): Locator { + return this.page.locator('.see-all'); + } + + public membersUserInfo(): Locator { + return this.page.locator('.flex-tab-container .info'); + } + + public avatarImage(): Locator { + return this.page.locator('aside.rcx-vertical-bar .rcx-avatar'); + } + + public memberUserName(): Locator { + return this.page.locator('.info h3'); + } + + public memberRealName(): Locator { + return this.page.locator('.info p'); + } + + // Search Tab + public searchTab(): Locator { + return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-magnifier'); + } + + public searchTabContent(): Locator { + return this.page.locator('.rocket-search-result'); + } + + public messageSearchBar(): Locator { + return this.page.locator('#message-search'); + } + + public searchResult(): Locator { + return this.page.locator('.new-day'); + } + + // Notifications Tab + public notificationsTab(): Locator { + return this.page.locator('.rcx-option__content:contains("Notifications Preferences")'); + } + + public notificationsSettings(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-bell'); + } + + // Files Tab + public filesTab(): Locator { + return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-clip'); + } + + public fileItem(): Locator { + return this.page.locator('.uploaded-files-list ul:first-child'); + } + + public filesTabContent(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-icon--name-attachment'); + } + + public fileDelete(): Locator { + return this.page.locator('.uploaded-files-list ul:first-child .file-delete'); + } + + public fileDownload(): Locator { + return this.page.locator('.uploaded-files-list ul:first-child .file-download'); + } + + public fileName(): Locator { + return this.page.locator('.uploaded-files-list ul:first-child .room-file-item'); + } + + // Mentions Tab + public mentionsTab(): Locator { + return this.page.locator('.rcx-option__content:contains("Mentions")'); + } + + public mentionsTabContent(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-icon--name-at'); + } + + // Starred Tab + public starredTab(): Locator { + return this.page.locator('.rcx-option__content:contains("Starred Messages")'); + } + + public starredTabContent(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-icon--name-star'); + } + + // Pinned Tab + public pinnedTab(): Locator { + return this.page.locator('.rcx-option__content:contains("Pinned Messages")'); + } + + public pinnedTabContent(): Locator { + return this.page.locator('aside > h3 > div > i.rcx-icon--name-pin'); + } + + public firstSetting(): Locator { + return this.page.locator('.clearfix li:nth-child(1) .current-setting'); + } + + public secondSetting(): Locator { + return this.page.locator('.clearfix li:nth-child(2) .current-setting'); + } + + public thirdSetting(): Locator { + return this.page.locator('.clearfix li:nth-child(3) .current-setting'); + } + + public fourthSetting(): Locator { + return this.page.locator('.clearfix li:nth-child(4) .current-setting'); + } + + // admin view flextab items + public usersSendInvitationTab(): Locator { + return this.page.locator('.tab-button:not(.hidden) .tab-button-icon--send'); + } + + public usersAddUserTab(): Locator { + return this.page.locator('.tab-button:not(.hidden) .tab-button-icon--plus'); + } + + public usersSendInvitationTextArea(): Locator { + return this.page.locator('#inviteEmails'); + } + + public usersButtonCancel(): Locator { + return this.page.locator('.button.cancel'); + } + + public usersSendInvitationSend(): Locator { + return this.page.locator('.button.send'); + } + + public usersButtonSave(): Locator { + return this.page.locator('.button.save'); + } + + public usersAddUserName(): Locator { + return this.page.locator('#name'); + } + + public usersAddUserUsername(): Locator { + return this.page.locator('#username'); + } + + public usersAddUserEmail(): Locator { + return this.page.locator('#email'); + } + + public usersAddUserRoleList(): Locator { + return this.page.locator('#roleSelect'); + } + + public usersAddUserPassword(): Locator { + return this.page.locator('#password'); + } + + public usersAddUserRoleButton(): Locator { + return this.page.locator('#addRole'); + } + + public usersAddUserVerifiedCheckbox(): Locator { + return this.page.locator('#verified'); + } + + public usersAddUserChangePasswordCheckbox(): Locator { + return this.page.locator('#changePassword'); + } + + public usersAddUserDefaultChannelCheckbox(): Locator { + return this.page.locator('#joinDefaultChannels'); + } + + public usersAddUserWelcomeEmailCheckbox(): Locator { + return this.page.locator('#sendWelcomeEmail'); + } + + public usersAddUserRandomPassword(): Locator { + return this.page.locator('#randomPassword'); + } + + public emojiNewAliases(): Locator { + return this.page.locator('#aliases'); + } + + public emojiNewImageInput(): Locator { + return this.page.locator('#image'); + } + + public usersView(): Locator { + return this.page.locator('.rcx-vertical-bar:contains("User Info")'); + } + + public usersActivate(): Locator { + return this.page.locator('.rcx-option__content:contains("Activate")'); + } + + public usersDeactivate(): Locator { + return this.page.locator('.rcx-option__content:contains("Deactivate")'); + } + + public getUserEl(username: any): Locator { + return this.page.locator(`.flex-tab button[title="${username}"] > p`); + } + + public async archiveChannel(): Promise { + await this.archiveBtn().waitFor(); + await this.archiveBtn().click(); + await this.archiveRadio().waitFor(); + await this.archiveRadio().click(); + await this.archiveSave().click(); + } + + public async addPeopleToChannel(user: any): Promise { + await this.userSearchBar().waitFor(); + await this.userSearchBar().type(user); + this.page.waitForSelector('.-autocomplete-item'); + this.page.click('.-autocomplete-item'); + } +} + +export default FlexTab; diff --git a/tests/e2e/utils/pageobjects/main-content.page.ts b/tests/e2e/utils/pageobjects/main-content.page.ts new file mode 100644 index 000000000000..6b8ee9697f3c --- /dev/null +++ b/tests/e2e/utils/pageobjects/main-content.page.ts @@ -0,0 +1,260 @@ +import { expect, Locator } from '@playwright/test'; + +import Pages from './Pages'; + +class MainContent extends Pages { + public mainContent(): Locator { + return this.page.locator('.main-content'); + } + + // Main Content Header (Channel Title Area) + public emptyFavoriteStar(): Locator { + return this.page.locator('.rcx-room-header .rcx-icon--name-star'); + } + + public favoriteStar(): Locator { + return this.page.locator('.rcx-room-header .rcx-icon--name-star-filled'); + } + + public channelTitle(): Locator { + return this.page.locator('.rcx-room-header'); + } + + // Main Content Footer (Message Input Area) + public messageInput(): Locator { + return this.page.locator('.js-input-message'); + } + + public sendBtn(): Locator { + return this.page.locator('.rc-message-box__icon.js-send'); + } + + public messageBoxActions(): Locator { + return this.page.locator('.rc-message-box__icon'); + } + + public recordBtn(): Locator { + return this.page.locator('.js-audio-message-record'); + } + + public emojiBtn(): Locator { + return this.page.locator('.rc-message-box__icon.emoji-picker-icon'); + } + + public messagePopUp(): Locator { + return this.page.locator('.message-popup'); + } + + public messagePopUpTitle(): Locator { + return this.page.locator('.message-popup-title'); + } + + public messagePopUpItems(): Locator { + return this.page.locator('.message-popup-items'); + } + + public messagePopUpFirstItem(): Locator { + return this.page.locator('.popup-item.selected'); + } + + public mentionAllPopUp(): Locator { + return this.page.locator('.popup-item[data-id="all"]'); + } + + public joinChannelBtn(): Locator { + return this.page.locator('.button.join'); + } + + // Messages + public lastMessageUser(): Locator { + return this.page.locator('.message:last-child .title .user-card-message'); + } + + public lastMessage(): Locator { + return this.page.locator('.message:last-child'); + } + + public lastMessageDesc(): Locator { + return this.page.locator('.message:last-child .body .attachment-description'); + } + + public lastMessageRoleAdded(): Locator { + return this.page.locator('.message:last-child.subscription-role-added .body'); + } + + public beforeLastMessage(): Locator { + return this.page.locator('.message:nth-last-child(2) .body'); + } + + public lastMessageUserTag(): Locator { + return this.page.locator('.message:last-child .role-tag'); + } + + public lastMessageImg(): Locator { + return this.page.locator('.message:last-child .attachment-image img'); + } + + public lastMessageTextAttachment(): Locator { + return this.page.locator('.message:last-child .attachment-text'); + } + + public beforeLastMessageQuote(): Locator { + return this.page.locator('.message:nth-last-child(2)'); + } + + public lastMessageQuote(): Locator { + return this.page.locator('.message:last-child'); + } + + public messageOptionsBtn(): Locator { + return this.page.locator('.message:last-child .message-actions__menu'); + } + + public messageOptionsBtns(): Locator { + return this.page.locator('.message:last-child .message-actions'); + } + + public messageActionMenu(): Locator { + return this.page.locator('.rc-popover .rc-popover__content'); + } + + public messageReply(): Locator { + return this.page.locator('.message:last-child .message-actions__button[data-message-action="reply-in-thread"]'); + } + + public messageEdit(): Locator { + return this.page.locator('[data-id="edit-message"][data-type="message-action"]'); + } + + public messageDelete(): Locator { + return this.page.locator('[data-id="delete-message"][data-type="message-action"]'); + } + + public messagePermalink(): Locator { + return this.page.locator('[data-id="permalink"][data-type="message-action"]'); + } + + public messageCopy(): Locator { + return this.page.locator('[data-id="copy"][data-type="message-action"]'); + } + + public messageQuote(): Locator { + return this.page.locator('[data-id="quote-message"][data-type="message-action"]'); + } + + public messageStar(): Locator { + return this.page.locator('[data-id="star-message"][data-type="message-action"]'); + } + + public messageUnread(): Locator { + return this.page.locator('[data-id="mark-message-as-unread"][data-type="message-action"]'); + } + + public messageReplyInDM(): Locator { + return this.page.locator('[data-id="reply-directly"][data-type="message-action"]'); + } + + // public messageReaction(): Locator { return this.page.locator('.message-actions__button[data-message-action="reaction-message"]'); } + public messagePin(): Locator { + return this.page.locator('[data-id="pin-message"][data-type="message-action"]'); + } + // public messageClose(): Locator { return this.page.locator('[data-id="rc-popover-close"][data-type="message-action"]'); } + + // Emojis + public emojiPickerMainScreen(): Locator { + return this.page.locator('.emoji-picker'); + } + + public emojiPickerPeopleIcon(): Locator { + return this.page.locator('.emoji-picker .icon-people'); + } + + public emojiPickerNatureIcon(): Locator { + return this.page.locator('.emoji-picker .icon-nature'); + } + + public emojiPickerFoodIcon(): Locator { + return this.page.locator('.emoji-picker .icon-food'); + } + + public emojiPickerActivityIcon(): Locator { + return this.page.locator('.emoji-picker .icon-activity'); + } + + public emojiPickerTravelIcon(): Locator { + return this.page.locator('.emoji-picker .icon-travel'); + } + + public emojiPickerObjectsIcon(): Locator { + return this.page.locator('.emoji-picker .icon-objects'); + } + + public emojiPickerSymbolsIcon(): Locator { + return this.page.locator('.emoji-picker .icon-symbols'); + } + + public emojiPickerFlagsIcon(): Locator { + return this.page.locator('.emoji-picker .icon-flags'); + } + + public emojiPickerModifierIcon(): Locator { + return this.page.locator('.emoji-picker .icon-symbols'); + } + + public emojiPickerChangeTone(): Locator { + return this.page.locator('.emoji-picker .change-tone'); + } + + public emojiPickerCustomIcon(): Locator { + return this.page.locator('.emoji-picker .icon-rocket'); + } + + public emojiPickerRecentIcon(): Locator { + return this.page.locator('.emoji-picker .icon-recent'); + } + + public emojiPickerFilter(): Locator { + return this.page.locator('.emoji-picker .js-emojipicker-search'); + } + + public emojiPickerEmojiContainer(): Locator { + return this.page.locator('.emoji-picker .emojis'); + } + + public emojiGrinning(): Locator { + return this.page.locator('.emoji-picker .emoji-grinning'); + } + + public emojiSmile(): Locator { + return this.page.locator('.emoji-picker .emoji-smile'); + } + + // Popover + public popoverWrapper(): Locator { + return this.page.locator('.rc-popover'); + } + + // Sends a message and wait for the message to equal the text sent + public async sendMessage(text: any): Promise { + this.setTextToInput(text); + await this.sendBtn().click(); + await expect(this.page.locator('.message:last-child .body')).toBeVisible(); + await expect(this.page.locator('.message:last-child .body')).toContain(text); + } + + // adds text to the input + public async addTextToInput(text: any): Promise { + await this.messageInput().type(text); + } + + // Clear and sets the text to the input + public async setTextToInput(text: any): Promise { + // cy.wait(200); + await this.messageInput().fill(''); + if (text) { + this.messageInput().type(text); + } + } +} + +export default MainContent; diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts new file mode 100644 index 000000000000..e750b1373589 --- /dev/null +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -0,0 +1,225 @@ +import { expect, Locator } from '@playwright/test'; + +import Pages from './Pages'; +// import mainContent from './main-content.page'; + +class SideNav extends Pages { + // New channel + public channelType(): Locator { + return this.page.locator('#modal-root .rcx-field:contains("Private") .rcx-toggle-switch__fake'); + } + + public channelReadOnly(): Locator { + return this.page.locator('.create-channel__switches .rc-switch__button'); + } + + public channelName(): Locator { + return this.page.locator('#modal-root [placeholder="Channel Name"]'); + } + + public saveChannelBtn(): Locator { + return this.page.locator('#modal-root button:contains("Create")'); + } + + // Account box + public getPopOverContent(): Locator { + return this.page.locator('.rc-popover__content'); + } + + public accountBoxUserName(): Locator { + return this.page.locator('.sidebar__account-username'); + } + + public accountBoxUserAvatar(): Locator { + return this.page.locator('.sidebar__account .avatar-image'); + } + + public accountMenu(): Locator { + return this.page.locator('.sidebar__account'); + } + + public sidebarHeader(): Locator { + return this.page.locator('.sidebar__header'); + } + + public sidebarUserMenu(): Locator { + return this.page.locator('[data-qa="sidebar-avatar-button"]'); + } + + public sidebarMenu(): Locator { + return this.page.locator('.sidebar__toolbar-button-icon--menu'); + } + + public popOverContent(): Locator { + return this.page.locator('.rc-popover__content'); + } + + public popOverHideOption(): Locator { + return this.page.locator('.rcx-option__content:contains("Hide")'); + } + + public statusOnline(): Locator { + return this.page.locator('.rcx-box--with-inline-elements:contains("online")'); + } + + public statusAway(): Locator { + return this.page.locator('.rcx-box--with-inline-elements:contains("away")'); + } + + public statusBusy(): Locator { + return this.page.locator('.rcx-box--with-inline-elements:contains("busy")'); + } + + public statusOffline(): Locator { + return this.page.locator('.rcx-box--with-inline-elements:contains("offline")'); + } + + public account(): Locator { + return this.page.locator('.rcx-option__content:contains("My Account")'); + } + + public admin(): Locator { + return this.page.locator('.rcx-option__content:contains("Administration")'); + } + + public logout(): Locator { + return this.page.locator('.rcx-option__content:contains("Logout")'); + } + + public sideNavBar(): Locator { + return this.page.locator('.sidebar'); + } + + // Toolbar + public spotlightSearchIcon(): Locator { + return this.page.locator('[data-qa="sidebar-search"]'); + } + + public spotlightSearch(): Locator { + return this.page.locator('[data-qa="sidebar-search-input"]'); + } + + public spotlightSearchPopUp(): Locator { + return this.page.locator('[data-qa="sidebar-search-result"]'); + } + + public newChannelBtnToolbar(): Locator { + return this.page.locator('[data-qa="sidebar-create"]'); + } + + public newChannelBtn(): Locator { + return this.page.locator('.rcx-option__content:contains("Channel")'); + } + + public newDiscussionBtn(): Locator { + return this.page.locator('.rcx-option__content:contains("Discussion")'); + } + + public newChannelIcon(): Locator { + return this.page.locator('[data-qa="sidebar-create-channel"]'); + } + + // Rooms List + public async general(): Promise { + return this.getChannelFromList('general'); + } + + public channelLeave(): Locator { + return this.page.locator('.leave-room'); + } + + public channelHoverIcon(): Locator { + return this.page.locator('.rooms-list > .wrapper > ul [title="general"] .icon-eye-off'); + } + + // Account + public preferences(): Locator { + return this.page.locator('[href="/account/preferences"]'); + } + + public profile(): Locator { + return this.page.locator('[href="/account/profile"]'); + } + + public avatar(): Locator { + return this.page.locator('[href="/changeavatar"]'); + } + + public preferencesClose(): Locator { + return this.page.locator('.flex-nav i.rcx-icon--name-cross'); + } + + public burgerBtn(): Locator { + return this.page.locator('.burger, [aria-label="Open_menu"]'); + } + + public sidebarWrap(): Locator { + return this.page.locator('.sidebar-wrap'); + } + + public firstSidebarItem(): Locator { + return this.page.locator('.sidebar-item'); + } + + public firstSidebarItemMenu(): Locator { + return this.page.locator('[data-qa=sidebar-avatar-button]'); + } + + public popoverOverlay(): Locator { + return this.page.locator('.rc-popover.rc-popover--sidebar-item'); + } + + // Opens a channel via rooms list + public async openChannel(channelName: any): Promise { + await this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).scrollIntoViewIfNeeded(); + await this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).click(); + await expect(this.page.locator('.rcx-room-header')).toContainText(channelName); + } + + // Opens a channel via spotlight search + public async searchChannel(channelName: any): Promise { + await this.spotlightSearch().should('be.visible'); + + // Should have focus automatically, but some times it's not happening + await this.spotlightSearch().click(); + + await expect(this.spotlightSearch()).toBeFocused(); + await this.spotlightSearch().type(channelName); + // cy.wait(500); + + // cy.get( + // `[data-qa="sidebar-search-result"] .rcx-sidebar-item--clickable:contains("${channelName}"), [data-qa="sidebar-search-result"] .rcx-sidebar-item[aria-label='${channelName}']`, + // ).click(); + + await expect(this.page.locator('.rcx-room-header')).toContainText(channelName); + } + + // Gets a channel from the rooms list + public async getChannelFromList(channelName: any): Promise { + return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).scrollIntoViewIfNeeded(); + } + + public async createChannel(channelName: any, isPrivate: any /* isReadOnly*/): Promise { + await this.newChannelBtnToolbar().click(); + + await this.newChannelBtn().click(); + + if (!isPrivate) { + await this.channelType().click(); + } + + await this.channelName().type(channelName); + + await expect(this.saveChannelBtn()).toBeEnabled(); + + // if (isReadOnly) { + // this.channelReadOnly.click(); + // } + + await this.saveChannelBtn().click(); + await expect(this.channelType()).not.toBeVisible(); + // mainContent.messageInput().should('be.focused'); + } +} + +export default SideNav; From 2ae4ed1d81adc32b4c5d1e2f0090eed6b8a90b2b Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Wed, 30 Mar 2022 09:12:01 -0300 Subject: [PATCH 19/35] test: create main-elements tests file --- tests/e2e/04-main-elements-render.spec.ts | 303 ++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 tests/e2e/04-main-elements-render.spec.ts diff --git a/tests/e2e/04-main-elements-render.spec.ts b/tests/e2e/04-main-elements-render.spec.ts new file mode 100644 index 000000000000..90f705191ec6 --- /dev/null +++ b/tests/e2e/04-main-elements-render.spec.ts @@ -0,0 +1,303 @@ +import { test, expect } from '@playwright/test'; + +import MainContent from './utils/pageobjects/main-content.page'; +import SideNav from './utils/pageobjects/side-nav.page'; +import FlexTab from './utils/pageobjects/flex-tab.page'; +import LoginPage from './utils/pageobjects/login.page'; + +describe('[Main Elements Render]', function () { + let loginPage: LoginPage; + let mainContent: MainContent; + let sideNav: SideNav; + let flexTab: FlexTab; + + test.beforeAll(async ({ browser, baseURL }) => { + loginPage = new LoginPage(browser, baseURL as string); + await loginPage.open(); + await loginPage.login('user.test', 'user.test'); + }); + + describe('[Side Nav Bar]', () => { + describe('render:', () => { + test('expect show the new channel button', () => { + sideNav.newChannelBtnToolbar().should('be.visible'); + }); + + test('expect show "general" channel', () => { + sideNav.general().should('be.visible'); + }); + }); + + describe('spotlight search render:', () => { + after(() => { + mainContent.messageInput.click(); + }); + test('expect show spotlight search bar', () => { + sideNav.spotlightSearchIcon.click(); + sideNav.spotlightSearch.should('be.visible'); + }); + + test('expect click the spotlight and show the channel list', () => { + sideNav.spotlightSearch.click('center'); + sideNav.spotlightSearchPopUp.should('be.visible'); + }); + + it.skip('expect remove the list when the spotlight loses focus', () => { + sideNav.spotlightSearchPopUp.should('be.visible'); + mainContent.messageInput.click(); + mainContent.lastMessage.click(); + sideNav.spotlightSearchPopUp.should('not.exist'); + }); + + test('expect add text to the spotlight and show the channel list', () => { + sideNav.spotlightSearch.type('rocket.cat'); + sideNav.spotlightSearchPopUp.should('be.visible'); + }); + + it.skip('expect remove the text on the spotlight and the list when lost focus', () => { + sideNav.spotlightSearchPopUp.should('be.visible'); + mainContent.messageInput.click(); + sideNav.spotlightSearchPopUp.should('not.exist'); + sideNav.spotlightSearch.should('have.text', ''); + }); + }); + }); + + describe('[User Options]', () => { + describe('render:', () => { + before(() => { + sideNav.sidebarUserMenu.click(); + }); + + after(() => { + sideNav.sidebarUserMenu.click(); + }); + + test('expect show online button', () => { + sideNav.statusOnline.should('be.visible'); + }); + + test('expect show away button', () => { + sideNav.statusAway.should('be.visible'); + }); + + test('expect show busy button', () => { + sideNav.statusBusy.should('be.visible'); + }); + + test('expect show offline button', () => { + sideNav.statusOffline.should('be.visible'); + }); + + test('expect show my account button', () => { + sideNav.account.should('be.visible'); + }); + + test('expect show logout button', () => { + sideNav.logout.should('be.visible'); + }); + }); + }); + + describe('[Main Content]', () => { + describe('render:', () => { + before(() => { + sideNav.openChannel('general'); + }); + + test('expect show the title of the channel', () => { + mainContent.channelTitle.contains('general').should('be.visible'); + }); + + test('expect show the empty favorite star', () => { + mainContent.emptyFavoriteStar.should('be.visible'); + }); + + test('expect click the star', () => { + mainContent.emptyFavoriteStar.click(); + }); + + test('expect show the filled favorite star', () => { + mainContent.favoriteStar.should('be.visible'); + }); + + test('expect click the star', () => { + mainContent.favoriteStar.click(); + }); + + test('expect show the empty favorite star', () => { + mainContent.emptyFavoriteStar.should('be.visible'); + }); + + test('expect show the message input bar', () => { + mainContent.messageInput.should('be.visible'); + }); + + test('expect show the message box actions button', () => { + mainContent.messageBoxActions.should('be.visible'); + }); + + // issues with the new message box action button and the no animations on tests + + test('expect show the audio recording button', () => { + mainContent.recordBtn.should('be.visible'); + }); + + test('expect show the emoji button', () => { + mainContent.emojiBtn.should('be.visible'); + }); + + test('expect show the last message', () => { + mainContent.lastMessage.should('be.visible'); + }); + + test('expect be that the last message is from the logged user', () => { + mainContent.lastMessageUser.should('contain', username); + }); + + test('expect not show the Admin tag', () => { + mainContent.lastMessageUserTag.should('not.exist'); + }); + }); + }); + + describe('[Flextab]', () => { + describe('[Render]', () => { + before(() => { + sideNav.openChannel('general'); + }); + + describe('Room Info Tab:', () => { + before(() => { + flexTab.operateFlexTab('info', true); + }); + + after(() => { + flexTab.operateFlexTab('info', false); + }); + + test('expect show the room info button', () => { + flexTab.channelTab.should('be.visible'); + }); + + test('expect show the room info tab content', () => { + flexTab.channelSettings.should('be.visible'); + }); + + it.skip('expect show the room name', () => { + flexTab.channelSettingName.should('have.attr', 'title', 'general'); + }); + }); + + describe('Search Tab:', () => { + before(() => { + flexTab.operateFlexTab('search', true); + }); + + after(() => { + flexTab.operateFlexTab('search', false); + }); + + test('expect show the message search button', () => { + flexTab.searchTab.should('be.visible'); + }); + + test('expect show the message tab content', () => { + flexTab.searchTabContent.should('be.visible'); + }); + }); + + describe('Members Tab:', () => { + before(() => { + flexTab.operateFlexTab('members', true); + }); + + after(() => { + flexTab.operateFlexTab('members', false); + }); + + test('expect show the members tab button', () => { + flexTab.membersTab.should('be.visible'); + }); + + test('expect show the members content', () => { + flexTab.membersTabContent.should('be.visible'); + }); + }); + + describe('Notifications Tab:', () => { + before(() => { + flexTab.operateFlexTab('notifications', true); + }); + + after(() => { + flexTab.operateFlexTab('notifications', false); + }); + + test('expect not show the notifications button', () => { + flexTab.notificationsTab.should('not.exist'); + }); + + test('expect show the notifications Tab content', () => { + flexTab.notificationsSettings.should('be.visible'); + }); + }); + + describe('Files Tab:', () => { + before(() => { + flexTab.operateFlexTab('files', true); + }); + + after(() => { + flexTab.operateFlexTab('files', false); + }); + + test('expect show the files Tab content', () => { + flexTab.filesTabContent.should('be.visible'); + }); + }); + + describe('Mentions Tab:', () => { + before(() => { + flexTab.operateFlexTab('mentions', true); + }); + + after(() => { + flexTab.operateFlexTab('mentions', false); + }); + + test('expect show the mentions Tab content', () => { + flexTab.mentionsTabContent.should('be.visible'); + }); + }); + + describe('Starred Messages Tab:', () => { + before(() => { + flexTab.operateFlexTab('starred', true); + }); + + after(() => { + flexTab.operateFlexTab('starred', false); + }); + + test('expect show the starred messages Tab content', () => { + flexTab.starredTabContent.should('be.visible'); + }); + }); + + describe('Pinned Messages Tab:', () => { + before(() => { + flexTab.operateFlexTab('pinned', true); + }); + + after(() => { + flexTab.operateFlexTab('pinned', false); + }); + + test('expect show the pinned messages Tab content', () => { + flexTab.pinnedTabContent.should('be.visible'); + }); + }); + }); + }); +}); From d71b5b7de0d93a3aae9713c78a141e77d0604a60 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Wed, 30 Mar 2022 16:25:33 -0300 Subject: [PATCH 20/35] refactor: for playwright --- tests/e2e/04-main-elements-render.spec.ts | 401 +++++++++--------- tests/e2e/utils/pageobjects/flex-tab.page.ts | 85 +++- .../utils/pageobjects/main-content.page.ts | 17 +- tests/e2e/utils/pageobjects/side-nav.page.ts | 27 +- 4 files changed, 307 insertions(+), 223 deletions(-) diff --git a/tests/e2e/04-main-elements-render.spec.ts b/tests/e2e/04-main-elements-render.spec.ts index 90f705191ec6..05e1baf228d4 100644 --- a/tests/e2e/04-main-elements-render.spec.ts +++ b/tests/e2e/04-main-elements-render.spec.ts @@ -4,8 +4,11 @@ import MainContent from './utils/pageobjects/main-content.page'; import SideNav from './utils/pageobjects/side-nav.page'; import FlexTab from './utils/pageobjects/flex-tab.page'; import LoginPage from './utils/pageobjects/login.page'; +import { adminUsername, adminPassword } from './utils/mocks/userAndPasswordMock'; -describe('[Main Elements Render]', function () { +const username = adminUsername; + +test.describe('[Main Elements Render]', function () { let loginPage: LoginPage; let mainContent: MainContent; let sideNav: SideNav; @@ -14,165 +17,151 @@ describe('[Main Elements Render]', function () { test.beforeAll(async ({ browser, baseURL }) => { loginPage = new LoginPage(browser, baseURL as string); await loginPage.open(); - await loginPage.login('user.test', 'user.test'); + await loginPage.login({ email: adminUsername, password: adminPassword }); + sideNav = new SideNav(browser, baseURL as string, loginPage.getPage()); + mainContent = new MainContent(browser, baseURL as string, loginPage.getPage()); + flexTab = new FlexTab(browser, baseURL as string, loginPage.getPage()); }); - describe('[Side Nav Bar]', () => { - describe('render:', () => { - test('expect show the new channel button', () => { - sideNav.newChannelBtnToolbar().should('be.visible'); + test.describe('[Side Nav Bar]', () => { + test.describe('render:', () => { + test('expect show the new channel button', async () => { + await expect(sideNav.newChannelBtnToolbar()).toBeVisible(); }); - test('expect show "general" channel', () => { - sideNav.general().should('be.visible'); + test('expect show "general" channel', async () => { + await expect(sideNav.general()).toBeVisible(); }); }); - describe('spotlight search render:', () => { - after(() => { - mainContent.messageInput.click(); - }); - test('expect show spotlight search bar', () => { - sideNav.spotlightSearchIcon.click(); - sideNav.spotlightSearch.should('be.visible'); - }); - - test('expect click the spotlight and show the channel list', () => { - sideNav.spotlightSearch.click('center'); - sideNav.spotlightSearchPopUp.should('be.visible'); + test.describe('spotlight search render:', () => { + test('expect show spotlight search bar', async () => { + await sideNav.spotlightSearchIcon().click(); + await expect(sideNav.spotlightSearch()).toBeVisible(); }); - it.skip('expect remove the list when the spotlight loses focus', () => { - sideNav.spotlightSearchPopUp.should('be.visible'); - mainContent.messageInput.click(); - mainContent.lastMessage.click(); - sideNav.spotlightSearchPopUp.should('not.exist'); + test('expect click the spotlight and show the channel list', async () => { + await sideNav.spotlightSearch().click(); + await expect(sideNav.spotlightSearchPopUp()).toBeVisible(); }); - test('expect add text to the spotlight and show the channel list', () => { - sideNav.spotlightSearch.type('rocket.cat'); - sideNav.spotlightSearchPopUp.should('be.visible'); - }); - - it.skip('expect remove the text on the spotlight and the list when lost focus', () => { - sideNav.spotlightSearchPopUp.should('be.visible'); - mainContent.messageInput.click(); - sideNav.spotlightSearchPopUp.should('not.exist'); - sideNav.spotlightSearch.should('have.text', ''); + test('expect add text to the spotlight and show the channel list', async () => { + await sideNav.spotlightSearch().type('rocket.cat'); + await expect(sideNav.spotlightSearchPopUp()).toBeVisible(); + await sideNav.getPage().locator('//*[@data-qa="sidebar-search-result"]//*[@data-index="0"]').click(); }); }); }); - - describe('[User Options]', () => { - describe('render:', () => { - before(() => { - sideNav.sidebarUserMenu.click(); + test.describe('[User Options]', () => { + test.describe('render:', () => { + test.beforeEach(async () => { + await sideNav.sidebarUserMenu().click(); }); - after(() => { - sideNav.sidebarUserMenu.click(); + test.afterEach(async () => { + await sideNav.sidebarUserMenu().click(); }); - test('expect show online button', () => { - sideNav.statusOnline.should('be.visible'); + test('expect show online button', async () => { + await expect(sideNav.statusOnline()).toBeVisible(); }); - test('expect show away button', () => { - sideNav.statusAway.should('be.visible'); + test('expect show away button', async () => { + await expect(sideNav.statusAway()).toBeVisible(); }); - test('expect show busy button', () => { - sideNav.statusBusy.should('be.visible'); + test('expect show busy button', async () => { + await expect(sideNav.statusBusy()).toBeVisible(); }); - test('expect show offline button', () => { - sideNav.statusOffline.should('be.visible'); + test('expect show offline button', async () => { + await expect(sideNav.statusOffline()).toBeVisible(); }); - test('expect show my account button', () => { - sideNav.account.should('be.visible'); + test('expect show my account button', async () => { + await expect(sideNav.account()).toBeVisible(); }); - test('expect show logout button', () => { - sideNav.logout.should('be.visible'); + test('expect show logout button', async () => { + await expect(sideNav.logout()).toBeVisible(); }); }); }); - describe('[Main Content]', () => { - describe('render:', () => { - before(() => { - sideNav.openChannel('general'); + test.describe.only('[Main Content]', () => { + test.describe('render:', () => { + test.beforeAll(async () => { + await sideNav.openChannel('general'); }); - test('expect show the title of the channel', () => { - mainContent.channelTitle.contains('general').should('be.visible'); + test('expect show the title of the channel', async () => { + await expect(mainContent.channelTitle('general')).toBeVisible(); }); - test('expect show the empty favorite star', () => { - mainContent.emptyFavoriteStar.should('be.visible'); + test('expect show the empty favorite star (before)', async () => { + await expect(mainContent.emptyFavoriteStar()).toBeVisible(); }); - test('expect click the star', () => { - mainContent.emptyFavoriteStar.click(); + test('expect click the empty star', async () => { + await mainContent.emptyFavoriteStar().click(); }); - test('expect show the filled favorite star', () => { - mainContent.favoriteStar.should('be.visible'); + test('expect show the filled favorite star', async () => { + await expect(mainContent.favoriteStar()).toBeVisible(); }); - test('expect click the star', () => { - mainContent.favoriteStar.click(); + test('expect click the star', async () => { + await mainContent.favoriteStar().click(); }); - test('expect show the empty favorite star', () => { - mainContent.emptyFavoriteStar.should('be.visible'); + test('expect show the empty favorite star (after)', async () => { + await expect(mainContent.emptyFavoriteStar()).toBeVisible(); }); - test('expect show the message input bar', () => { - mainContent.messageInput.should('be.visible'); + test('expect show the message input bar', async () => { + await expect(mainContent.messageInput()).toBeVisible(); }); - test('expect show the message box actions button', () => { - mainContent.messageBoxActions.should('be.visible'); + test('expect show the message box actions button', async () => { + await expect(mainContent.messageBoxActions()).toBeVisible(); }); // issues with the new message box action button and the no animations on tests - test('expect show the audio recording button', () => { - mainContent.recordBtn.should('be.visible'); + test('expect show the audio recording button', async () => { + await expect(mainContent.recordBtn()).toBeVisible(); }); - test('expect show the emoji button', () => { - mainContent.emojiBtn.should('be.visible'); + test('expect show the emoji button', async () => { + await expect(mainContent.emojiBtn()).toBeVisible(); }); - test('expect show the last message', () => { - mainContent.lastMessage.should('be.visible'); + test('expect show the last message', async () => { + await expect(mainContent.lastMessage()).toBeVisible(); }); - test('expect be that the last message is from the logged user', () => { - mainContent.lastMessageUser.should('contain', username); + test('expect be that the last message is from the logged user', async () => { + await expect(mainContent.lastMessageUser()).toContainText(username); }); - test('expect not show the Admin tag', () => { - mainContent.lastMessageUserTag.should('not.exist'); + test('expect not show the Admin tag', async () => { + await expect(mainContent.lastMessageUserTag()).not.toBeVisible(); }); }); }); - describe('[Flextab]', () => { - describe('[Render]', () => { - before(() => { - sideNav.openChannel('general'); + test.describe('[Flextab]', () => { + test.describe('[Render]', () => { + test.beforeAll(async () => { + await sideNav.openChannel('general'); }); - describe('Room Info Tab:', () => { - before(() => { - flexTab.operateFlexTab('info', true); + test.describe('Room Info Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('info', true); }); - after(() => { + test.afterAll(() => { flexTab.operateFlexTab('info', false); }); @@ -188,116 +177,118 @@ describe('[Main Elements Render]', function () { flexTab.channelSettingName.should('have.attr', 'title', 'general'); }); }); - - describe('Search Tab:', () => { - before(() => { - flexTab.operateFlexTab('search', true); - }); - - after(() => { - flexTab.operateFlexTab('search', false); - }); - - test('expect show the message search button', () => { - flexTab.searchTab.should('be.visible'); - }); - - test('expect show the message tab content', () => { - flexTab.searchTabContent.should('be.visible'); - }); - }); - - describe('Members Tab:', () => { - before(() => { - flexTab.operateFlexTab('members', true); - }); - - after(() => { - flexTab.operateFlexTab('members', false); - }); - - test('expect show the members tab button', () => { - flexTab.membersTab.should('be.visible'); - }); - - test('expect show the members content', () => { - flexTab.membersTabContent.should('be.visible'); - }); - }); - - describe('Notifications Tab:', () => { - before(() => { - flexTab.operateFlexTab('notifications', true); - }); - - after(() => { - flexTab.operateFlexTab('notifications', false); - }); - - test('expect not show the notifications button', () => { - flexTab.notificationsTab.should('not.exist'); - }); - - test('expect show the notifications Tab content', () => { - flexTab.notificationsSettings.should('be.visible'); - }); - }); - - describe('Files Tab:', () => { - before(() => { - flexTab.operateFlexTab('files', true); - }); - - after(() => { - flexTab.operateFlexTab('files', false); - }); - - test('expect show the files Tab content', () => { - flexTab.filesTabContent.should('be.visible'); - }); - }); - - describe('Mentions Tab:', () => { - before(() => { - flexTab.operateFlexTab('mentions', true); - }); - - after(() => { - flexTab.operateFlexTab('mentions', false); - }); - - test('expect show the mentions Tab content', () => { - flexTab.mentionsTabContent.should('be.visible'); - }); - }); - - describe('Starred Messages Tab:', () => { - before(() => { - flexTab.operateFlexTab('starred', true); - }); - - after(() => { - flexTab.operateFlexTab('starred', false); - }); - - test('expect show the starred messages Tab content', () => { - flexTab.starredTabContent.should('be.visible'); - }); - }); - - describe('Pinned Messages Tab:', () => { - before(() => { - flexTab.operateFlexTab('pinned', true); - }); - - after(() => { - flexTab.operateFlexTab('pinned', false); - }); - - test('expect show the pinned messages Tab content', () => { - flexTab.pinnedTabContent.should('be.visible'); - }); - }); - }); - }); -}); + }); // remove + }); // remove +}); // remove + // describe('Search Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('search', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('search', false); + // }); + + // test('expect show the message search button', () => { + // flexTab.searchTab.should('be.visible'); + // }); + + // test('expect show the message tab content', () => { + // flexTab.searchTabContent.should('be.visible'); + // }); + // }); + + // describe('Members Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('members', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('members', false); + // }); + + // test('expect show the members tab button', () => { + // flexTab.membersTab.should('be.visible'); + // }); + + // test('expect show the members content', () => { + // flexTab.membersTabContent.should('be.visible'); + // }); + // }); + + // describe('Notifications Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('notifications', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('notifications', false); + // }); + + // test('expect not show the notifications button', () => { + // flexTab.notificationsTab.should('not.exist'); + // }); + + // test('expect show the notifications Tab content', () => { + // flexTab.notificationsSettings.should('be.visible'); + // }); + // }); + + // describe('Files Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('files', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('files', false); + // }); + + // test('expect show the files Tab content', () => { + // flexTab.filesTabContent.should('be.visible'); + // }); + // }); + + // describe('Mentions Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('mentions', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('mentions', false); + // }); + + // test('expect show the mentions Tab content', () => { + // flexTab.mentionsTabContent.should('be.visible'); + // }); + // }); + + // describe('Starred Messages Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('starred', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('starred', false); + // }); + + // test('expect show the starred messages Tab content', () => { + // flexTab.starredTabContent.should('be.visible'); + // }); + // }); + + // describe('Pinned Messages Tab:', () => { + // before(() => { + // flexTab.operateFlexTab('pinned', true); + // }); + + // after(() => { + // flexTab.operateFlexTab('pinned', false); + // }); + + // test('expect show the pinned messages Tab content', () => { + // flexTab.pinnedTabContent.should('be.visible'); + // }); + // }); + // }); + // }); +// }); diff --git a/tests/e2e/utils/pageobjects/flex-tab.page.ts b/tests/e2e/utils/pageobjects/flex-tab.page.ts index 93e590a78b2f..a9378f056dcb 100644 --- a/tests/e2e/utils/pageobjects/flex-tab.page.ts +++ b/tests/e2e/utils/pageobjects/flex-tab.page.ts @@ -1,9 +1,14 @@ -import { Locator } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import Pages from './Pages'; // import Global from './global'; class FlexTab extends Pages { + constructor(browser: any, baseURL: any, page: Page) { + super(browser, baseURL); + this.page = page; + } + public headerMoreActions(): Locator { return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); } @@ -367,6 +372,84 @@ class FlexTab extends Pages { this.page.waitForSelector('.-autocomplete-item'); this.page.click('.-autocomplete-item'); } + + public async operateFlexTab(desiredTab: string, desiredState: boolean): Promise { + // desiredState true=open false=closed + const functionNames: { [K: string]: Function } = { + channelSettings: this.channelSettings, + messageSearchBar: this.messageSearchBar, + avatarImage: this.avatarImage, + notificationsSettings: this.notificationsSettings, + filesTabContent: this.filesTabContent, + mentionsTabContent: this.mentionsTabContent, + starredTabContent: this.starredTabContent, + pinnedTabContent: this.pinnedTabContent, + }; + + const callFunction = (name: string): Locator => { + return functionNames[name](); + }; + + const operate = async (tab: string, panel: string, more: boolean): Promise => { + // this[panel].should(!desiredState ? 'be.visible' : 'not.exist'); + if (desiredState) { + await expect(callFunction(panel)).toBeVisible(); + } else { + await expect(callFunction(panel)).toBeVisible(); + } + + if (more) { + this.headerMoreActions().click(); + } + + this[tab].click(); + + // The button "more" keeps the focus when popover is closed from a click + // on an item, need to click again to change the status to unselected and + // allow the next click to open the popover again + if (more) { + this.headerMoreActions.click(); + } + + this[panel].should(desiredState ? 'be.visible' : 'not.exist'); + }; + + const tabs = { + info() { + operate('channelTab', 'channelSettings'); + }, + + search() { + operate('searchTab', 'messageSearchBar'); + }, + + members() { + operate('membersTab', 'avatarImage'); + }, + + notifications() { + operate('notificationsTab', 'notificationsSettings', true); + }, + + files() { + operate('filesTab', 'filesTabContent'); + }, + + mentions() { + operate('mentionsTab', 'mentionsTabContent', true); + }, + + starred() { + operate('starredTab', 'starredTabContent', true); + }, + + pinned() { + operate('pinnedTab', 'pinnedTabContent', true); + }, + }; + + tabs[desiredTab].call(this); + } } export default FlexTab; diff --git a/tests/e2e/utils/pageobjects/main-content.page.ts b/tests/e2e/utils/pageobjects/main-content.page.ts index 6b8ee9697f3c..c93a44344f06 100644 --- a/tests/e2e/utils/pageobjects/main-content.page.ts +++ b/tests/e2e/utils/pageobjects/main-content.page.ts @@ -1,23 +1,28 @@ -import { expect, Locator } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import Pages from './Pages'; class MainContent extends Pages { + constructor(browser: any, baseURL: any, page: Page) { + super(browser, baseURL); + this.page = page; + } + public mainContent(): Locator { return this.page.locator('.main-content'); } // Main Content Header (Channel Title Area) public emptyFavoriteStar(): Locator { - return this.page.locator('.rcx-room-header .rcx-icon--name-star'); + return this.page.locator('//*[contains(@class, "rcx-room-header")]//*[contains(@class, "rcx-icon--name-star")]'); } public favoriteStar(): Locator { - return this.page.locator('.rcx-room-header .rcx-icon--name-star-filled'); + return this.page.locator('//*[contains(@class, "rcx-room-header")]//*[contains(@class, "rcx-icon--name-star-filled")]'); } - public channelTitle(): Locator { - return this.page.locator('.rcx-room-header'); + public channelTitle(title: string): Locator { + return this.page.locator('.rcx-room-header', { hasText: title }); } // Main Content Footer (Message Input Area) @@ -30,7 +35,7 @@ class MainContent extends Pages { } public messageBoxActions(): Locator { - return this.page.locator('.rc-message-box__icon'); + return this.page.locator('(//*[contains(@class, "rc-message-box__icon")])[1]'); } public recordBtn(): Locator { diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts index e750b1373589..d899a7f3b122 100644 --- a/tests/e2e/utils/pageobjects/side-nav.page.ts +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -1,9 +1,14 @@ -import { expect, Locator } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import Pages from './Pages'; // import mainContent from './main-content.page'; class SideNav extends Pages { + constructor(browser: any, baseURL: any, page: Page) { + super(browser, baseURL); + this.page = page; + } + // New channel public channelType(): Locator { return this.page.locator('#modal-root .rcx-field:contains("Private") .rcx-toggle-switch__fake'); @@ -59,31 +64,31 @@ class SideNav extends Pages { } public statusOnline(): Locator { - return this.page.locator('.rcx-box--with-inline-elements:contains("online")'); + return this.page.locator('(//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "online")])[1]'); } public statusAway(): Locator { - return this.page.locator('.rcx-box--with-inline-elements:contains("away")'); + return this.page.locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "away")]'); } public statusBusy(): Locator { - return this.page.locator('.rcx-box--with-inline-elements:contains("busy")'); + return this.page.locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "busy")]'); } public statusOffline(): Locator { - return this.page.locator('.rcx-box--with-inline-elements:contains("offline")'); + return this.page.locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "offline")]'); } public account(): Locator { - return this.page.locator('.rcx-option__content:contains("My Account")'); + return this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "My Account")]'); } public admin(): Locator { - return this.page.locator('.rcx-option__content:contains("Administration")'); + return this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Administration")]'); } public logout(): Locator { - return this.page.locator('.rcx-option__content:contains("Logout")'); + return this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Logout")]'); } public sideNavBar(): Locator { @@ -120,7 +125,7 @@ class SideNav extends Pages { } // Rooms List - public async general(): Promise { + public general(): Locator { return this.getChannelFromList('general'); } @@ -195,8 +200,8 @@ class SideNav extends Pages { } // Gets a channel from the rooms list - public async getChannelFromList(channelName: any): Promise { - return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).scrollIntoViewIfNeeded(); + public getChannelFromList(channelName: any): Locator { + return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }); } public async createChannel(channelName: any, isPrivate: any /* isReadOnly*/): Promise { From b17e15a32906173e50f7d7a1c700cce8fe51a0d1 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Wed, 30 Mar 2022 16:53:15 -0300 Subject: [PATCH 21/35] refactor: apply new pattern --- tests/e2e/04-main-elements-render.spec.ts | 19 +- tests/e2e/utils/pageobjects/flex-tab.page.ts | 187 +++++++++--------- .../utils/pageobjects/main-content.page.ts | 131 ++++++------ tests/e2e/utils/pageobjects/side-nav.page.ts | 99 +++++----- 4 files changed, 215 insertions(+), 221 deletions(-) diff --git a/tests/e2e/04-main-elements-render.spec.ts b/tests/e2e/04-main-elements-render.spec.ts index 05e1baf228d4..8df6574ea965 100644 --- a/tests/e2e/04-main-elements-render.spec.ts +++ b/tests/e2e/04-main-elements-render.spec.ts @@ -4,7 +4,8 @@ import MainContent from './utils/pageobjects/main-content.page'; import SideNav from './utils/pageobjects/side-nav.page'; import FlexTab from './utils/pageobjects/flex-tab.page'; import LoginPage from './utils/pageobjects/login.page'; -import { adminUsername, adminPassword } from './utils/mocks/userAndPasswordMock'; +import { adminLogin } from './utils/mocks/userAndPasswordMock'; +import { LOCALHOST } from './utils/mocks/urlMock'; const username = adminUsername; @@ -15,12 +16,16 @@ test.describe('[Main Elements Render]', function () { let flexTab: FlexTab; test.beforeAll(async ({ browser, baseURL }) => { - loginPage = new LoginPage(browser, baseURL as string); - await loginPage.open(); - await loginPage.login({ email: adminUsername, password: adminPassword }); - sideNav = new SideNav(browser, baseURL as string, loginPage.getPage()); - mainContent = new MainContent(browser, baseURL as string, loginPage.getPage()); - flexTab = new FlexTab(browser, baseURL as string, loginPage.getPage()); + const context = await browser.newContext(); + const page = await context.newPage(); + const URL = baseURL || LOCALHOST; + loginPage = new LoginPage(page); + await loginPage.goto(URL); + + await loginPage.login(adminLogin); + sideNav = new SideNav(page); + mainContent = new MainContent(page); + flexTab = new FlexTab(page); }); test.describe('[Side Nav Bar]', () => { diff --git a/tests/e2e/utils/pageobjects/flex-tab.page.ts b/tests/e2e/utils/pageobjects/flex-tab.page.ts index a9378f056dcb..340cb27a6756 100644 --- a/tests/e2e/utils/pageobjects/flex-tab.page.ts +++ b/tests/e2e/utils/pageobjects/flex-tab.page.ts @@ -1,361 +1,358 @@ -import { expect, Locator, Page } from '@playwright/test'; +import { expect, Locator } from '@playwright/test'; -import Pages from './Pages'; +import BasePage from './BasePage'; // import Global from './global'; -class FlexTab extends Pages { - constructor(browser: any, baseURL: any, page: Page) { - super(browser, baseURL); - this.page = page; - } +class FlexTab extends BasePage { + public headerMoreActions(): Locator { - return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); + return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); } public moreActions(): Locator { - return this.page.locator('.rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); + return this.getPage().locator('.rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); } public sendBtn(): Locator { - return this.page.locator('.rcx-vertical-bar .rc-message-box__icon.js-send'); + return this.getPage().locator('.rcx-vertical-bar .rc-message-box__icon.js-send'); } public messageInput(): Locator { - return this.page.locator('.rcx-vertical-bar .js-input-message'); + return this.getPage().locator('.rcx-vertical-bar .js-input-message'); } public threadTab(): Locator { - return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-thread'); + return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-thread'); } // Channel Info Tab public channelTab(): Locator { - return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-info-circled'); + return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-info-circled'); } public channelSettings(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-info-circled'); + return this.getPage().locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-info-circled'); } public channelSettingName(): Locator { - return this.page.locator('.channel-settings .rc-user-info__name'); + return this.getPage().locator('.channel-settings .rc-user-info__name'); } public archiveBtn(): Locator { - return this.page.locator('.clearfix:last-child .icon-pencil'); + return this.getPage().locator('.clearfix:last-child .icon-pencil'); } public archiveRadio(): Locator { - return this.page.locator('.editing'); + return this.getPage().locator('.editing'); } public archiveSave(): Locator { - return this.page.locator('.save'); + return this.getPage().locator('.save'); } public editNameBtn(): Locator { - return this.page.locator('[data-edit="name"]'); + return this.getPage().locator('[data-edit="name"]'); } public editTopicBtn(): Locator { - return this.page.locator('[data-edit="topic"]'); + return this.getPage().locator('[data-edit="topic"]'); } public editAnnouncementBtn(): Locator { - return this.page.locator('[data-edit="announcement"]'); + return this.getPage().locator('[data-edit="announcement"]'); } public editDescriptionBtn(): Locator { - return this.page.locator('[data-edit="description"]'); + return this.getPage().locator('[data-edit="description"]'); } public editNotificationBtn(): Locator { - return this.page.locator('[data-edit="desktopNotifications"]'); + return this.getPage().locator('[data-edit="desktopNotifications"]'); } public editMobilePushBtn(): Locator { - return this.page.locator('[data-edit="mobilePushNotifications"]'); + return this.getPage().locator('[data-edit="mobilePushNotifications"]'); } public editEmailNotificationBtn(): Locator { - return this.page.locator('[data-edit="emailNotifications"]'); + return this.getPage().locator('[data-edit="emailNotifications"]'); } public editUnreadAlertBtn(): Locator { - return this.page.locator('[data-edit="unreadAlert"]'); + return this.getPage().locator('[data-edit="unreadAlert"]'); } public editNameTextInput(): Locator { - return this.page.locator('.channel-settings input[name="name"]'); + return this.getPage().locator('.channel-settings input[name="name"]'); } public editTopicTextInput(): Locator { - return this.page.locator('.channel-settings input[name="topic"]'); + return this.getPage().locator('.channel-settings input[name="topic"]'); } public editAnnouncementTextInput(): Locator { - return this.page.locator('.channel-settings input[name="announcement"]'); + return this.getPage().locator('.channel-settings input[name="announcement"]'); } public editDescriptionTextInput(): Locator { - return this.page.locator('.channel-settings input[name="description"]'); + return this.getPage().locator('.channel-settings input[name="description"]'); } public editNameSave(): Locator { - return this.page.locator('.channel-settings .save'); + return this.getPage().locator('.channel-settings .save'); } public deleteBtn(): Locator { - return this.page.locator('.channel-settings .js-delete'); + return this.getPage().locator('.channel-settings .js-delete'); } // Members Tab public membersTab(): Locator { - return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-members'); + return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-members'); } public membersTabContent(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-members'); + return this.getPage().locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-members'); } public userSearchBar(): Locator { - return this.page.locator('#user-add-search'); + return this.getPage().locator('#user-add-search'); } public removeUserBtn(): Locator { - return this.page.locator('.remove-user'); + return this.getPage().locator('.remove-user'); } public setOwnerBtn(): Locator { - return this.page.locator('.set-owner'); + return this.getPage().locator('.set-owner'); } public setModeratorBtn(): Locator { - return this.page.locator('.set-moderator'); + return this.getPage().locator('.set-moderator'); } public muteUserBtn(): Locator { - return this.page.locator('.mute-user'); + return this.getPage().locator('.mute-user'); } public viewAllBtn(): Locator { - return this.page.locator('.button.back'); + return this.getPage().locator('.button.back'); } public startVideoCall(): Locator { - return this.page.locator('.start-video-call'); + return this.getPage().locator('.start-video-call'); } public startAudioCall(): Locator { - return this.page.locator('.start-audio-call'); + return this.getPage().locator('.start-audio-call'); } public showAll(): Locator { - return this.page.locator('.see-all'); + return this.getPage().locator('.see-all'); } public membersUserInfo(): Locator { - return this.page.locator('.flex-tab-container .info'); + return this.getPage().locator('.flex-tab-container .info'); } public avatarImage(): Locator { - return this.page.locator('aside.rcx-vertical-bar .rcx-avatar'); + return this.getPage().locator('aside.rcx-vertical-bar .rcx-avatar'); } public memberUserName(): Locator { - return this.page.locator('.info h3'); + return this.getPage().locator('.info h3'); } public memberRealName(): Locator { - return this.page.locator('.info p'); + return this.getPage().locator('.info p'); } // Search Tab public searchTab(): Locator { - return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-magnifier'); + return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-magnifier'); } public searchTabContent(): Locator { - return this.page.locator('.rocket-search-result'); + return this.getPage().locator('.rocket-search-result'); } public messageSearchBar(): Locator { - return this.page.locator('#message-search'); + return this.getPage().locator('#message-search'); } public searchResult(): Locator { - return this.page.locator('.new-day'); + return this.getPage().locator('.new-day'); } // Notifications Tab public notificationsTab(): Locator { - return this.page.locator('.rcx-option__content:contains("Notifications Preferences")'); + return this.getPage().locator('.rcx-option__content:contains("Notifications Preferences")'); } public notificationsSettings(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-bell'); + return this.getPage().locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-bell'); } // Files Tab public filesTab(): Locator { - return this.page.locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-clip'); + return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-clip'); } public fileItem(): Locator { - return this.page.locator('.uploaded-files-list ul:first-child'); + return this.getPage().locator('.uploaded-files-list ul:first-child'); } public filesTabContent(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-icon--name-attachment'); + return this.getPage().locator('aside > h3 > div > i.rcx-icon--name-attachment'); } public fileDelete(): Locator { - return this.page.locator('.uploaded-files-list ul:first-child .file-delete'); + return this.getPage().locator('.uploaded-files-list ul:first-child .file-delete'); } public fileDownload(): Locator { - return this.page.locator('.uploaded-files-list ul:first-child .file-download'); + return this.getPage().locator('.uploaded-files-list ul:first-child .file-download'); } public fileName(): Locator { - return this.page.locator('.uploaded-files-list ul:first-child .room-file-item'); + return this.getPage().locator('.uploaded-files-list ul:first-child .room-file-item'); } // Mentions Tab public mentionsTab(): Locator { - return this.page.locator('.rcx-option__content:contains("Mentions")'); + return this.getPage().locator('.rcx-option__content:contains("Mentions")'); } public mentionsTabContent(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-icon--name-at'); + return this.getPage().locator('aside > h3 > div > i.rcx-icon--name-at'); } // Starred Tab public starredTab(): Locator { - return this.page.locator('.rcx-option__content:contains("Starred Messages")'); + return this.getPage().locator('.rcx-option__content:contains("Starred Messages")'); } public starredTabContent(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-icon--name-star'); + return this.getPage().locator('aside > h3 > div > i.rcx-icon--name-star'); } // Pinned Tab public pinnedTab(): Locator { - return this.page.locator('.rcx-option__content:contains("Pinned Messages")'); + return this.getPage().locator('.rcx-option__content:contains("Pinned Messages")'); } public pinnedTabContent(): Locator { - return this.page.locator('aside > h3 > div > i.rcx-icon--name-pin'); + return this.getPage().locator('aside > h3 > div > i.rcx-icon--name-pin'); } public firstSetting(): Locator { - return this.page.locator('.clearfix li:nth-child(1) .current-setting'); + return this.getPage().locator('.clearfix li:nth-child(1) .current-setting'); } public secondSetting(): Locator { - return this.page.locator('.clearfix li:nth-child(2) .current-setting'); + return this.getPage().locator('.clearfix li:nth-child(2) .current-setting'); } public thirdSetting(): Locator { - return this.page.locator('.clearfix li:nth-child(3) .current-setting'); + return this.getPage().locator('.clearfix li:nth-child(3) .current-setting'); } public fourthSetting(): Locator { - return this.page.locator('.clearfix li:nth-child(4) .current-setting'); + return this.getPage().locator('.clearfix li:nth-child(4) .current-setting'); } // admin view flextab items public usersSendInvitationTab(): Locator { - return this.page.locator('.tab-button:not(.hidden) .tab-button-icon--send'); + return this.getPage().locator('.tab-button:not(.hidden) .tab-button-icon--send'); } public usersAddUserTab(): Locator { - return this.page.locator('.tab-button:not(.hidden) .tab-button-icon--plus'); + return this.getPage().locator('.tab-button:not(.hidden) .tab-button-icon--plus'); } public usersSendInvitationTextArea(): Locator { - return this.page.locator('#inviteEmails'); + return this.getPage().locator('#inviteEmails'); } public usersButtonCancel(): Locator { - return this.page.locator('.button.cancel'); + return this.getPage().locator('.button.cancel'); } public usersSendInvitationSend(): Locator { - return this.page.locator('.button.send'); + return this.getPage().locator('.button.send'); } public usersButtonSave(): Locator { - return this.page.locator('.button.save'); + return this.getPage().locator('.button.save'); } public usersAddUserName(): Locator { - return this.page.locator('#name'); + return this.getPage().locator('#name'); } public usersAddUserUsername(): Locator { - return this.page.locator('#username'); + return this.getPage().locator('#username'); } public usersAddUserEmail(): Locator { - return this.page.locator('#email'); + return this.getPage().locator('#email'); } public usersAddUserRoleList(): Locator { - return this.page.locator('#roleSelect'); + return this.getPage().locator('#roleSelect'); } public usersAddUserPassword(): Locator { - return this.page.locator('#password'); + return this.getPage().locator('#password'); } public usersAddUserRoleButton(): Locator { - return this.page.locator('#addRole'); + return this.getPage().locator('#addRole'); } public usersAddUserVerifiedCheckbox(): Locator { - return this.page.locator('#verified'); + return this.getPage().locator('#verified'); } public usersAddUserChangePasswordCheckbox(): Locator { - return this.page.locator('#changePassword'); + return this.getPage().locator('#changePassword'); } public usersAddUserDefaultChannelCheckbox(): Locator { - return this.page.locator('#joinDefaultChannels'); + return this.getPage().locator('#joinDefaultChannels'); } public usersAddUserWelcomeEmailCheckbox(): Locator { - return this.page.locator('#sendWelcomeEmail'); + return this.getPage().locator('#sendWelcomeEmail'); } public usersAddUserRandomPassword(): Locator { - return this.page.locator('#randomPassword'); + return this.getPage().locator('#randomPassword'); } public emojiNewAliases(): Locator { - return this.page.locator('#aliases'); + return this.getPage().locator('#aliases'); } public emojiNewImageInput(): Locator { - return this.page.locator('#image'); + return this.getPage().locator('#image'); } public usersView(): Locator { - return this.page.locator('.rcx-vertical-bar:contains("User Info")'); + return this.getPage().locator('.rcx-vertical-bar:contains("User Info")'); } public usersActivate(): Locator { - return this.page.locator('.rcx-option__content:contains("Activate")'); + return this.getPage().locator('.rcx-option__content:contains("Activate")'); } public usersDeactivate(): Locator { - return this.page.locator('.rcx-option__content:contains("Deactivate")'); + return this.getPage().locator('.rcx-option__content:contains("Deactivate")'); } public getUserEl(username: any): Locator { - return this.page.locator(`.flex-tab button[title="${username}"] > p`); + return this.getPage().locator(`.flex-tab button[title="${username}"] > p`); } public async archiveChannel(): Promise { @@ -369,8 +366,8 @@ class FlexTab extends Pages { public async addPeopleToChannel(user: any): Promise { await this.userSearchBar().waitFor(); await this.userSearchBar().type(user); - this.page.waitForSelector('.-autocomplete-item'); - this.page.click('.-autocomplete-item'); + this.getPage().waitForSelector('.-autocomplete-item'); + this.getPage().click('.-autocomplete-item'); } public async operateFlexTab(desiredTab: string, desiredState: boolean): Promise { @@ -384,6 +381,8 @@ class FlexTab extends Pages { mentionsTabContent: this.mentionsTabContent, starredTabContent: this.starredTabContent, pinnedTabContent: this.pinnedTabContent, + channelTab: this.channelTab, + }; const callFunction = (name: string): Locator => { diff --git a/tests/e2e/utils/pageobjects/main-content.page.ts b/tests/e2e/utils/pageobjects/main-content.page.ts index c93a44344f06..4e4135696ea3 100644 --- a/tests/e2e/utils/pageobjects/main-content.page.ts +++ b/tests/e2e/utils/pageobjects/main-content.page.ts @@ -1,250 +1,245 @@ -import { expect, Locator, Page } from '@playwright/test'; +import { expect, Locator } from '@playwright/test'; -import Pages from './Pages'; - -class MainContent extends Pages { - constructor(browser: any, baseURL: any, page: Page) { - super(browser, baseURL); - this.page = page; - } +import BasePage from './BasePage'; +class MainContent extends BasePage { public mainContent(): Locator { - return this.page.locator('.main-content'); + return this.getPage().locator('.main-content'); } // Main Content Header (Channel Title Area) public emptyFavoriteStar(): Locator { - return this.page.locator('//*[contains(@class, "rcx-room-header")]//*[contains(@class, "rcx-icon--name-star")]'); + return this.getPage().locator('//*[contains(@class, "rcx-room-header")]//*[contains(@class, "rcx-icon--name-star")]'); } public favoriteStar(): Locator { - return this.page.locator('//*[contains(@class, "rcx-room-header")]//*[contains(@class, "rcx-icon--name-star-filled")]'); + return this.getPage().locator('//*[contains(@class, "rcx-room-header")]//*[contains(@class, "rcx-icon--name-star-filled")]'); } public channelTitle(title: string): Locator { - return this.page.locator('.rcx-room-header', { hasText: title }); + return this.getPage().locator('.rcx-room-header', { hasText: title }); } // Main Content Footer (Message Input Area) public messageInput(): Locator { - return this.page.locator('.js-input-message'); + return this.getPage().locator('.js-input-message'); } public sendBtn(): Locator { - return this.page.locator('.rc-message-box__icon.js-send'); + return this.getPage().locator('.rc-message-box__icon.js-send'); } public messageBoxActions(): Locator { - return this.page.locator('(//*[contains(@class, "rc-message-box__icon")])[1]'); + return this.getPage().locator('(//*[contains(@class, "rc-message-box__icon")])[1]'); } public recordBtn(): Locator { - return this.page.locator('.js-audio-message-record'); + return this.getPage().locator('.js-audio-message-record'); } public emojiBtn(): Locator { - return this.page.locator('.rc-message-box__icon.emoji-picker-icon'); + return this.getPage().locator('.rc-message-box__icon.emoji-picker-icon'); } public messagePopUp(): Locator { - return this.page.locator('.message-popup'); + return this.getPage().locator('.message-popup'); } public messagePopUpTitle(): Locator { - return this.page.locator('.message-popup-title'); + return this.getPage().locator('.message-popup-title'); } public messagePopUpItems(): Locator { - return this.page.locator('.message-popup-items'); + return this.getPage().locator('.message-popup-items'); } public messagePopUpFirstItem(): Locator { - return this.page.locator('.popup-item.selected'); + return this.getPage().locator('.popup-item.selected'); } public mentionAllPopUp(): Locator { - return this.page.locator('.popup-item[data-id="all"]'); + return this.getPage().locator('.popup-item[data-id="all"]'); } public joinChannelBtn(): Locator { - return this.page.locator('.button.join'); + return this.getPage().locator('.button.join'); } // Messages public lastMessageUser(): Locator { - return this.page.locator('.message:last-child .title .user-card-message'); + return this.getPage().locator('.message:last-child .title .user-card-message'); } public lastMessage(): Locator { - return this.page.locator('.message:last-child'); + return this.getPage().locator('.message:last-child'); } public lastMessageDesc(): Locator { - return this.page.locator('.message:last-child .body .attachment-description'); + return this.getPage().locator('.message:last-child .body .attachment-description'); } public lastMessageRoleAdded(): Locator { - return this.page.locator('.message:last-child.subscription-role-added .body'); + return this.getPage().locator('.message:last-child.subscription-role-added .body'); } public beforeLastMessage(): Locator { - return this.page.locator('.message:nth-last-child(2) .body'); + return this.getPage().locator('.message:nth-last-child(2) .body'); } public lastMessageUserTag(): Locator { - return this.page.locator('.message:last-child .role-tag'); + return this.getPage().locator('.message:last-child .role-tag'); } public lastMessageImg(): Locator { - return this.page.locator('.message:last-child .attachment-image img'); + return this.getPage().locator('.message:last-child .attachment-image img'); } public lastMessageTextAttachment(): Locator { - return this.page.locator('.message:last-child .attachment-text'); + return this.getPage().locator('.message:last-child .attachment-text'); } public beforeLastMessageQuote(): Locator { - return this.page.locator('.message:nth-last-child(2)'); + return this.getPage().locator('.message:nth-last-child(2)'); } public lastMessageQuote(): Locator { - return this.page.locator('.message:last-child'); + return this.getPage().locator('.message:last-child'); } public messageOptionsBtn(): Locator { - return this.page.locator('.message:last-child .message-actions__menu'); + return this.getPage().locator('.message:last-child .message-actions__menu'); } public messageOptionsBtns(): Locator { - return this.page.locator('.message:last-child .message-actions'); + return this.getPage().locator('.message:last-child .message-actions'); } public messageActionMenu(): Locator { - return this.page.locator('.rc-popover .rc-popover__content'); + return this.getPage().locator('.rc-popover .rc-popover__content'); } public messageReply(): Locator { - return this.page.locator('.message:last-child .message-actions__button[data-message-action="reply-in-thread"]'); + return this.getPage().locator('.message:last-child .message-actions__button[data-message-action="reply-in-thread"]'); } public messageEdit(): Locator { - return this.page.locator('[data-id="edit-message"][data-type="message-action"]'); + return this.getPage().locator('[data-id="edit-message"][data-type="message-action"]'); } public messageDelete(): Locator { - return this.page.locator('[data-id="delete-message"][data-type="message-action"]'); + return this.getPage().locator('[data-id="delete-message"][data-type="message-action"]'); } public messagePermalink(): Locator { - return this.page.locator('[data-id="permalink"][data-type="message-action"]'); + return this.getPage().locator('[data-id="permalink"][data-type="message-action"]'); } public messageCopy(): Locator { - return this.page.locator('[data-id="copy"][data-type="message-action"]'); + return this.getPage().locator('[data-id="copy"][data-type="message-action"]'); } public messageQuote(): Locator { - return this.page.locator('[data-id="quote-message"][data-type="message-action"]'); + return this.getPage().locator('[data-id="quote-message"][data-type="message-action"]'); } public messageStar(): Locator { - return this.page.locator('[data-id="star-message"][data-type="message-action"]'); + return this.getPage().locator('[data-id="star-message"][data-type="message-action"]'); } public messageUnread(): Locator { - return this.page.locator('[data-id="mark-message-as-unread"][data-type="message-action"]'); + return this.getPage().locator('[data-id="mark-message-as-unread"][data-type="message-action"]'); } public messageReplyInDM(): Locator { - return this.page.locator('[data-id="reply-directly"][data-type="message-action"]'); + return this.getPage().locator('[data-id="reply-directly"][data-type="message-action"]'); } - // public messageReaction(): Locator { return this.page.locator('.message-actions__button[data-message-action="reaction-message"]'); } + // public messageReaction(): Locator { return this.getPage().locator('.message-actions__button[data-message-action="reaction-message"]'); } public messagePin(): Locator { - return this.page.locator('[data-id="pin-message"][data-type="message-action"]'); + return this.getPage().locator('[data-id="pin-message"][data-type="message-action"]'); } - // public messageClose(): Locator { return this.page.locator('[data-id="rc-popover-close"][data-type="message-action"]'); } + // public messageClose(): Locator { return this.getPage().locator('[data-id="rc-popover-close"][data-type="message-action"]'); } // Emojis public emojiPickerMainScreen(): Locator { - return this.page.locator('.emoji-picker'); + return this.getPage().locator('.emoji-picker'); } public emojiPickerPeopleIcon(): Locator { - return this.page.locator('.emoji-picker .icon-people'); + return this.getPage().locator('.emoji-picker .icon-people'); } public emojiPickerNatureIcon(): Locator { - return this.page.locator('.emoji-picker .icon-nature'); + return this.getPage().locator('.emoji-picker .icon-nature'); } public emojiPickerFoodIcon(): Locator { - return this.page.locator('.emoji-picker .icon-food'); + return this.getPage().locator('.emoji-picker .icon-food'); } public emojiPickerActivityIcon(): Locator { - return this.page.locator('.emoji-picker .icon-activity'); + return this.getPage().locator('.emoji-picker .icon-activity'); } public emojiPickerTravelIcon(): Locator { - return this.page.locator('.emoji-picker .icon-travel'); + return this.getPage().locator('.emoji-picker .icon-travel'); } public emojiPickerObjectsIcon(): Locator { - return this.page.locator('.emoji-picker .icon-objects'); + return this.getPage().locator('.emoji-picker .icon-objects'); } public emojiPickerSymbolsIcon(): Locator { - return this.page.locator('.emoji-picker .icon-symbols'); + return this.getPage().locator('.emoji-picker .icon-symbols'); } public emojiPickerFlagsIcon(): Locator { - return this.page.locator('.emoji-picker .icon-flags'); + return this.getPage().locator('.emoji-picker .icon-flags'); } public emojiPickerModifierIcon(): Locator { - return this.page.locator('.emoji-picker .icon-symbols'); + return this.getPage().locator('.emoji-picker .icon-symbols'); } public emojiPickerChangeTone(): Locator { - return this.page.locator('.emoji-picker .change-tone'); + return this.getPage().locator('.emoji-picker .change-tone'); } public emojiPickerCustomIcon(): Locator { - return this.page.locator('.emoji-picker .icon-rocket'); + return this.getPage().locator('.emoji-picker .icon-rocket'); } public emojiPickerRecentIcon(): Locator { - return this.page.locator('.emoji-picker .icon-recent'); + return this.getPage().locator('.emoji-picker .icon-recent'); } public emojiPickerFilter(): Locator { - return this.page.locator('.emoji-picker .js-emojipicker-search'); + return this.getPage().locator('.emoji-picker .js-emojipicker-search'); } public emojiPickerEmojiContainer(): Locator { - return this.page.locator('.emoji-picker .emojis'); + return this.getPage().locator('.emoji-picker .emojis'); } public emojiGrinning(): Locator { - return this.page.locator('.emoji-picker .emoji-grinning'); + return this.getPage().locator('.emoji-picker .emoji-grinning'); } public emojiSmile(): Locator { - return this.page.locator('.emoji-picker .emoji-smile'); + return this.getPage().locator('.emoji-picker .emoji-smile'); } // Popover public popoverWrapper(): Locator { - return this.page.locator('.rc-popover'); + return this.getPage().locator('.rc-popover'); } // Sends a message and wait for the message to equal the text sent public async sendMessage(text: any): Promise { this.setTextToInput(text); await this.sendBtn().click(); - await expect(this.page.locator('.message:last-child .body')).toBeVisible(); - await expect(this.page.locator('.message:last-child .body')).toContain(text); + await expect(this.getPage().locator('.message:last-child .body')).toBeVisible(); + await expect(this.getPage().locator('.message:last-child .body')).toContain(text); } // adds text to the input diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts index d899a7f3b122..eb69a78ca714 100644 --- a/tests/e2e/utils/pageobjects/side-nav.page.ts +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -1,127 +1,122 @@ -import { expect, Locator, Page } from '@playwright/test'; +import { expect, Locator } from '@playwright/test'; -import Pages from './Pages'; +import BasePage from './BasePage'; // import mainContent from './main-content.page'; -class SideNav extends Pages { - constructor(browser: any, baseURL: any, page: Page) { - super(browser, baseURL); - this.page = page; - } - +class SideNav extends BasePage { // New channel public channelType(): Locator { - return this.page.locator('#modal-root .rcx-field:contains("Private") .rcx-toggle-switch__fake'); + return this.getPage().locator('#modal-root .rcx-field:contains("Private") .rcx-toggle-switch__fake'); } public channelReadOnly(): Locator { - return this.page.locator('.create-channel__switches .rc-switch__button'); + return this.getPage().locator('.create-channel__switches .rc-switch__button'); } public channelName(): Locator { - return this.page.locator('#modal-root [placeholder="Channel Name"]'); + return this.getPage().locator('#modal-root [placeholder="Channel Name"]'); } public saveChannelBtn(): Locator { - return this.page.locator('#modal-root button:contains("Create")'); + return this.getPage().locator('#modal-root button:contains("Create")'); } // Account box public getPopOverContent(): Locator { - return this.page.locator('.rc-popover__content'); + return this.getPage().locator('.rc-popover__content'); } public accountBoxUserName(): Locator { - return this.page.locator('.sidebar__account-username'); + return this.getPage().locator('.sidebar__account-username'); } public accountBoxUserAvatar(): Locator { - return this.page.locator('.sidebar__account .avatar-image'); + return this.getPage().locator('.sidebar__account .avatar-image'); } public accountMenu(): Locator { - return this.page.locator('.sidebar__account'); + return this.getPage().locator('.sidebar__account'); } public sidebarHeader(): Locator { - return this.page.locator('.sidebar__header'); + return this.getPage().locator('.sidebar__header'); } public sidebarUserMenu(): Locator { - return this.page.locator('[data-qa="sidebar-avatar-button"]'); + return this.getPage().locator('[data-qa="sidebar-avatar-button"]'); } public sidebarMenu(): Locator { - return this.page.locator('.sidebar__toolbar-button-icon--menu'); + return this.getPage().locator('.sidebar__toolbar-button-icon--menu'); } public popOverContent(): Locator { - return this.page.locator('.rc-popover__content'); + return this.getPage().locator('.rc-popover__content'); } public popOverHideOption(): Locator { - return this.page.locator('.rcx-option__content:contains("Hide")'); + return this.getPage().locator('.rcx-option__content:contains("Hide")'); } public statusOnline(): Locator { - return this.page.locator('(//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "online")])[1]'); + return this.getPage().locator('(//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "online")])[1]'); } public statusAway(): Locator { - return this.page.locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "away")]'); + return this.getPage().locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "away")]'); } public statusBusy(): Locator { - return this.page.locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "busy")]'); + return this.getPage().locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "busy")]'); } public statusOffline(): Locator { - return this.page.locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "offline")]'); + return this.getPage().locator('//*[contains(@class, "rcx-box--with-inline-elements") and contains(text(), "offline")]'); } public account(): Locator { - return this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "My Account")]'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "My Account")]'); } public admin(): Locator { - return this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Administration")]'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Administration")]'); } public logout(): Locator { - return this.page.locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Logout")]'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Logout")]'); } public sideNavBar(): Locator { - return this.page.locator('.sidebar'); + return this.getPage().locator('.sidebar'); } // Toolbar public spotlightSearchIcon(): Locator { - return this.page.locator('[data-qa="sidebar-search"]'); + return this.getPage().locator('[data-qa="sidebar-search"]'); } public spotlightSearch(): Locator { - return this.page.locator('[data-qa="sidebar-search-input"]'); + return this.getPage().locator('[data-qa="sidebar-search-input"]'); } public spotlightSearchPopUp(): Locator { - return this.page.locator('[data-qa="sidebar-search-result"]'); + return this.getPage().locator('[data-qa="sidebar-search-result"]'); } public newChannelBtnToolbar(): Locator { - return this.page.locator('[data-qa="sidebar-create"]'); + return this.getPage().locator('[data-qa="sidebar-create"]'); } public newChannelBtn(): Locator { - return this.page.locator('.rcx-option__content:contains("Channel")'); + return this.getPage().locator('.rcx-option__content:contains("Channel")'); } public newDiscussionBtn(): Locator { - return this.page.locator('.rcx-option__content:contains("Discussion")'); + return this.getPage().locator('.rcx-option__content:contains("Discussion")'); } public newChannelIcon(): Locator { - return this.page.locator('[data-qa="sidebar-create-channel"]'); + return this.getPage().locator('[data-qa="sidebar-create-channel"]'); } // Rooms List @@ -130,55 +125,55 @@ class SideNav extends Pages { } public channelLeave(): Locator { - return this.page.locator('.leave-room'); + return this.getPage().locator('.leave-room'); } public channelHoverIcon(): Locator { - return this.page.locator('.rooms-list > .wrapper > ul [title="general"] .icon-eye-off'); + return this.getPage().locator('.rooms-list > .wrapper > ul [title="general"] .icon-eye-off'); } // Account public preferences(): Locator { - return this.page.locator('[href="/account/preferences"]'); + return this.getPage().locator('[href="/account/preferences"]'); } public profile(): Locator { - return this.page.locator('[href="/account/profile"]'); + return this.getPage().locator('[href="/account/profile"]'); } public avatar(): Locator { - return this.page.locator('[href="/changeavatar"]'); + return this.getPage().locator('[href="/changeavatar"]'); } public preferencesClose(): Locator { - return this.page.locator('.flex-nav i.rcx-icon--name-cross'); + return this.getPage().locator('.flex-nav i.rcx-icon--name-cross'); } public burgerBtn(): Locator { - return this.page.locator('.burger, [aria-label="Open_menu"]'); + return this.getPage().locator('.burger, [aria-label="Open_menu"]'); } public sidebarWrap(): Locator { - return this.page.locator('.sidebar-wrap'); + return this.getPage().locator('.sidebar-wrap'); } public firstSidebarItem(): Locator { - return this.page.locator('.sidebar-item'); + return this.getPage().locator('.sidebar-item'); } public firstSidebarItemMenu(): Locator { - return this.page.locator('[data-qa=sidebar-avatar-button]'); + return this.getPage().locator('[data-qa=sidebar-avatar-button]'); } public popoverOverlay(): Locator { - return this.page.locator('.rc-popover.rc-popover--sidebar-item'); + return this.getPage().locator('.rc-popover.rc-popover--sidebar-item'); } // Opens a channel via rooms list public async openChannel(channelName: any): Promise { - await this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).scrollIntoViewIfNeeded(); - await this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).click(); - await expect(this.page.locator('.rcx-room-header')).toContainText(channelName); + await this.getPage().locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).scrollIntoViewIfNeeded(); + await this.getPage().locator('[data-qa="sidebar-item-title"]', { hasText: channelName }).click(); + await expect(this.getPage().locator('.rcx-room-header')).toContainText(channelName); } // Opens a channel via spotlight search @@ -196,12 +191,12 @@ class SideNav extends Pages { // `[data-qa="sidebar-search-result"] .rcx-sidebar-item--clickable:contains("${channelName}"), [data-qa="sidebar-search-result"] .rcx-sidebar-item[aria-label='${channelName}']`, // ).click(); - await expect(this.page.locator('.rcx-room-header')).toContainText(channelName); + await expect(this.getPage().locator('.rcx-room-header')).toContainText(channelName); } // Gets a channel from the rooms list public getChannelFromList(channelName: any): Locator { - return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: channelName }); + return this.getPage().locator('[data-qa="sidebar-item-title"]', { hasText: channelName }); } public async createChannel(channelName: any, isPrivate: any /* isReadOnly*/): Promise { From 5dbf97c98e01fae92114eb6f240132dbdd914fe6 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 09:04:24 -0300 Subject: [PATCH 22/35] test: ending 04-main-elements-render --- tests/e2e/04-main-elements-render.spec.ts | 244 +++++++++--------- tests/e2e/utils/pageobjects/flex-tab.page.ts | 110 ++++---- .../utils/pageobjects/main-content.page.ts | 2 +- 3 files changed, 181 insertions(+), 175 deletions(-) diff --git a/tests/e2e/04-main-elements-render.spec.ts b/tests/e2e/04-main-elements-render.spec.ts index 8df6574ea965..c894e75dee6c 100644 --- a/tests/e2e/04-main-elements-render.spec.ts +++ b/tests/e2e/04-main-elements-render.spec.ts @@ -7,7 +7,7 @@ import LoginPage from './utils/pageobjects/login.page'; import { adminLogin } from './utils/mocks/userAndPasswordMock'; import { LOCALHOST } from './utils/mocks/urlMock'; -const username = adminUsername; +const username = adminLogin.password; test.describe('[Main Elements Render]', function () { let loginPage: LoginPage; @@ -93,7 +93,7 @@ test.describe('[Main Elements Render]', function () { }); }); - test.describe.only('[Main Content]', () => { + test.describe('[Main Content]', () => { test.describe('render:', () => { test.beforeAll(async () => { await sideNav.openChannel('general'); @@ -166,134 +166,128 @@ test.describe('[Main Elements Render]', function () { await flexTab.operateFlexTab('info', true); }); - test.afterAll(() => { - flexTab.operateFlexTab('info', false); + test.afterAll(async () => { + await flexTab.operateFlexTab('info', false); }); - test('expect show the room info button', () => { - flexTab.channelTab.should('be.visible'); + test('expect show the room info button', async () => { + await expect(flexTab.channelTab()).toBeVisible(); }); - test('expect show the room info tab content', () => { - flexTab.channelSettings.should('be.visible'); + test('expect show the room info tab content', async () => { + await expect(flexTab.channelSettings()).toBeVisible(); }); + }); + + test.describe('Search Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('search', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('search', false); + }); + + test('expect show the message search button', async () => { + await expect(flexTab.searchTab()).toBeVisible(); + }); + + test('expect show the message tab content', async () => { + await expect(flexTab.searchTabContent()).toBeVisible(); + }); + }); + + test.describe('Members Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('members', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('members', false); + }); + + test('expect show the members tab button', async () => { + await expect(flexTab.membersTab()).toBeVisible(); + }); + + test('expect show the members content', async () => { + await expect(flexTab.membersTabContent()).toBeVisible(); + }); + }); + + test.describe('Notifications Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('notifications', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('notifications', false); + }); + + test('expect not show the notifications button', async () => { + await expect(flexTab.notificationsTab()).not.toBeVisible(); + }); + + test('expect show the notifications Tab content', async () => { + await expect(flexTab.notificationsSettings()).toBeVisible(); + }); + }); - it.skip('expect show the room name', () => { - flexTab.channelSettingName.should('have.attr', 'title', 'general'); + test.describe('Files Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('files', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('files', false); + }); + + test('expect show the files Tab content', async () => { + await expect(flexTab.filesTabContent()).toBeVisible(); + }); + }); + + test.describe('Mentions Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('mentions', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('mentions', false); + }); + + test('expect show the mentions Tab content', async () => { + await expect(flexTab.mentionsTabContent()).toBeVisible(); }); }); - }); // remove - }); // remove -}); // remove - // describe('Search Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('search', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('search', false); - // }); - - // test('expect show the message search button', () => { - // flexTab.searchTab.should('be.visible'); - // }); - - // test('expect show the message tab content', () => { - // flexTab.searchTabContent.should('be.visible'); - // }); - // }); - - // describe('Members Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('members', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('members', false); - // }); - - // test('expect show the members tab button', () => { - // flexTab.membersTab.should('be.visible'); - // }); - - // test('expect show the members content', () => { - // flexTab.membersTabContent.should('be.visible'); - // }); - // }); - - // describe('Notifications Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('notifications', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('notifications', false); - // }); - - // test('expect not show the notifications button', () => { - // flexTab.notificationsTab.should('not.exist'); - // }); - - // test('expect show the notifications Tab content', () => { - // flexTab.notificationsSettings.should('be.visible'); - // }); - // }); - - // describe('Files Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('files', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('files', false); - // }); - - // test('expect show the files Tab content', () => { - // flexTab.filesTabContent.should('be.visible'); - // }); - // }); - - // describe('Mentions Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('mentions', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('mentions', false); - // }); - - // test('expect show the mentions Tab content', () => { - // flexTab.mentionsTabContent.should('be.visible'); - // }); - // }); - - // describe('Starred Messages Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('starred', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('starred', false); - // }); - - // test('expect show the starred messages Tab content', () => { - // flexTab.starredTabContent.should('be.visible'); - // }); - // }); - - // describe('Pinned Messages Tab:', () => { - // before(() => { - // flexTab.operateFlexTab('pinned', true); - // }); - - // after(() => { - // flexTab.operateFlexTab('pinned', false); - // }); - - // test('expect show the pinned messages Tab content', () => { - // flexTab.pinnedTabContent.should('be.visible'); - // }); - // }); - // }); - // }); -// }); + + test.describe('Starred Messages Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('starred', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('starred', false); + }); + + test('expect show the starred messages Tab content', async () => { + await expect(flexTab.starredTabContent()).toBeVisible(); + }); + }); + + test.describe('Pinned Messages Tab:', () => { + test.beforeAll(async () => { + await flexTab.operateFlexTab('pinned', true); + }); + + test.afterAll(async () => { + await flexTab.operateFlexTab('pinned', false); + }); + + test('expect show the pinned messages Tab content', async () => { + await expect(flexTab.pinnedTabContent()).toBeVisible(); + }); + }); + }); + }); +}); diff --git a/tests/e2e/utils/pageobjects/flex-tab.page.ts b/tests/e2e/utils/pageobjects/flex-tab.page.ts index 340cb27a6756..610e323f12ec 100644 --- a/tests/e2e/utils/pageobjects/flex-tab.page.ts +++ b/tests/e2e/utils/pageobjects/flex-tab.page.ts @@ -4,10 +4,8 @@ import BasePage from './BasePage'; // import Global from './global'; class FlexTab extends BasePage { - - public headerMoreActions(): Locator { - return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-kebab'); + return this.getPage().locator('//main/header//*[contains(@class, "rcx-icon--name-kebab")]/..'); } public moreActions(): Locator { @@ -28,11 +26,13 @@ class FlexTab extends BasePage { // Channel Info Tab public channelTab(): Locator { - return this.getPage().locator('.rcx-room-header .rcx-button-group__item:not(.hidden) .rcx-icon--name-info-circled'); + return this.getPage().locator('(//main//*[contains(@class, "rcx-icon--name-info-circled")])[1]/..'); } public channelSettings(): Locator { - return this.getPage().locator('aside > h3 > div > i.rcx-box--full.rcx-icon--name-info-circled'); + return this.getPage().locator( + '//aside/h3/div/i[contains(@class,"rcx-icon--name-info-circled") and contains(@class,"rcx-icon--name-info-circled")]', + ); } public channelSettingName(): Locator { @@ -187,7 +187,8 @@ class FlexTab extends BasePage { // Notifications Tab public notificationsTab(): Locator { - return this.getPage().locator('.rcx-option__content:contains("Notifications Preferences")'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Notifications Preferences")]'); + // return this.getPage().locator('.rcx-option__content:contains("Notifications Preferences")'); } public notificationsSettings(): Locator { @@ -221,16 +222,17 @@ class FlexTab extends BasePage { // Mentions Tab public mentionsTab(): Locator { - return this.getPage().locator('.rcx-option__content:contains("Mentions")'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Mentions")]'); } public mentionsTabContent(): Locator { return this.getPage().locator('aside > h3 > div > i.rcx-icon--name-at'); + // aside//h3//div//i[contains(@class, "i.rcx-icon--name-at")] } // Starred Tab public starredTab(): Locator { - return this.getPage().locator('.rcx-option__content:contains("Starred Messages")'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Starred Messages")]'); } public starredTabContent(): Locator { @@ -239,7 +241,7 @@ class FlexTab extends BasePage { // Pinned Tab public pinnedTab(): Locator { - return this.getPage().locator('.rcx-option__content:contains("Pinned Messages")'); + return this.getPage().locator('//*[contains(@class, "rcx-option__content") and contains(text(), "Pinned Messages")]'); } public pinnedTabContent(): Locator { @@ -372,82 +374,92 @@ class FlexTab extends BasePage { public async operateFlexTab(desiredTab: string, desiredState: boolean): Promise { // desiredState true=open false=closed - const functionNames: { [K: string]: Function } = { - channelSettings: this.channelSettings, - messageSearchBar: this.messageSearchBar, - avatarImage: this.avatarImage, - notificationsSettings: this.notificationsSettings, - filesTabContent: this.filesTabContent, - mentionsTabContent: this.mentionsTabContent, - starredTabContent: this.starredTabContent, - pinnedTabContent: this.pinnedTabContent, - channelTab: this.channelTab, - - }; - - const callFunction = (name: string): Locator => { - return functionNames[name](); + const locator: { [K: string]: Locator } = { + channelSettings: this.channelSettings(), + messageSearchBar: this.messageSearchBar(), + avatarImage: this.avatarImage(), + notificationsSettings: this.notificationsSettings(), + filesTabContent: this.filesTabContent(), + mentionsTabContent: this.mentionsTabContent(), + starredTabContent: this.starredTabContent(), + pinnedTabContent: this.pinnedTabContent(), + channelTab: this.channelTab(), + searchTab: this.searchTab(), + membersTab: this.membersTab(), + notificationsTab: this.notificationsTab(), + filesTab: this.filesTab(), + mentionsTab: this.mentionsTab(), + starredTab: this.starredTab(), + pinnedTab: this.pinnedTab(), }; const operate = async (tab: string, panel: string, more: boolean): Promise => { // this[panel].should(!desiredState ? 'be.visible' : 'not.exist'); - if (desiredState) { - await expect(callFunction(panel)).toBeVisible(); + if (!desiredState) { + await expect(locator[panel]).toBeVisible(); } else { - await expect(callFunction(panel)).toBeVisible(); + await expect(locator[panel]).not.toBeVisible(); } if (more) { - this.headerMoreActions().click(); + await this.headerMoreActions().click(); } - this[tab].click(); + await locator[tab].click(); // The button "more" keeps the focus when popover is closed from a click // on an item, need to click again to change the status to unselected and // allow the next click to open the popover again if (more) { - this.headerMoreActions.click(); + await this.headerMoreActions().click(); } - this[panel].should(desiredState ? 'be.visible' : 'not.exist'); + if (desiredState) { + await expect(locator[panel]).toBeVisible(); + } else { + await expect(locator[panel]).not.toBeVisible(); + } }; - const tabs = { - info() { - operate('channelTab', 'channelSettings'); + const tabs: { [K: string]: Function } = { + info: async (): Promise => { + await operate('channelTab', 'channelSettings', false); }, - search() { - operate('searchTab', 'messageSearchBar'); + search: async (): Promise => { + await operate('searchTab', 'messageSearchBar', false); }, - members() { - operate('membersTab', 'avatarImage'); + members: async (): Promise => { + await operate('membersTab', 'avatarImage', false); }, - notifications() { - operate('notificationsTab', 'notificationsSettings', true); + notifications: async (): Promise => { + await operate('notificationsTab', 'notificationsSettings', true); }, - files() { - operate('filesTab', 'filesTabContent'); + files: async (): Promise => { + await operate('filesTab', 'filesTabContent', false); }, - mentions() { - operate('mentionsTab', 'mentionsTabContent', true); + mentions: async (): Promise => { + await operate('mentionsTab', 'mentionsTabContent', true); }, - starred() { - operate('starredTab', 'starredTabContent', true); + starred: async (): Promise => { + await operate('starredTab', 'starredTabContent', true); }, - pinned() { - operate('pinnedTab', 'pinnedTabContent', true); + pinned: async (): Promise => { + await operate('pinnedTab', 'pinnedTabContent', true); }, }; - tabs[desiredTab].call(this); + const callFunctionTabs = async (name: string): Promise => { + return tabs[name](); + }; + + await callFunctionTabs(desiredTab); } } diff --git a/tests/e2e/utils/pageobjects/main-content.page.ts b/tests/e2e/utils/pageobjects/main-content.page.ts index 4e4135696ea3..7f442eb38a92 100644 --- a/tests/e2e/utils/pageobjects/main-content.page.ts +++ b/tests/e2e/utils/pageobjects/main-content.page.ts @@ -67,7 +67,7 @@ class MainContent extends BasePage { // Messages public lastMessageUser(): Locator { - return this.getPage().locator('.message:last-child .title .user-card-message'); + return this.getPage().locator('(//*[contains(@class, "message") and contains(@class, "user-card-message")])[last()]'); } public lastMessage(): Locator { From 93f629a10848b861adcada819446ca8bdef1bf84 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 11:24:11 -0300 Subject: [PATCH 23/35] test: migrate 07-emoji to playwright --- tests/e2e/07-emoji.spec.ts | 165 +++++++++++++++++++ tests/e2e/utils/pageobjects/side-nav.page.ts | 2 +- 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tests/e2e/07-emoji.spec.ts diff --git a/tests/e2e/07-emoji.spec.ts b/tests/e2e/07-emoji.spec.ts new file mode 100644 index 000000000000..bc546339db4a --- /dev/null +++ b/tests/e2e/07-emoji.spec.ts @@ -0,0 +1,165 @@ +import { test, expect } from '@playwright/test'; + +import MainContent from './utils/pageobjects/main-content.page'; +import SideNav from './utils/pageobjects/side-nav.page'; +import LoginPage from './utils/pageobjects/login.page'; +import { adminLogin } from './utils/mocks/userAndPasswordMock'; +import { LOCALHOST } from './utils/mocks/urlMock'; +import mainContent from "/tests/cypress/pageobjects/main-content.page"; +import sideNav from "/tests/cypress/pageobjects/side-nav.page"; + +test.describe('[Emoji]', function () { + let loginPage: LoginPage; + let mainContent: MainContent; + let sideNav: SideNav; + + test.beforeAll(async ({ browser, baseURL }) => { + const context = await browser.newContext(); + const page = await context.newPage(); + const URL = baseURL || LOCALHOST; + loginPage = new LoginPage(page); + await loginPage.goto(URL); + + await loginPage.login(adminLogin); + sideNav = new SideNav(page); + mainContent = new MainContent(page); + + await sideNav.spotlightSearchIcon().click(); + await sideNav.searchChannel('general'); + }); + + test.describe('Render:', () => { + before(async () => { + await mainContent.emojiBtn().click(); + }); + + after(async () => { + await mainContent.emojiSmile().first().click(); + await mainContent.setTextToInput(''); + }); + + test('it should show the emoji picker menu', async () => { + await expect(mainContent.emojiPickerMainScreen()).toBeVisible(); + }); + + test('it should click the emoji picker people tab', async () => { + await mainContent.emojiPickerPeopleIcon().click(); + }); + + test('it should show the emoji picker people tab', async () => { + await expect(mainContent.emojiPickerPeopleIcon()).toBeVisible(); + }); + + test('it should show the emoji picker nature tab', async () => { + await expect(mainContent.emojiPickerNatureIcon()).toBeVisible(); + }); + + test('it should show the emoji picker food tab', async () => { + await expect(mainContent.emojiPickerFoodIcon()).toBeVisible(); + }); + + test('it should show the emoji picker activity tab', async () => { + await expect(mainContent.emojiPickerActivityIcon()).toBeVisible(); + }); + + test('it should show the emoji picker travel tab', async () => { + await expect(mainContent.emojiPickerTravelIcon()).toBeVisible(); + }); + + test('it should show the emoji picker objects tab', async () => { + await expect(mainContent.emojiPickerObjectsIcon()).toBeVisible(); + }); + + test('it should show the emoji picker symbols tab', async () => { + await expect(mainContent.emojiPickerSymbolsIcon()).toBeVisible(); + }); + + test('it should show the emoji picker flags tab', async () => { + await expect(mainContent.emojiPickerFlagsIcon()).toBeVisible(); + }); + + test('it should show the emoji picker custom tab', async () => { + await expect(mainContent.emojiPickerCustomIcon()).toBeVisible(); + }); + + test('it should show the emoji picker change tone button', async () => { + await expect(mainContent.emojiPickerChangeTone()).toBeVisible(); + }); + + test('it should show the emoji picker search bar', async () => { + await expect(mainContent.emojiPickerFilter()).toBeVisible(); + }); + }); + + test.describe('[Usage]', () => { + test.describe('send emoji via screen:', () => { + test.beforeAll(async () => { + await mainContent.emojiBtn().click(); + await mainContent.emojiPickerPeopleIcon().click(); + }); + + test('it should select a grinning emoji', async () => { + await mainContent.emojiGrinning().first().click(); + }); + + test('it should be that the value on the message input is the same as the emoji clicked', async () => { + await mainContent.messageInput().should('have.value', ':grinning: '); + }); + + test('it should send the emoji', async () => { + await mainContent.addTextToInput(' '); + await mainContent.sendBtn().click(); + }); + + test('it should be that the value on the message is the same as the emoji clicked', async () => { + await expect(mainContent.lastMessage()).toContainText('😀'); + }); + }); + + test.describe('send emoji via text:', () => { + test('it should add emoji text to the message input', async () => { + await mainContent.addTextToInput(':smile'); + }); + + test('it should show the emoji popup bar', async () => { + await expect(mainContent.messagePopUp()).toBeVisible(); + }); + + test('it should be that the emoji popup bar title is emoji', async () => { + await expect(mainContent.messagePopUpTitle()).toContainText('Emoji'); + }); + + test('it should show the emoji popup bar items', async () => { + await expect(mainContent.messagePopUpItems()).toBeVisible(); + }); + + test('it should click the first emoji on the popup list', async () => { + await mainContent.messagePopUpFirstItem().click(); + }); + + test('it should be that the value on the message input is the same as the emoji clicked', async () => { + await expect(mainContent.messageInput()).toHaveValue(':smile: '); + }); + + test('it should send the emoji', async () => { + await mainContent.sendBtn().click(); + }); + + test('it should be that the value on the message is the same as the emoji clicked', async () => { + await expect(mainContent.lastMessage()).toContainText('😄'); + }); + }); + + test.describe("send texts and make sure they're not converted to emojis:", () => { + test('should render numbers', () => { + mainContent.sendMessage('0 1 2 3 4 5 6 7 8 9'); + mainContent.waitForLastMessageEqualsHtml('0 1 2 3 4 5 6 7 8 9'); + }); + + test('should render special characters', () => { + mainContent.sendMessage('# * ® © ™'); + mainContent.waitForLastMessageEqualsHtml('# * ® © ™'); + }); + }); + }); +}); diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts index eb69a78ca714..c0c8806e26a2 100644 --- a/tests/e2e/utils/pageobjects/side-nav.page.ts +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -178,7 +178,7 @@ class SideNav extends BasePage { // Opens a channel via spotlight search public async searchChannel(channelName: any): Promise { - await this.spotlightSearch().should('be.visible'); + await expect(this.spotlightSearch()).toBeVisible(); // Should have focus automatically, but some times it's not happening await this.spotlightSearch().click(); From 2a2e7577f94badacbc9679577138c46eaedae637 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 11:27:21 -0300 Subject: [PATCH 24/35] test: remove docker-compose.yml from commit --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e73b670b22f8..76a663537960 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,6 @@ services: - MONGO_URL=mongodb://mongo:27017/rocketchat - MONGO_OPLOG_URL=mongodb://mongo:27017/local - REG_TOKEN=${REG_TOKEN} - - TEST_MODE=true # - MAIL_URL=smtp://smtp.email # - HTTP_PROXY=http://proxy.domain.com # - HTTPS_PROXY=http://proxy.domain.com From 30a4c14502218939de8eb160f3ba7be39f186b5d Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 11:32:28 -0300 Subject: [PATCH 25/35] test: remove app.json from commit --- app.json | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/app.json b/app.json index d079803f58a0..1513ba1382a8 100644 --- a/app.json +++ b/app.json @@ -1,25 +1,20 @@ { - "name": "Rocket.Chat", - "description": "Have your own open-source Slack-like online chat platform.", - "repository": "https://github.com/RocketChat/Rocket.Chat", - "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", - "keywords": [ - "meteor", - "social", - "community", - "chat" - ], - "website": "https://rocket.chat", - "env": { - "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", - "HEROKU_APP_NAME": { - "description": "Please re-enter your App Name from the top.", - "required": true - }, - "DEPLOY_PLATFORM": "heroku" - }, - "addons": [ - "mongolab", - "logentries" - ] + "name": "Rocket.Chat", + "description": "Have your own open-source Slack-like online chat platform.", + "repository": "https://github.com/RocketChat/Rocket.Chat", + "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", + "keywords": ["meteor", "social", "community", "chat"], + "website": "https://rocket.chat", + "env": { + "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", + "HEROKU_APP_NAME": { + "description": "Please re-enter your App Name from the top.", + "required": true + }, + "DEPLOY_PLATFORM": "heroku" + }, + "addons": [ + "mongolab", + "logentries" + ] } From f6c1b0bfe2179676aa53cc0afdba2abe4d7f51a7 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 15:36:25 -0300 Subject: [PATCH 26/35] test: end migrate 07-emoji tests to playwright --- tests/e2e/07-emoji.spec.ts | 79 +++++++++---------- .../utils/pageobjects/main-content.page.ts | 41 +++++----- tests/e2e/utils/pageobjects/side-nav.page.ts | 13 ++- 3 files changed, 67 insertions(+), 66 deletions(-) diff --git a/tests/e2e/07-emoji.spec.ts b/tests/e2e/07-emoji.spec.ts index bc546339db4a..9b0e77b6318e 100644 --- a/tests/e2e/07-emoji.spec.ts +++ b/tests/e2e/07-emoji.spec.ts @@ -5,8 +5,6 @@ import SideNav from './utils/pageobjects/side-nav.page'; import LoginPage from './utils/pageobjects/login.page'; import { adminLogin } from './utils/mocks/userAndPasswordMock'; import { LOCALHOST } from './utils/mocks/urlMock'; -import mainContent from "/tests/cypress/pageobjects/main-content.page"; -import sideNav from "/tests/cypress/pageobjects/side-nav.page"; test.describe('[Emoji]', function () { let loginPage: LoginPage; @@ -24,69 +22,68 @@ test.describe('[Emoji]', function () { sideNav = new SideNav(page); mainContent = new MainContent(page); - await sideNav.spotlightSearchIcon().click(); - await sideNav.searchChannel('general'); + await sideNav.openChannel('general'); }); test.describe('Render:', () => { - before(async () => { + test.beforeAll(async () => { await mainContent.emojiBtn().click(); }); - after(async () => { + test.afterAll(async () => { await mainContent.emojiSmile().first().click(); await mainContent.setTextToInput(''); }); - test('it should show the emoji picker menu', async () => { + test('expect show the emoji picker menu', async () => { await expect(mainContent.emojiPickerMainScreen()).toBeVisible(); }); - test('it should click the emoji picker people tab', async () => { + test('expect click the emoji picker people tab', async () => { await mainContent.emojiPickerPeopleIcon().click(); }); - test('it should show the emoji picker people tab', async () => { + test('expect show the emoji picker people tab', async () => { await expect(mainContent.emojiPickerPeopleIcon()).toBeVisible(); }); - test('it should show the emoji picker nature tab', async () => { + test('expect show the emoji picker nature tab', async () => { await expect(mainContent.emojiPickerNatureIcon()).toBeVisible(); }); - test('it should show the emoji picker food tab', async () => { + test('expect show the emoji picker food tab', async () => { await expect(mainContent.emojiPickerFoodIcon()).toBeVisible(); }); - test('it should show the emoji picker activity tab', async () => { + test('expect show the emoji picker activity tab', async () => { await expect(mainContent.emojiPickerActivityIcon()).toBeVisible(); }); - test('it should show the emoji picker travel tab', async () => { + test('expect show the emoji picker travel tab', async () => { await expect(mainContent.emojiPickerTravelIcon()).toBeVisible(); }); - test('it should show the emoji picker objects tab', async () => { + test('expect show the emoji picker objects tab', async () => { await expect(mainContent.emojiPickerObjectsIcon()).toBeVisible(); }); - test('it should show the emoji picker symbols tab', async () => { + test('expect show the emoji picker symbols tab', async () => { await expect(mainContent.emojiPickerSymbolsIcon()).toBeVisible(); }); - test('it should show the emoji picker flags tab', async () => { + test('expect show the emoji picker flags tab', async () => { await expect(mainContent.emojiPickerFlagsIcon()).toBeVisible(); }); - test('it should show the emoji picker custom tab', async () => { + test('expect show the emoji picker custom tab', async () => { await expect(mainContent.emojiPickerCustomIcon()).toBeVisible(); }); - test('it should show the emoji picker change tone button', async () => { + test('expect show the emoji picker change tone button', async () => { await expect(mainContent.emojiPickerChangeTone()).toBeVisible(); }); - test('it should show the emoji picker search bar', async () => { + test('expect show the emoji picker search bar', async () => { await expect(mainContent.emojiPickerFilter()).toBeVisible(); }); }); @@ -98,67 +95,67 @@ test.describe('[Emoji]', function () { await mainContent.emojiPickerPeopleIcon().click(); }); - test('it should select a grinning emoji', async () => { + test('expect select a grinning emoji', async () => { await mainContent.emojiGrinning().first().click(); }); - test('it should be that the value on the message input is the same as the emoji clicked', async () => { - await mainContent.messageInput().should('have.value', ':grinning: '); + test('expect be that the value on the message input is the same as the emoji clicked', async () => { + await expect(mainContent.messageInput()).toHaveValue(':grinning: '); }); - test('it should send the emoji', async () => { + test('expect send the emoji', async () => { await mainContent.addTextToInput(' '); await mainContent.sendBtn().click(); }); - test('it should be that the value on the message is the same as the emoji clicked', async () => { + test('expect be that the value on the message is the same as the emoji clicked', async () => { await expect(mainContent.lastMessage()).toContainText('😀'); }); }); test.describe('send emoji via text:', () => { - test('it should add emoji text to the message input', async () => { - await mainContent.addTextToInput(':smile'); + test('expect add emoji text to the message input', async () => { + await mainContent.addTextToInput(':smiley'); }); - test('it should show the emoji popup bar', async () => { + test('expect show the emoji popup bar', async () => { await expect(mainContent.messagePopUp()).toBeVisible(); }); - test('it should be that the emoji popup bar title is emoji', async () => { + test('expect be that the emoji popup bar title is emoji', async () => { await expect(mainContent.messagePopUpTitle()).toContainText('Emoji'); }); - test('it should show the emoji popup bar items', async () => { + test('expect show the emoji popup bar items', async () => { await expect(mainContent.messagePopUpItems()).toBeVisible(); }); - test('it should click the first emoji on the popup list', async () => { + test('expect click the first emoji on the popup list', async () => { await mainContent.messagePopUpFirstItem().click(); }); - test('it should be that the value on the message input is the same as the emoji clicked', async () => { - await expect(mainContent.messageInput()).toHaveValue(':smile: '); + test('expect be that the value on the message input is the same as the emoji clicked', async () => { + await expect(mainContent.messageInput()).toHaveValue(':smiley: '); }); - test('it should send the emoji', async () => { + test('expect send the emoji', async () => { await mainContent.sendBtn().click(); }); - test('it should be that the value on the message is the same as the emoji clicked', async () => { - await expect(mainContent.lastMessage()).toContainText('😄'); + test('expect be that the value on the message is the same as the emoji clicked', async () => { + await expect(mainContent.lastMessage()).toContainText('😃'); }); }); test.describe("send texts and make sure they're not converted to emojis:", () => { - test('should render numbers', () => { - mainContent.sendMessage('0 1 2 3 4 5 6 7 8 9'); - mainContent.waitForLastMessageEqualsHtml('0 1 2 3 4 5 6 7 8 9'); + test('should render numbers', async () => { + await mainContent.sendMessage('0 1 2 3 4 5 6 7 8 9'); + await mainContent.waitForLastMessageEqualsHtml('0 1 2 3 4 5 6 7 8 9'); }); - test('should render special characters', () => { - mainContent.sendMessage('# * ® © ™'); - mainContent.waitForLastMessageEqualsHtml('# * ® © ™'); + test('should render special characters', async () => { + await mainContent.sendMessage('# * ® © ™'); + await mainContent.waitForLastMessageEqualsHtml('# * ® © ™'); }); }); }); diff --git a/tests/e2e/utils/pageobjects/main-content.page.ts b/tests/e2e/utils/pageobjects/main-content.page.ts index 7f442eb38a92..bbde1d8aa203 100644 --- a/tests/e2e/utils/pageobjects/main-content.page.ts +++ b/tests/e2e/utils/pageobjects/main-content.page.ts @@ -166,19 +166,19 @@ class MainContent extends BasePage { } public emojiPickerPeopleIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-people'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-people")]'); } public emojiPickerNatureIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-nature'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-nature")]'); } public emojiPickerFoodIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-food'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-food")]'); } public emojiPickerActivityIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-activity'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-activity")]'); } public emojiPickerTravelIcon(): Locator { @@ -186,47 +186,47 @@ class MainContent extends BasePage { } public emojiPickerObjectsIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-objects'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-objects")]'); } public emojiPickerSymbolsIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-symbols'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-symbols")]'); } public emojiPickerFlagsIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-flags'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-flags")]'); } public emojiPickerModifierIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-symbols'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-symbols")]'); } public emojiPickerChangeTone(): Locator { - return this.getPage().locator('.emoji-picker .change-tone'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "change-tone")]'); } public emojiPickerCustomIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-rocket'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-rocket")]'); } public emojiPickerRecentIcon(): Locator { - return this.getPage().locator('.emoji-picker .icon-recent'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "icon-recent")]'); } public emojiPickerFilter(): Locator { - return this.getPage().locator('.emoji-picker .js-emojipicker-search'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "js-emojipicker-search")]'); } public emojiPickerEmojiContainer(): Locator { - return this.getPage().locator('.emoji-picker .emojis'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "emojis")]'); } public emojiGrinning(): Locator { - return this.getPage().locator('.emoji-picker .emoji-grinning'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "emoji-grinning")]'); } public emojiSmile(): Locator { - return this.getPage().locator('.emoji-picker .emoji-smile'); + return this.getPage().locator('//*[contains(@class, "emoji-picker")]//*[contains(@class, "emoji-smile")]'); } // Popover @@ -234,12 +234,17 @@ class MainContent extends BasePage { return this.getPage().locator('.rc-popover'); } + public async waitForLastMessageEqualsHtml(text: string): Promise { + await expect(this.getPage().locator('(//*[contains(@class, "message") and contains(@class, "body")])[last()]')).toContainText(text); + } + // Sends a message and wait for the message to equal the text sent public async sendMessage(text: any): Promise { - this.setTextToInput(text); + await this.setTextToInput(text); await this.sendBtn().click(); - await expect(this.getPage().locator('.message:last-child .body')).toBeVisible(); - await expect(this.getPage().locator('.message:last-child .body')).toContain(text); + await expect( + this.getPage().locator('(//*[contains(@class, "message-body-wrapper")])[last()]/div[contains(@class, "body")]'), + ).toContainText(text); } // adds text to the input diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts index c0c8806e26a2..8a68713bd837 100644 --- a/tests/e2e/utils/pageobjects/side-nav.page.ts +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -177,23 +177,22 @@ class SideNav extends BasePage { } // Opens a channel via spotlight search - public async searchChannel(channelName: any): Promise { + public async searchChannel(channelName: string): Promise { await expect(this.spotlightSearch()).toBeVisible(); - // Should have focus automatically, but some times it's not happening await this.spotlightSearch().click(); await expect(this.spotlightSearch()).toBeFocused(); await this.spotlightSearch().type(channelName); - // cy.wait(500); - - // cy.get( - // `[data-qa="sidebar-search-result"] .rcx-sidebar-item--clickable:contains("${channelName}"), [data-qa="sidebar-search-result"] .rcx-sidebar-item[aria-label='${channelName}']`, - // ).click(); await expect(this.getPage().locator('.rcx-room-header')).toContainText(channelName); } + public async searchChannelAndOpen(channelName: string): Promise { + await this.searchChannel(channelName); + + } + // Gets a channel from the rooms list public getChannelFromList(channelName: any): Locator { return this.getPage().locator('[data-qa="sidebar-item-title"]', { hasText: channelName }); From 0722c1de650d64b4d19fd10a07c60adc2c3b654d Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 11:27:21 -0300 Subject: [PATCH 27/35] test: remove docker-compose.yml from commit --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e73b670b22f8..76a663537960 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,6 @@ services: - MONGO_URL=mongodb://mongo:27017/rocketchat - MONGO_OPLOG_URL=mongodb://mongo:27017/local - REG_TOKEN=${REG_TOKEN} - - TEST_MODE=true # - MAIL_URL=smtp://smtp.email # - HTTP_PROXY=http://proxy.domain.com # - HTTPS_PROXY=http://proxy.domain.com From 48bb78ccc0804a77811f2c75fd04b2abf57ca243 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 11:32:28 -0300 Subject: [PATCH 28/35] test: remove app.json from commit --- app.json | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/app.json b/app.json index d079803f58a0..1513ba1382a8 100644 --- a/app.json +++ b/app.json @@ -1,25 +1,20 @@ { - "name": "Rocket.Chat", - "description": "Have your own open-source Slack-like online chat platform.", - "repository": "https://github.com/RocketChat/Rocket.Chat", - "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", - "keywords": [ - "meteor", - "social", - "community", - "chat" - ], - "website": "https://rocket.chat", - "env": { - "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", - "HEROKU_APP_NAME": { - "description": "Please re-enter your App Name from the top.", - "required": true - }, - "DEPLOY_PLATFORM": "heroku" - }, - "addons": [ - "mongolab", - "logentries" - ] + "name": "Rocket.Chat", + "description": "Have your own open-source Slack-like online chat platform.", + "repository": "https://github.com/RocketChat/Rocket.Chat", + "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", + "keywords": ["meteor", "social", "community", "chat"], + "website": "https://rocket.chat", + "env": { + "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", + "HEROKU_APP_NAME": { + "description": "Please re-enter your App Name from the top.", + "required": true + }, + "DEPLOY_PLATFORM": "heroku" + }, + "addons": [ + "mongolab", + "logentries" + ] } From 3c11e2895dd5c925354230fcad0fd2688680b15f Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 17:02:45 -0300 Subject: [PATCH 29/35] chore: include playwright --- package-lock.json | 1031 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- 2 files changed, 1030 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5ea3a74f71b..f0288dcc40ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5363,6 +5363,470 @@ } } }, + "@playwright/test": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.20.1.tgz", + "integrity": "sha512-muk3KZXfA7sXTwUEXfL3m4tusj/MBGYjxIFmooi+F2Pf6hKjjVl4+8niy77Xujk4jpL7hZbbqq9v5bRl2m+C8Q==", + "dev": true, + "requires": { + "@babel/code-frame": "7.16.7", + "@babel/core": "7.16.12", + "@babel/helper-plugin-utils": "7.16.7", + "@babel/plugin-proposal-class-properties": "7.16.7", + "@babel/plugin-proposal-dynamic-import": "7.16.7", + "@babel/plugin-proposal-export-namespace-from": "7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.16.7", + "@babel/plugin-proposal-numeric-separator": "7.16.7", + "@babel/plugin-proposal-optional-chaining": "7.16.7", + "@babel/plugin-proposal-private-methods": "7.16.11", + "@babel/plugin-proposal-private-property-in-object": "7.16.7", + "@babel/plugin-syntax-async-generators": "7.8.4", + "@babel/plugin-syntax-json-strings": "7.8.3", + "@babel/plugin-syntax-object-rest-spread": "7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "7.8.3", + "@babel/plugin-transform-modules-commonjs": "7.16.8", + "@babel/preset-typescript": "7.16.7", + "colors": "1.4.0", + "commander": "8.3.0", + "debug": "4.3.3", + "expect": "27.2.5", + "jest-matcher-utils": "27.2.5", + "json5": "2.2.1", + "mime": "3.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "open": "8.4.0", + "pirates": "4.0.4", + "playwright-core": "1.20.1", + "rimraf": "3.0.2", + "source-map-support": "0.4.18", + "stack-utils": "2.0.5", + "yazl": "2.5.1" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", + "dev": true + }, + "@babel/core": { + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.12", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", + "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.8.tgz", + "integrity": "sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "browserslist": { + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001323", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz", + "integrity": "sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==", + "dev": true + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.4.103", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz", + "integrity": "sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "pirates": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", + "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "dev": true + }, + "playwright-core": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.20.1.tgz", + "integrity": "sha512-A8ZsZ09gaSbxP0UijoLyzp3LJc0kWMxDooLPi+mm4/5iYnTbd6PF5nKjoFw1a7KwjZIEgdhJduah4BcUIh+IPA==", + "dev": true, + "requires": { + "colors": "1.4.0", + "commander": "8.3.0", + "debug": "4.3.3", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.0", + "jpeg-js": "0.4.3", + "mime": "3.0.0", + "pixelmatch": "5.2.1", + "pngjs": "6.0.0", + "progress": "2.0.3", + "proper-lockfile": "4.1.2", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "socks-proxy-agent": "6.1.1", + "stack-utils": "2.0.5", + "ws": "8.4.2", + "yauzl": "2.10.0", + "yazl": "2.5.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "ws": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz", + "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==", + "dev": true + } + } + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz", @@ -11118,6 +11582,12 @@ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, "@types/stream-buffers": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.3.tgz", @@ -16322,8 +16792,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true + "dev": true }, "combined-stream": { "version": "1.0.7", @@ -17756,6 +18225,12 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -17899,6 +18374,12 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -19703,6 +20184,101 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, + "expect": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.5.tgz", + "integrity": "sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.2.5", + "jest-message-util": "^27.2.5", + "jest-regex-util": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -24571,6 +25147,69 @@ "iterate-iterator": "^1.0.1" } }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, "jest-haste-map": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", @@ -24657,6 +25296,261 @@ } } }, + "jest-matcher-utils": { + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz", + "integrity": "sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.2.5", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, "jest-mock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", @@ -24911,6 +25805,12 @@ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", "dev": true }, + "jpeg-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", + "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==", + "dev": true + }, "jquery": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", @@ -30148,6 +31048,23 @@ "node-modules-regexp": "^1.0.0" } }, + "pixelmatch": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.2.1.tgz", + "integrity": "sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==", + "dev": true, + "requires": { + "pngjs": "^4.0.1" + }, + "dependencies": { + "pngjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-4.0.1.tgz", + "integrity": "sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==", + "dev": true + } + } + }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -30207,6 +31124,12 @@ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" }, + "pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true + }, "pnp-webpack-plugin": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", @@ -31885,6 +32808,25 @@ "react-is": "^16.8.1" } }, + "proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + } + } + }, "property-information": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", @@ -31937,6 +32879,12 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -34027,6 +34975,12 @@ "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=" }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, "snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -34170,6 +35124,53 @@ } } }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "sodium-native": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-3.2.1.tgz", @@ -34392,6 +35393,23 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "stackframe": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", @@ -38860,6 +39878,15 @@ "fd-slicer": "~1.1.0" } }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 2f4713c999d3..94b4629f509e 100644 --- a/package.json +++ b/package.json @@ -359,4 +359,4 @@ "node": "14.18.2", "npm": "6.14.15" } -} \ No newline at end of file +} From c919adc9309550ded98ff5c95967985ab07d965f Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 17:10:36 -0300 Subject: [PATCH 30/35] refactor: use admin Username --- tests/e2e/04-main-elements-render.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/04-main-elements-render.spec.ts b/tests/e2e/04-main-elements-render.spec.ts index c894e75dee6c..6fc7a4005ed8 100644 --- a/tests/e2e/04-main-elements-render.spec.ts +++ b/tests/e2e/04-main-elements-render.spec.ts @@ -4,10 +4,10 @@ import MainContent from './utils/pageobjects/main-content.page'; import SideNav from './utils/pageobjects/side-nav.page'; import FlexTab from './utils/pageobjects/flex-tab.page'; import LoginPage from './utils/pageobjects/login.page'; -import { adminLogin } from './utils/mocks/userAndPasswordMock'; +import { adminLogin, adminRegister } from './utils/mocks/userAndPasswordMock'; import { LOCALHOST } from './utils/mocks/urlMock'; -const username = adminLogin.password; +const username = adminRegister.name; test.describe('[Main Elements Render]', function () { let loginPage: LoginPage; From 3356def93669e0b5be8f689c3098ab8654b9ac53 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Thu, 31 Mar 2022 17:54:36 -0300 Subject: [PATCH 31/35] fix: eslint --- tests/e2e/utils/pageobjects/side-nav.page.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts index 8a68713bd837..6b703f70246f 100644 --- a/tests/e2e/utils/pageobjects/side-nav.page.ts +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -190,7 +190,6 @@ class SideNav extends BasePage { public async searchChannelAndOpen(channelName: string): Promise { await this.searchChannel(channelName); - } // Gets a channel from the rooms list From 6a4096e03565dda77cd613e4304fe41359926650 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Fri, 1 Apr 2022 08:11:47 -0300 Subject: [PATCH 32/35] refactor: remove unused functions --- tests/e2e/06-messaging.spec.ts | 3 ++- tests/e2e/utils/pageobjects/wizard.page.ts | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/e2e/06-messaging.spec.ts b/tests/e2e/06-messaging.spec.ts index 8f87d46ba64c..d273d0889ffa 100644 --- a/tests/e2e/06-messaging.spec.ts +++ b/tests/e2e/06-messaging.spec.ts @@ -1,5 +1,6 @@ -import { test } from '@playwright/test'; +import { expect, test } from '@playwright/test'; +// TODO: will be implemented soon test.describe('[Messaging]', () => { test.beforeAll(async () => { expect(1).toBe(1); diff --git a/tests/e2e/utils/pageobjects/wizard.page.ts b/tests/e2e/utils/pageobjects/wizard.page.ts index 03a164b47547..7e2f9de2db5b 100644 --- a/tests/e2e/utils/pageobjects/wizard.page.ts +++ b/tests/e2e/utils/pageobjects/wizard.page.ts @@ -98,10 +98,6 @@ class SetupWizard extends BasePage { return this.getPage().locator('//input[@name="companyEmail"]/../following-sibling::span'); } - private organizationNameInvalidText(): Locator { - return this.getPage().locator('//input[@name="organizationName"]/../following-sibling::span'); - } - private passwordInvalidText(): Locator { return this.getPage().locator('//input[@name="password"]/../../../span[contains(@class, "rcx-field__error")]'); } @@ -118,10 +114,6 @@ class SetupWizard extends BasePage { return this.getPage().locator('//div[@name="country"]/../following-sibling::span'); } - private invalidInputEmail(): Locator { - return this.getPage().locator('$$("input:invalid")'); - } - public async goNext(): Promise { await this.nextStep().click(); } From 28f1f96799bd47b8e4429dd86da61a2d40a03cb4 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Fri, 1 Apr 2022 11:15:31 -0300 Subject: [PATCH 33/35] test: begin 10-user-preferences.spec.ts (playwright) --- tests/e2e/10-user-preferences.spec.ts | 163 ++++++++++++++++++ .../preferences-main-content.page.ts | 73 ++++++++ 2 files changed, 236 insertions(+) create mode 100644 tests/e2e/10-user-preferences.spec.ts create mode 100644 tests/e2e/utils/pageobjects/preferences-main-content.page.ts diff --git a/tests/e2e/10-user-preferences.spec.ts b/tests/e2e/10-user-preferences.spec.ts new file mode 100644 index 000000000000..20ff29d59105 --- /dev/null +++ b/tests/e2e/10-user-preferences.spec.ts @@ -0,0 +1,163 @@ +import { test, expect } from '@playwright/test'; + +import MainContent from './utils/pageobjects/main-content.page'; +import SideNav from './utils/pageobjects/side-nav.page'; +import LoginPage from './utils/pageobjects/login.page'; +import PreferencesMainContent from './utils/pageobjects/preferences-main-content.page'; +import { adminLogin } from './utils/mocks/userAndPasswordMock'; +import { LOCALHOST } from './utils/mocks/urlMock'; + +test.describe('[User Preferences]', function () { + test.describe('default', () => { + let loginPage: LoginPage; + let mainContent: MainContent; + let sideNav: SideNav; + let preferencesMainContent: PreferencesMainContent; + + test.beforeAll(async ({ browser, baseURL }) => { + const context = await browser.newContext(); + const page = await context.newPage(); + const URL = baseURL || LOCALHOST; + loginPage = new LoginPage(page); + await loginPage.goto(URL); + + await loginPage.login(adminLogin); + sideNav = new SideNav(page); + mainContent = new MainContent(page); + preferencesMainContent = new PreferencesMainContent(page); + + await sideNav.openChannel('general'); + }); + + test.describe('render:', () => { + test('it should show the preferences link', () => { + sideNav.preferences.should('be.visible'); + }); + + test('it should show the profile link', () => { + sideNav.profile.should('be.visible'); + }); + + test('it should click on the profile link', () => { + sideNav.profile.click(); + }); + + test('it should show the username input', () => { + preferencesMainContent.userNameTextInput.should('be.visible'); + }); + + test('it should show the real name input', () => { + preferencesMainContent.realNameTextInput.should('be.visible'); + }); + + test('it should show the email input', () => { + preferencesMainContent.emailTextInput.scrollIntoView().should('be.visible'); + }); + + test('it should show the password input', () => { + preferencesMainContent.passwordTextInput.scrollIntoView().should('be.visible'); + }); + + test('it should show the submit button', () => { + preferencesMainContent.submitBtn.should('be.visible').should('be.disabled'); + }); + }); + + test.describe('user info change:', () => { + test('it should click on the profile link', () => { + sideNav.profile.click(); + }); + + test('it should change the name field', () => { + preferencesMainContent.changeRealName(`EditedRealName${username}`); + }); + + test('it should change the Username field', () => { + preferencesMainContent.changeUsername(`EditedUserName${username}`); + }); + + it.skip('it should change the email field', () => { + preferencesMainContent.changeEmail(`EditedUserEmail${username}@gmail.com`); + }); + + it.skip('it should put the password in the modal input', () => { + preferencesMainContent.acceptPasswordOverlay(password); + }); + + test('it should save the settings', () => { + preferencesMainContent.saveChanges(); + }); + + it.skip('it should put the password in the modal input', () => { + preferencesMainContent.acceptPasswordOverlay(password); + }); + + test('it should close the preferences menu', () => { + sideNav.preferencesClose.click(); + sideNav.getChannelFromList('general').scrollIntoView().click(); + }); + + test('it should send a message to be tested', () => { + mainContent.sendMessage('HI'); + mainContent.waitForLastMessageEqualsText('HI'); + }); + + it.skip('it should be that the name on the last message is the edited one', () => { + mainContent.waitForLastMessageUserEqualsText(`EditedUserName${username}`); + mainContent.lastMessageUser.getText().should.equal(`EditedUserName${username}`); + }); + + it.skip('it should be that the user name on the members flex tab is the edited one', () => { + mainContent.lastMessageUser.click(); + flexTab.memberUserName.getText().should.equal(`EditedUserName${username}`); + }); + + it.skip('it should that the real name on the members flex tab is the edited one', () => { + flexTab.memberRealName.getText().should.equal(`EditedRealName${username}`); + }); + }); + }); + + test.describe('admin', () => { + test.describe.skip('user info change forbidden:', () => { + test.beforeAll(() => { + checkIfUserIsValid(adminUsername, adminEmail, adminPassword); + admin.open('admin/Accounts'); + admin.accountsRealNameChangeFalse.click(); + admin.adminSaveChanges(); + admin.accountsUsernameChangeFalse.click(); + admin.adminSaveChanges(); + admin.settingsSearch.type(''); + sideNav.preferencesClose.click(); + }); + + test.afterAll(() => { + admin.open('admin/Accounts'); + admin.accountsRealNameChangeTrue.click(); + admin.adminSaveChanges(); + admin.accountsUsernameChangeTrue.click(); + admin.adminSaveChanges(); + admin.settingsSearch.type(''); + sideNav.preferencesClose.click(); + }); + + test('it should open profile', () => { + sideNav.accountMenu.click(); + sideNav.account.click(); + sideNav.profile.click(); + }); + + test('it should be that the name field is disabled', () => { + preferencesMainContent.realNameTextInputEnabled().should.be.false; + }); + + test('it should be that the Username field is disabled', () => { + preferencesMainContent.userNameTextInputEnabled().should.be.false; + }); + + test('it should close profile', () => { + sideNav.preferencesClose.click(); + }); + }); + }); +}); diff --git a/tests/e2e/utils/pageobjects/preferences-main-content.page.ts b/tests/e2e/utils/pageobjects/preferences-main-content.page.ts new file mode 100644 index 000000000000..6ea8e4100799 --- /dev/null +++ b/tests/e2e/utils/pageobjects/preferences-main-content.page.ts @@ -0,0 +1,73 @@ +import { expect, Locator } from '@playwright/test'; + +import BasePage from './BasePage'; + +class PreferencesMainContent extends BasePage { + public formTextInput() { + return this.getPage().locator('.rocket-form'); + } + + public realNameTextInput() { + return this.getPage().locator('label:contains("Name")').closest('.rcx-field').find('input'); + } + + public userNameTextInput() { + return this.getPage().locator('label:contains("Username")').closest('.rcx-field').find('input'); + } + + public emailTextInput() { + return this.getPage().locator('label:contains("Email")').closest('.rcx-field').find('input'); + } + + public passwordTextInput() { + return this.getPage().locator('label:contains("Password")').closest('.rcx-field').find('input'); + } + + public resendVerificationEmailBtn() { + return this.getPage().locator('#resend-verification-email'); + } + + public avatarFileInput() { + return this.getPage().locator('.avatar-file-input'); + } + + public useUploadedAvatar() { + return this.getPage().locator('.avatar-suggestion-item:nth-of-type(2) .select-service'); + } + + public submitBtn() { + return this.getPage().locator('button:contains("Save changes")'); + } + + realNameTextInputEnabled() { + return browser.isEnabled('input[name="realname"]'); + } + + userNameTextInputEnabled() { + return browser.isEnabled('input[name="username"]'); + } + + changeUsername(userName) { + this.userNameTextInput.clear().type(userName); + } + + changeRealName(realName) { + this.realNameTextInput.clear().type(realName); + } + + changeEmail(email) { + this.emailTextInput.clear().type(email); + } + + saveChanges() { + this.submitBtn.should('be.enabled'); + this.submitBtn.click(); + } + + changeAvatarUpload(url) { + this.avatarFileInput.chooseFile(url); + this.useUploadedAvatar.click(); + } +} + +export default PreferencesMainContent; From 7adea341f15572c086a23e358c11755dd4531e61 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Mon, 4 Apr 2022 09:23:03 -0300 Subject: [PATCH 34/35] refactor: end migrate 10-user-preferences.spec.ts tests to playwright --- tests/e2e/10-user-preferences.spec.ts | 197 +++++++++--------- .../utils/pageobjects/main-content.page.ts | 6 +- .../preferences-main-content.page.ts | 60 +++--- tests/e2e/utils/pageobjects/side-nav.page.ts | 2 +- 4 files changed, 132 insertions(+), 133 deletions(-) diff --git a/tests/e2e/10-user-preferences.spec.ts b/tests/e2e/10-user-preferences.spec.ts index 20ff29d59105..ca3a559807cd 100644 --- a/tests/e2e/10-user-preferences.spec.ts +++ b/tests/e2e/10-user-preferences.spec.ts @@ -4,7 +4,7 @@ import MainContent from './utils/pageobjects/main-content.page'; import SideNav from './utils/pageobjects/side-nav.page'; import LoginPage from './utils/pageobjects/login.page'; import PreferencesMainContent from './utils/pageobjects/preferences-main-content.page'; -import { adminLogin } from './utils/mocks/userAndPasswordMock'; +import { adminLogin, adminRegister } from './utils/mocks/userAndPasswordMock'; import { LOCALHOST } from './utils/mocks/urlMock'; test.describe('[User Preferences]', function () { @@ -26,138 +26,141 @@ test.describe('[User Preferences]', function () { mainContent = new MainContent(page); preferencesMainContent = new PreferencesMainContent(page); - await sideNav.openChannel('general'); + await sideNav.sidebarUserMenu().click(); + await sideNav.account().click(); }); test.describe('render:', () => { - test('it should show the preferences link', () => { - sideNav.preferences.should('be.visible'); + test('expect show the preferences link', async () => { + await expect(sideNav.preferences()).toBeVisible(); }); - test('it should show the profile link', () => { - sideNav.profile.should('be.visible'); + test('expect show the profile link', async () => { + await expect(sideNav.profile()).toBeVisible(); }); - test('it should click on the profile link', () => { - sideNav.profile.click(); + test('expect click on the profile link', async () => { + await sideNav.profile().click(); }); - test('it should show the username input', () => { - preferencesMainContent.userNameTextInput.should('be.visible'); + test('expect show the username input', async () => { + await expect(preferencesMainContent.userNameTextInput()).toBeVisible(); }); - test('it should show the real name input', () => { - preferencesMainContent.realNameTextInput.should('be.visible'); + test('expect show the real name input', async () => { + await expect(preferencesMainContent.realNameTextInput()).toBeVisible(); }); - test('it should show the email input', () => { - preferencesMainContent.emailTextInput.scrollIntoView().should('be.visible'); + test('expect show the email input', async () => { + await expect(preferencesMainContent.emailTextInput()).toBeVisible(); // .scrollIntoView() }); - test('it should show the password input', () => { - preferencesMainContent.passwordTextInput.scrollIntoView().should('be.visible'); + test('expect show the password input', async () => { + await expect(preferencesMainContent.passwordTextInput()).toBeVisible(); // .scrollIntoView() }); - test('it should show the submit button', () => { - preferencesMainContent.submitBtn.should('be.visible').should('be.disabled'); + test('expect show the submit button', async () => { + await expect(preferencesMainContent.submitBtn()).toBeVisible(); + await expect(preferencesMainContent.submitBtn()).toBeDisabled(); }); }); test.describe('user info change:', () => { - test('it should click on the profile link', () => { - sideNav.profile.click(); + test('expect click on the profile link', async () => { + await sideNav.profile().click(); }); - test('it should change the name field', () => { - preferencesMainContent.changeRealName(`EditedRealName${username}`); + test('expect change the name field', async () => { + await preferencesMainContent.changeRealName(`Edited${adminRegister.name}${Date.now()}`); }); - test('it should change the Username field', () => { - preferencesMainContent.changeUsername(`EditedUserName${username}`); + test('expect change the Username field', async () => { + await preferencesMainContent.changeUsername(`Edited${adminRegister.name}${Date.now()}`); }); - it.skip('it should change the email field', () => { - preferencesMainContent.changeEmail(`EditedUserEmail${username}@gmail.com`); - }); - - it.skip('it should put the password in the modal input', () => { - preferencesMainContent.acceptPasswordOverlay(password); - }); + // test.skip('expect change the email field', async () => { + // preferencesMainContent.changeEmail(`EditedUserEmail${adminRegister.name}@gmail.com`); + // }); + // + // test.skip('expect put the password in the modal input', async () => { + // preferencesMainContent.acceptPasswordOverlay(adminLogin.password); + // }); - test('it should save the settings', () => { - preferencesMainContent.saveChanges(); + test('expect save the settings', async () => { + await preferencesMainContent.saveChanges(); }); - it.skip('it should put the password in the modal input', () => { - preferencesMainContent.acceptPasswordOverlay(password); - }); - - test('it should close the preferences menu', () => { - sideNav.preferencesClose.click(); - sideNav.getChannelFromList('general').scrollIntoView().click(); - }); + // test.skip('expect put the password in the modal input', async () => { + // preferencesMainContent.acceptPasswordOverlay(adminLogin.password); + // }); - test('it should send a message to be tested', () => { - mainContent.sendMessage('HI'); - mainContent.waitForLastMessageEqualsText('HI'); + test('expect close the preferences menu', async () => { + await sideNav.preferencesClose().click(); + await sideNav.getChannelFromList('general').scrollIntoViewIfNeeded(); + await sideNav.getChannelFromList('general').click(); }); - it.skip('it should be that the name on the last message is the edited one', () => { - mainContent.waitForLastMessageUserEqualsText(`EditedUserName${username}`); - mainContent.lastMessageUser.getText().should.equal(`EditedUserName${username}`); + test('expect send a message to be tested', async () => { + await mainContent.sendMessage('HI'); + await mainContent.waitForLastMessageEqualsText('HI'); }); - it.skip('it should be that the user name on the members flex tab is the edited one', () => { - mainContent.lastMessageUser.click(); - flexTab.memberUserName.getText().should.equal(`EditedUserName${username}`); - }); - - it.skip('it should that the real name on the members flex tab is the edited one', () => { - flexTab.memberRealName.getText().should.equal(`EditedRealName${username}`); - }); + // test.skip('expect be that the name on the last message is the edited one', async () => { + // mainContent.waitForLastMessageUserEqualsText(`EditedUserName${adminRegister.name}`); + // mainContent.lastMessageUser().getText().should.equal(`EditedUserName${adminRegister.name}`); + // }); + // + // test.skip('expect be that the user name on the members flex tab is the edited one', async () => { + // mainContent.lastMessageUser().click(); + // flexTab.memberUserName.getText().should.equal(`EditedUserName${adminRegister.name}`); + // }); + // + // test.skip('expect that the real name on the members flex tab is the edited one', async () => { + // flexTab.memberRealName.getText().should.equal(`EditedRealName${adminRegister.name}`); + // }); }); }); - test.describe('admin', () => { - test.describe.skip('user info change forbidden:', () => { - test.beforeAll(() => { - checkIfUserIsValid(adminUsername, adminEmail, adminPassword); - admin.open('admin/Accounts'); - admin.accountsRealNameChangeFalse.click(); - admin.adminSaveChanges(); - admin.accountsUsernameChangeFalse.click(); - admin.adminSaveChanges(); - admin.settingsSearch.type(''); - sideNav.preferencesClose.click(); - }); - - test.afterAll(() => { - admin.open('admin/Accounts'); - admin.accountsRealNameChangeTrue.click(); - admin.adminSaveChanges(); - admin.accountsUsernameChangeTrue.click(); - admin.adminSaveChanges(); - admin.settingsSearch.type(''); - sideNav.preferencesClose.click(); - }); - - test('it should open profile', () => { - sideNav.accountMenu.click(); - sideNav.account.click(); - sideNav.profile.click(); - }); - - test('it should be that the name field is disabled', () => { - preferencesMainContent.realNameTextInputEnabled().should.be.false; - }); - - test('it should be that the Username field is disabled', () => { - preferencesMainContent.userNameTextInputEnabled().should.be.false; - }); - - test('it should close profile', () => { - sideNav.preferencesClose.click(); - }); - }); - }); + // test.describe('admin', () => { + // test.describe.skip('user info change forbidden:', () => { + // test.beforeAll(() => { + // checkIfUserIsValid(adminUsername, adminEmail, adminPassword); + // admin.open('admin/Accounts'); + // admin.accountsRealNameChangeFalse.click(); + // admin.adminSaveChanges(); + // admin.accountsUsernameChangeFalse.click(); + // admin.adminSaveChanges(); + // admin.settingsSearch.type(''); + // sideNav.preferencesClose.click(); + // }); + // + // test.afterAll(() => { + // admin.open('admin/Accounts'); + // admin.accountsRealNameChangeTrue.click(); + // admin.adminSaveChanges(); + // admin.accountsUsernameChangeTrue.click(); + // admin.adminSaveChanges(); + // admin.settingsSearch.type(''); + // sideNav.preferencesClose.click(); + // }); + // + // test('expect open profile', () => { + // sideNav.accountMenu.click(); + // sideNav.account.click(); + // sideNav.profile.click(); + // }); + // + // test('expect be that the name field is disabled', () => { + // preferencesMainContent.realNameTextInputEnabled().should.be.false; + // }); + // + // test('expect be that the Username field is disabled', () => { + // preferencesMainContent.userNameTextInputEnabled().should.be.false; + // }); + // + // test('expect close profile', () => { + // sideNav.preferencesClose.click(); + // }); + // }); + // }); }); diff --git a/tests/e2e/utils/pageobjects/main-content.page.ts b/tests/e2e/utils/pageobjects/main-content.page.ts index bbde1d8aa203..8891b9f157aa 100644 --- a/tests/e2e/utils/pageobjects/main-content.page.ts +++ b/tests/e2e/utils/pageobjects/main-content.page.ts @@ -238,6 +238,10 @@ class MainContent extends BasePage { await expect(this.getPage().locator('(//*[contains(@class, "message") and contains(@class, "body")])[last()]')).toContainText(text); } + public async waitForLastMessageEqualsText(text: string): Promise { + await expect(this.getPage().locator('(//*[contains(@class, "message") and contains(@class, "body")])[last()]')).toContainText(text); + } + // Sends a message and wait for the message to equal the text sent public async sendMessage(text: any): Promise { await this.setTextToInput(text); @@ -257,7 +261,7 @@ class MainContent extends BasePage { // cy.wait(200); await this.messageInput().fill(''); if (text) { - this.messageInput().type(text); + await this.messageInput().type(text); } } } diff --git a/tests/e2e/utils/pageobjects/preferences-main-content.page.ts b/tests/e2e/utils/pageobjects/preferences-main-content.page.ts index 6ea8e4100799..8e74a12b54b8 100644 --- a/tests/e2e/utils/pageobjects/preferences-main-content.page.ts +++ b/tests/e2e/utils/pageobjects/preferences-main-content.page.ts @@ -3,70 +3,62 @@ import { expect, Locator } from '@playwright/test'; import BasePage from './BasePage'; class PreferencesMainContent extends BasePage { - public formTextInput() { + public formTextInput(): Locator { return this.getPage().locator('.rocket-form'); } - public realNameTextInput() { - return this.getPage().locator('label:contains("Name")').closest('.rcx-field').find('input'); + public realNameTextInput(): Locator { + return this.getPage().locator('//label[contains(text(), "Name")]/..//input'); } - public userNameTextInput() { - return this.getPage().locator('label:contains("Username")').closest('.rcx-field').find('input'); + public userNameTextInput(): Locator { + return this.getPage().locator('//label[contains(text(), "Username")]/..//input'); } - public emailTextInput() { - return this.getPage().locator('label:contains("Email")').closest('.rcx-field').find('input'); + public emailTextInput(): Locator { + return this.getPage().locator('//label[contains(text(), "Email")]/..//input'); } - public passwordTextInput() { - return this.getPage().locator('label:contains("Password")').closest('.rcx-field').find('input'); + public passwordTextInput(): Locator { + return this.getPage().locator('//label[contains(text(), "Password")]/..//input'); } - public resendVerificationEmailBtn() { + public resendVerificationEmailBtn(): Locator { return this.getPage().locator('#resend-verification-email'); } - public avatarFileInput() { + public avatarFileInput(): Locator { return this.getPage().locator('.avatar-file-input'); } - public useUploadedAvatar() { + public useUploadedAvatar(): Locator { return this.getPage().locator('.avatar-suggestion-item:nth-of-type(2) .select-service'); } - public submitBtn() { - return this.getPage().locator('button:contains("Save changes")'); + public submitBtn(): Locator { + return this.getPage().locator('//button[contains(text(), "Save changes")]'); } - realNameTextInputEnabled() { - return browser.isEnabled('input[name="realname"]'); + public async changeUsername(userName: string): Promise { + await this.userNameTextInput().fill(userName); } - userNameTextInputEnabled() { - return browser.isEnabled('input[name="username"]'); + public async changeRealName(realName: string): Promise { + await this.realNameTextInput().fill(realName); } - changeUsername(userName) { - this.userNameTextInput.clear().type(userName); + public async changeEmail(email: string): Promise { + await this.emailTextInput().fill(email); } - changeRealName(realName) { - this.realNameTextInput.clear().type(realName); + public async saveChanges(): Promise { + await expect(this.submitBtn()).toBeEnabled(); + await this.submitBtn().click(); } - changeEmail(email) { - this.emailTextInput.clear().type(email); - } - - saveChanges() { - this.submitBtn.should('be.enabled'); - this.submitBtn.click(); - } - - changeAvatarUpload(url) { - this.avatarFileInput.chooseFile(url); - this.useUploadedAvatar.click(); + public async changeAvatarUpload(url: string): Promise { + await this.avatarFileInput().setInputFiles(url); + await this.useUploadedAvatar().click(); } } diff --git a/tests/e2e/utils/pageobjects/side-nav.page.ts b/tests/e2e/utils/pageobjects/side-nav.page.ts index 6b703f70246f..bb3ad41f1d88 100644 --- a/tests/e2e/utils/pageobjects/side-nav.page.ts +++ b/tests/e2e/utils/pageobjects/side-nav.page.ts @@ -146,7 +146,7 @@ class SideNav extends BasePage { } public preferencesClose(): Locator { - return this.getPage().locator('.flex-nav i.rcx-icon--name-cross'); + return this.getPage().locator('//*[contains(@class,"flex-nav")]//i[contains(@class, "rcx-icon--name-cross")]'); } public burgerBtn(): Locator { From b4e75f3f1495c3592d0c5f19e8b330813bd91933 Mon Sep 17 00:00:00 2001 From: Tiago Ulisses Montini Date: Mon, 4 Apr 2022 12:12:36 -0300 Subject: [PATCH 35/35] fix a skip test --- tests/e2e/10-user-preferences.spec.ts | 82 +++++---------------------- 1 file changed, 14 insertions(+), 68 deletions(-) diff --git a/tests/e2e/10-user-preferences.spec.ts b/tests/e2e/10-user-preferences.spec.ts index ca3a559807cd..57b08a938c7b 100644 --- a/tests/e2e/10-user-preferences.spec.ts +++ b/tests/e2e/10-user-preferences.spec.ts @@ -3,12 +3,14 @@ import { test, expect } from '@playwright/test'; import MainContent from './utils/pageobjects/main-content.page'; import SideNav from './utils/pageobjects/side-nav.page'; import LoginPage from './utils/pageobjects/login.page'; +import FlexTab from './utils/pageobjects/flex-tab.page'; import PreferencesMainContent from './utils/pageobjects/preferences-main-content.page'; import { adminLogin, adminRegister } from './utils/mocks/userAndPasswordMock'; import { LOCALHOST } from './utils/mocks/urlMock'; test.describe('[User Preferences]', function () { test.describe('default', () => { + let flexTab: FlexTab; let loginPage: LoginPage; let mainContent: MainContent; let sideNav: SideNav; @@ -78,22 +80,10 @@ test.describe('[User Preferences]', function () { await preferencesMainContent.changeUsername(`Edited${adminRegister.name}${Date.now()}`); }); - // test.skip('expect change the email field', async () => { - // preferencesMainContent.changeEmail(`EditedUserEmail${adminRegister.name}@gmail.com`); - // }); - // - // test.skip('expect put the password in the modal input', async () => { - // preferencesMainContent.acceptPasswordOverlay(adminLogin.password); - // }); - test('expect save the settings', async () => { await preferencesMainContent.saveChanges(); }); - // test.skip('expect put the password in the modal input', async () => { - // preferencesMainContent.acceptPasswordOverlay(adminLogin.password); - // }); - test('expect close the preferences menu', async () => { await sideNav.preferencesClose().click(); await sideNav.getChannelFromList('general').scrollIntoViewIfNeeded(); @@ -105,62 +95,18 @@ test.describe('[User Preferences]', function () { await mainContent.waitForLastMessageEqualsText('HI'); }); - // test.skip('expect be that the name on the last message is the edited one', async () => { - // mainContent.waitForLastMessageUserEqualsText(`EditedUserName${adminRegister.name}`); - // mainContent.lastMessageUser().getText().should.equal(`EditedUserName${adminRegister.name}`); - // }); - // - // test.skip('expect be that the user name on the members flex tab is the edited one', async () => { - // mainContent.lastMessageUser().click(); - // flexTab.memberUserName.getText().should.equal(`EditedUserName${adminRegister.name}`); - // }); - // - // test.skip('expect that the real name on the members flex tab is the edited one', async () => { - // flexTab.memberRealName.getText().should.equal(`EditedRealName${adminRegister.name}`); - // }); + test('expect be that the name on the last message is the edited one', async () => { + await expect(mainContent.lastMessageUser()).toContainText(`Edited${adminRegister.name}`); + }); + + test.skip('expect be that the user name on the members flex tab is the edited one', async () => { + mainContent.lastMessageUser().click(); + await expect(flexTab.memberUserName()).toContainText(`Edited${adminRegister.name}`); + }); + + test.skip('expect that the real name on the members flex tab is the edited one', async () => { + await expect(flexTab.memberRealName()).toContainText(`Edited${adminRegister.name}`); + }); }); }); - - // test.describe('admin', () => { - // test.describe.skip('user info change forbidden:', () => { - // test.beforeAll(() => { - // checkIfUserIsValid(adminUsername, adminEmail, adminPassword); - // admin.open('admin/Accounts'); - // admin.accountsRealNameChangeFalse.click(); - // admin.adminSaveChanges(); - // admin.accountsUsernameChangeFalse.click(); - // admin.adminSaveChanges(); - // admin.settingsSearch.type(''); - // sideNav.preferencesClose.click(); - // }); - // - // test.afterAll(() => { - // admin.open('admin/Accounts'); - // admin.accountsRealNameChangeTrue.click(); - // admin.adminSaveChanges(); - // admin.accountsUsernameChangeTrue.click(); - // admin.adminSaveChanges(); - // admin.settingsSearch.type(''); - // sideNav.preferencesClose.click(); - // }); - // - // test('expect open profile', () => { - // sideNav.accountMenu.click(); - // sideNav.account.click(); - // sideNav.profile.click(); - // }); - // - // test('expect be that the name field is disabled', () => { - // preferencesMainContent.realNameTextInputEnabled().should.be.false; - // }); - // - // test('expect be that the Username field is disabled', () => { - // preferencesMainContent.userNameTextInputEnabled().should.be.false; - // }); - // - // test('expect close profile', () => { - // sideNav.preferencesClose.click(); - // }); - // }); - // }); });