diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index c4f4708db..b1d7b8871 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -18,8 +18,8 @@ jobs: node-version: '10.16.0' - run: npm ci - run: npm install jest --global - - run: npm run dist - run: npm run test:e2e-docker-up + - run: npm run dist - run: npm run test:e2e-docker-ping - run: npm run test:e2e - run: npm run test:e2e-docker-down diff --git a/client/extensions/woocommerce/woocommerce-services/views/packages/edit-package.js b/client/extensions/woocommerce/woocommerce-services/views/packages/edit-package.js index d1d3bba0f..9a46f1b63 100644 --- a/client/extensions/woocommerce/woocommerce-services/views/packages/edit-package.js +++ b/client/extensions/woocommerce/woocommerce-services/views/packages/edit-package.js @@ -9,6 +9,7 @@ import PropTypes from 'prop-types'; import { localize } from 'i18n-calypso'; import { omit, trim } from 'lodash'; import { TextControl } from '@wordpress/components'; +import classNames from 'classnames'; /** * Internal dependencies @@ -130,7 +131,7 @@ const EditPackage = props => { placeholder={ translate( '0.0' ) } value={ box_weight || '' } onChange={ value => updateTextField( value, 'box_weight' ) } - className={ modalErrors.box_weight ? 'is-error' : '' } + className={ classNames( 'form-dimensions-input__box_weight', { 'is-error':modalErrors.box_weight } ) } type="number" suffix={ weightUnit } /> diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 12e34958a..8356e9106 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1511,6 +1511,26 @@ "source-map": "^0.5.0" } }, + "@babel/compat-data": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.9.tgz", + "integrity": "sha512-p3QjZmMGHDGdpcwEYYWu7i7oJShJvtgMjJeb0W95PPhSm++3lm8YXYOh45Y6iCN9PkZLTZ7CIX5nFrp7pw7TXw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz", + "integrity": "sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, "@babel/plugin-proposal-class-properties": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", @@ -1537,17 +1557,39 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-transform-classes": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz", + "integrity": "sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.14.5", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", + "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.14.5" + } + }, "@babel/preset-env": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.8.tgz", - "integrity": "sha512-a9aOppDU93oArQ51H+B8M1vH+tayZbuBqzjOhntGetZVa+4tTu5jp+XTwqHGG2lxslqomPYVSjIxQkFwXzgnxg==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.9.tgz", + "integrity": "sha512-BV5JvCwBDebkyh67bPKBYVCC6gGw0MCzU6HfKe5Pm3upFpPVqiC/hB33zkOe0tVdAzaMywah0LSXQeD9v/BYdQ==", "requires": { - "@babel/compat-data": "^7.14.7", + "@babel/compat-data": "^7.14.9", "@babel/helper-compilation-targets": "^7.14.5", "@babel/helper-plugin-utils": "^7.14.5", "@babel/helper-validator-option": "^7.14.5", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-async-generator-functions": "^7.14.7", + "@babel/plugin-proposal-async-generator-functions": "^7.14.9", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-static-block": "^7.14.5", "@babel/plugin-proposal-dynamic-import": "^7.14.5", @@ -1580,7 +1622,7 @@ "@babel/plugin-transform-async-to-generator": "^7.14.5", "@babel/plugin-transform-block-scoped-functions": "^7.14.5", "@babel/plugin-transform-block-scoping": "^7.14.5", - "@babel/plugin-transform-classes": "^7.14.5", + "@babel/plugin-transform-classes": "^7.14.9", "@babel/plugin-transform-computed-properties": "^7.14.5", "@babel/plugin-transform-destructuring": "^7.14.7", "@babel/plugin-transform-dotall-regex": "^7.14.5", @@ -1594,7 +1636,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.14.5", "@babel/plugin-transform-modules-systemjs": "^7.14.5", "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", "@babel/plugin-transform-new-target": "^7.14.5", "@babel/plugin-transform-object-super": "^7.14.5", "@babel/plugin-transform-parameters": "^7.14.5", @@ -1609,11 +1651,11 @@ "@babel/plugin-transform-unicode-escapes": "^7.14.5", "@babel/plugin-transform-unicode-regex": "^7.14.5", "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.14.8", + "@babel/types": "^7.14.9", "babel-plugin-polyfill-corejs2": "^0.2.2", "babel-plugin-polyfill-corejs3": "^0.2.2", "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.15.0", + "core-js-compat": "^3.16.0", "semver": "^6.3.0" } }, @@ -1625,6 +1667,15 @@ "regenerator-runtime": "^0.13.4" } }, + "@babel/types": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.9.tgz", + "integrity": "sha512-u0bLTnv3DFHeaQLYzb7oRJ1JHr1sv/SYDM7JSqHFFLwXG1wTZRughxFI5NCP8qBEo1rVVsn7Yg2Lvw49nne/Ow==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, "@wordpress/e2e-test-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-3.0.0.tgz", @@ -1678,6 +1729,22 @@ "readdirp": "~3.6.0" } }, + "core-js-compat": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.0.tgz", + "integrity": "sha512-5D9sPHCdewoUK7pSUPfTF7ZhLh8k9/CoJXWUEo+F1dZT5Z1DVgcuRqUKhjeKW+YLb8f21rTFgWwQJiNw1hoZ5Q==", + "requires": { + "browserslist": "^4.16.6", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + } + } + }, "debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", @@ -1728,6 +1795,16 @@ "table": "^5.2.3", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "requires": { + "type-fest": "^0.8.1" + } + } } }, "fill-range": { @@ -1753,14 +1830,6 @@ "is-glob": "^4.0.1" } }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "requires": { - "type-fest": "^0.8.1" - } - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1808,9 +1877,9 @@ } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "to-regex-range": { "version": "5.0.1", @@ -5517,9 +5586,9 @@ }, "dependencies": { "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" } } }, @@ -6217,9 +6286,9 @@ "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==" }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "resolve-cwd": { "version": "3.0.0", @@ -6922,16 +6991,16 @@ } }, "@wordpress/e2e-test-utils": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-2.4.3.tgz", - "integrity": "sha512-I/83+QhF1E4anCMy+ZqkX8S9v6TKhDvitbYgx2DQNfRFPsf07KWFun2lttWI7+apZ081JRSBKT+5SCoU121iSA==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-5.4.1.tgz", + "integrity": "sha512-FixAC2Kyspv/FCSC9NPDpZzbohioO42n0fG6pq9Vj2DW8kIc2NobapGW/7Uke2V4KlqMvWrD9uaiX6Gp/eaGRg==", "dev": true, "requires": { - "@babel/runtime": "^7.4.4", - "@wordpress/keycodes": "^2.6.2", - "@wordpress/url": "^2.8.2", - "lodash": "^4.17.15", - "node-fetch": "^1.7.3" + "@babel/runtime": "^7.13.10", + "@wordpress/keycodes": "^3.2.1", + "@wordpress/url": "^3.2.1", + "lodash": "^4.17.21", + "node-fetch": "^2.6.0" }, "dependencies": { "@babel/runtime": { @@ -6943,10 +7012,62 @@ "regenerator-runtime": "^0.13.4" } }, + "@wordpress/hooks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.2.0.tgz", + "integrity": "sha512-nVR6V9kPxl8+aYQzQJdoDt+aKBKHHD0zplcYZbu2MHxjmHMvppAeL9mjzVhQZj/3n10NR2Ftk94mHQzHWfhCCg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@wordpress/i18n": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.2.1.tgz", + "integrity": "sha512-56TW1rGRTgBZd2wZiMVxTuSi+1z5INpbQrLFjPwqhQJNiasDAUuUFzu4dRojkyBexJbB+1McYA1gv9xZlsJ8lg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.13.10", + "@wordpress/hooks": "^3.2.0", + "gettext-parser": "^1.3.1", + "lodash": "^4.17.21", + "memize": "^1.1.0", + "sprintf-js": "^1.1.1", + "tannin": "^1.2.0" + } + }, + "@wordpress/keycodes": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.2.1.tgz", + "integrity": "sha512-mjJu6a7bmWR4y2mrWUMIfJIkqF50u09y8seP9o1YDdecrJBon8VAOjVmfh+N4W6L/bVLHfTq4/6IZQaVKCy3xw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.13.10", + "@wordpress/i18n": "^4.2.1", + "lodash": "^4.17.21" + } + }, + "@wordpress/url": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.2.1.tgz", + "integrity": "sha512-+AJt74qWz+iXkT05sBUBjx5EF3niFkvr1CqaIbWCew9/j47de6r0AHjaFhaiCCsq5fg1eqRe74sZKHrMmIWKQQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.13.10", + "lodash": "^4.17.21", + "react-native-url-polyfill": "^1.1.2" + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true } } @@ -7219,9 +7340,9 @@ } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "supports-color": { "version": "7.2.0", @@ -7996,9 +8117,9 @@ } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" } } }, @@ -14093,9 +14214,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" diff --git a/package.json b/package.json index a250f4f2f..e4769595d 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@woocommerce/woocommerce-rest-api": "^1.0.1", "@wordpress/dependency-extraction-webpack-plugin": "^2.9.0", "@wordpress/base-styles": "^3.3.0", - "@wordpress/e2e-test-utils": "^2.4.3", + "@wordpress/e2e-test-utils": "^5.4.1", "archiver": "^1.3.0", "babel-jest": "24.7.1", "babel-plugin-dynamic-import-node": "2.2.0", @@ -91,12 +91,12 @@ "@babel/preset-react": "7.0.0", "@babel/runtime": "7.1.2", "@hot-loader/react-dom": "^16.14.0", + "@woocommerce/e2e-environment": "^0.2.2", + "@woocommerce/woocommerce-rest-api": "^1.0.1", "@wordpress/babel-preset-default": "^5.0.1", "@wordpress/base-styles": "^3.3.0", "@wordpress/components": "^11.1.5", "@wordpress/element": "^2.19.1", - "@woocommerce/e2e-environment": "^0.2.0", - "@woocommerce/woocommerce-rest-api": "^1.0.1", "autoprefixer": "^6.7.4", "babel-eslint": "10.0.1", "babel-loader": "8.0.4", diff --git a/tests/bin/install.sh b/tests/bin/install.sh index b88321f9d..00baaac17 100755 --- a/tests/bin/install.sh +++ b/tests/bin/install.sh @@ -211,6 +211,16 @@ PHP php wp-cli.phar plugin activate wc-services-testing-helper php wp-cli.phar option update jetpack_tos_agreed 1 + php wp-cli.phar option set woocommerce_store_address "60 29th Street" + php wp-cli.phar option set woocommerce_store_address_2 "#343" + php wp-cli.phar option set woocommerce_store_city "San Francisco" + php wp-cli.phar option set woocommerce_default_country "US:CA" + php wp-cli.phar option set woocommerce_store_postcode "94110" + php wp-cli.phar option set woocommerce_currency "USD" + php wp-cli.phar config set JETPACK_DEV_DEBUG true --raw + php wp-cli.phar config set WOOCOMMERCE_SERVICES_LOCAL_TEST_MODE true --raw + php wp-cli.phar config set WOOCOMMERCE_CONNECT_FREQUENT_FETCH true --raw + php wp-cli.phar config set WOOCOMMERCE_CONNECT_SERVER_URL http://host.docker.internal:5000/ php wp-cli.phar option update wc_connect_options '{"tos_accepted": true }' --format=json diff --git a/tests/bin/run-e2e-travis.sh b/tests/bin/run-e2e-travis.sh deleted file mode 100755 index 719c129d4..000000000 --- a/tests/bin/run-e2e-travis.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -if [[ ${RUN_E2E} == 1 ]]; then - export WP_BASE_URL="http://localhost:8080" - export WP_ADMIN_USER_NAME=admin - export WP_ADMIN_USER_PW=password - export WC_E2E_REST_API_CONSUMER_KEY=ck_wc_rest_api_consumer_key - export WC_E2E_REST_API_CONSUMER_SECRET=cs_wc_rest_api_consumer_secret - -fi diff --git a/tests/e2e/config/jest-puppeteer.config.js b/tests/e2e/config/jest-puppeteer.config.js index f350b10de..d2d9696f6 100644 --- a/tests/e2e/config/jest-puppeteer.config.js +++ b/tests/e2e/config/jest-puppeteer.config.js @@ -1,10 +1,8 @@ const { useE2EJestPuppeteerConfig } = require( '@woocommerce/e2e-environment' ); -const puppeteerConfig = useE2EJestPuppeteerConfig( { +module.exports = useE2EJestPuppeteerConfig( { launch: { slowMo: 100, args: [ '--window-size=1920,1080', '--user-agent=chrome --runInBand --maxWorkers=4' ], } } ); - -module.exports = puppeteerConfig; diff --git a/tests/e2e/config/travis/wc-services-testing-helper.php b/tests/e2e/config/travis/wc-services-testing-helper.php index 83cf9da5e..f885c5d60 100644 --- a/tests/e2e/config/travis/wc-services-testing-helper.php +++ b/tests/e2e/config/travis/wc-services-testing-helper.php @@ -8,22 +8,6 @@ Author URI: http:// */ -define( 'JETPACK_DEV_DEBUG', true ); -define( 'WOOCOMMERCE_SERVICES_LOCAL_TEST_MODE', true ); -define( 'WOOCOMMERCE_CONNECT_FREQUENT_FETCH', true ); -define( 'WOOCOMMERCE_CONNECT_SERVER_URL', 'http://host.docker.internal:5000/' ); -define( 'WOOCOMMERCE_SERVICES_CI_TEST_MODE', true ); - -if ( get_option( 'woocommerce_default_country' ) !== 'US:NY' ) { - update_option( 'woocommerce_store_address', '1480 York Ave' ); - update_option( 'woocommerce_store_city', 'New York' ); - update_option( 'woocommerce_store_postcode', '10075' ); - update_option( 'woocommerce_default_country', 'US:NY' ); - update_option( 'woocommerce_currency', 'USD' ); - update_option( 'woocommerce_weight_unit', 'oz' ); - update_option( 'woocommerce_dimension_unit', 'in' ); -} - // Mock out Jetpack Options $jp_options = get_option( 'jetpack_options' ); $jp_options['master_user'] = 1; diff --git a/tests/e2e/docker/initialize.sh b/tests/e2e/docker/initialize.sh index 947422c07..722f02d83 100644 --- a/tests/e2e/docker/initialize.sh +++ b/tests/e2e/docker/initialize.sh @@ -1,14 +1,30 @@ - #!/bin/bash +#!/bin/bash echo "Initializing WooCommerce Services E2E" WP_CORE_DIR="/var/www/html" WCS_DIR="$WP_CORE_DIR/wp-content/plugins/woocommerce-services" # install default theme -wp theme install twentynineteen --activate -# install woocommerce, jetpack +wp theme install storefront --activate + wp plugin install woocommerce --activate + +## adding basic settings and configuration +wp option set woocommerce_store_address "60 29th Street" +wp option set woocommerce_store_address_2 "#343" +wp option set woocommerce_store_city "San Francisco" +wp option set woocommerce_default_country "US:CA" +wp option set woocommerce_store_postcode "94110" +wp option set woocommerce_currency "USD" +wp option set woocommerce_weight_unit "oz" +wp option set woocommerce_dimension_unit "in" +wp option set woocommerce_product_type "both" +wp option set woocommerce_allow_tracking "no" +wp option update woocommerce_onboarding_profile '{"skipped": true }' --format=json + wp plugin install jetpack --activate +wp config set JETPACK_DEV_DEBUG true --raw + # create credentials for REST API wp eval-file "$WCS_DIR/tests/bin/wc_rest_api_credentials.php" @@ -16,6 +32,9 @@ wp eval-file "$WCS_DIR/tests/bin/wc_rest_api_credentials.php" cp "$WCS_DIR/tests/e2e/config/travis/wc-services-testing-helper.php" "$WP_CORE_DIR/wp-content/plugins/" # finally activate WCS +wp config set WOOCOMMERCE_SERVICES_LOCAL_TEST_MODE true --raw +wp config set WOOCOMMERCE_CONNECT_FREQUENT_FETCH true --raw +wp config set WOOCOMMERCE_CONNECT_SERVER_URL http://host.docker.internal:5000/ wp plugin activate woocommerce-services wp plugin activate wc-services-testing-helper wp option update jetpack_tos_agreed 1 diff --git a/tests/e2e/fixtures/index.js b/tests/e2e/fixtures/index.js index 1bc7af1e2..70365d9e9 100644 --- a/tests/e2e/fixtures/index.js +++ b/tests/e2e/fixtures/index.js @@ -68,6 +68,7 @@ const createShippingLabel = async ( order ) => { createShippingLabelJson.packages[0].products = [ order.line_items[0].product_id ]; const response = await apiV1.post( `connect/label/${ order.id }`, createShippingLabelJson ); + return response.data; } @@ -80,7 +81,6 @@ const destroyOrder = async ( order ) => { } const withOrder = async ( callback ) => { - const product = await createProduct(); const order = await createOrder( product ); diff --git a/tests/e2e/mocks/index.js b/tests/e2e/mocks/index.js index 1a137af2a..60e3a1ba8 100644 --- a/tests/e2e/mocks/index.js +++ b/tests/e2e/mocks/index.js @@ -3,50 +3,49 @@ */ const withMockedShippingLabel = async( shippingLabel, callback ) => { - - const mockedShippingLabel = { - "success": true, - "label": { - "label_id": shippingLabel.label_id, - "tracking": "9405536897846488998110", - "refundable_amount": 13.2, - "created": shippingLabel.created, - "carrier_id": "usps", - "service_name": "USPS - Priority Mail", - "status": "PURCHASED", - "package_name": "Medium Flat Rate Box 2, Side Loading", - "product_names": shippingLabel.product_names, - "receipt_item_id": 24151858, - "created_date": shippingLabel.created_date, - "main_receipt_id": 19629638, - "rate": 13.2, - "currency": "USD", - "expiry_date": shippingLabel.expiry_date - }, - - } - - const mockedRefund = { - "success": true, - "refund": { - "status": "pending", - "request_date": Date.now() - } - } - await page.setRequestInterception(true); const getShippingLabelRequestListener = (request) => { if ( request.url().match( 'wp-json/wc/v1/connect/label/.*/refund' ) ) { request.respond( { status: 200, contentType: 'application/json; charset=UTF-8', - body: JSON.stringify( mockedRefund ) + body: JSON.stringify( { + success: true, + refund: { + status: 'pending', + request_date: Date.now() + } + } ) } ); } else if ( request.url().match( 'wp-json/wc/v1/connect/label/.*' ) ) { request.respond( { status: 200, contentType: 'application/json; charset=UTF-8', - body: JSON.stringify( mockedShippingLabel ) + body: JSON.stringify( { + success: true, + labels: [ + { + carrier_id: 'usps', + commercial_invoice_url: null, + created: shippingLabel.created, + created_date: shippingLabel.created_date, + currency: 'USD', + is_letter: false, + label_id: shippingLabel.label_id, + main_receipt_id: 19629638, + package_name: 'Medium Flat Rate Box 2, Side Loading', + product_ids: [shippingLabel.product_ids], + product_names: [shippingLabel.product_names], + rate: 13.2, + receipt_item_id: 24151858, + service_name: 'USPS - Priority Mail', + refundable_amount: 13.2, + status: 'PURCHASED', + expiry_date: shippingLabel.expiry_date, + tracking: '9405536897846488998110', + } + ], + } ) } ); } else { request.continue(); diff --git a/tests/e2e/specs/admin/1-activate-extension.test.js b/tests/e2e/specs/admin/1-activate-extension.test.js index d17f5dc2e..8bb9607d0 100644 --- a/tests/e2e/specs/admin/1-activate-extension.test.js +++ b/tests/e2e/specs/admin/1-activate-extension.test.js @@ -1,12 +1,11 @@ /** * Internal dependencies */ -import { StoreOwnerFlow } from "../../utils/flows"; +import { StoreOwnerFlow } from '../../utils'; describe( 'Store admin can login and make sure WooCommerce Shipping & Tax extension is activated', () => { - it( 'Can activate WooCommerce Shipping & Tax extension if it is deactivated' , async () => { - let slug = 'woocommerce-services'; + const slug = 'woocommerce-services' await StoreOwnerFlow.login(); await StoreOwnerFlow.openPluginsPage(); const disableLink = await page.$( `tr[data-slug="${ slug }"] .deactivate a` ); @@ -16,5 +15,4 @@ describe( 'Store admin can login and make sure WooCommerce Shipping & Tax extens await page.click( `tr[data-slug="${ slug }"] .activate a` ); await page.waitForSelector( `tr[data-slug="${ slug }"] .deactivate a` ); }); - } ); diff --git a/tests/e2e/specs/admin/2-shipping-settings.test.js b/tests/e2e/specs/admin/2-shipping-settings.test.js index 495e98677..74831ac74 100644 --- a/tests/e2e/specs/admin/2-shipping-settings.test.js +++ b/tests/e2e/specs/admin/2-shipping-settings.test.js @@ -8,21 +8,22 @@ import { AccountWithNoCreditCard, AccountWithOneCreditCard, AccountWithTwoCredit describe( 'Saving shipping label settings', () => { - it( 'Can toggle shipping labels' , async () => { await StoreOwnerFlow.login(); await StoreOwnerFlow.openSettings('shipping', 'woocommerce-services-settings'); - await page.waitForSelector('.form-toggle__switch'); - await expect(page).toClick('.form-toggle__switch'); + await page.waitForSelector('.components-form-toggle__input'); + await expect(page).toClick('.components-form-toggle__input'); await page.waitForSelector('.card.label-settings__labels-container', { visible: false }); - await expect( page ).toClick( '.button.is-primary', { text: 'Save changes' } ); - await page.waitForSelector('.card.label-settings__labels-container', { + + await saveAndWait(); + + await page.waitForSelector('.card.label-settings__labels-container', { visible: false }); - await expect(page).toClick('.form-toggle__switch'); + await expect(page).toClick('.components-form-toggle__input'); await saveAndWait(); }); @@ -155,7 +156,7 @@ describe( 'Shipping label payment method', () => { await expect(secondCardExpiryDate).toEqual('Expires 2025-12-31'); // Verify the default box is checked. - const cardDefaultCheckbox = await page.$$('.label-settings__card-checkbox.form-checkbox'); + const cardDefaultCheckbox = await page.$$('.label-settings__card-checkbox input'); const firstCardDefaultCheckboxElement = await cardDefaultCheckbox[VISA_CARD_INDEX].getProperty('checked'); const firstCardDefaultCheckbox = await firstCardDefaultCheckboxElement.jsonValue(); await expect(firstCardDefaultCheckbox).toBeFalsy(); @@ -204,7 +205,7 @@ describe( 'Shipping label payment method', () => { await expect(secondCardExpiryDate).toEqual('Expires 2025-12-31'); // Verify that no default box is checked. - const cardDefaultCheckbox = await page.$$('.label-settings__card-checkbox.form-checkbox'); + const cardDefaultCheckbox = await page.$$('.label-settings__card-checkbox input'); const firstCardDefaultCheckboxElement = await cardDefaultCheckbox[VISA_CARD_INDEX].getProperty('checked'); const firstCardDefaultCheckbox = await firstCardDefaultCheckboxElement.jsonValue(); await expect(firstCardDefaultCheckbox).toBeFalsy(); @@ -227,7 +228,6 @@ describe( 'Shipping label payment method', () => { }); describe( 'Packaging', () => { - afterAll( async() => { await deleteAllPackages(); await saveAndWait(); @@ -249,15 +249,15 @@ describe( 'Packaging', () => { await waitForSelectorAndText( '.packages__add-edit-title.form-section-heading', 'Add a package' ); // Set this once globally, all following test will use this metric - const metricSystem = await page.$$('.form-text-input-with-affixes .form-text-input-with-affixes__suffix'); + const metricSystem = await page.$$('.text-control-with-affixes .text-control-with-affixes__suffix'); const metricSystemElement = await metricSystem[0].getProperty('innerText'); metricSystemValue = await metricSystemElement.jsonValue(); await expect( page ).toFill( '.packages__properties-group #name', packageName ); - await expect( page ).toFill( '.form-text-input.form-dimensions-input__length', '5' ); - await expect( page ).toFill( '.form-text-input.form-dimensions-input__width', '5' ); - await expect( page ).toFill( '.form-text-input.form-dimensions-input__height', '5' ); - await expect( page ).toFill( '.form-text-input-with-affixes #box_weight', '0.5' ); + await expect( page ).toFill( '.form-dimensions-input__length input', '5' ); + await expect( page ).toFill( '.form-dimensions-input__width input', '5' ); + await expect( page ).toFill( '.form-dimensions-input__height input', '5' ); + await expect( page ).toFill( '.form-dimensions-input__box_weight input', '0.5' ); await expect( page ).toClick( '.button.form-button.is-primary', { text: 'Add package' } ); // Verify package shows up in list @@ -288,10 +288,10 @@ describe( 'Packaging', () => { // Edit package await waitForSelectorAndText( '.packages__add-edit-title.form-section-heading', 'Edit package' ); await expect( page ).toFill( '.packages__properties-group #name', packageName ); - await expect( page ).toFill( '.form-text-input.form-dimensions-input__length', '10' ); - await expect( page ).toFill( '.form-text-input.form-dimensions-input__width', '10' ); - await expect( page ).toFill( '.form-text-input.form-dimensions-input__height', '10' ); - await expect( page ).toFill( '.form-text-input-with-affixes #box_weight', '0.8' ); + await expect( page ).toFill( '.form-dimensions-input__length input', '10' ); + await expect( page ).toFill( '.form-dimensions-input__width input', '10' ); + await expect( page ).toFill( '.form-dimensions-input__height input', '10' ); + await expect( page ).toFill( '.form-dimensions-input__box_weight input', '0.8' ); await expect( page ).toClick( '.button.form-button.is-primary', { text: 'Done' } ) // Verify package shows up in list diff --git a/tests/e2e/specs/admin/3-create-shipping-label.test.js b/tests/e2e/specs/admin/3-create-shipping-label.test.js index f158577ec..8debc4f5a 100644 --- a/tests/e2e/specs/admin/3-create-shipping-label.test.js +++ b/tests/e2e/specs/admin/3-create-shipping-label.test.js @@ -6,7 +6,6 @@ /** * Internal dependencies */ -import { clickReactButton } from '../../utils/index'; import { StoreOwnerFlow } from '../../utils/flows'; import { withOrder } from '../../fixtures/index'; import { deleteAllPackages, saveAndWait } from '../../utils/components'; @@ -23,7 +22,6 @@ describe( 'Create shipping label', () => { afterAll( async () => { await deleteAllPackages(); - await expect( page ).toClick( '.button.is-primary', { text: 'Save changes' } ); await saveAndWait(); } ); @@ -34,27 +32,24 @@ describe( 'Create shipping label', () => { await StoreOwnerFlow.openExistingOrderPage( order.id ); // Click on Create shipping label button - const newLabelButton = await page.$( '.shipping-label__new-label-button' ); - if( ! newLabelButton ) { - throw new Error( 'No button to create new shipping label for order' ); - } - await clickReactButton( '.shipping-label__new-label-button', { text: 'Create shipping label' } ); - await page.waitForSelector( '.dialog__content' ); + await expect( page ).toClick( '.shipping-label__new-label-button', { text: 'Create shipping label' } ); + await page.waitForSelector( '.label-purchase-modal__content' ); - await page.waitForSelector( '.address-step__suggestion-title', { text: 'Address entered' } ); await expect( page ).toClick( '.address-step__suggestion-title', { text: 'Address entered' } ); - const enterOriginPhone = await page.$( '.address-step__phone #origin_phone' ); + const enterOriginPhone = await page.$( '.address-step__phone input' ); if ( enterOriginPhone ) { - await expect( page ).toFill( '.address-step__phone #origin_phone', '11111111111' ); + await expect( page ).toFill( '.address-step__phone input', '11111111111' ); + await expect( page ).toClick( '.address-step__actions .form-button', { text: 'Use address as entered' } ) - await page.waitForSelector( '.address-step__suggestion-title', { text: 'Address entered' } ); await expect( page ).toClick( '.address-step__suggestion-title', { text: 'Address entered' } ); } await expect( page ).toClick( '.button.is-primary', { text: 'Use selected address' } ); + await expect( page ).toFill( '#weight_default_box', '1' ); + const selectAPackageType = await page.$( '.packages-step__no-packages a', { text: 'Select a package type' } ); @@ -64,7 +59,6 @@ describe( 'Create shipping label', () => { const packageName = 'My Package'; if ( selectAPackageType ) { await selectAPackageType.click(); - await expect( page ).toFill( '#weight_default_box', '1' ); await page.waitForSelector( '.packages__add-edit-dialog' ); @@ -79,7 +73,6 @@ describe( 'Create shipping label', () => { } else if( addPackage ) { await addPackage.click(); - await expect( page ).toFill( '#weight_default_box', '1' ); await page.waitForSelector( '.packages__add-edit-dialog' ); @@ -93,13 +86,12 @@ describe( 'Create shipping label', () => { await page.waitForSelector( '.notice.is-success .notice__text', { text: 'Your shipping packages have been saved.' } ); } - await clickReactButton( '.button.is-primary', { text: 'Use these packages' } ); + await expect( page ).toClick( '.button.is-primary', { text: 'Use these packages' } ); await page.waitForSelector( '.is-success', { text: '1 item in 1 package: 2 kg total' } ); - await page.waitForSelector( '#inspector-radio-control-0-0' ); await expect( page ).toClick( '#inspector-radio-control-0-0' ); await expect( page ).toClick( '.button.is-primary', { diff --git a/tests/e2e/specs/admin/4-refund-label.test.js b/tests/e2e/specs/admin/4-refund-label.test.js index bf3937da5..20ae67b8d 100644 --- a/tests/e2e/specs/admin/4-refund-label.test.js +++ b/tests/e2e/specs/admin/4-refund-label.test.js @@ -11,7 +11,6 @@ import { StoreOwnerFlow } from '../../utils/flows'; import { withExpiredShippingLabelAndOrder, withShippingLabelAndOrder } from '../../fixtures/index'; describe( 'Refund shipping label', () => { - beforeAll( async () => { page.setDefaultTimeout( 0 ); page.setDefaultNavigationTimeout( 0 ); @@ -27,36 +26,25 @@ describe( 'Refund shipping label', () => { it( "works if the label hasn't been used", async () => { await withShippingLabelAndOrder( async ( { order } ) => { - await StoreOwnerFlow.openExistingOrderPage( order.id ); await clickReactButton( '.ellipsis-menu > .button' ); await clickReactButton( 'div > .popover > .popover__inner > .popover__menu > .popover__menu-item:nth-child(3)' ); - await clickReactButton( '.ReactModalPortal > .ReactModal__Overlay > .ReactModal__Content > .dialog__action-buttons > .button:nth-child(2)' ); - - await clickReactButton( '#postbox-container-2 > #normal-sortables > #woocommerce-order-label > .inside > .wcc-root' ); - const newLabelButton = await page.$( '.wcc-root > .shipping-label__container > div > div > .button' ); - if( ! newLabelButton ) { - throw new Error( 'No button to create new shipping label for order' ); - } - await clickReactButton( '.wcc-root > .shipping-label__container > div > div > .button' ); - await clickReactButton( '.label-purchase-modal__body > .label-purchase-modal__sidebar > .label-purchase-modal__purchase-container > .purchase-section > .button' ); + await clickReactButton( '.label-refund-modal > .dialog__action-buttons > .button:nth-child(2)' ); await page.waitForSelector( '.notice.is-success .notice__text', { text: 'The refund request has been sent successfully.' - } ) + } ); }); } ); it( "doesn't work for expired labels", async () => { - await withExpiredShippingLabelAndOrder( async ( { order } ) => { await StoreOwnerFlow.openExistingOrderPage( order.id ); await clickReactButton( '.ellipsis-menu > .button' ); await expect( page ).toMatchElement( '.ellipsis-menu__menu .shipping-label__item-menu-reprint-expired' ); - }); } ); } ); diff --git a/tests/e2e/utils/components.js b/tests/e2e/utils/components.js index 20337255b..8b4b10915 100644 --- a/tests/e2e/utils/components.js +++ b/tests/e2e/utils/components.js @@ -5,79 +5,28 @@ /** * Internal dependencies */ -import { StoreOwnerFlow } from "./flows"; -import { clickTab, clickReactButton, waitForSelectorAndText } from "./index"; +import { StoreOwnerFlow } from './flows'; +import { waitForSelectorAndText } from '.'; -const verifyAndPublish = async () => { - // Wait for auto save - await page.waitForSelector( '#sample-permalink' ); - - // Publish product - console.log( 'about to save the product' ) - await clickReactButton( '#publish' ); - console.log( 'product saved!' ) - - // Verify - await page.waitForSelector( '.updated.notice', { text: 'Product published.', timeout: 1500 } ); - await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } ); - console.log( 'product saved confirmed!' ) -}; - -/** - * Create simple product. - */ -const createSimpleProduct = async () => { - // Go to "add product" page - await StoreOwnerFlow.openNewProduct(); - - // Make sure we're on the add product page - await expect( page ).toMatchElement( '.wp-heading-inline', { text: 'Add new product' } ) - - // Set product data - await expect(page).toFill('#title', 'Simple product'); - await clickTab('General'); - await expect(page).toFill('#_regular_price', '9.99'); - - await verifyAndPublish(); -}; - -/** - * Login and confirm that extension is activated on the site. - */ -const loginAndConfirmExtensionActivation = async () => { - const slug = 'woocommerce-services'; - await StoreOwnerFlow.login(); - await StoreOwnerFlow.openPluginsPage(); - const disableLink = await page.$( `tr[data-slug="${ slug }"] .deactivate a` ); - if ( disableLink ) { - return; - } - await page.click( `tr[data-slug="${ slug }"] .activate a` ); - await page.waitForSelector( `tr[data-slug="${ slug }"] .deactivate a` ); -}; - -const deleteAllPackages = async () => { +export const deleteAllPackages = async () => { await StoreOwnerFlow.login(); await StoreOwnerFlow.openSettings( 'shipping', 'woocommerce-services-settings' ); // Wait for "Add package" to finish loading, click "edit" once this session is loaded await waitForSelectorAndText('.button:not([disabled])', 'Add package'); + let editButton = await page.$( '.button.is-compact', { text: 'Edit' } ); - do { - if( editButton ) { - await expect( page ).toClick( '.button.is-compact', { text: 'Edit' } ); - // Delete package - await page.waitForSelector( '.packages__add-edit-title.form-section-heading', { text: 'Edit package' } ); - await expect( page ).toClick( '.button.packages__delete.is-scary.is-borderless', { text: 'Delete this package' } ); - } + while ( editButton ) { + await expect( page ).toClick( '.button.is-compact', { text: 'Edit' } ); + // Delete package + await page.waitForSelector( '.packages__add-edit-title.form-section-heading', { text: 'Edit package' } ); + await expect( page ).toClick( '.button.packages__delete.is-scary.is-borderless', { text: 'Delete this package' } ); editButton = await page.$( '.button.is-compact', { text: 'Edit' } ); - } while ( editButton ); + } }; // Click save and wait until it's saved. -const saveAndWait = async () => { +export const saveAndWait = async () => { await expect( page ).toClick( '.button.is-primary', { text: 'Save changes' } ); - await page.waitForSelector('[class="button is-primary"]'); + await page.waitForSelector( '.button.is-primary.is-busy', { hidden: true } ); }; - -export { createSimpleProduct, loginAndConfirmExtensionActivation, deleteAllPackages, saveAndWait }; diff --git a/tests/e2e/utils/index.js b/tests/e2e/utils/index.js index be7841c49..a352df425 100644 --- a/tests/e2e/utils/index.js +++ b/tests/e2e/utils/index.js @@ -26,7 +26,7 @@ const settingsPageSaveChanges = async () => { /** * Set checkbox. * - * @param {string} selector + * @param {string} selector Selector of the element */ const setCheckbox = async( selector ) => { await page.focus( selector ); @@ -58,15 +58,15 @@ const verifyCheckboxIsSet = async( selector ) => { await expect( checkboxStatus ).toBe( true ); }; -const clickReactButton = async( selector ) => { - await page.waitForSelector( selector ); - //await page.click( selector ); - await page.$eval( selector, elem => { - if ( !elem ) { - console.log( `.clickReactButton => Element not found: ${ selector }` ); - } - return elem.click(); - } ); +/** + * Clicks on an element, ensuring it is present in the DOM. + * + * @param {string} selector Selector of the element. + * @param {object} options Other options to pass to Puppeteer. + */ +const clickReactButton = async( selector, options ) => { + await page.waitForSelector( selector ); + await expect( page ).toClick( selector, options ); }; /**