Improve page object encapsulation, refactor e2e suite, add more e2e tests. (https://github.com/woocommerce/woocommerce-admin/pull/6682)
This commit is contained in:
parent
588776deb3
commit
9dd75e83f8
|
@ -23,17 +23,16 @@ jobs:
|
||||||
uses: actions/setup-node@v2-beta
|
uses: actions/setup-node@v2-beta
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '14'
|
||||||
- name: Build
|
- name: Build and run E2E Tests
|
||||||
env:
|
env:
|
||||||
WP_VERSION: latest
|
WP_VERSION: latest
|
||||||
WP_MULTISITE: 0
|
WC_E2E_SCREENSHOTS: 1
|
||||||
WP_CORE_DIR: /tmp/wordpress
|
E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }}
|
||||||
RUN_E2E: 1
|
E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }}
|
||||||
|
GITHUB_ACTIONS: 1
|
||||||
run: |
|
run: |
|
||||||
npm i
|
npm i
|
||||||
composer require wp-cli/i18n-command
|
composer require wp-cli/i18n-command
|
||||||
npm run build
|
npm run build
|
||||||
npm install jest --global
|
npx wc-e2e docker:up
|
||||||
WP_VERSION=5.6.2
|
npx wc-e2e test:e2e
|
||||||
npm run docker:up
|
|
||||||
npm run test:e2e
|
|
||||||
|
|
|
@ -32,29 +32,32 @@ For local development setup using Docker [see here](./docker/wc-admin-wp-env/REA
|
||||||
|
|
||||||
#### End-to-end tests
|
#### End-to-end tests
|
||||||
|
|
||||||
Tests live in `./tests/e2e`. An existing build is required prior running, please refer to the section above for steps. E2E tests have their own Docker container to run the WordPress server. Start
|
Tests live in `./tests/e2e`. An existing build is required prior running, please refer to the section above for steps. E2E tests use the `@woocommerce/e2e-environment` package which hosts a Docker container for testing, by default the container can be accessed at `http://localhost:8084`
|
||||||
the server using:
|
|
||||||
|
All the commands from `@woocommerce/e2e-environment` can be run through `npx`.
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run docker:up
|
# Set up the e2e environment
|
||||||
|
npm i
|
||||||
|
npx wc-e2e docker:up
|
||||||
```
|
```
|
||||||
|
|
||||||
Run tests using:
|
Run tests using:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test:e2e-dev
|
npx wc-e2e test:e2e-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
or in headless mode:
|
or in headless mode:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test:e2e
|
npx wc-e2e test:e2e
|
||||||
```
|
```
|
||||||
|
|
||||||
Run a single test by adding the file name:
|
Run a single test by adding the path to the file name:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test:e2e-dev complete-onboarding-wizard.test.js
|
npx wc-e2e test:e2e-dev tests/e2e/specs/activate-and-setup/complete-onboarding-wizard.test.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
## Common Issues
|
## Common Issues
|
||||||
|
|
|
@ -52,43 +52,21 @@
|
||||||
"puppeteer": "^2.0.0"
|
"puppeteer": "^2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/cli": {
|
"@slack/web-api": {
|
||||||
"version": "7.12.16",
|
"version": "5.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.12.16.tgz",
|
"resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-5.15.0.tgz",
|
||||||
"integrity": "sha512-cKWkNCxbpjSuYLbdeJs4kOnyW1E2D65pu7SodXDOkzahIN/wSgT8geIqf6+pJTgCo47zrOMGcJTmjSFe5WKYwQ==",
|
"integrity": "sha512-tjQ8Zqv/Fmj9SOL9yIEd7IpTiKfKHi9DKAkfRVeotoX0clMr3SqQtBqO+KZMX27gm7dmgJsQaDKlILyzdCO+IA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents",
|
"@slack/logger": ">=1.0.0 <3.0.0",
|
||||||
"chokidar": "^3.4.0",
|
"@slack/types": "^1.7.0",
|
||||||
"commander": "^4.0.1",
|
"@types/is-stream": "^1.1.0",
|
||||||
"convert-source-map": "^1.1.0",
|
"@types/node": ">=8.9.0",
|
||||||
"fs-readdir-recursive": "^1.1.0",
|
"axios": "^0.21.1",
|
||||||
"glob": "^7.0.0",
|
"eventemitter3": "^3.1.0",
|
||||||
"lodash": "^4.17.19",
|
"form-data": "^2.5.0",
|
||||||
"make-dir": "^2.1.0",
|
"is-stream": "^1.1.0",
|
||||||
"slash": "^2.0.0",
|
"p-queue": "^6.6.1",
|
||||||
"source-map": "^0.5.0"
|
"p-retry": "^4.0.0"
|
||||||
}
|
|
||||||
},
|
|
||||||
"@babel/core": {
|
|
||||||
"version": "7.12.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.16.tgz",
|
|
||||||
"integrity": "sha512-t/hHIB504wWceOeaOoONOhu+gX+hpjfeN6YRBT209X/4sibZQfSF1I0HFRRlBe97UZZosGx5XwUg1ZgNbelmNw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/code-frame": "^7.12.13",
|
|
||||||
"@babel/generator": "^7.12.15",
|
|
||||||
"@babel/helper-module-transforms": "^7.12.13",
|
|
||||||
"@babel/helpers": "^7.12.13",
|
|
||||||
"@babel/parser": "^7.12.16",
|
|
||||||
"@babel/template": "^7.12.13",
|
|
||||||
"@babel/traverse": "^7.12.13",
|
|
||||||
"@babel/types": "^7.12.13",
|
|
||||||
"convert-source-map": "^1.7.0",
|
|
||||||
"debug": "^4.1.0",
|
|
||||||
"gensync": "^1.0.0-beta.1",
|
|
||||||
"json5": "^2.1.2",
|
|
||||||
"lodash": "^4.17.19",
|
|
||||||
"semver": "^5.4.1",
|
|
||||||
"source-map": "^0.5.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@wordpress/e2e-test-utils": {
|
"@wordpress/e2e-test-utils": {
|
||||||
|
@ -155,7 +133,6 @@
|
||||||
"version": "7.13.14",
|
"version": "7.13.14",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.13.14.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.13.14.tgz",
|
||||||
"integrity": "sha512-zmEFV8WBRsW+mPQumO1/4b34QNALBVReaiHJOkxhUsdo/AvYM62c+SKSuLi2aZ42t3ocK6OI0uwUXRvrIbREZw==",
|
"integrity": "sha512-zmEFV8WBRsW+mPQumO1/4b34QNALBVReaiHJOkxhUsdo/AvYM62c+SKSuLi2aZ42t3ocK6OI0uwUXRvrIbREZw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents",
|
"@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents",
|
||||||
"chokidar": "^3.4.0",
|
"chokidar": "^3.4.0",
|
||||||
|
@ -186,7 +163,6 @@
|
||||||
"version": "7.13.14",
|
"version": "7.13.14",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.14.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.14.tgz",
|
||||||
"integrity": "sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==",
|
"integrity": "sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.12.13",
|
"@babel/code-frame": "^7.12.13",
|
||||||
"@babel/generator": "^7.13.9",
|
"@babel/generator": "^7.13.9",
|
||||||
|
@ -208,14 +184,12 @@
|
||||||
"@babel/compat-data": {
|
"@babel/compat-data": {
|
||||||
"version": "7.13.12",
|
"version": "7.13.12",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz",
|
||||||
"integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==",
|
"integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@babel/generator": {
|
"@babel/generator": {
|
||||||
"version": "7.13.9",
|
"version": "7.13.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz",
|
||||||
"integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==",
|
"integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.13.0",
|
"@babel/types": "^7.13.0",
|
||||||
"jsesc": "^2.5.1",
|
"jsesc": "^2.5.1",
|
||||||
|
@ -226,7 +200,6 @@
|
||||||
"version": "7.13.13",
|
"version": "7.13.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz",
|
||||||
"integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==",
|
"integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/compat-data": "^7.13.12",
|
"@babel/compat-data": "^7.13.12",
|
||||||
"@babel/helper-validator-option": "^7.12.17",
|
"@babel/helper-validator-option": "^7.12.17",
|
||||||
|
@ -238,7 +211,6 @@
|
||||||
"version": "7.13.12",
|
"version": "7.13.12",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz",
|
||||||
"integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==",
|
"integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.13.12"
|
"@babel/types": "^7.13.12"
|
||||||
}
|
}
|
||||||
|
@ -247,7 +219,6 @@
|
||||||
"version": "7.13.12",
|
"version": "7.13.12",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz",
|
||||||
"integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==",
|
"integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.13.12"
|
"@babel/types": "^7.13.12"
|
||||||
}
|
}
|
||||||
|
@ -256,7 +227,6 @@
|
||||||
"version": "7.13.14",
|
"version": "7.13.14",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz",
|
||||||
"integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==",
|
"integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-module-imports": "^7.13.12",
|
"@babel/helper-module-imports": "^7.13.12",
|
||||||
"@babel/helper-replace-supers": "^7.13.12",
|
"@babel/helper-replace-supers": "^7.13.12",
|
||||||
|
@ -272,7 +242,6 @@
|
||||||
"version": "7.13.12",
|
"version": "7.13.12",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz",
|
||||||
"integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==",
|
"integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-member-expression-to-functions": "^7.13.12",
|
"@babel/helper-member-expression-to-functions": "^7.13.12",
|
||||||
"@babel/helper-optimise-call-expression": "^7.12.13",
|
"@babel/helper-optimise-call-expression": "^7.12.13",
|
||||||
|
@ -284,7 +253,6 @@
|
||||||
"version": "7.13.12",
|
"version": "7.13.12",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz",
|
||||||
"integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==",
|
"integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.13.12"
|
"@babel/types": "^7.13.12"
|
||||||
}
|
}
|
||||||
|
@ -293,7 +261,6 @@
|
||||||
"version": "7.13.10",
|
"version": "7.13.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz",
|
||||||
"integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==",
|
"integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/template": "^7.12.13",
|
"@babel/template": "^7.12.13",
|
||||||
"@babel/traverse": "^7.13.0",
|
"@babel/traverse": "^7.13.0",
|
||||||
|
@ -303,14 +270,12 @@
|
||||||
"@babel/parser": {
|
"@babel/parser": {
|
||||||
"version": "7.13.13",
|
"version": "7.13.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz",
|
||||||
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==",
|
"integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@babel/traverse": {
|
"@babel/traverse": {
|
||||||
"version": "7.13.13",
|
"version": "7.13.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz",
|
||||||
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
"integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.12.13",
|
"@babel/code-frame": "^7.12.13",
|
||||||
"@babel/generator": "^7.13.9",
|
"@babel/generator": "^7.13.9",
|
||||||
|
@ -326,7 +291,6 @@
|
||||||
"version": "7.13.14",
|
"version": "7.13.14",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz",
|
||||||
"integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==",
|
"integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-validator-identifier": "^7.12.11",
|
"@babel/helper-validator-identifier": "^7.12.11",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
|
@ -336,8 +300,7 @@
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6593,14 +6556,14 @@
|
||||||
"integrity": "sha512-tA7GG7Tj479vojfV3AoxbckalA48aK6giGjNtgH6ihpLwTyHE3fIgRrvt8TWfLwW8X8dyu7vgmAsGLRG7hWWOg=="
|
"integrity": "sha512-tA7GG7Tj479vojfV3AoxbckalA48aK6giGjNtgH6ihpLwTyHE3fIgRrvt8TWfLwW8X8dyu7vgmAsGLRG7hWWOg=="
|
||||||
},
|
},
|
||||||
"@slack/web-api": {
|
"@slack/web-api": {
|
||||||
"version": "5.15.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-5.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-6.1.0.tgz",
|
||||||
"integrity": "sha512-tjQ8Zqv/Fmj9SOL9yIEd7IpTiKfKHi9DKAkfRVeotoX0clMr3SqQtBqO+KZMX27gm7dmgJsQaDKlILyzdCO+IA==",
|
"integrity": "sha512-9MVHw+rDBaFvkvzm8lDNH/nlkvJCDKRIjFGMdpbyZlVLsm4rcht4qyiL71bqdyLATHXJnWknb/sl0FQGLLobIA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@slack/logger": ">=1.0.0 <3.0.0",
|
"@slack/logger": ">=1.0.0 <3.0.0",
|
||||||
"@slack/types": "^1.7.0",
|
"@slack/types": "^1.7.0",
|
||||||
"@types/is-stream": "^1.1.0",
|
"@types/is-stream": "^1.1.0",
|
||||||
"@types/node": ">=8.9.0",
|
"@types/node": ">=12.0.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"eventemitter3": "^3.1.0",
|
"eventemitter3": "^3.1.0",
|
||||||
"form-data": "^2.5.0",
|
"form-data": "^2.5.0",
|
||||||
|
@ -10939,53 +10902,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@woocommerce/e2e-environment": {
|
"@woocommerce/e2e-environment": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@woocommerce/e2e-environment/-/e2e-environment-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@woocommerce/e2e-environment/-/e2e-environment-0.2.1.tgz",
|
||||||
"integrity": "sha512-PynrpNBlUvVrTuofukmhjA4v90zzvH/BGtHFF19jefRayZiq9/57uDVmn5xNrVsR7OA3QdlID7ERij3MUcFQ9w==",
|
"integrity": "sha512-VsgxGg01Abe70B7lxkNVEhyH7ei8NuckjBfnc7SAXKU+SxNwzWQQnZafsVnZMQ8qBFm7eEtviABEu5Ajr6l+aA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@automattic/puppeteer-utils": "github:Automattic/puppeteer-utils#0f3ec50",
|
"@automattic/puppeteer-utils": "github:Automattic/puppeteer-utils#0f3ec50",
|
||||||
"@jest/test-sequencer": "^25.5.4",
|
"@jest/test-sequencer": "^25.5.4",
|
||||||
|
"@slack/web-api": "^6.1.0",
|
||||||
"@wordpress/e2e-test-utils": "^4.15.0",
|
"@wordpress/e2e-test-utils": "^4.15.0",
|
||||||
"@wordpress/jest-preset-default": "^6.4.0",
|
"@wordpress/jest-preset-default": "^6.4.0",
|
||||||
"app-root-path": "^3.0.0",
|
"app-root-path": "^3.0.0",
|
||||||
"jest": "^25.1.0",
|
"jest": "^25.1.0",
|
||||||
|
"jest-each": "25.5.0",
|
||||||
"jest-puppeteer": "^4.4.0"
|
"jest-puppeteer": "^4.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": {
|
|
||||||
"version": "7.12.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.16.tgz",
|
|
||||||
"integrity": "sha512-t/hHIB504wWceOeaOoONOhu+gX+hpjfeN6YRBT209X/4sibZQfSF1I0HFRRlBe97UZZosGx5XwUg1ZgNbelmNw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/code-frame": "^7.12.13",
|
|
||||||
"@babel/generator": "^7.12.15",
|
|
||||||
"@babel/helper-module-transforms": "^7.12.13",
|
|
||||||
"@babel/helpers": "^7.12.13",
|
|
||||||
"@babel/parser": "^7.12.16",
|
|
||||||
"@babel/template": "^7.12.13",
|
|
||||||
"@babel/traverse": "^7.12.13",
|
|
||||||
"@babel/types": "^7.12.13",
|
|
||||||
"convert-source-map": "^1.7.0",
|
|
||||||
"debug": "^4.1.0",
|
|
||||||
"gensync": "^1.0.0-beta.1",
|
|
||||||
"json5": "^2.1.2",
|
|
||||||
"lodash": "^4.17.19",
|
|
||||||
"semver": "^5.4.1",
|
|
||||||
"source-map": "^0.5.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"semver": {
|
|
||||||
"version": "5.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
|
||||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
|
||||||
},
|
|
||||||
"source-map": {
|
|
||||||
"version": "0.5.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
|
||||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@jest/console": {
|
"@jest/console": {
|
||||||
"version": "25.5.0",
|
"version": "25.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jest/console/-/console-25.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@jest/console/-/console-25.5.0.tgz",
|
||||||
|
@ -11270,6 +11201,23 @@
|
||||||
"istanbul-lib-report": "^3.0.0"
|
"istanbul-lib-report": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jest-each": {
|
||||||
|
"version": "25.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.5.0.tgz",
|
||||||
|
"integrity": "sha512-QBogUxna3D8vtiItvn54xXde7+vuzqRrEeaw8r1s+1TG9eZLVJE5ZkKoSUlqFwRjnlaA4hyKGiu9OlkFIuKnjA==",
|
||||||
|
"requires": {
|
||||||
|
"@jest/types": "^25.5.0",
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"jest-get-type": "^25.2.6",
|
||||||
|
"jest-util": "^25.5.0",
|
||||||
|
"pretty-format": "^25.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jest-get-type": {
|
||||||
|
"version": "25.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz",
|
||||||
|
"integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig=="
|
||||||
|
},
|
||||||
"jest-haste-map": {
|
"jest-haste-map": {
|
||||||
"version": "25.5.1",
|
"version": "25.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.5.1.tgz",
|
||||||
|
@ -11428,6 +11376,17 @@
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
||||||
},
|
},
|
||||||
|
"pretty-format": {
|
||||||
|
"version": "25.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz",
|
||||||
|
"integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==",
|
||||||
|
"requires": {
|
||||||
|
"@jest/types": "^25.5.0",
|
||||||
|
"ansi-regex": "^5.0.0",
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"react-is": "^16.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||||
|
@ -21693,9 +21652,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-glob": "^4.0.1"
|
"is-glob": "^4.0.1"
|
||||||
}
|
}
|
||||||
|
@ -23263,9 +23222,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.13.2",
|
"version": "1.13.3",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
||||||
"integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA=="
|
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
|
||||||
},
|
},
|
||||||
"for-each": {
|
"for-each": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
|
@ -32883,9 +32842,9 @@
|
||||||
"integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo="
|
"integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo="
|
||||||
},
|
},
|
||||||
"p-retry": {
|
"p-retry": {
|
||||||
"version": "4.3.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.5.0.tgz",
|
||||||
"integrity": "sha512-Pow4yaHpOiJou1QcpGcBJhGHiS4782LdDa6GhU91hlaNh3ExOOupjSJcxPQZYmUSZk3Pl2ARz/LRvW8Qu0+3mQ==",
|
"integrity": "sha512-5Hwh4aVQSu6BEP+w2zKlVXtFAaYQe1qWuVADSgoeVlLjwe/Q/AMSoRR4MDeaAfu8llT+YNbEijWu/YF3m6avkg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/retry": "^0.12.0",
|
"@types/retry": "^0.12.0",
|
||||||
"retry": "^0.12.0"
|
"retry": "^0.12.0"
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
"clean": "rimraf ./dist ./packages/*/build ./packages/*/build-module ./packages/*/build-style",
|
"clean": "rimraf ./dist ./packages/*/build ./packages/*/build-module ./packages/*/build-style",
|
||||||
"predev": "npm run -s install-if-deps-outdated && php ./bin/update-version.php",
|
"predev": "npm run -s install-if-deps-outdated && php ./bin/update-version.php",
|
||||||
"dev": "cross-env WC_ADMIN_PHASE=development npm run build:feature-config && cross-env WC_ADMIN_PHASE=development npm run build:packages && cross-env WC_ADMIN_PHASE=development webpack",
|
"dev": "cross-env WC_ADMIN_PHASE=development npm run build:feature-config && cross-env WC_ADMIN_PHASE=development npm run build:packages && cross-env WC_ADMIN_PHASE=development webpack",
|
||||||
"docker:up": "npm explore @woocommerce/e2e-environment -- npm run docker:up",
|
|
||||||
"docker:down": "npm explore @woocommerce/e2e-environment -- npm run docker:down",
|
|
||||||
"docs": "node ./bin/generate-docs",
|
"docs": "node ./bin/generate-docs",
|
||||||
"i18n": "npm run -s i18n:js && npm run -s i18n:check && npm run -s i18n:pot && npm run -s i18n:build",
|
"i18n": "npm run -s i18n:js && npm run -s i18n:check && npm run -s i18n:pot && npm run -s i18n:build",
|
||||||
"i18n:build": "php bin/combine-pot-files.php languages/woocommerce-admin.po languages/woocommerce-admin.pot",
|
"i18n:build": "php bin/combine-pot-files.php languages/woocommerce-admin.po languages/woocommerce-admin.pot",
|
||||||
|
@ -60,10 +58,8 @@
|
||||||
"prestart": "npm run -s install-if-deps-outdated",
|
"prestart": "npm run -s install-if-deps-outdated",
|
||||||
"start": "cross-env WC_ADMIN_PHASE=development npm run build:packages && cross-env WC_ADMIN_PHASE=development npm run build:feature-config && concurrently \"cross-env WC_ADMIN_PHASE=development webpack --watch\" \"node ./bin/packages/watch.js\"",
|
"start": "cross-env WC_ADMIN_PHASE=development npm run build:packages && cross-env WC_ADMIN_PHASE=development npm run build:feature-config && concurrently \"cross-env WC_ADMIN_PHASE=development webpack --watch\" \"node ./bin/packages/watch.js\"",
|
||||||
"pretest": "npm run -s install-if-no-packages",
|
"pretest": "npm run -s install-if-no-packages",
|
||||||
"test:e2e": "bash ./bin/wait-for-build.sh && ./node_modules/@woocommerce/e2e-environment/bin/e2e-test-integration.js",
|
|
||||||
"test:e2e-dev": "bash ./bin/wait-for-build.sh && DEBUG=1 ./node_modules/@woocommerce/e2e-environment/bin/e2e-test-integration.js --dev",
|
|
||||||
"test:e2e-debug": "bash ./bin/wait-for-build.sh && DEBUG=1 ./node_modules/@woocommerce/e2e-environment/bin/e2e-test-integration.js --dev --debug",
|
|
||||||
"test": "./node_modules/jest-24.9.0/bin/jest.js --config tests/js/jest.config.json",
|
"test": "./node_modules/jest-24.9.0/bin/jest.js --config tests/js/jest.config.json",
|
||||||
|
"test:e2e": "WP_VERSION=latest npm run build && npx wc-e2e docker:down && npx wc-e2e docker:up && npx wc-e2e test:e2e",
|
||||||
"test-staged": "./node_modules/jest-24.9.0/bin/jest.js --bail --config tests/js/jest.config.json --findRelatedTests",
|
"test-staged": "./node_modules/jest-24.9.0/bin/jest.js --bail --config tests/js/jest.config.json --findRelatedTests",
|
||||||
"test:help": "wp-scripts test-unit-js --help",
|
"test:help": "wp-scripts test-unit-js --help",
|
||||||
"test:php": "docker-compose -f docker/wc-admin-php-test-suite/docker-compose.yml run --rm phpunit",
|
"test:php": "docker-compose -f docker/wc-admin-php-test-suite/docker-compose.yml run --rm phpunit",
|
||||||
|
@ -94,7 +90,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@woocommerce/e2e-environment": "0.2.0",
|
"@woocommerce/e2e-environment": "0.2.1",
|
||||||
"@woocommerce/e2e-utils": "0.1.2",
|
"@woocommerce/e2e-utils": "0.1.2",
|
||||||
"@wordpress/api-fetch": "2.2.8",
|
"@wordpress/api-fetch": "2.2.8",
|
||||||
"@wordpress/base-styles": "3.3.0",
|
"@wordpress/base-styles": "3.3.0",
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
const { useE2EJestPuppeteerConfig } = require( '@woocommerce/e2e-environment' );
|
||||||
|
|
||||||
|
const puppeteerConfig = useE2EJestPuppeteerConfig( {
|
||||||
|
launch: {
|
||||||
|
browserContext: 'incognito',
|
||||||
|
args: [ '--incognito' ],
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
|
||||||
|
module.exports = puppeteerConfig;
|
|
@ -7,7 +7,16 @@ module.exports = {
|
||||||
roots: [ path.resolve( __dirname, '../specs' ) ],
|
roots: [ path.resolve( __dirname, '../specs' ) ],
|
||||||
testMatch: [ '**/*.(test|spec).(j|t)s', '*.(test|spec).(j|t)s' ],
|
testMatch: [ '**/*.(test|spec).(j|t)s', '*.(test|spec).(j|t)s' ],
|
||||||
testTimeout: 30000,
|
testTimeout: 30000,
|
||||||
// transform: {
|
transform: {
|
||||||
// '^.+\\.(ts|tsx|js|jsx)$': 'babel-jest',
|
'\\.[jt]sx?$': [
|
||||||
// },
|
'babel-jest',
|
||||||
|
{
|
||||||
|
configFile: path.join(
|
||||||
|
__dirname,
|
||||||
|
'../../../',
|
||||||
|
'babel.config.js'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Page } from 'puppeteer';
|
||||||
|
|
||||||
|
export abstract class BaseElement {
|
||||||
|
protected page: Page;
|
||||||
|
protected selector: string;
|
||||||
|
|
||||||
|
constructor( page: Page, selector: string ) {
|
||||||
|
this.page = page;
|
||||||
|
this.selector = selector;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { getElementByText, getInputValue } from '../utils/actions';
|
||||||
|
import { BaseElement } from './BaseElement';
|
||||||
|
|
||||||
|
export class DropdownField extends BaseElement {
|
||||||
|
async select( value: string ) {
|
||||||
|
const currentVal = await getInputValue( this.selector + ' input' );
|
||||||
|
if ( currentVal !== value ) {
|
||||||
|
await this.page.click(
|
||||||
|
this.selector + ' .woocommerce-select-control__control'
|
||||||
|
);
|
||||||
|
const button = await getElementByText(
|
||||||
|
'button',
|
||||||
|
value,
|
||||||
|
this.selector
|
||||||
|
);
|
||||||
|
await button?.click();
|
||||||
|
await this.checkSelected( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkSelected( value: string ) {
|
||||||
|
const currentVal = await getInputValue( this.selector + ' input' );
|
||||||
|
expect( currentVal ).toBe( value );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,16 @@
|
||||||
import { Page } from 'puppeteer';
|
import { clearAndFillInput } from '@woocommerce/e2e-utils';
|
||||||
import {
|
import { BaseElement } from './BaseElement';
|
||||||
clearAndFillInput,
|
|
||||||
verifyValueOfInputField,
|
|
||||||
} from '@woocommerce/e2e-utils';
|
|
||||||
|
|
||||||
export class DropdownTypeaheadField {
|
export class DropdownTypeaheadField extends BaseElement {
|
||||||
page: Page;
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
constructor( page: Page, id: string ) {
|
|
||||||
this.page = page;
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
async search( text: string ) {
|
async search( text: string ) {
|
||||||
await clearAndFillInput( this.id + '-0__control-input', text );
|
await clearAndFillInput( this.selector + '-0__control-input', text );
|
||||||
}
|
}
|
||||||
async select( selector: string ) {
|
async select( selector: string ) {
|
||||||
await this.page.click( this.id + `__option-0-${ selector }` );
|
await this.page.click( this.selector + `__option-0-${ selector }` );
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkSelected( value: string ) {
|
async checkSelected( value: string ) {
|
||||||
const selector = this.id + '-0__control-input';
|
const selector = this.selector + '-0__control-input';
|
||||||
await page.focus( selector );
|
await page.focus( selector );
|
||||||
const field = await this.page.$( selector );
|
const field = await this.page.$( selector );
|
||||||
const curValue = await field?.getProperty( 'value' );
|
const curValue = await field?.getProperty( 'value' );
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { BaseElement } from './BaseElement';
|
||||||
|
|
||||||
|
import { hasClass } from '../utils/actions';
|
||||||
|
|
||||||
|
export class FormToggle extends BaseElement {
|
||||||
|
// Represents a FormToggle input. Use `selector` to represent the container its found in.
|
||||||
|
async switchOn() {
|
||||||
|
const container = await this.getCheckboxContainer();
|
||||||
|
if ( container && ! ( await hasClass( container, 'is-checked' ) ) ) {
|
||||||
|
const input = await this.getCheckboxInput();
|
||||||
|
|
||||||
|
if ( ! input ) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find form toggle with selector ${ this.selector }`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
input?.click();
|
||||||
|
|
||||||
|
// Wait for it to be checked.
|
||||||
|
await this.page.waitForSelector(
|
||||||
|
`${ this.selector } .components-form-toggle.is-checked`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async switchOff() {
|
||||||
|
const container = await this.getCheckboxContainer();
|
||||||
|
if ( container && ( await hasClass( container, 'is-checked' ) ) ) {
|
||||||
|
const input = await this.getCheckboxInput();
|
||||||
|
|
||||||
|
if ( ! input ) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find form toggle with selector ${ this.selector }`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
input?.click();
|
||||||
|
|
||||||
|
// Wait for a not checked toggle to be present.
|
||||||
|
await page.waitForFunction(
|
||||||
|
( selector ) => {
|
||||||
|
return document.querySelectorAll( selector ).length;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
`${ this.selector } .components-form-toggle:not(.is-checked)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCheckboxContainer() {
|
||||||
|
return this.page.$( `${ this.selector } .components-form-toggle` );
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCheckboxInput() {
|
||||||
|
return this.page.$(
|
||||||
|
`${ this.selector } .components-form-toggle__input`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEnabled() {
|
||||||
|
await this.page.waitForSelector(
|
||||||
|
`${ this.selector } .components-form-toggle.is-checked`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { getElementByText, getInputValue } from '../utils/actions';
|
|
||||||
|
|
||||||
export class DropdownField {
|
|
||||||
page: Page;
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
constructor( page: Page, id: string ) {
|
|
||||||
this.page = page;
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
async select( value: string ) {
|
|
||||||
const currentVal = await getInputValue( this.id + ' input' );
|
|
||||||
if ( currentVal !== value ) {
|
|
||||||
await this.page.click(
|
|
||||||
this.id + ' .woocommerce-select-control__control'
|
|
||||||
);
|
|
||||||
const button = await getElementByText( 'button', value, this.id );
|
|
||||||
await button?.click();
|
|
||||||
await this.checkSelected( value );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkSelected( value: string ) {
|
|
||||||
const currentVal = await getInputValue( this.id + ' input' );
|
|
||||||
expect( currentVal ).toBe( value );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { WP_ADMIN_PERMALINK_SETTINGS } from '../utils/constants';
|
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { getElementByText, waitForElementByText } from '../utils/actions';
|
|
||||||
|
|
||||||
export class WpSettings {
|
|
||||||
page: Page;
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
async openPermalinkSettings() {
|
|
||||||
await this.page.goto( WP_ADMIN_PERMALINK_SETTINGS, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
await waitForElementByText( 'h1', 'Permalink Settings' );
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveSettings() {
|
|
||||||
await page.click( '#submit' );
|
|
||||||
await this.page.waitForNavigation( {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { getElementByText, waitForElementByText } from '../../utils/actions';
|
|
||||||
|
|
||||||
export class BenefitsSection {
|
|
||||||
page: Page;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
async isDisplayed() {
|
|
||||||
await waitForElementByText(
|
|
||||||
'h2',
|
|
||||||
'Enhance your store with Jetpack and WooCommerce Shipping & Tax'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async noThanks() {
|
|
||||||
// Click on "No thanks" button to move to the next step
|
|
||||||
const button = await getElementByText( 'button', 'No thanks' );
|
|
||||||
await button?.click();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { setCheckbox } from '@woocommerce/e2e-utils';
|
|
||||||
import { getElementByText, waitForElementByText } from '../../utils/actions';
|
|
||||||
|
|
||||||
export class IndustrySection {
|
|
||||||
page: Page;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
async isDisplayed( industryCount?: number ) {
|
|
||||||
await waitForElementByText(
|
|
||||||
'h2',
|
|
||||||
'In which industry does the store operate?'
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( industryCount ) {
|
|
||||||
const length = await this.page.$$eval(
|
|
||||||
'.components-checkbox-control__input',
|
|
||||||
( items ) => items.length
|
|
||||||
);
|
|
||||||
|
|
||||||
expect( length === industryCount ).toBeTruthy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async uncheckIndustries() {
|
|
||||||
const industryCheckboxes = await this.page.$$(
|
|
||||||
'.components-checkbox-control__input'
|
|
||||||
);
|
|
||||||
|
|
||||||
for ( const checkbox of industryCheckboxes ) {
|
|
||||||
const checkboxStatus = await (
|
|
||||||
await checkbox.getProperty( 'checked' )
|
|
||||||
).jsonValue();
|
|
||||||
if ( checkboxStatus === true ) {
|
|
||||||
await checkbox.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async selectIndustry( industryLabel: string ) {
|
|
||||||
const checkbox = await getElementByText( 'label', industryLabel );
|
|
||||||
await checkbox?.click();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { setCheckbox } from '@woocommerce/e2e-utils';
|
|
||||||
import { getElementByText, waitForElementByText } from '../../utils/actions';
|
|
||||||
|
|
||||||
export class ProductTypeSection {
|
|
||||||
page: Page;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
async isDisplayed( productCount: number ) {
|
|
||||||
await waitForElementByText(
|
|
||||||
'h2',
|
|
||||||
'What type of products will be listed?'
|
|
||||||
);
|
|
||||||
const length = await this.page.$$eval(
|
|
||||||
'.components-checkbox-control__input',
|
|
||||||
( items ) => items.length
|
|
||||||
);
|
|
||||||
expect( length === productCount ).toBeTruthy();
|
|
||||||
}
|
|
||||||
|
|
||||||
async uncheckProducts() {
|
|
||||||
const productCheckboxes = await this.page.$$(
|
|
||||||
'.components-checkbox-control__input'
|
|
||||||
);
|
|
||||||
|
|
||||||
for ( const checkbox of productCheckboxes ) {
|
|
||||||
const checkboxStatus = await (
|
|
||||||
await checkbox.getProperty( 'checked' )
|
|
||||||
).jsonValue();
|
|
||||||
if ( checkboxStatus === true ) {
|
|
||||||
await checkbox.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async selectProduct( productLabel: string ) {
|
|
||||||
const checkbox = await getElementByText( 'label', productLabel );
|
|
||||||
await checkbox?.click();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import {
|
|
||||||
setCheckbox,
|
|
||||||
clearAndFillInput,
|
|
||||||
verifyCheckboxIsSet,
|
|
||||||
verifyCheckboxIsUnset,
|
|
||||||
} from '@woocommerce/e2e-utils';
|
|
||||||
import { DropdownTypeaheadField } from '../DropdownTypeaheadField';
|
|
||||||
|
|
||||||
export class StoreDetailsSection {
|
|
||||||
page: Page;
|
|
||||||
countryDropdown: DropdownTypeaheadField;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
this.countryDropdown = new DropdownTypeaheadField(
|
|
||||||
page,
|
|
||||||
'#woocommerce-select-control'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fillAddress( address: string ) {
|
|
||||||
await clearAndFillInput( '#inspector-text-control-0', address );
|
|
||||||
}
|
|
||||||
|
|
||||||
async fillAddressLineTwo( address: string ) {
|
|
||||||
await clearAndFillInput( '#inspector-text-control-1', address );
|
|
||||||
}
|
|
||||||
|
|
||||||
async selectCountry( search: string, selector: string ) {
|
|
||||||
await this.countryDropdown.search( search );
|
|
||||||
await this.countryDropdown.select( selector );
|
|
||||||
}
|
|
||||||
|
|
||||||
async fillCity( city: string ) {
|
|
||||||
await clearAndFillInput( '#inspector-text-control-2', city );
|
|
||||||
}
|
|
||||||
|
|
||||||
async fillPostalCode( postalCode: string ) {
|
|
||||||
await clearAndFillInput( '#inspector-text-control-3', postalCode );
|
|
||||||
}
|
|
||||||
|
|
||||||
async selectSetupForClient() {
|
|
||||||
setCheckbox( '.components-checkbox-control__input' );
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkClientSetupCheckbox( selected: boolean ) {
|
|
||||||
if ( selected ) {
|
|
||||||
await verifyCheckboxIsSet( '.components-checkbox-control__input' );
|
|
||||||
} else {
|
|
||||||
await verifyCheckboxIsUnset(
|
|
||||||
'.components-checkbox-control__input'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { getElementByText, waitForElementByText } from '../../utils/actions';
|
|
||||||
|
|
||||||
export class ThemeSection {
|
|
||||||
page: Page;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
async isDisplayed() {
|
|
||||||
await waitForElementByText( 'h2', 'Choose a theme' );
|
|
||||||
await waitForElementByText( 'button', 'All themes' );
|
|
||||||
}
|
|
||||||
|
|
||||||
async continueWithActiveTheme() {
|
|
||||||
const button = await getElementByText(
|
|
||||||
'button',
|
|
||||||
'Continue with my active theme'
|
|
||||||
);
|
|
||||||
await button?.click();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class AllOrdersView extends BasePage {
|
||||||
|
url = 'wp-admin/edit.php?post_type=shop_order';
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export type AnalyticsSection =
|
||||||
|
| 'overview'
|
||||||
|
| 'products'
|
||||||
|
| 'revenue'
|
||||||
|
| 'orders'
|
||||||
|
| 'variations'
|
||||||
|
| 'categories'
|
||||||
|
| 'coupons'
|
||||||
|
| 'taxes'
|
||||||
|
| 'downloads'
|
||||||
|
| 'stock'
|
||||||
|
| 'settings';
|
||||||
|
|
||||||
|
export class Analytics extends BasePage {
|
||||||
|
// If you need to navigate to the base analytics page you can go to the overview
|
||||||
|
url = 'wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2Foverview';
|
||||||
|
|
||||||
|
// If you need to go to a specific single page of the analytics use `navigateToSection`
|
||||||
|
async navigateToSection( section: AnalyticsSection ) {
|
||||||
|
await this.goto( this.url.replace( 'overview', section ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
async isDisplayed() {
|
||||||
|
// This is a smoke test that ensures the single page was rendered without crashing
|
||||||
|
await this.page.waitForSelector( '#woocommerce-layout__primary' );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
import { ElementHandle, Page } from 'puppeteer';
|
||||||
|
import { DropdownField } from '../elements/DropdownField';
|
||||||
|
import { DropdownTypeaheadField } from '../elements/DropdownTypeaheadField';
|
||||||
|
import { FormToggle } from '../elements/FormToggle';
|
||||||
|
import { getElementByText } from '../utils/actions';
|
||||||
|
|
||||||
|
const config = require( 'config' );
|
||||||
|
const baseUrl = config.get( 'url' );
|
||||||
|
|
||||||
|
// Represents a page that can be navigated to
|
||||||
|
export abstract class BasePage {
|
||||||
|
protected page: Page;
|
||||||
|
protected url: string = '';
|
||||||
|
protected baseUrl: string = baseUrl;
|
||||||
|
|
||||||
|
// cache of elements that have been setup, note that they are unique "per page/per selector"
|
||||||
|
private dropDownElements: Record< string, DropdownField > = {};
|
||||||
|
private dropDownTypeAheadElements: Record<
|
||||||
|
string,
|
||||||
|
DropdownTypeaheadField
|
||||||
|
> = {};
|
||||||
|
private formToggleElements: Record< string, FormToggle > = {};
|
||||||
|
|
||||||
|
constructor( page: Page ) {
|
||||||
|
this.page = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDropdownField( selector: string ) {
|
||||||
|
if ( ! this.dropDownElements[ selector ] ) {
|
||||||
|
this.dropDownElements[ selector ] = new DropdownField(
|
||||||
|
page,
|
||||||
|
selector
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dropDownElements[ selector ];
|
||||||
|
}
|
||||||
|
|
||||||
|
getDropdownTypeahead( selector: string ) {
|
||||||
|
if ( ! this.dropDownTypeAheadElements[ selector ] ) {
|
||||||
|
this.dropDownTypeAheadElements[
|
||||||
|
selector
|
||||||
|
] = new DropdownTypeaheadField( page, selector );
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dropDownTypeAheadElements[ selector ];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormToggle( selector: string ) {
|
||||||
|
if ( ! this.formToggleElements[ selector ] ) {
|
||||||
|
this.formToggleElements[ selector ] = new FormToggle(
|
||||||
|
page,
|
||||||
|
selector
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.formToggleElements[ selector ];
|
||||||
|
}
|
||||||
|
|
||||||
|
async click( selector: string ) {
|
||||||
|
await this.page.waitForSelector( selector );
|
||||||
|
await this.page.click( selector );
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickButtonWithText( text: string ) {
|
||||||
|
const el = await getElementByText( 'button', text );
|
||||||
|
await el?.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async setCheckboxWithLabel( labelText: string ) {
|
||||||
|
const checkbox = await getElementByText( 'label', labelText );
|
||||||
|
|
||||||
|
if ( checkbox ) {
|
||||||
|
const checkboxStatus = await (
|
||||||
|
await checkbox.getProperty( 'checked' )
|
||||||
|
).jsonValue();
|
||||||
|
|
||||||
|
if ( checkboxStatus !== true ) {
|
||||||
|
await checkbox.click();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find checkbox with label "${ labelText }"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async unsetAllCheckboxes( selector: string ) {
|
||||||
|
const checkboxes = await page.$$( selector );
|
||||||
|
// Uncheck all checkboxes, to avoid installing plugins
|
||||||
|
for ( const checkbox of checkboxes ) {
|
||||||
|
await this.toggleCheckbox( checkbox, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async setAllCheckboxes( selector: string ) {
|
||||||
|
const checkboxes = await page.$$( selector );
|
||||||
|
// Uncheck all checkboxes, to avoid installing plugins
|
||||||
|
for ( const checkbox of checkboxes ) {
|
||||||
|
await this.toggleCheckbox( checkbox, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set or unset a checkbox based on `checked` value passed.
|
||||||
|
async toggleCheckbox(
|
||||||
|
checkbox: ElementHandle< Element >,
|
||||||
|
checked: boolean
|
||||||
|
) {
|
||||||
|
const checkboxStatus = await (
|
||||||
|
await checkbox.getProperty( 'checked' )
|
||||||
|
).jsonValue();
|
||||||
|
|
||||||
|
if ( checkboxStatus !== checked ) {
|
||||||
|
await checkbox.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async navigate() {
|
||||||
|
if ( ! this.url ) {
|
||||||
|
throw new Error( 'You must define a url for the page object' );
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.goto( this.url );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async goto( url: string ) {
|
||||||
|
const fullUrl = baseUrl + url;
|
||||||
|
try {
|
||||||
|
await this.page.goto( fullUrl, {
|
||||||
|
waitUntil: 'networkidle0',
|
||||||
|
} );
|
||||||
|
} catch ( e ) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not navigate to url: ${ fullUrl } with error: ${ e.message }`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class Dashboard extends BasePage {
|
||||||
|
url = 'wp-admin';
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { clearAndFillInput } from '@woocommerce/e2e-utils';
|
||||||
|
import { getElementByText } from '../utils/actions';
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
const config = require( 'config' );
|
||||||
|
|
||||||
|
export class Login extends BasePage {
|
||||||
|
url = 'wp-login.php';
|
||||||
|
|
||||||
|
async login() {
|
||||||
|
await this.navigate();
|
||||||
|
|
||||||
|
await getElementByText( 'label', 'Username or Email Address' );
|
||||||
|
await expect( this.page.title() ).resolves.toMatch( 'Log In' );
|
||||||
|
|
||||||
|
await clearAndFillInput( '#user_login', ' ' );
|
||||||
|
|
||||||
|
await this.page.type(
|
||||||
|
'#user_login',
|
||||||
|
config.get( 'users.admin.username' )
|
||||||
|
);
|
||||||
|
await this.page.type(
|
||||||
|
'#user_pass',
|
||||||
|
config.get( 'users.admin.password' )
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all( [
|
||||||
|
this.page.click( 'input[type=submit]' ),
|
||||||
|
this.page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||||
|
] );
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout() {
|
||||||
|
// Log out link in admin bar is not visible so can't be clicked directly.
|
||||||
|
const logoutLinks = await this.page.$$eval(
|
||||||
|
'#wp-admin-bar-logout a',
|
||||||
|
( am ) =>
|
||||||
|
am
|
||||||
|
.filter( ( e ) => ( e as HTMLLinkElement ).href )
|
||||||
|
.map( ( e ) => ( e as HTMLLinkElement ).href )
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.goto( logoutLinks[ 0 ], {
|
||||||
|
waitUntil: 'networkidle0',
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class NewCoupon extends BasePage {
|
||||||
|
url = 'wp-admin/post-new.php?post_type=shop_coupon';
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class NewOrder extends BasePage {
|
||||||
|
url = 'wp-admin/post-new.php?post_type=shop_order';
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class NewProduct extends BasePage {
|
||||||
|
url = 'wp-admin/post-new.php?post_type=product';
|
||||||
|
}
|
|
@ -1,15 +1,15 @@
|
||||||
import { Page } from 'puppeteer';
|
import { Page } from 'puppeteer';
|
||||||
import { getElementByText } from '../utils/actions';
|
import { BenefitsSection } from '../sections/onboarding/BenefitsSection';
|
||||||
import { WP_ADMIN_START_PROFILE_WIZARD } from '../utils/constants';
|
import { BusinessSection } from '../sections/onboarding/BusinessSection';
|
||||||
import { BenefitsSection } from './onboarding/BenefitsSection';
|
import { IndustrySection } from '../sections/onboarding/IndustrySection';
|
||||||
import { BusinessSection } from './onboarding/BusinessSection';
|
import { ProductTypeSection } from '../sections/onboarding/ProductTypesSection';
|
||||||
import { IndustrySection } from './onboarding/IndustrySection';
|
import { StoreDetailsSection } from '../sections/onboarding/StoreDetailsSection';
|
||||||
import { ProductTypeSection } from './onboarding/ProductTypesSection';
|
import { ThemeSection } from '../sections/onboarding/ThemeSection';
|
||||||
import { StoreDetailsSection } from './onboarding/StoreDetailsSection';
|
import { BasePage } from './BasePage';
|
||||||
import { ThemeSection } from './onboarding/ThemeSection';
|
|
||||||
|
export class OnboardingWizard extends BasePage {
|
||||||
|
url = 'wp-admin/admin.php?page=wc-admin&path=/setup-wizard';
|
||||||
|
|
||||||
export class OnboardingWizard {
|
|
||||||
page: Page;
|
|
||||||
storeDetails: StoreDetailsSection;
|
storeDetails: StoreDetailsSection;
|
||||||
industry: IndustrySection;
|
industry: IndustrySection;
|
||||||
productTypes: ProductTypeSection;
|
productTypes: ProductTypeSection;
|
||||||
|
@ -18,7 +18,7 @@ export class OnboardingWizard {
|
||||||
benefits: BenefitsSection;
|
benefits: BenefitsSection;
|
||||||
|
|
||||||
constructor( page: Page ) {
|
constructor( page: Page ) {
|
||||||
this.page = page;
|
super( page );
|
||||||
this.storeDetails = new StoreDetailsSection( page );
|
this.storeDetails = new StoreDetailsSection( page );
|
||||||
this.industry = new IndustrySection( page );
|
this.industry = new IndustrySection( page );
|
||||||
this.productTypes = new ProductTypeSection( page );
|
this.productTypes = new ProductTypeSection( page );
|
||||||
|
@ -27,22 +27,20 @@ export class OnboardingWizard {
|
||||||
this.benefits = new BenefitsSection( page );
|
this.benefits = new BenefitsSection( page );
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async skipStoreSetup() {
|
||||||
await this.page.goto( WP_ADMIN_START_PROFILE_WIZARD, {
|
await this.clickButtonWithText( 'Skip setup store details' );
|
||||||
waitUntil: 'networkidle0',
|
await this.optionallySelectUsageTracking( false );
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async continue() {
|
async continue() {
|
||||||
const button = await getElementByText( 'button', 'Continue' );
|
await this.clickButtonWithText( 'Continue' );
|
||||||
await button?.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async optionallySelectUsageTracking( select = false ) {
|
async optionallySelectUsageTracking( select = false ) {
|
||||||
const usageTrackingHeader = await this.page.waitForSelector(
|
const usageTrackingHeader = await this.page.waitForSelector(
|
||||||
'.components-modal__header-heading',
|
'.components-modal__header-heading',
|
||||||
{
|
{
|
||||||
timeout: 2000,
|
timeout: 5000,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( ! usageTrackingHeader ) {
|
if ( ! usageTrackingHeader ) {
|
||||||
|
@ -60,15 +58,11 @@ export class OnboardingWizard {
|
||||||
expect( primaryButtons ).toHaveLength( 2 );
|
expect( primaryButtons ).toHaveLength( 2 );
|
||||||
|
|
||||||
if ( select ) {
|
if ( select ) {
|
||||||
const button = await getElementByText(
|
await this.clickButtonWithText( 'Yes, count me in' );
|
||||||
'button',
|
|
||||||
'Yes, count me in'
|
|
||||||
);
|
|
||||||
await button?.click();
|
|
||||||
} else {
|
} else {
|
||||||
const button = await getElementByText( 'button', 'No thanks' );
|
await this.clickButtonWithText( 'No thanks' );
|
||||||
await button?.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.page.waitForNavigation( {
|
this.page.waitForNavigation( {
|
||||||
waitUntil: 'networkidle0',
|
waitUntil: 'networkidle0',
|
||||||
timeout: 2000,
|
timeout: 2000,
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { waitForElementByText } from '../utils/actions';
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
type PaymentMethodWithSetupButton =
|
||||||
|
| 'wcpay'
|
||||||
|
| 'stripe'
|
||||||
|
| 'paypal'
|
||||||
|
| 'klarna_payments'
|
||||||
|
| 'mollie'
|
||||||
|
| 'bacs';
|
||||||
|
|
||||||
|
type PaymentMethod = PaymentMethodWithSetupButton | 'cod';
|
||||||
|
|
||||||
|
export class PaymentsSetup extends BasePage {
|
||||||
|
url = 'wp-admin/admin.php?page=wc-admin&task=payments';
|
||||||
|
|
||||||
|
async isDisplayed() {
|
||||||
|
await waitForElementByText( 'h1', 'Choose payment methods' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async closeHelpModal() {
|
||||||
|
await this.clickButtonWithText( 'Got it' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async goToPaymentMethodSetup( method: PaymentMethodWithSetupButton ) {
|
||||||
|
const selector = `.woocommerce-task-payment-${ method } button`;
|
||||||
|
const button = await this.page.$( selector );
|
||||||
|
|
||||||
|
if ( ! button ) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find button with selector: ${ selector }`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await button.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async methodHasBeenSetup( method: PaymentMethod ) {
|
||||||
|
const toggle = this.getFormToggle(
|
||||||
|
`.woocommerce-task-payment-${ method }`
|
||||||
|
);
|
||||||
|
|
||||||
|
await toggle.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
async enableCashOnDelivery() {
|
||||||
|
const toggle = this.getFormToggle( '.woocommerce-task-payment-cod' );
|
||||||
|
await toggle.switchOn();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class PermalinkSettings extends BasePage {
|
||||||
|
url = 'wp-admin/options-permalink.php';
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class Plugins extends BasePage {
|
||||||
|
url = 'wp-admin/plugins.php';
|
||||||
|
}
|
|
@ -1,12 +1,8 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { getElementByText, waitForElementByText } from '../utils/actions';
|
import { getElementByText, waitForElementByText } from '../utils/actions';
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
export class WcHomescreen {
|
export class WcHomescreen extends BasePage {
|
||||||
page: Page;
|
url = 'wp-admin/admin.php?page=wc-admin';
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
}
|
|
||||||
|
|
||||||
async isDisplayed() {
|
async isDisplayed() {
|
||||||
// Wait for Benefits section to appear
|
// Wait for Benefits section to appear
|
||||||
|
@ -21,16 +17,13 @@ export class WcHomescreen {
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( modal ) {
|
if ( modal ) {
|
||||||
let button = await getElementByText( 'button', 'Next' );
|
await this.clickButtonWithText( 'Next' );
|
||||||
await button?.click();
|
await this.clickButtonWithText( 'Next' );
|
||||||
button = await getElementByText( 'button', 'Next' );
|
await this.click( '.components-guide__finish-button' );
|
||||||
await button?.click();
|
|
||||||
await this.page.click( '.components-guide__finish-button' );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTaskList() {
|
async getTaskList() {
|
||||||
// Log out link in admin bar is not visible so can't be clicked directly.
|
|
||||||
await page.waitForSelector(
|
await page.waitForSelector(
|
||||||
'.woocommerce-task-card .woocommerce-list__item-title'
|
'.woocommerce-task-card .woocommerce-list__item-title'
|
||||||
);
|
);
|
||||||
|
@ -49,8 +42,15 @@ export class WcHomescreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
async clickOnTaskList( taskTitle: string ) {
|
async clickOnTaskList( taskTitle: string ) {
|
||||||
const item = await getElementByText( 'div', taskTitle );
|
const item = await waitForElementByText( 'div', taskTitle );
|
||||||
await item?.click();
|
|
||||||
|
if ( ! item ) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find task list item with title: ${ taskTitle }`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await item.click();
|
||||||
await waitForElementByText( 'h1', taskTitle );
|
await waitForElementByText( 'h1', taskTitle );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,29 +1,18 @@
|
||||||
import { setCheckbox } from '@woocommerce/e2e-utils';
|
import { setCheckbox } from '@woocommerce/e2e-utils';
|
||||||
import { WP_ADMIN_WC_SETTINGS } from '../utils/constants';
|
import { getAttribute, waitForElementByText } from '../utils/actions';
|
||||||
import { Page } from 'puppeteer';
|
import { BasePage } from './BasePage';
|
||||||
import {
|
|
||||||
getAttribute,
|
|
||||||
getElementByText,
|
|
||||||
waitForElementByText,
|
|
||||||
} from '../utils/actions';
|
|
||||||
|
|
||||||
export class WcSettings {
|
export class WcSettings extends BasePage {
|
||||||
page: Page;
|
url = 'wp-admin/admin.php?page=wc-settings';
|
||||||
|
|
||||||
constructor( page: Page ) {
|
async navigate( tab = 'general', section = '' ) {
|
||||||
this.page = page;
|
let settingsUrl = this.url + `&tab=${ tab }`;
|
||||||
}
|
|
||||||
|
|
||||||
async open( tab = 'general', section = '' ) {
|
|
||||||
let settingsUrl = WP_ADMIN_WC_SETTINGS + tab;
|
|
||||||
|
|
||||||
if ( section ) {
|
if ( section ) {
|
||||||
settingsUrl += `§ion=${ section }`;
|
settingsUrl += `§ion=${ section }`;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.page.goto( settingsUrl, {
|
await this.goto( settingsUrl );
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
await waitForElementByText( 'a', 'General' );
|
await waitForElementByText( 'a', 'General' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +26,7 @@ export class WcSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
const button = await getElementByText( 'button', 'Save changes' );
|
this.clickButtonWithText( 'Save changes' );
|
||||||
await button?.click();
|
|
||||||
await this.page.waitForNavigation( {
|
await this.page.waitForNavigation( {
|
||||||
waitUntil: 'networkidle0',
|
waitUntil: 'networkidle0',
|
||||||
} );
|
} );
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { waitForElementByText } from '../utils/actions';
|
||||||
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
|
export class WpSettings extends BasePage {
|
||||||
|
url = 'wp-admin/options-permalink.php';
|
||||||
|
|
||||||
|
async openPermalinkSettings() {
|
||||||
|
await waitForElementByText( 'h1', 'Permalink Settings' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveSettings() {
|
||||||
|
await this.click( '#submit' );
|
||||||
|
await this.page.waitForNavigation( {
|
||||||
|
waitUntil: 'networkidle0',
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { BasePage } from '../../pages/BasePage';
|
||||||
|
import { waitForElementByText } from '../../utils/actions';
|
||||||
|
|
||||||
|
export class BenefitsSection extends BasePage {
|
||||||
|
async isDisplayed() {
|
||||||
|
await waitForElementByText(
|
||||||
|
'h2',
|
||||||
|
'Enhance your store with Jetpack and WooCommerce Shipping & Tax'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async noThanks() {
|
||||||
|
// Click on "No thanks" button to move to the next step
|
||||||
|
await this.clickButtonWithText( 'No thanks' );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,8 @@
|
||||||
import { Page } from 'puppeteer';
|
|
||||||
import { setCheckbox, unsetCheckbox } from '@woocommerce/e2e-utils';
|
import { setCheckbox, unsetCheckbox } from '@woocommerce/e2e-utils';
|
||||||
import { DropdownField } from '../DropdownField';
|
import { BasePage } from '../../pages/BasePage';
|
||||||
import { waitForElementByText } from '../../utils/actions';
|
import { waitForElementByText } from '../../utils/actions';
|
||||||
|
|
||||||
export class BusinessSection {
|
export class BusinessSection extends BasePage {
|
||||||
page: Page;
|
|
||||||
howManyProductsDropdown: DropdownField;
|
|
||||||
sellingElsewhereDropdown: DropdownField;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
|
||||||
this.page = page;
|
|
||||||
this.howManyProductsDropdown = new DropdownField(
|
|
||||||
page,
|
|
||||||
'.components-card__body > div:nth-child(1)'
|
|
||||||
);
|
|
||||||
this.sellingElsewhereDropdown = new DropdownField(
|
|
||||||
page,
|
|
||||||
'.components-card__body > div:nth-child(2)'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async isDisplayed() {
|
async isDisplayed() {
|
||||||
await waitForElementByText( 'h2', 'Tell us about your business' );
|
await waitForElementByText( 'h2', 'Tell us about your business' );
|
||||||
}
|
}
|
||||||
|
@ -29,11 +12,19 @@ export class BusinessSection {
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectProductNumber( productLabel: string ) {
|
async selectProductNumber( productLabel: string ) {
|
||||||
await this.howManyProductsDropdown.select( productLabel );
|
const howManyProductsDropdown = this.getDropdownField(
|
||||||
|
'.components-card__body > div:nth-child(1)'
|
||||||
|
);
|
||||||
|
|
||||||
|
await howManyProductsDropdown.select( productLabel );
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectCurrentlySelling( currentlySelling: string ) {
|
async selectCurrentlySelling( currentlySelling: string ) {
|
||||||
await this.sellingElsewhereDropdown.select( currentlySelling );
|
const sellingElsewhereDropdown = this.getDropdownField(
|
||||||
|
'.components-card__body > div:nth-child(2)'
|
||||||
|
);
|
||||||
|
|
||||||
|
await sellingElsewhereDropdown.select( currentlySelling );
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectInstallFreeBusinessFeatures( select: boolean ) {
|
async selectInstallFreeBusinessFeatures( select: boolean ) {
|
||||||
|
@ -47,8 +38,8 @@ export class BusinessSection {
|
||||||
async expandRecommendedBusinessFeatures() {
|
async expandRecommendedBusinessFeatures() {
|
||||||
const expandButtonSelector =
|
const expandButtonSelector =
|
||||||
'.woocommerce-admin__business-details__selective-extensions-bundle__expand';
|
'.woocommerce-admin__business-details__selective-extensions-bundle__expand';
|
||||||
await this.page.waitForSelector( expandButtonSelector );
|
|
||||||
await this.page.click( expandButtonSelector );
|
await this.click( expandButtonSelector );
|
||||||
|
|
||||||
// Confirm that expanding the list shows all the extensions available to install.
|
// Confirm that expanding the list shows all the extensions available to install.
|
||||||
await this.page.waitForFunction( () => {
|
await this.page.waitForFunction( () => {
|
||||||
|
@ -60,35 +51,13 @@ export class BusinessSection {
|
||||||
}
|
}
|
||||||
|
|
||||||
async uncheckAllRecommendedBusinessFeatures() {
|
async uncheckAllRecommendedBusinessFeatures() {
|
||||||
const allCheckboxes = await this.page.$$(
|
await this.unsetAllCheckboxes( '.components-checkbox-control__input' );
|
||||||
'.components-checkbox-control__input'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Uncheck all checkboxes, to avoid installing plugins
|
|
||||||
for ( const checkbox of allCheckboxes ) {
|
|
||||||
const checkboxStatus = await (
|
|
||||||
await checkbox.getProperty( 'checked' )
|
|
||||||
).jsonValue();
|
|
||||||
if ( checkboxStatus === true ) {
|
|
||||||
await checkbox.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The old list displayed on the dropdown page
|
// The old list displayed on the dropdown page
|
||||||
async uncheckBusinessFeatures() {
|
async uncheckBusinessFeatures() {
|
||||||
// checkbox is present, uncheck it.
|
await this.unsetAllCheckboxes(
|
||||||
const installFeaturesCheckboxes = await page.$$(
|
|
||||||
'.woocommerce-profile-wizard__benefit .components-form-toggle__input'
|
'.woocommerce-profile-wizard__benefit .components-form-toggle__input'
|
||||||
);
|
);
|
||||||
// Uncheck all checkboxes, to avoid installing plugins
|
|
||||||
for ( const checkbox of installFeaturesCheckboxes ) {
|
|
||||||
const checkboxStatus = await (
|
|
||||||
await checkbox.getProperty( 'checked' )
|
|
||||||
).jsonValue();
|
|
||||||
if ( checkboxStatus === true ) {
|
|
||||||
await checkbox.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { BasePage } from '../../pages/BasePage';
|
||||||
|
import { waitForElementByText } from '../../utils/actions';
|
||||||
|
|
||||||
|
export class IndustrySection extends BasePage {
|
||||||
|
async isDisplayed( industryCount?: number ) {
|
||||||
|
await waitForElementByText(
|
||||||
|
'h2',
|
||||||
|
'In which industry does the store operate?'
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( industryCount ) {
|
||||||
|
const length = await this.page.$$eval(
|
||||||
|
'.components-checkbox-control__input',
|
||||||
|
( items ) => items.length
|
||||||
|
);
|
||||||
|
|
||||||
|
expect( length === industryCount ).toBeTruthy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async uncheckIndustries() {
|
||||||
|
await this.unsetAllCheckboxes( '.components-checkbox-control__input' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectIndustry( industryLabel: string ) {
|
||||||
|
await this.setCheckboxWithLabel( industryLabel );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { BasePage } from '../../pages/BasePage';
|
||||||
|
import { waitForElementByText } from '../../utils/actions';
|
||||||
|
|
||||||
|
export class ProductTypeSection extends BasePage {
|
||||||
|
async isDisplayed( productCount: number ) {
|
||||||
|
await waitForElementByText(
|
||||||
|
'h2',
|
||||||
|
'What type of products will be listed?'
|
||||||
|
);
|
||||||
|
const length = await this.page.$$eval(
|
||||||
|
'.components-checkbox-control__input',
|
||||||
|
( items ) => items.length
|
||||||
|
);
|
||||||
|
expect( length === productCount ).toBeTruthy();
|
||||||
|
}
|
||||||
|
|
||||||
|
async uncheckProducts() {
|
||||||
|
await this.unsetAllCheckboxes( '.components-checkbox-control__input' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectProduct( productLabel: string ) {
|
||||||
|
await this.setCheckboxWithLabel( productLabel );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
import {
|
||||||
|
setCheckbox,
|
||||||
|
clearAndFillInput,
|
||||||
|
verifyCheckboxIsSet,
|
||||||
|
verifyCheckboxIsUnset,
|
||||||
|
} from '@woocommerce/e2e-utils';
|
||||||
|
import { DropdownTypeaheadField } from '../../elements/DropdownTypeaheadField';
|
||||||
|
import { BasePage } from '../../pages/BasePage';
|
||||||
|
const config = require( 'config' );
|
||||||
|
|
||||||
|
interface StoreDetails {
|
||||||
|
addressLine1?: string;
|
||||||
|
addressLine2?: string;
|
||||||
|
countryRegionSubstring?: string;
|
||||||
|
countryRegionSelector?: string;
|
||||||
|
countryRegion?: string;
|
||||||
|
city?: string;
|
||||||
|
postcode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StoreDetailsSection extends BasePage {
|
||||||
|
private get countryDropdown(): DropdownTypeaheadField {
|
||||||
|
return this.getDropdownTypeahead( '#woocommerce-select-control' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async completeStoreDetailsSection( storeDetails: StoreDetails = {} ) {
|
||||||
|
// const onboardingWizard = new OnboardingWizard( page );
|
||||||
|
// Fill store's address - first line
|
||||||
|
await this.fillAddress(
|
||||||
|
storeDetails.addressLine1 ||
|
||||||
|
config.get( 'addresses.admin.store.addressfirstline' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fill store's address - second line
|
||||||
|
await this.fillAddressLineTwo(
|
||||||
|
storeDetails.addressLine2 ||
|
||||||
|
config.get( 'addresses.admin.store.addresssecondline' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Type the requested country/region substring or 'cali' in the
|
||||||
|
// country/region select, then select the requested country/region
|
||||||
|
// substring or 'US:CA'.
|
||||||
|
await this.selectCountry(
|
||||||
|
storeDetails.countryRegionSubstring || 'cali',
|
||||||
|
storeDetails.countryRegionSelector || 'US\\:CA'
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( storeDetails.countryRegion ) {
|
||||||
|
await this.checkCountrySelected( storeDetails.countryRegion );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the city where the store is located
|
||||||
|
await this.fillCity(
|
||||||
|
storeDetails.city || config.get( 'addresses.admin.store.city' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fill postcode of the store
|
||||||
|
await this.fillPostalCode(
|
||||||
|
storeDetails.postcode ||
|
||||||
|
config.get( 'addresses.admin.store.postcode' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that checkbox next to "I'm setting up a store for a client" is not selected
|
||||||
|
await this.checkClientSetupCheckbox( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
async fillAddress( address: string ) {
|
||||||
|
await clearAndFillInput( '#inspector-text-control-0', address );
|
||||||
|
}
|
||||||
|
|
||||||
|
async fillAddressLineTwo( address: string ) {
|
||||||
|
await clearAndFillInput( '#inspector-text-control-1', address );
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectCountry( search: string, selector: string ) {
|
||||||
|
await this.countryDropdown.search( search );
|
||||||
|
await this.countryDropdown.select( selector );
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkCountrySelected( country: string ) {
|
||||||
|
await this.countryDropdown.checkSelected( country );
|
||||||
|
}
|
||||||
|
|
||||||
|
async fillCity( city: string ) {
|
||||||
|
await clearAndFillInput( '#inspector-text-control-2', city );
|
||||||
|
}
|
||||||
|
|
||||||
|
async fillPostalCode( postalCode: string ) {
|
||||||
|
await clearAndFillInput( '#inspector-text-control-3', postalCode );
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectSetupForClient() {
|
||||||
|
setCheckbox( '.components-checkbox-control__input' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkClientSetupCheckbox( selected: boolean ) {
|
||||||
|
if ( selected ) {
|
||||||
|
await verifyCheckboxIsSet( '.components-checkbox-control__input' );
|
||||||
|
} else {
|
||||||
|
await verifyCheckboxIsUnset(
|
||||||
|
'.components-checkbox-control__input'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { BasePage } from '../../pages/BasePage';
|
||||||
|
import { waitForElementByText } from '../../utils/actions';
|
||||||
|
|
||||||
|
export class ThemeSection extends BasePage {
|
||||||
|
async isDisplayed() {
|
||||||
|
await waitForElementByText( 'h2', 'Choose a theme' );
|
||||||
|
await waitForElementByText( 'button', 'All themes' );
|
||||||
|
}
|
||||||
|
|
||||||
|
async continueWithActiveTheme() {
|
||||||
|
await this.clickButtonWithText( 'Continue with my active theme' );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { clearAndFillInput } from '@woocommerce/e2e-utils';
|
||||||
|
import { BasePage } from '../../pages/BasePage';
|
||||||
|
|
||||||
|
type AccountDetails = {
|
||||||
|
accountName: string;
|
||||||
|
accountNumber: string;
|
||||||
|
bankName: string;
|
||||||
|
sortCode: string;
|
||||||
|
iban: string;
|
||||||
|
swiftCode: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class BankAccountTransferSetup extends BasePage {
|
||||||
|
url = 'wp-admin/admin.php?page=wc-admin&task=payments&method=bacs';
|
||||||
|
|
||||||
|
async saveAccountDetails( {
|
||||||
|
accountName,
|
||||||
|
accountNumber,
|
||||||
|
bankName,
|
||||||
|
sortCode,
|
||||||
|
iban,
|
||||||
|
swiftCode,
|
||||||
|
}: AccountDetails ) {
|
||||||
|
await clearAndFillInput( '[placeholder="Account name"]', accountName );
|
||||||
|
await clearAndFillInput(
|
||||||
|
'[placeholder="Account number"]',
|
||||||
|
accountNumber
|
||||||
|
);
|
||||||
|
await clearAndFillInput( '[placeholder="Bank name"]', bankName );
|
||||||
|
await clearAndFillInput( '[placeholder="Sort code"]', sortCode );
|
||||||
|
await clearAndFillInput( '[placeholder="IBAN"]', iban );
|
||||||
|
await clearAndFillInput( '[placeholder="BIC / Swift"]', swiftCode );
|
||||||
|
|
||||||
|
await this.clickButtonWithText( 'Save' );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* @format
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
clearAndFillInput,
|
clearAndFillInput,
|
||||||
|
@ -9,39 +9,26 @@ import {
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { StoreOwnerFlow } from '../../utils/flows';
|
import { WcSettings } from '../../pages/WcSettings';
|
||||||
import { WcSettings } from '../../models/WcSettings';
|
import { WpSettings } from '../../pages/WpSettings';
|
||||||
import { WpSettings } from '../../models/WpSettings';
|
import { Login } from '../../pages/Login';
|
||||||
|
|
||||||
describe( 'Store owner can login and make sure WooCommerce is activated', () => {
|
|
||||||
it( 'can login', async () => {
|
|
||||||
await StoreOwnerFlow.login();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'can make sure WooCommerce is activated. If not, activate it', async () => {
|
|
||||||
const slug = 'woocommerce';
|
|
||||||
await StoreOwnerFlow.openPlugins();
|
|
||||||
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` );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
describe( 'Store owner can finish initial store setup', () => {
|
describe( 'Store owner can finish initial store setup', () => {
|
||||||
it( 'can enable tax rates and calculations', async () => {
|
|
||||||
const wcSettings = new WcSettings( page );
|
const wcSettings = new WcSettings( page );
|
||||||
|
const wpSettings = new WpSettings( page );
|
||||||
|
const login = new Login( page );
|
||||||
|
|
||||||
|
beforeAll( async () => {
|
||||||
|
await login.login();
|
||||||
|
} );
|
||||||
|
afterAll( async () => {
|
||||||
|
await login.logout();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can enable tax rates and calculations', async () => {
|
||||||
// Go to general settings page
|
// Go to general settings page
|
||||||
await wcSettings.open();
|
await wcSettings.navigate( 'general' );
|
||||||
|
|
||||||
await wcSettings.enableTaxRates();
|
await wcSettings.enableTaxRates();
|
||||||
|
|
||||||
await wcSettings.saveSettings();
|
await wcSettings.saveSettings();
|
||||||
|
|
||||||
// Verify that settings have been saved
|
// Verify that settings have been saved
|
||||||
|
@ -50,8 +37,8 @@ describe( 'Store owner can finish initial store setup', () => {
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'can configure permalink settings', async () => {
|
it( 'can configure permalink settings', async () => {
|
||||||
const wpSettings = new WpSettings( page );
|
|
||||||
// Go to Permalink Settings page
|
// Go to Permalink Settings page
|
||||||
|
await wpSettings.navigate();
|
||||||
await wpSettings.openPermalinkSettings();
|
await wpSettings.openPermalinkSettings();
|
||||||
|
|
||||||
// Select "Post name" option in common settings section
|
// Select "Post name" option in common settings section
|
|
@ -1,37 +0,0 @@
|
||||||
/**
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { OnboardingWizard } from '../../models/OnboardingWizard';
|
|
||||||
const config = require( 'config' );
|
|
||||||
|
|
||||||
export async function completeBusinessSection() {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
await onboarding.business.isDisplayed();
|
|
||||||
|
|
||||||
await onboarding.business.selectProductNumber(
|
|
||||||
config.get( 'onboardingwizard.numberofproducts' )
|
|
||||||
);
|
|
||||||
await onboarding.business.selectCurrentlySelling(
|
|
||||||
config.get( 'onboardingwizard.sellingelsewhere' )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Site is in US so the "Install recommended free business features"
|
|
||||||
await onboarding.business.uncheckBusinessFeatures();
|
|
||||||
|
|
||||||
await onboarding.continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function completeSelectiveBundleInstallBusinessDetailsTab() {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
await onboarding.business.isDisplayed();
|
|
||||||
|
|
||||||
await onboarding.business.selectProductNumber(
|
|
||||||
config.get( 'onboardingwizard.numberofproducts' )
|
|
||||||
);
|
|
||||||
await onboarding.business.selectCurrentlySelling(
|
|
||||||
config.get( 'onboardingwizard.sellingelsewhere' )
|
|
||||||
);
|
|
||||||
|
|
||||||
await onboarding.continue();
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/**
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { OnboardingWizard } from '../../models/OnboardingWizard';
|
|
||||||
|
|
||||||
export async function completeIndustrySection( expectedIndustryCount = 8 ) {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
// Query for the industries checkboxes
|
|
||||||
await onboarding.industry.isDisplayed( expectedIndustryCount );
|
|
||||||
|
|
||||||
await onboarding.industry.uncheckIndustries();
|
|
||||||
|
|
||||||
// Select just "fashion" and "health/beauty" to get the single checkbox business section when
|
|
||||||
// filling out details for a US store.
|
|
||||||
await onboarding.industry.selectIndustry(
|
|
||||||
'Fashion, apparel, and accessories'
|
|
||||||
);
|
|
||||||
|
|
||||||
await onboarding.industry.selectIndustry( 'Health and beauty' );
|
|
||||||
|
|
||||||
await onboarding.continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check industry checkboxes based on industryLabels passed in. Note each label must match
|
|
||||||
// the text contents of the label.
|
|
||||||
export async function chooseIndustries( industryLabels: string[] = [] ) {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
// Query for the industries checkboxes
|
|
||||||
await onboarding.industry.isDisplayed();
|
|
||||||
|
|
||||||
await onboarding.industry.uncheckIndustries();
|
|
||||||
|
|
||||||
for ( const labelText of industryLabels ) {
|
|
||||||
await onboarding.industry.selectIndustry( labelText );
|
|
||||||
}
|
|
||||||
|
|
||||||
await onboarding.continue();
|
|
||||||
}
|
|
|
@ -1,76 +1,152 @@
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { StoreOwnerFlow } from '../../utils/flows';
|
import { OnboardingWizard } from '../../pages/OnboardingWizard';
|
||||||
import { completeStoreDetailsSection } from './complete-store-details-section';
|
import { WcHomescreen } from '../../pages/WcHomescreen';
|
||||||
import {
|
|
||||||
chooseIndustries,
|
|
||||||
completeIndustrySection,
|
|
||||||
} from './complete-industry-section';
|
|
||||||
import { completeProductTypesSection } from './complete-product-types-section';
|
|
||||||
import {
|
|
||||||
completeBusinessSection,
|
|
||||||
completeSelectiveBundleInstallBusinessDetailsTab,
|
|
||||||
} from './complete-business-section';
|
|
||||||
import { completeThemeSelectionSection } from './complete-theme-selection-section';
|
|
||||||
import { OnboardingWizard } from '../../models/OnboardingWizard';
|
|
||||||
import { WcHomescreen } from '../../models/WcHomescreen';
|
|
||||||
import { TaskTitles } from '../../constants/taskTitles';
|
import { TaskTitles } from '../../constants/taskTitles';
|
||||||
import { getElementByText } from '../../utils/actions';
|
import { getElementByText } from '../../utils/actions';
|
||||||
|
import { Login } from '../../pages/Login';
|
||||||
|
|
||||||
|
const config = require( 'config' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tests a default, happy path for the onboarding wizard.
|
* This tests a default, happy path for the onboarding wizard.
|
||||||
*/
|
*/
|
||||||
describe( 'Store owner can complete onboarding wizard', () => {
|
describe( 'Store owner can complete onboarding wizard', () => {
|
||||||
it( 'can log in', StoreOwnerFlow.login );
|
const profileWizard = new OnboardingWizard( page );
|
||||||
it( 'can start the profile wizard', StoreOwnerFlow.startProfileWizard );
|
const login = new Login( page );
|
||||||
it( 'can complete the store details section', async () =>
|
|
||||||
await completeStoreDetailsSection() );
|
|
||||||
it( 'can complete the industry section', async () =>
|
|
||||||
await completeIndustrySection() );
|
|
||||||
it( 'can complete the product types section', async () =>
|
|
||||||
await completeProductTypesSection() );
|
|
||||||
it( 'can complete the business section', async () =>
|
|
||||||
await completeSelectiveBundleInstallBusinessDetailsTab() );
|
|
||||||
it( 'can unselect all business features and contine', async () => {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
|
|
||||||
await onboarding.business.freeFeaturesIsDisplayed();
|
beforeAll( async () => {
|
||||||
|
await login.login();
|
||||||
|
} );
|
||||||
|
afterAll( async () => {
|
||||||
|
await login.logout();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can start the profile wizard', async () => {
|
||||||
|
await profileWizard.navigate();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the store details section', async () => {
|
||||||
|
await profileWizard.storeDetails.completeStoreDetailsSection();
|
||||||
|
// Wait for "Continue" button to become active
|
||||||
|
await profileWizard.continue();
|
||||||
|
|
||||||
|
// Wait for usage tracking pop-up window to appear
|
||||||
|
await profileWizard.optionallySelectUsageTracking();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the industry section', async () => {
|
||||||
|
// Query for the industries checkboxes
|
||||||
|
await profileWizard.industry.isDisplayed( 8 );
|
||||||
|
await profileWizard.industry.uncheckIndustries();
|
||||||
|
|
||||||
|
// Select just "fashion" and "health/beauty" to get the single checkbox business section when
|
||||||
|
// filling out details for a US store.
|
||||||
|
await profileWizard.industry.selectIndustry(
|
||||||
|
'Fashion, apparel, and accessories'
|
||||||
|
);
|
||||||
|
await profileWizard.industry.selectIndustry( 'Health and beauty' );
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the product types section', async () => {
|
||||||
|
await profileWizard.productTypes.isDisplayed( 7 );
|
||||||
|
await profileWizard.productTypes.uncheckProducts();
|
||||||
|
|
||||||
|
// Select Physical and Downloadable products
|
||||||
|
await profileWizard.productTypes.selectProduct( 'Physical products' );
|
||||||
|
await profileWizard.productTypes.selectProduct( 'Downloads' );
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the business section', async () => {
|
||||||
|
await profileWizard.business.isDisplayed();
|
||||||
|
await profileWizard.business.selectProductNumber(
|
||||||
|
config.get( 'onboardingwizard.numberofproducts' )
|
||||||
|
);
|
||||||
|
await profileWizard.business.selectCurrentlySelling(
|
||||||
|
config.get( 'onboardingwizard.sellingelsewhere' )
|
||||||
|
);
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can unselect all business features and continue', async () => {
|
||||||
|
await profileWizard.business.freeFeaturesIsDisplayed();
|
||||||
// Add WC Pay check
|
// Add WC Pay check
|
||||||
await onboarding.business.expandRecommendedBusinessFeatures();
|
await profileWizard.business.expandRecommendedBusinessFeatures();
|
||||||
|
|
||||||
expect( page ).toMatchElement( 'a', {
|
expect( page ).toMatchElement( 'a', {
|
||||||
text: 'WooCommerce Payments',
|
text: 'WooCommerce Payments',
|
||||||
} );
|
} );
|
||||||
|
|
||||||
await onboarding.business.uncheckAllRecommendedBusinessFeatures();
|
await profileWizard.business.uncheckAllRecommendedBusinessFeatures();
|
||||||
|
await profileWizard.continue();
|
||||||
await onboarding.continue();
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the theme selection section', async () => {
|
||||||
|
await profileWizard.themes.isDisplayed();
|
||||||
|
await profileWizard.themes.continueWithActiveTheme();
|
||||||
} );
|
} );
|
||||||
it(
|
|
||||||
'can complete the theme selection section',
|
|
||||||
completeThemeSelectionSection
|
|
||||||
);
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A non-US store doesn't get the "install recommended features" checkbox.
|
* A non-US store doesn't get the "install recommended features" checkbox.
|
||||||
*/
|
*/
|
||||||
describe( 'A spanish store does not get the install recommended features tab, but sees the benefits section', () => {
|
describe( 'A spanish store does not get the install recommended features tab, but sees the benefits section', () => {
|
||||||
it( 'can log in', StoreOwnerFlow.login );
|
const profileWizard = new OnboardingWizard( page );
|
||||||
it( 'can start the profile wizard', StoreOwnerFlow.startProfileWizard );
|
const login = new Login( page );
|
||||||
|
|
||||||
|
beforeAll( async () => {
|
||||||
|
await login.login();
|
||||||
|
} );
|
||||||
|
afterAll( async () => {
|
||||||
|
await login.logout();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can start the profile wizard', async () => {
|
||||||
|
await profileWizard.navigate();
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'can complete the store details section', async () => {
|
it( 'can complete the store details section', async () => {
|
||||||
await completeStoreDetailsSection( {
|
await profileWizard.storeDetails.completeStoreDetailsSection( {
|
||||||
countryRegionSubstring: 'spain',
|
countryRegionSubstring: 'spain',
|
||||||
countryRegionSelector: 'ES\\:B',
|
countryRegionSelector: 'ES\\:B',
|
||||||
countryRegion: 'Spain - Barcelona',
|
countryRegion: 'Spain - Barcelona',
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// Wait for "Continue" button to become active
|
||||||
|
await profileWizard.continue();
|
||||||
|
|
||||||
|
// Wait for usage tracking pop-up window to appear
|
||||||
|
await profileWizard.optionallySelectUsageTracking();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'can complete the industry section', async () => {
|
it( 'can complete the industry section', async () => {
|
||||||
await completeIndustrySection( 7 );
|
await profileWizard.industry.isDisplayed( 7 );
|
||||||
|
await profileWizard.industry.uncheckIndustries();
|
||||||
|
await profileWizard.industry.selectIndustry(
|
||||||
|
'Fashion, apparel, and accessories'
|
||||||
|
);
|
||||||
|
await profileWizard.industry.selectIndustry( 'Health and beauty' );
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
it( 'can complete the product types section', async () =>
|
|
||||||
await completeProductTypesSection() );
|
it( 'can complete the product types section', async () => {
|
||||||
|
await profileWizard.productTypes.isDisplayed( 7 );
|
||||||
|
await profileWizard.productTypes.uncheckProducts();
|
||||||
|
|
||||||
|
// Select Physical and Downloadable products
|
||||||
|
await profileWizard.productTypes.selectProduct( 'Physical products' );
|
||||||
|
await profileWizard.productTypes.selectProduct( 'Downloads' );
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'does not have the install recommended features checkbox', async () => {
|
it( 'does not have the install recommended features checkbox', async () => {
|
||||||
const installFeaturesCheckbox = await page.$(
|
const installFeaturesCheckbox = await page.$(
|
||||||
'#woocommerce-business-extensions__checkbox'
|
'#woocommerce-business-extensions__checkbox'
|
||||||
|
@ -78,20 +154,39 @@ describe( 'A spanish store does not get the install recommended features tab, bu
|
||||||
|
|
||||||
expect( installFeaturesCheckbox ).toBe( null );
|
expect( installFeaturesCheckbox ).toBe( null );
|
||||||
} );
|
} );
|
||||||
it( 'can complete the business section', async () =>
|
|
||||||
await completeBusinessSection() );
|
it( 'can complete the business section', async () => {
|
||||||
it( 'can complete the theme selection section', async () =>
|
await profileWizard.business.isDisplayed();
|
||||||
await completeThemeSelectionSection() );
|
await profileWizard.business.selectProductNumber(
|
||||||
it( 'can complete the benefits section', async () => {
|
config.get( 'onboardingwizard.numberofproducts' )
|
||||||
const onboarding = new OnboardingWizard( page );
|
);
|
||||||
await onboarding.benefits.isDisplayed();
|
await profileWizard.business.selectCurrentlySelling(
|
||||||
await onboarding.benefits.noThanks();
|
config.get( 'onboardingwizard.sellingelsewhere' )
|
||||||
|
);
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the theme selection section', async () => {
|
||||||
|
// Make sure we're on the theme selection page before clicking continue
|
||||||
|
await profileWizard.themes.isDisplayed();
|
||||||
|
|
||||||
|
await profileWizard.themes.continueWithActiveTheme();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can complete the benefits section', async () => {
|
||||||
|
await profileWizard.benefits.isDisplayed();
|
||||||
|
// This performs a navigation to home screen.
|
||||||
|
await profileWizard.benefits.noThanks();
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should display the choose payments task, and not the woocommerce payments task', async () => {
|
it( 'should display the choose payments task, and not the woocommerce payments task', async () => {
|
||||||
const homescreen = new WcHomescreen( page );
|
const homescreen = new WcHomescreen( page );
|
||||||
await homescreen.isDisplayed();
|
await homescreen.isDisplayed();
|
||||||
await homescreen.possiblyDismissWelcomeModal();
|
await homescreen.possiblyDismissWelcomeModal();
|
||||||
|
|
||||||
const tasks = await homescreen.getTaskList();
|
const tasks = await homescreen.getTaskList();
|
||||||
|
|
||||||
expect( tasks ).toContain( TaskTitles.addPayments );
|
expect( tasks ).toContain( TaskTitles.addPayments );
|
||||||
expect( tasks ).not.toContain( TaskTitles.wooPayments );
|
expect( tasks ).not.toContain( TaskTitles.wooPayments );
|
||||||
} );
|
} );
|
||||||
|
@ -108,45 +203,88 @@ describe( 'A spanish store does not get the install recommended features tab, bu
|
||||||
} );
|
} );
|
||||||
|
|
||||||
describe( 'A japanese store can complete the selective bundle install but does not include WCPay. ', () => {
|
describe( 'A japanese store can complete the selective bundle install but does not include WCPay. ', () => {
|
||||||
it( 'can log in', StoreOwnerFlow.login );
|
const profileWizard = new OnboardingWizard( page );
|
||||||
it( 'can start the profile wizard', StoreOwnerFlow.startProfileWizard );
|
const login = new Login( page );
|
||||||
|
|
||||||
|
beforeAll( async () => {
|
||||||
|
await login.login();
|
||||||
|
} );
|
||||||
|
afterAll( async () => {
|
||||||
|
await login.logout();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'can start the profile wizard', async () => {
|
||||||
|
await profileWizard.navigate();
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'can complete the store details section', async () => {
|
it( 'can complete the store details section', async () => {
|
||||||
await completeStoreDetailsSection( {
|
await profileWizard.storeDetails.completeStoreDetailsSection( {
|
||||||
countryRegionSubstring: 'japan',
|
countryRegionSubstring: 'japan',
|
||||||
countryRegionSelector: 'JP\\:JP01',
|
countryRegionSelector: 'JP\\:JP01',
|
||||||
countryRegion: 'Japan — Hokkaido',
|
countryRegion: 'Japan — Hokkaido',
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// Wait for "Continue" button to become active
|
||||||
|
await profileWizard.continue();
|
||||||
|
|
||||||
|
// Wait for usage tracking pop-up window to appear
|
||||||
|
await profileWizard.optionallySelectUsageTracking();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// JP:JP01
|
// JP:JP01
|
||||||
it( 'can choose the "Other" industry', async () => {
|
it( 'can choose the "Other" industry', async () => {
|
||||||
await chooseIndustries( [ 'Other' ] );
|
// Query for the industries checkboxes
|
||||||
|
await profileWizard.industry.isDisplayed();
|
||||||
|
await profileWizard.industry.uncheckIndustries();
|
||||||
|
await profileWizard.industry.selectIndustry( 'Other' );
|
||||||
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
it( 'can complete the product types section', async () =>
|
|
||||||
await completeProductTypesSection() );
|
it( 'can complete the product types section', async () => {
|
||||||
|
await profileWizard.productTypes.isDisplayed( 7 );
|
||||||
|
await profileWizard.productTypes.uncheckProducts();
|
||||||
|
|
||||||
|
// Select Physical and Downloadable products
|
||||||
|
await profileWizard.productTypes.selectProduct( 'Physical products' );
|
||||||
|
await profileWizard.productTypes.selectProduct( 'Downloads' );
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
|
await page.waitForNavigation( { waitUntil: 'networkidle0' } );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'can complete the business details tab', async () => {
|
it( 'can complete the business details tab', async () => {
|
||||||
await completeSelectiveBundleInstallBusinessDetailsTab();
|
await profileWizard.business.isDisplayed();
|
||||||
|
|
||||||
|
await profileWizard.business.selectProductNumber(
|
||||||
|
config.get( 'onboardingwizard.numberofproducts' )
|
||||||
|
);
|
||||||
|
await profileWizard.business.selectCurrentlySelling(
|
||||||
|
config.get( 'onboardingwizard.sellingelsewhere' )
|
||||||
|
);
|
||||||
|
|
||||||
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'can choose not to install any extensions', async () => {
|
it( 'can choose not to install any extensions', async () => {
|
||||||
const onboarding = new OnboardingWizard( page );
|
await profileWizard.business.freeFeaturesIsDisplayed();
|
||||||
|
|
||||||
await onboarding.business.freeFeaturesIsDisplayed();
|
|
||||||
// Add WC Pay check
|
// Add WC Pay check
|
||||||
await onboarding.business.expandRecommendedBusinessFeatures();
|
await profileWizard.business.expandRecommendedBusinessFeatures();
|
||||||
|
|
||||||
expect( page ).not.toMatchElement( 'a', {
|
expect( page ).not.toMatchElement( 'a', {
|
||||||
text: 'WooCommerce Payments',
|
text: 'WooCommerce Payments',
|
||||||
} );
|
} );
|
||||||
|
|
||||||
await onboarding.business.uncheckAllRecommendedBusinessFeatures();
|
await profileWizard.business.uncheckAllRecommendedBusinessFeatures();
|
||||||
|
await profileWizard.continue();
|
||||||
await onboarding.continue();
|
} );
|
||||||
|
|
||||||
|
it( 'can finish the rest of the wizard successfully', async () => {
|
||||||
|
await profileWizard.themes.isDisplayed();
|
||||||
|
|
||||||
|
// This navigates to the home screen
|
||||||
|
await profileWizard.themes.continueWithActiveTheme();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it(
|
|
||||||
'can finish the rest of the wizard successfully',
|
|
||||||
completeThemeSelectionSection
|
|
||||||
);
|
|
||||||
it( 'should display the choose payments task, and not the woocommerce payments task', async () => {
|
it( 'should display the choose payments task, and not the woocommerce payments task', async () => {
|
||||||
const homescreen = new WcHomescreen( page );
|
const homescreen = new WcHomescreen( page );
|
||||||
await homescreen.isDisplayed();
|
await homescreen.isDisplayed();
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/**
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { OnboardingWizard } from '../../models/OnboardingWizard';
|
|
||||||
|
|
||||||
export async function completeProductTypesSection(
|
|
||||||
expectedProductTypeCount = 7
|
|
||||||
) {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
await onboarding.productTypes.isDisplayed( expectedProductTypeCount );
|
|
||||||
|
|
||||||
await onboarding.productTypes.uncheckProducts();
|
|
||||||
|
|
||||||
// Select Physical and Downloadable products
|
|
||||||
await onboarding.productTypes.selectProduct( 'Physical products' );
|
|
||||||
await onboarding.productTypes.selectProduct( 'Downloads' );
|
|
||||||
|
|
||||||
await onboarding.continue();
|
|
||||||
await page.waitForNavigation( { waitUntil: 'networkidle0' } );
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/**
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { OnboardingWizard } from '../../models/OnboardingWizard';
|
|
||||||
const config = require( 'config' );
|
|
||||||
|
|
||||||
interface StoreDetails {
|
|
||||||
addressLine1?: string;
|
|
||||||
addressLine2?: string;
|
|
||||||
countryRegionSubstring?: string;
|
|
||||||
countryRegionSelector?: string;
|
|
||||||
countryRegion?: string;
|
|
||||||
city?: string;
|
|
||||||
postcode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function completeStoreDetailsSection(
|
|
||||||
storeDetails: StoreDetails = {}
|
|
||||||
) {
|
|
||||||
const onboardingWizard = new OnboardingWizard( page );
|
|
||||||
// Fill store's address - first line
|
|
||||||
await onboardingWizard.storeDetails.fillAddress(
|
|
||||||
storeDetails.addressLine1 ||
|
|
||||||
config.get( 'addresses.admin.store.addressfirstline' )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Fill store's address - second line
|
|
||||||
await onboardingWizard.storeDetails.fillAddressLineTwo(
|
|
||||||
storeDetails.addressLine2 ||
|
|
||||||
config.get( 'addresses.admin.store.addresssecondline' )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Type the requested country/region substring or 'cali' in the
|
|
||||||
// country/region select, then select the requested country/region
|
|
||||||
// substring or 'US:CA'.
|
|
||||||
await onboardingWizard.storeDetails.selectCountry(
|
|
||||||
storeDetails.countryRegionSubstring || 'cali',
|
|
||||||
storeDetails.countryRegionSelector || 'US\\:CA'
|
|
||||||
);
|
|
||||||
if ( storeDetails.countryRegion ) {
|
|
||||||
await onboardingWizard.storeDetails.countryDropdown.checkSelected(
|
|
||||||
storeDetails.countryRegion
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the city where the store is located
|
|
||||||
await onboardingWizard.storeDetails.fillCity(
|
|
||||||
storeDetails.city || config.get( 'addresses.admin.store.city' )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Fill postcode of the store
|
|
||||||
await onboardingWizard.storeDetails.fillPostalCode(
|
|
||||||
storeDetails.postcode || config.get( 'addresses.admin.store.postcode' )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify that checkbox next to "I'm setting up a store for a client" is not selected
|
|
||||||
await onboardingWizard.storeDetails.checkClientSetupCheckbox( false );
|
|
||||||
|
|
||||||
// Wait for "Continue" button to become active
|
|
||||||
await onboardingWizard.continue();
|
|
||||||
|
|
||||||
// Wait for usage tracking pop-up window to appear
|
|
||||||
await onboardingWizard.optionallySelectUsageTracking();
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/**
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { OnboardingWizard } from '../../models/OnboardingWizard';
|
|
||||||
|
|
||||||
export async function completeThemeSelectionSection() {
|
|
||||||
const onboarding = new OnboardingWizard( page );
|
|
||||||
// Make sure we're on the theme selection page before clicking continue
|
|
||||||
await onboarding.themes.isDisplayed();
|
|
||||||
|
|
||||||
await onboarding.themes.continueWithActiveTheme();
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { Analytics } from '../../pages/Analytics';
|
||||||
|
import { Login } from '../../pages/Login';
|
||||||
|
|
||||||
|
describe( 'Analytics pages', () => {
|
||||||
|
const analyticsPage = new Analytics( page );
|
||||||
|
const login = new Login( page );
|
||||||
|
|
||||||
|
beforeAll( async () => {
|
||||||
|
await login.login();
|
||||||
|
} );
|
||||||
|
afterAll( async () => {
|
||||||
|
await login.logout();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics overview without it crashing', async () => {
|
||||||
|
await analyticsPage.navigate();
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for products without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'products' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for revenue without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'revenue' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for orders without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'orders' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for variations without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'variations' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for categories without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'categories' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for coupons without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'coupons' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for taxes without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'taxes' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for downloads without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'downloads' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for stock without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'stock' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'A user can view the analytics for settings without it crashing', async () => {
|
||||||
|
await analyticsPage.navigateToSection( 'settings' );
|
||||||
|
await analyticsPage.isDisplayed();
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { Login } from '../../pages/Login';
|
||||||
|
import { OnboardingWizard } from '../../pages/OnboardingWizard';
|
||||||
|
import { PaymentsSetup } from '../../pages/PaymentsSetup';
|
||||||
|
import { WcHomescreen } from '../../pages/WcHomescreen';
|
||||||
|
import { BankAccountTransferSetup } from '../../sections/payment-setup/BankAccountTransferSetup';
|
||||||
|
|
||||||
|
describe( 'Payment setup task', () => {
|
||||||
|
const profileWizard = new OnboardingWizard( page );
|
||||||
|
const homeScreen = new WcHomescreen( page );
|
||||||
|
const paymentsSetup = new PaymentsSetup( page );
|
||||||
|
const bankTransferSetup = new BankAccountTransferSetup( page );
|
||||||
|
const login = new Login( page );
|
||||||
|
|
||||||
|
beforeAll( async () => {
|
||||||
|
await login.login();
|
||||||
|
|
||||||
|
// This makes this test more isolated, by always navigating to the
|
||||||
|
// profile wizard and skipping, this behaves the same as if the
|
||||||
|
// profile wizard had not been run yet and the user is redirected
|
||||||
|
// to it when trying to go to wc-admin.
|
||||||
|
await profileWizard.navigate();
|
||||||
|
await profileWizard.skipStoreSetup();
|
||||||
|
|
||||||
|
await homeScreen.isDisplayed();
|
||||||
|
await homeScreen.possiblyDismissWelcomeModal();
|
||||||
|
} );
|
||||||
|
|
||||||
|
afterAll( async () => {
|
||||||
|
await login.logout();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'Can visit the payment setup task from the homescreen if the setup wizard has been skipped', async () => {
|
||||||
|
await homeScreen.clickOnTaskList( 'Choose payment methods' );
|
||||||
|
await paymentsSetup.closeHelpModal();
|
||||||
|
await paymentsSetup.isDisplayed();
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'Saving valid bank account transfer details enables the payment method', async () => {
|
||||||
|
await paymentsSetup.goToPaymentMethodSetup( 'bacs' );
|
||||||
|
await bankTransferSetup.saveAccountDetails( {
|
||||||
|
accountNumber: '1234',
|
||||||
|
accountName: 'Savings',
|
||||||
|
bankName: 'TestBank',
|
||||||
|
sortCode: '12',
|
||||||
|
iban: '12 3456 7890',
|
||||||
|
swiftCode: 'ABBA',
|
||||||
|
} );
|
||||||
|
|
||||||
|
await paymentsSetup.isDisplayed();
|
||||||
|
await paymentsSetup.methodHasBeenSetup( 'bacs' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'Toggling cash on delivery enables the payment method', async () => {
|
||||||
|
await paymentsSetup.enableCashOnDelivery();
|
||||||
|
await paymentsSetup.methodHasBeenSetup( 'cod' );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -55,6 +55,13 @@ const verifyPublishAndTrash = async (
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasClass = async ( element: ElementHandle, elementClass: string ) => {
|
||||||
|
const classNameProp = await element.getProperty( 'className' );
|
||||||
|
const classNameValue = ( await classNameProp.jsonValue() ) as string;
|
||||||
|
|
||||||
|
return classNameValue.includes( elementClass );
|
||||||
|
};
|
||||||
|
|
||||||
const getInputValue = async ( selector: string ) => {
|
const getInputValue = async ( selector: string ) => {
|
||||||
const field = await page.$( selector );
|
const field = await page.$( selector );
|
||||||
if ( field ) {
|
if ( field ) {
|
||||||
|
@ -114,4 +121,5 @@ export {
|
||||||
getAttribute,
|
getAttribute,
|
||||||
getElementByText,
|
getElementByText,
|
||||||
waitForElementByText,
|
waitForElementByText,
|
||||||
|
hasClass,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
const config = require( 'config' );
|
|
||||||
const baseUrl = config.get( 'url' );
|
|
||||||
|
|
||||||
export const WP_ADMIN_LOGIN = baseUrl + 'wp-login.php';
|
|
||||||
export const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin';
|
|
||||||
export const WP_ADMIN_PLUGINS = baseUrl + 'wp-admin/plugins.php';
|
|
||||||
export const WP_ADMIN_SETUP_WIZARD =
|
|
||||||
baseUrl + 'wp-admin/admin.php?page=wc-setup';
|
|
||||||
export const WP_ADMIN_ALL_ORDERS_VIEW =
|
|
||||||
baseUrl + 'wp-admin/edit.php?post_type=shop_order';
|
|
||||||
export const WP_ADMIN_NEW_COUPON =
|
|
||||||
baseUrl + 'wp-admin/post-new.php?post_type=shop_coupon';
|
|
||||||
export const WP_ADMIN_NEW_ORDER =
|
|
||||||
baseUrl + 'wp-admin/post-new.php?post_type=shop_order';
|
|
||||||
export const WP_ADMIN_NEW_PRODUCT =
|
|
||||||
baseUrl + 'wp-admin/post-new.php?post_type=product';
|
|
||||||
export const WP_ADMIN_WC_SETTINGS =
|
|
||||||
baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=';
|
|
||||||
export const WP_ADMIN_PERMALINK_SETTINGS =
|
|
||||||
baseUrl + 'wp-admin/options-permalink.php';
|
|
||||||
|
|
||||||
export const WP_ADMIN_START_PROFILE_WIZARD =
|
|
||||||
baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/setup-wizard';
|
|
||||||
|
|
||||||
export const WC_ADMIN_HOME = baseUrl + 'wp-admin/admin.php?page=wc-admin';
|
|
|
@ -1,92 +0,0 @@
|
||||||
/**
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
import { clearAndFillInput } from '@woocommerce/e2e-utils';
|
|
||||||
import { getElementByText } from './actions';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import * as constants from './constants';
|
|
||||||
|
|
||||||
const config = require( 'config' );
|
|
||||||
|
|
||||||
const StoreOwnerFlow = {
|
|
||||||
login: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_LOGIN, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
|
|
||||||
await getElementByText( 'label', 'Username or Email Address' );
|
|
||||||
await expect( page.title() ).resolves.toMatch( 'Log In' );
|
|
||||||
|
|
||||||
await clearAndFillInput( '#user_login', ' ' );
|
|
||||||
|
|
||||||
await page.type( '#user_login', config.get( 'users.admin.username' ) );
|
|
||||||
await page.type( '#user_pass', config.get( 'users.admin.password' ) );
|
|
||||||
|
|
||||||
await Promise.all( [
|
|
||||||
page.click( 'input[type=submit]' ),
|
|
||||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
|
||||||
] );
|
|
||||||
},
|
|
||||||
|
|
||||||
logout: async () => {
|
|
||||||
// Log out link in admin bar is not visible so can't be clicked directly.
|
|
||||||
const logoutLinks = await page.$$eval(
|
|
||||||
'#wp-admin-bar-logout a',
|
|
||||||
( am ) =>
|
|
||||||
am
|
|
||||||
.filter( ( e ) => ( e as HTMLLinkElement ).href )
|
|
||||||
.map( ( e ) => ( e as HTMLLinkElement ).href )
|
|
||||||
);
|
|
||||||
|
|
||||||
await page.goto( logoutLinks[ 0 ], {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
openAllOrdersView: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_ALL_ORDERS_VIEW, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
openDashboard: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_DASHBOARD, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
openNewCoupon: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_NEW_COUPON, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
openNewOrder: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_NEW_ORDER, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
openNewProduct: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_NEW_PRODUCT, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
openPlugins: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_PLUGINS, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
startProfileWizard: async () => {
|
|
||||||
await page.goto( constants.WP_ADMIN_START_PROFILE_WIZARD, {
|
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export { StoreOwnerFlow };
|
|
Loading…
Reference in New Issue