Compare commits
221 Commits
remove-com
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8f90cfc1b | ||
|
|
f8868b1e36 | ||
|
|
ffb8a2d434 | ||
|
|
a615cba2fa | ||
|
|
c09d7f4eec | ||
|
|
a67a08a5fb | ||
|
|
43ef53b703 | ||
|
|
1dc39fcce1 | ||
|
|
0a28ef2fb4 | ||
|
|
c2fa1fa2df | ||
|
|
44cf541b06 | ||
|
|
b5b12d0e87 | ||
|
|
b2862eeb42 | ||
|
|
92a333cc66 | ||
|
|
7a9d9bb300 | ||
|
|
fc4eb61ec9 | ||
|
|
b2972929c9 | ||
|
|
bc251a61b2 | ||
|
|
632e962161 | ||
|
|
5d913b720e | ||
|
|
f8a5cb50ed | ||
|
|
b97f777b6f | ||
|
|
b2f7579054 | ||
|
|
24742c1cf5 | ||
|
|
051383e68a | ||
|
|
5443ebd01b | ||
|
|
3aa2422735 | ||
|
|
90a7dfeb15 | ||
|
|
97c7bd744f | ||
|
|
55c5f705fb | ||
|
|
f4e2adc261 | ||
|
|
58ec90aca6 | ||
|
|
76e400f0ad | ||
|
|
5bd6926f2f | ||
|
|
43a584ebd1 | ||
|
|
4cf0a64d81 | ||
|
|
db3d007c51 | ||
|
|
55a930840f | ||
|
|
fad82b52ad | ||
|
|
41450686aa | ||
|
|
2fcda640f5 | ||
|
|
82252f9a7c | ||
|
|
818d0278a5 | ||
|
|
ff3fce99db | ||
|
|
157c302384 | ||
|
|
f2a905d373 | ||
|
|
e984a0b07b | ||
|
|
7150d4562a | ||
|
|
451056866f | ||
|
|
76f0cc54d9 | ||
|
|
fb70f7a1c2 | ||
|
|
b664150b4d | ||
|
|
da5a2e31b6 | ||
|
|
486d0bfd37 | ||
|
|
9332fc113a | ||
|
|
181e837ca4 | ||
|
|
735a9afc3c | ||
|
|
319c48f1c8 | ||
|
|
fbd73bfbfe | ||
|
|
27a63cf406 | ||
|
|
7ea351f6a0 | ||
|
|
61e8c254d7 | ||
|
|
3a08e790c3 | ||
|
|
b4c5171886 | ||
|
|
7b83c416f8 | ||
|
|
a3c261bb13 | ||
|
|
98d03aa29f | ||
|
|
f5d5e2fd02 | ||
|
|
490bf27ed1 | ||
|
|
780acac2fd | ||
|
|
2ea763701d | ||
|
|
e2d9ba5857 | ||
|
|
747d656f0a | ||
|
|
8638ed5cf4 | ||
|
|
ca2e7f554a | ||
|
|
0e94124d74 | ||
|
|
af7edd8a3f | ||
|
|
9323f119c8 | ||
|
|
38a1924c6a | ||
|
|
2d7303009f | ||
|
|
dfcb94a831 | ||
|
|
520dd6ed6b | ||
|
|
1b32dbfa19 | ||
|
|
f7d9bdb5b5 | ||
|
|
063ec80cde | ||
|
|
3cbb134c3a | ||
|
|
059a60d1c8 | ||
|
|
c88d701271 | ||
|
|
33b98b356b | ||
|
|
1f81699af4 | ||
|
|
13aa77fc70 | ||
|
|
66531831b7 | ||
|
|
846d3f0662 | ||
|
|
f78e84ee0a | ||
|
|
2d27da2391 | ||
|
|
78413be34a | ||
|
|
88866a39c1 | ||
|
|
dc9699c033 | ||
|
|
00a0e27062 | ||
|
|
6839afcf3c | ||
|
|
1cd9c58c1a | ||
|
|
5d481a93c7 | ||
|
|
438d1fcfa7 | ||
|
|
bc912ce139 | ||
|
|
ab1c2d5379 | ||
|
|
c109f6e771 | ||
|
|
8976647190 | ||
|
|
cb051a83ad | ||
|
|
1b8aec5709 | ||
|
|
9a68e95fcc | ||
|
|
c90980afb0 | ||
|
|
abb8ae5085 | ||
|
|
8bb7462098 | ||
|
|
b4a5397ba1 | ||
|
|
a43c620dc4 | ||
|
|
93d11b8485 | ||
|
|
68e13d4daf | ||
|
|
f6617935e3 | ||
|
|
5f4591c046 | ||
|
|
ae52a8cb65 | ||
|
|
b8df66ad23 | ||
|
|
923776ab96 | ||
|
|
f170f5e3f0 | ||
|
|
730875ceb2 | ||
|
|
812350d24a | ||
|
|
6879bacb89 | ||
|
|
9b2b0f2019 | ||
|
|
87884f2d91 | ||
|
|
3e20fcae57 | ||
|
|
173896811d | ||
|
|
7af4a08bd9 | ||
|
|
6c12b3b034 | ||
|
|
5304085cd8 | ||
|
|
3cd9ae130c | ||
|
|
28ad2c2cf6 | ||
|
|
3e889df109 | ||
|
|
52c6efc34d | ||
|
|
584a84a99c | ||
|
|
7e4ab1c74c | ||
|
|
13d89cb3a0 | ||
|
|
5a1e2e6c97 | ||
|
|
6f1cf29a60 | ||
|
|
159f1ae30e | ||
|
|
e2e626552f | ||
|
|
308d7c62e4 | ||
|
|
0bc78da55d | ||
|
|
6527caea54 | ||
|
|
a52912e35b | ||
|
|
6479382b90 | ||
|
|
4ce36bb12c | ||
|
|
4cc7723984 | ||
|
|
3c3d359d4e | ||
|
|
cccbf3a9d1 | ||
|
|
4a3fd2ee8e | ||
|
|
48d7cb386a | ||
|
|
bdf9cab869 | ||
|
|
be02dabf40 | ||
|
|
c535fb9d24 | ||
|
|
8ab8d09b97 | ||
|
|
286c70d50f | ||
|
|
8939e5b91f | ||
|
|
bc9f7b3bce | ||
|
|
fd0bcb9e5f | ||
|
|
98e0167ef1 | ||
|
|
8091085f45 | ||
|
|
cd5abd1d9c | ||
|
|
2a88f435b9 | ||
|
|
fe1e9c5629 | ||
|
|
0e363ca724 | ||
|
|
c874638bd1 | ||
|
|
e5c3b1ed41 | ||
|
|
8a27b8cc37 | ||
|
|
046fbeab01 | ||
|
|
27ea509989 | ||
|
|
27f0508e6e | ||
|
|
c53fedf7a1 | ||
|
|
0f1a5e9aef | ||
|
|
6cb4b799b7 | ||
|
|
439b9161b5 | ||
|
|
6ffa45f0c1 | ||
|
|
a03ba3e3b3 | ||
|
|
e2a206caa5 | ||
|
|
3a963da819 | ||
|
|
4a65f0a84c | ||
|
|
9688bd3699 | ||
|
|
c123815a55 | ||
|
|
182e669593 | ||
|
|
65533b8d58 | ||
|
|
45185dba70 | ||
|
|
444c4b4434 | ||
|
|
d629d66bf2 | ||
|
|
9d46d68150 | ||
|
|
a4ed6a362e | ||
|
|
a1a0d3cd96 | ||
|
|
950c401e88 | ||
|
|
ce056c9ad2 | ||
|
|
3bd6e454d0 | ||
|
|
f52129a11e | ||
|
|
ea01050163 | ||
|
|
c1ec9b6e99 | ||
|
|
2c509b00ac | ||
|
|
ef358fe741 | ||
|
|
56e0520d9c | ||
|
|
1f7b7f5c41 | ||
|
|
471fa75155 | ||
|
|
c89d16e529 | ||
|
|
fc02ab820a | ||
|
|
ac23cdcc7a | ||
|
|
02c4c5be29 | ||
|
|
3bd7d61e3a | ||
|
|
32ebc69c0e | ||
|
|
c98c3b16c5 | ||
|
|
287fe3adfe | ||
|
|
d4e7b7b371 | ||
|
|
ad78f068e0 | ||
|
|
d156de2e66 | ||
|
|
99bca1bd9b | ||
|
|
8efb22595c | ||
|
|
73e8913f90 | ||
|
|
3ddaf795f2 | ||
|
|
a18df02d37 |
3
.env
3
.env
@@ -23,6 +23,7 @@ POST_REGISTRATION_REDIRECT_URL=''
|
|||||||
SEARCH_CATALOG_URL=''
|
SEARCH_CATALOG_URL=''
|
||||||
# ***** Features flags *****
|
# ***** Features flags *****
|
||||||
DISABLE_ENTERPRISE_LOGIN=''
|
DISABLE_ENTERPRISE_LOGIN=''
|
||||||
|
ENABLE_AUTO_GENERATED_USERNAME=''
|
||||||
ENABLE_DYNAMIC_REGISTRATION_FIELDS=''
|
ENABLE_DYNAMIC_REGISTRATION_FIELDS=''
|
||||||
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN=''
|
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN=''
|
||||||
ENABLE_POST_REGISTRATION_RECOMMENDATIONS=''
|
ENABLE_POST_REGISTRATION_RECOMMENDATIONS=''
|
||||||
@@ -40,3 +41,5 @@ BANNER_IMAGE_EXTRA_SMALL=''
|
|||||||
# ***** Miscellaneous *****
|
# ***** Miscellaneous *****
|
||||||
APP_ID=''
|
APP_ID=''
|
||||||
MFE_CONFIG_API_URL=''
|
MFE_CONFIG_API_URL=''
|
||||||
|
# Fallback in local style files
|
||||||
|
PARAGON_THEME_URLS={}
|
||||||
|
|||||||
@@ -41,3 +41,5 @@ APP_ID=''
|
|||||||
MFE_CONFIG_API_URL=''
|
MFE_CONFIG_API_URL=''
|
||||||
ZENDESK_KEY=''
|
ZENDESK_KEY=''
|
||||||
ZENDESK_LOGO_URL=''
|
ZENDESK_LOGO_URL=''
|
||||||
|
# Fallback in local style files
|
||||||
|
PARAGON_THEME_URLS={}
|
||||||
|
|||||||
@@ -18,3 +18,4 @@ SEGMENT_KEY=''
|
|||||||
SITE_NAME='Your Platform Name Here'
|
SITE_NAME='Your Platform Name Here'
|
||||||
APP_ID=''
|
APP_ID=''
|
||||||
MFE_CONFIG_API_URL=''
|
MFE_CONFIG_API_URL=''
|
||||||
|
PARAGON_THEME_URLS={}
|
||||||
|
|||||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* @openedx/2U-infinity
|
||||||
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Adding new check for github-actions
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -25,5 +25,5 @@ Include a link to the sandbox for design changes or screenshot for before and af
|
|||||||
|
|
||||||
#### Post-merge Checklist
|
#### Post-merge Checklist
|
||||||
|
|
||||||
* [ ] Deploy the changes to prod after verifying on stage or ask **@openedx/2u-vanguards** to do it.
|
* [ ] Deploy the changes to prod after verifying on stage or ask **@openedx/2u-infinity** to do it.
|
||||||
* [ ] 🎉 🙌 Celebrate! Thanks for your contribution.
|
* [ ] 🎉 🙌 Celebrate! Thanks for your contribution.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
autoupdate:
|
autoupdate:
|
||||||
name: autoupdate
|
name: autoupdate
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: docker://chinthakagodawita/autoupdate-action:v1
|
- uses: docker://chinthakagodawita/autoupdate-action:v1
|
||||||
env:
|
env:
|
||||||
|
|||||||
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
@@ -10,17 +10,15 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Nodejs Env
|
|
||||||
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
|
|
||||||
- name: Setup Nodejs
|
- name: Setup Nodejs
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VER }}
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -41,4 +39,7 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Run Code Coverage
|
- name: Run Code Coverage
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v5
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
fail_ci_if_error: true
|
||||||
|
|||||||
2
.github/workflows/lockfileversion-check.yml
vendored
2
.github/workflows/lockfileversion-check.yml
vendored
@@ -10,4 +10,4 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
version-check:
|
version-check:
|
||||||
uses: openedx/.github/.github/workflows/lockfile-check.yml@master
|
uses: openedx/.github/.github/workflows/lockfileversion-check-v3.yml@master
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# The following users are the owners of all frontend-app-authn files
|
|
||||||
* @openedx/2u-vanguards
|
|
||||||
16
README.rst
16
README.rst
@@ -29,7 +29,13 @@ Getting Started
|
|||||||
Installation
|
Installation
|
||||||
============
|
============
|
||||||
|
|
||||||
This MFE is bundled with `Devstack <https://github.com/openedx/devstack>`_, see the `Getting Started <https://github.com/openedx/devstack#getting-started>`_ section for setup instructions.
|
`Tutor`_ is currently recommended as a development environment for your new MFE. Please refer to the `relevant tutor-mfe documentation`_ to get started using it.
|
||||||
|
|
||||||
|
.. _Tutor: https://github.com/overhangio/tutor
|
||||||
|
.. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe?tab=readme-ov-file#mfe-development
|
||||||
|
|
||||||
|
Devstack (Deprecated) instructions
|
||||||
|
==================================
|
||||||
|
|
||||||
1. Install Devstack using the `Getting Started <https://github.com/openedx/devstack#getting-started>`_ instructions.
|
1. Install Devstack using the `Getting Started <https://github.com/openedx/devstack#getting-started>`_ instructions.
|
||||||
|
|
||||||
@@ -51,7 +57,7 @@ This MFE is bundled with `Devstack <https://github.com/openedx/devstack>`_, see
|
|||||||
Environment Variables/Setup Notes
|
Environment Variables/Setup Notes
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
This MFE is configured via environment variables supplied at build time. All micro-frontends have a shared set of required environment variables, as documented in the Open edX Developer Guide under `Required Environment Variables <https://edx.readthedocs.io/projects/edx-developer-docs/en/latest/developers_guide/micro_frontends_in_open_edx.html#required-environment-variables>`__.
|
This MFE is configured via environment variables supplied at build time. All micro-frontends have a shared set of required environment variables, as documented in the Open edX Developer Guide under `Required Environment Variables <https://github.com/overhangio/tutor-mfe?tab=readme-ov-file#mfe-development>`__.
|
||||||
|
|
||||||
The authentication micro-frontend also requires the following additional variable:
|
The authentication micro-frontend also requires the following additional variable:
|
||||||
|
|
||||||
@@ -142,13 +148,13 @@ Furthermore, there are several edX-specific environment variables that enable in
|
|||||||
- ``true`` | ``''`` (empty strings are falsy)
|
- ``true`` | ``''`` (empty strings are falsy)
|
||||||
|
|
||||||
For more information see the document: `Micro-frontend applications in Open
|
For more information see the document: `Micro-frontend applications in Open
|
||||||
edX <https://edx.readthedocs.io/projects/edx-developer-docs/en/latest/developers_guide/micro_frontends_in_open_edx.html#required-environment-variables>`__.
|
edX <https://github.com/overhangio/tutor-mfe?tab=readme-ov-file#mfe-development>`__.
|
||||||
|
|
||||||
How To Contribute
|
How To Contribute
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Contributions are very welcome, and strongly encouraged! We've
|
Contributions are very welcome, and strongly encouraged! We've
|
||||||
put together `some documentation that describes our contribution process <https://edx.readthedocs.org/projects/edx-developer-guide/en/latest/process/index.html>`_.
|
put together `some documentation that describes our contribution process <https://docs.openedx.org/en/latest/developers/references/developer_guide/process/index.html>`_.
|
||||||
|
|
||||||
Even though they were written with edx-platform in mind, the guidelines should be followed for Open edX code in general.
|
Even though they were written with edx-platform in mind, the guidelines should be followed for Open edX code in general.
|
||||||
|
|
||||||
@@ -187,7 +193,7 @@ All community members are expected to follow the `Open edX Code of Conduct <http
|
|||||||
People
|
People
|
||||||
======
|
======
|
||||||
The assigned maintainers for this component and other project details may be
|
The assigned maintainers for this component and other project details may be
|
||||||
found in `Backstage <https://backstage.openedx.org/catalog/default/group/2u-vanguards>`_. Backstage pulls this data from the ``catalog-info.yaml``
|
found in `Backstage <https://backstage.openedx.org/catalog/default/group/2u-infinity>`_. Backstage pulls this data from the ``catalog-info.yaml``
|
||||||
file in this repo.
|
file in this repo.
|
||||||
|
|
||||||
Reporting Security Issues
|
Reporting Security Issues
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ metadata:
|
|||||||
icon: 'Article'
|
icon: 'Article'
|
||||||
annotations:
|
annotations:
|
||||||
openedx.org/arch-interest-groups: ""
|
openedx.org/arch-interest-groups: ""
|
||||||
|
openedx.org/release: "master"
|
||||||
spec:
|
spec:
|
||||||
owner: group:2u-vanguards
|
owner: group:2u-infinity
|
||||||
type: 'service'
|
type: 'service'
|
||||||
lifecycle: 'production'
|
lifecycle: 'production'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Enable Social Auth Locally
|
|||||||
|
|
||||||
Please follow the steps below to enable social auth (SSO) locally.
|
Please follow the steps below to enable social auth (SSO) locally.
|
||||||
|
|
||||||
1. Follow `Enabling Third Party Authentication <https://edx.readthedocs.io/projects/edx-installing-configuring-and-running/en/latest/configuration/tpa/index.html>`_ for backend configuration.
|
1. Follow `Enabling Third Party Authentication <https://docs.openedx.org/en/latest/site_ops/install_configure_run_guide/configuration/tpa/index.html>`_ for backend configuration.
|
||||||
|
|
||||||
2. Authn has a component for rendering Social Auth providers at frontend which goes through each provider.
|
2. Authn has a component for rendering Social Auth providers at frontend which goes through each provider.
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# This file describes this Open edX repo, as described in OEP-2:
|
|
||||||
# http://open-edx-proposals.readthedocs.io/en/latest/oeps/oep-0002.html#specification
|
|
||||||
|
|
||||||
nick: Authn MFE
|
|
||||||
oeps: {}
|
|
||||||
owner: openedx/2u-vanguards
|
|
||||||
openedx-release:
|
|
||||||
ref: master
|
|
||||||
32069
package-lock.json
generated
32069
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
59
package.json
59
package.json
@@ -13,15 +13,12 @@
|
|||||||
"build": "fedx-scripts webpack",
|
"build": "fedx-scripts webpack",
|
||||||
"i18n_extract": "fedx-scripts formatjs extract",
|
"i18n_extract": "fedx-scripts formatjs extract",
|
||||||
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
|
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
|
||||||
|
"lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx .",
|
||||||
"snapshot": "fedx-scripts jest --updateSnapshot",
|
"snapshot": "fedx-scripts jest --updateSnapshot",
|
||||||
"start": "fedx-scripts webpack-dev-server --progress",
|
"start": "fedx-scripts webpack-dev-server --progress",
|
||||||
|
"dev": "PUBLIC_PATH=/authn/ MFE_CONFIG_API_URL='http://localhost:8000/api/mfe_config/v1' fedx-scripts webpack-dev-server --progress --host apps.local.openedx.io",
|
||||||
"test": "fedx-scripts jest --coverage --passWithNoTests"
|
"test": "fedx-scripts jest --coverage --passWithNoTests"
|
||||||
},
|
},
|
||||||
"husky": {
|
|
||||||
"hooks": {
|
|
||||||
"pre-commit": "npm run lint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"author": "edX",
|
"author": "edX",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"homepage": "https://github.com/openedx/frontend-app-authn#readme",
|
"homepage": "https://github.com/openedx/frontend-app-authn#readme",
|
||||||
@@ -33,53 +30,51 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||||
"@edx/frontend-platform": "7.1.3",
|
"@edx/frontend-platform": "^8.3.1",
|
||||||
"@edx/openedx-atlas": "^0.6.0",
|
"@edx/openedx-atlas": "^0.6.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.5.2",
|
"@fortawesome/fontawesome-svg-core": "6.7.2",
|
||||||
"@fortawesome/free-brands-svg-icons": "6.5.2",
|
"@fortawesome/free-brands-svg-icons": "6.7.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.5.2",
|
"@fortawesome/free-solid-svg-icons": "6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "0.2.6",
|
||||||
"@openedx/paragon": "^22.1.1",
|
"@openedx/paragon": "^23.4.2",
|
||||||
"@optimizely/react-sdk": "^2.9.1",
|
"@optimizely/react-sdk": "^2.9.1",
|
||||||
"@redux-devtools/extension": "3.3.0",
|
"@redux-devtools/extension": "3.3.0",
|
||||||
"@testing-library/react": "^12.1.5",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@testing-library/react-hooks": "^8.0.1",
|
|
||||||
"algoliasearch": "^4.14.3",
|
"algoliasearch": "^4.14.3",
|
||||||
"algoliasearch-helper": "^3.14.0",
|
"algoliasearch-helper": "^3.26.0",
|
||||||
"classnames": "2.5.1",
|
"classnames": "2.5.1",
|
||||||
"core-js": "3.36.1",
|
"core-js": "3.43.0",
|
||||||
"fastest-levenshtein": "1.0.16",
|
"fastest-levenshtein": "1.0.16",
|
||||||
"form-urlencoded": "6.1.4",
|
"form-urlencoded": "6.1.6",
|
||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"query-string": "7.1.3",
|
"query-string": "7.1.3",
|
||||||
"react": "^17.0.2",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^18.3.1",
|
||||||
"react-helmet": "6.1.0",
|
"react-helmet": "6.1.0",
|
||||||
"react-loading-skeleton": "3.4.0",
|
"react-loading-skeleton": "3.5.0",
|
||||||
"react-redux": "7.2.9",
|
"react-redux": "7.2.9",
|
||||||
"react-responsive": "8.2.0",
|
"react-responsive": "8.2.0",
|
||||||
"react-router": "6.22.3",
|
"react-router": "6.30.1",
|
||||||
"react-router-dom": "6.22.3",
|
"react-router-dom": "6.30.1",
|
||||||
"react-zendesk": "^0.1.13",
|
"react-zendesk": "^0.1.13",
|
||||||
"redux": "4.2.0",
|
"redux": "4.2.1",
|
||||||
"redux-logger": "3.0.6",
|
"redux-logger": "3.0.6",
|
||||||
"redux-mock-store": "1.5.4",
|
"redux-mock-store": "1.5.5",
|
||||||
"redux-saga": "1.3.0",
|
"redux-saga": "1.3.0",
|
||||||
"redux-thunk": "2.4.2",
|
"redux-thunk": "2.4.2",
|
||||||
"regenerator-runtime": "0.14.1",
|
"regenerator-runtime": "0.14.1",
|
||||||
"reselect": "4.1.8",
|
"reselect": "5.1.1",
|
||||||
"universal-cookie": "4.0.4"
|
"universal-cookie": "7.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@edx/browserslist-config": "^1.1.1",
|
"@edx/browserslist-config": "^1.1.1",
|
||||||
"@edx/reactifex": "1.1.0",
|
"@openedx/frontend-build": "^14.6.2",
|
||||||
"@openedx/frontend-build": "13.1.4",
|
"babel-plugin-formatjs": "10.5.41",
|
||||||
"babel-plugin-formatjs": "10.5.14",
|
"eslint-plugin-import": "2.32.0",
|
||||||
"eslint-plugin-import": "2.29.1",
|
|
||||||
"glob": "7.2.3",
|
"glob": "7.2.3",
|
||||||
"history": "5.3.0",
|
"history": "5.3.0",
|
||||||
"husky": "7.0.4",
|
"jest": "30.2.0",
|
||||||
"jest": "29.7.0",
|
"react-test-renderer": "^18.3.1",
|
||||||
"react-test-renderer": "^17.0.2"
|
"ts-jest": "^29.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon"/>
|
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon"/>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.9/iframeResizer.contentWindow.min.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.4.4/iframeResizer.contentWindow.min.js"
|
||||||
integrity="sha512-mdT/HQRzoRP4laVz49Mndx6rcCGA3IhuyhP3gaY0E9sZPkwbtDk9ttQIq9o8qGCf5VvJv1Xsy3k2yTjfUoczqw=="
|
integrity="sha512-IWwZFBvHzN41wNI6etRLLuLrDDj/6AwJcPt7cmKJAzluYTIHHQ1PF8wh0rSy05jxEvvjflVvH2MxeV6riyEEXg=="
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
referrerpolicy="no-referrer">
|
referrerpolicy="no-referrer">
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const ThirdPartyAuth = (props) => {
|
|||||||
const isSocialAuthActive = !!providers.length && !currentProvider;
|
const isSocialAuthActive = !!providers.length && !currentProvider;
|
||||||
const isEnterpriseLoginDisabled = getConfig().DISABLE_ENTERPRISE_LOGIN;
|
const isEnterpriseLoginDisabled = getConfig().DISABLE_ENTERPRISE_LOGIN;
|
||||||
const enterpriseLoginURL = getConfig().LMS_BASE_URL + ENTERPRISE_LOGIN_URL;
|
const enterpriseLoginURL = getConfig().LMS_BASE_URL + ENTERPRISE_LOGIN_URL;
|
||||||
|
const isThirdPartyAuthActive = isSocialAuthActive || (isEnterpriseLoginDisabled && isInstitutionAuthActive);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -61,7 +62,7 @@ const ThirdPartyAuth = (props) => {
|
|||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{thirdPartyAuthApiStatus === PENDING_STATE ? (
|
{thirdPartyAuthApiStatus === PENDING_STATE && isThirdPartyAuthActive ? (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<Skeleton className="tpa-skeleton" height={36} count={2} />
|
<Skeleton className="tpa-skeleton" height={36} count={2} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ import React from 'react';
|
|||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import { PAGE_NOT_FOUND, REGISTER_EMBEDDED_PAGE } from '../../data/constants';
|
|
||||||
import EmbeddedRegistrationRoute from '../EmbeddedRegistrationRoute';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MemoryRouter, Route, BrowserRouter as Router, Routes,
|
MemoryRouter, Route, BrowserRouter as Router, Routes,
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
|
|
||||||
|
import { PAGE_NOT_FOUND, REGISTER_EMBEDDED_PAGE } from '../../data/constants';
|
||||||
|
import EmbeddedRegistrationRoute from '../EmbeddedRegistrationRoute';
|
||||||
|
|
||||||
const RRD = require('react-router-dom');
|
const RRD = require('react-router-dom');
|
||||||
// Just render plain div with its children
|
// Just render plain div with its children
|
||||||
// eslint-disable-next-line react/prop-types
|
// eslint-disable-next-line react/prop-types
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
@@ -37,7 +36,6 @@ describe('FormGroup', () => {
|
|||||||
|
|
||||||
describe('PasswordField', () => {
|
describe('PasswordField', () => {
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
const IntlPasswordField = injectIntl(PasswordField);
|
|
||||||
let props = {};
|
let props = {};
|
||||||
let store = {};
|
let store = {};
|
||||||
|
|
||||||
@@ -66,7 +64,7 @@ describe('PasswordField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show/hide password on icon click', () => {
|
it('should show/hide password on icon click', () => {
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = getByLabelText('Password');
|
const passwordInput = getByLabelText('Password');
|
||||||
|
|
||||||
const showPasswordButton = getByLabelText('Show password');
|
const showPasswordButton = getByLabelText('Show password');
|
||||||
@@ -79,7 +77,7 @@ describe('PasswordField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show password requirement tooltip on focus', async () => {
|
it('should show password requirement tooltip on focus', async () => {
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = getByLabelText('Password');
|
const passwordInput = getByLabelText('Password');
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -96,7 +94,7 @@ describe('PasswordField', () => {
|
|||||||
...props,
|
...props,
|
||||||
value: '',
|
value: '',
|
||||||
};
|
};
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = getByLabelText('Password');
|
const passwordInput = getByLabelText('Password');
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -119,7 +117,7 @@ describe('PasswordField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update password requirement checks', async () => {
|
it('should update password requirement checks', async () => {
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = getByLabelText('Password');
|
const passwordInput = getByLabelText('Password');
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -142,7 +140,7 @@ describe('PasswordField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not run validations when blur is fired on password icon click', () => {
|
it('should not run validations when blur is fired on password icon click', () => {
|
||||||
const { container, getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { container, getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = container.querySelector('input[name="password"]');
|
const passwordInput = container.querySelector('input[name="password"]');
|
||||||
|
|
||||||
const passwordIcon = getByLabelText('Show password');
|
const passwordIcon = getByLabelText('Show password');
|
||||||
@@ -163,7 +161,7 @@ describe('PasswordField', () => {
|
|||||||
...props,
|
...props,
|
||||||
handleBlur: jest.fn(),
|
handleBlur: jest.fn(),
|
||||||
};
|
};
|
||||||
const { container } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { container } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = container.querySelector('input[name="password"]');
|
const passwordInput = container.querySelector('input[name="password"]');
|
||||||
|
|
||||||
fireEvent.blur(passwordInput, {
|
fireEvent.blur(passwordInput, {
|
||||||
@@ -181,7 +179,7 @@ describe('PasswordField', () => {
|
|||||||
...props,
|
...props,
|
||||||
handleErrorChange: jest.fn(),
|
handleErrorChange: jest.fn(),
|
||||||
};
|
};
|
||||||
const { container } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { container } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordInput = container.querySelector('input[name="password"]');
|
const passwordInput = container.querySelector('input[name="password"]');
|
||||||
|
|
||||||
fireEvent.blur(passwordInput, {
|
fireEvent.blur(passwordInput, {
|
||||||
@@ -204,7 +202,7 @@ describe('PasswordField', () => {
|
|||||||
handleErrorChange: jest.fn(),
|
handleErrorChange: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
|
|
||||||
const passwordIcon = getByLabelText('Show password');
|
const passwordIcon = getByLabelText('Show password');
|
||||||
|
|
||||||
@@ -224,7 +222,7 @@ describe('PasswordField', () => {
|
|||||||
handleErrorChange: jest.fn(),
|
handleErrorChange: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
|
|
||||||
const passwordIcon = getByLabelText('Show password');
|
const passwordIcon = getByLabelText('Show password');
|
||||||
|
|
||||||
@@ -248,7 +246,7 @@ describe('PasswordField', () => {
|
|||||||
...props,
|
...props,
|
||||||
handleErrorChange: jest.fn(),
|
handleErrorChange: jest.fn(),
|
||||||
};
|
};
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
const passwordField = getByLabelText('Password');
|
const passwordField = getByLabelText('Password');
|
||||||
fireEvent.blur(passwordField, {
|
fireEvent.blur(passwordField, {
|
||||||
target: {
|
target: {
|
||||||
@@ -268,7 +266,7 @@ describe('PasswordField', () => {
|
|||||||
handleErrorChange: jest.fn(),
|
handleErrorChange: jest.fn(),
|
||||||
handleBlur: jest.fn(),
|
handleBlur: jest.fn(),
|
||||||
};
|
};
|
||||||
const { getByLabelText } = render(reduxWrapper(<IntlPasswordField {...props} />));
|
const { getByLabelText } = render(reduxWrapper(<PasswordField {...props} />));
|
||||||
|
|
||||||
const passwordIcon = getByLabelText('Show password');
|
const passwordIcon = getByLabelText('Show password');
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ import React from 'react';
|
|||||||
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import { UnAuthOnlyRoute } from '..';
|
|
||||||
import { REGISTER_PAGE } from '../../data/constants';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MemoryRouter, Route, BrowserRouter as Router, Routes,
|
MemoryRouter, Route, BrowserRouter as Router, Routes,
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
|
|
||||||
|
import { UnAuthOnlyRoute } from '..';
|
||||||
|
import { REGISTER_PAGE } from '../../data/constants';
|
||||||
|
|
||||||
jest.mock('@edx/frontend-platform/auth', () => ({
|
jest.mock('@edx/frontend-platform/auth', () => ({
|
||||||
getAuthenticatedUser: jest.fn(),
|
getAuthenticatedUser: jest.fn(),
|
||||||
fetchAuthenticatedUser: jest.fn(),
|
fetchAuthenticatedUser: jest.fn(),
|
||||||
|
|||||||
@@ -66,14 +66,14 @@ exports[`SocialAuthProviders should match social auth provider with iconClass sn
|
|||||||
data-prefix="fab"
|
data-prefix="fab"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
role="img"
|
role="img"
|
||||||
style={Object {}}
|
style={{}}
|
||||||
viewBox="0 0 488 512"
|
viewBox="0 0 488 512"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"
|
d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
style={Object {}}
|
style={{}}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,7 +93,7 @@ exports[`SocialAuthProviders should match social auth provider with iconClass sn
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SocialAuthProviders should match social auth provider with iconImage snapshot 1`] = `
|
exports[`SocialAuthProviders should match social auth provider with iconImage snapshot 1`] = `
|
||||||
Array [
|
[
|
||||||
<button
|
<button
|
||||||
className="btn-social btn-oa2-apple-id mr-3"
|
className="btn-social btn-oa2-apple-id mr-3"
|
||||||
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
|
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ exports[`ThirdPartyAuthAlert should match login page third party auth alert mess
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`ThirdPartyAuthAlert should match register page third party auth alert message snapshot 1`] = `
|
exports[`ThirdPartyAuthAlert should match register page third party auth alert message snapshot 1`] = `
|
||||||
Array [
|
[
|
||||||
<div
|
<div
|
||||||
className="fade alert-content alert-success mt-n2 mb-5 alert show"
|
className="fade alert-content alert-success mt-n2 mb-5 alert show"
|
||||||
id="tpa-alert"
|
id="tpa-alert"
|
||||||
|
|||||||
@@ -5,23 +5,23 @@ exports[`Zendesk Help should match login page third party auth alert message sna
|
|||||||
cookies={true}
|
cookies={true}
|
||||||
defer={true}
|
defer={true}
|
||||||
webWidget={
|
webWidget={
|
||||||
Object {
|
{
|
||||||
"answerBot": Object {
|
"answerBot": {
|
||||||
"avatar": Object {
|
"avatar": {
|
||||||
"name": Object {
|
"name": {
|
||||||
"*": "edX Support",
|
"*": "edX Support",
|
||||||
},
|
},
|
||||||
"url": undefined,
|
"url": undefined,
|
||||||
},
|
},
|
||||||
"contactOnlyAfterQuery": true,
|
"contactOnlyAfterQuery": true,
|
||||||
"suppress": false,
|
"suppress": false,
|
||||||
"title": Object {
|
"title": {
|
||||||
"*": "edX Support",
|
"*": "edX Support",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chat": Object {
|
"chat": {
|
||||||
"departments": Object {
|
"departments": {
|
||||||
"enabled": Array [
|
"enabled": [
|
||||||
"account settings",
|
"account settings",
|
||||||
"billing and payments",
|
"billing and payments",
|
||||||
"certificates",
|
"certificates",
|
||||||
@@ -33,17 +33,17 @@ exports[`Zendesk Help should match login page third party auth alert message sna
|
|||||||
},
|
},
|
||||||
"suppress": false,
|
"suppress": false,
|
||||||
},
|
},
|
||||||
"contactForm": Object {
|
"contactForm": {
|
||||||
"attachments": true,
|
"attachments": true,
|
||||||
"selectTicketForm": Object {
|
"selectTicketForm": {
|
||||||
"*": "Please choose your request type:",
|
"*": "Please choose your request type:",
|
||||||
},
|
},
|
||||||
"ticketForms": Array [
|
"ticketForms": [
|
||||||
Object {
|
{
|
||||||
"fields": Array [
|
"fields": [
|
||||||
Object {
|
{
|
||||||
"id": "description",
|
"id": "description",
|
||||||
"prefill": Object {
|
"prefill": {
|
||||||
"*": "",
|
"*": "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -53,10 +53,10 @@ exports[`Zendesk Help should match login page third party auth alert message sna
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"contactOptions": Object {
|
"contactOptions": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
},
|
},
|
||||||
"helpCenter": Object {
|
"helpCenter": {
|
||||||
"originalArticleButton": true,
|
"originalArticleButton": true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const configuration = {
|
|||||||
USER_RETENTION_COOKIE_NAME: process.env.USER_RETENTION_COOKIE_NAME || '',
|
USER_RETENTION_COOKIE_NAME: process.env.USER_RETENTION_COOKIE_NAME || '',
|
||||||
// Features
|
// Features
|
||||||
DISABLE_ENTERPRISE_LOGIN: process.env.DISABLE_ENTERPRISE_LOGIN || '',
|
DISABLE_ENTERPRISE_LOGIN: process.env.DISABLE_ENTERPRISE_LOGIN || '',
|
||||||
|
ENABLE_AUTO_GENERATED_USERNAME: process.env.ENABLE_AUTO_GENERATED_USERNAME || false,
|
||||||
ENABLE_DYNAMIC_REGISTRATION_FIELDS: process.env.ENABLE_DYNAMIC_REGISTRATION_FIELDS || false,
|
ENABLE_DYNAMIC_REGISTRATION_FIELDS: process.env.ENABLE_DYNAMIC_REGISTRATION_FIELDS || false,
|
||||||
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: process.env.ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN || false,
|
ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN: process.env.ENABLE_PROGRESSIVE_PROFILING_ON_AUTHN || false,
|
||||||
ENABLE_POST_REGISTRATION_RECOMMENDATIONS: process.env.ENABLE_POST_REGISTRATION_RECOMMENDATIONS || false,
|
ENABLE_POST_REGISTRATION_RECOMMENDATIONS: process.env.ENABLE_POST_REGISTRATION_RECOMMENDATIONS || false,
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { mergeConfig } from '@edx/frontend-platform';
|
import { mergeConfig } from '@edx/frontend-platform';
|
||||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
fireEvent, render, screen,
|
fireEvent, render, screen,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -26,7 +25,6 @@ jest.mock('react-router-dom', () => ({
|
|||||||
useNavigate: () => mockedNavigator,
|
useNavigate: () => mockedNavigator,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlForgotPasswordPage = injectIntl(ForgotPasswordPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
@@ -78,7 +76,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
it('not should display need other help signing in button', () => {
|
it('not should display need other help signing in button', () => {
|
||||||
const { queryByTestId } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { queryByTestId } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const forgotPasswordButton = queryByTestId('forgot-password');
|
const forgotPasswordButton = queryByTestId('forgot-password');
|
||||||
expect(forgotPasswordButton).toBeNull();
|
expect(forgotPasswordButton).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -87,14 +85,14 @@ describe('ForgotPasswordPage', () => {
|
|||||||
mergeConfig({
|
mergeConfig({
|
||||||
LOGIN_ISSUE_SUPPORT_LINK: '/support',
|
LOGIN_ISSUE_SUPPORT_LINK: '/support',
|
||||||
});
|
});
|
||||||
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const forgotPasswordButton = screen.findByText('Need help signing in?');
|
const forgotPasswordButton = screen.findByText('Need help signing in?');
|
||||||
expect(forgotPasswordButton).toBeDefined();
|
expect(forgotPasswordButton).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display email validation error message', async () => {
|
it('should display email validation error message', async () => {
|
||||||
const validationMessage = 'We were unable to contact you.Enter a valid email address below.';
|
const validationMessage = 'We were unable to contact you.Enter a valid email address below.';
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
|
|
||||||
const emailInput = screen.getByLabelText('Email');
|
const emailInput = screen.getByLabelText('Email');
|
||||||
|
|
||||||
@@ -115,7 +113,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
const expectedMessage = 'We were unable to contact you.'
|
const expectedMessage = 'We were unable to contact you.'
|
||||||
+ 'An error has occurred. Try refreshing the page, or check your internet connection.';
|
+ 'An error has occurred. Try refreshing the page, or check your internet connection.';
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
|
|
||||||
const alertElements = container.querySelectorAll('.alert-danger');
|
const alertElements = container.querySelectorAll('.alert-danger');
|
||||||
const validationErrors = alertElements[0].textContent;
|
const validationErrors = alertElements[0].textContent;
|
||||||
@@ -124,7 +122,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
|
|
||||||
it('should display empty email validation message', async () => {
|
it('should display empty email validation message', async () => {
|
||||||
const validationMessage = 'We were unable to contact you.Enter your email below.';
|
const validationMessage = 'We were unable to contact you.Enter your email below.';
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
|
|
||||||
const submitButton = screen.getByText('Submit');
|
const submitButton = screen.getByText('Submit');
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
@@ -141,7 +139,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
forgotPassword: { status: 'forbidden' },
|
forgotPassword: { status: 'forbidden' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
|
|
||||||
const alertElements = container.querySelectorAll('.alert-danger');
|
const alertElements = container.querySelectorAll('.alert-danger');
|
||||||
const validationErrors = alertElements[0].textContent;
|
const validationErrors = alertElements[0].textContent;
|
||||||
@@ -149,7 +147,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not display any error message on change event', () => {
|
it('should not display any error message on change event', () => {
|
||||||
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
|
|
||||||
const emailInput = screen.getByLabelText('Email');
|
const emailInput = screen.getByLabelText('Email');
|
||||||
|
|
||||||
@@ -172,7 +170,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const emailInput = screen.getByLabelText('Email');
|
const emailInput = screen.getByLabelText('Email');
|
||||||
|
|
||||||
fireEvent.blur(emailInput);
|
fireEvent.blur(emailInput);
|
||||||
@@ -187,7 +185,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
emailValidationError: validationMessage,
|
emailValidationError: validationMessage,
|
||||||
email: '',
|
email: '',
|
||||||
};
|
};
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const validationElement = container.querySelector('.pgn__form-text-invalid');
|
const validationElement = container.querySelector('.pgn__form-text-invalid');
|
||||||
expect(validationElement.textContent).toEqual(validationMessage);
|
expect(validationElement.textContent).toEqual(validationMessage);
|
||||||
});
|
});
|
||||||
@@ -205,7 +203,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const emailInput = screen.getByLabelText('Email');
|
const emailInput = screen.getByLabelText('Email');
|
||||||
|
|
||||||
fireEvent.focus(emailInput);
|
fireEvent.focus(emailInput);
|
||||||
@@ -219,7 +217,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
emailValidationError: '',
|
emailValidationError: '',
|
||||||
email: '',
|
email: '',
|
||||||
};
|
};
|
||||||
render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const errorElement = screen.queryByTestId('email-invalid-feedback');
|
const errorElement = screen.queryByTestId('email-invalid-feedback');
|
||||||
expect(errorElement).toBeNull();
|
expect(errorElement).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -236,7 +234,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
+ 'receive a password reset message after 1 minute, verify that you entered the correct email address,'
|
+ 'receive a password reset message after 1 minute, verify that you entered the correct email address,'
|
||||||
+ ' or check your spam folder. If you need further assistance, contact technical support.';
|
+ ' or check your spam folder. If you need further assistance, contact technical support.';
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const successElement = findByTextContent(container, successMessage);
|
const successElement = findByTextContent(container, successMessage);
|
||||||
|
|
||||||
expect(successElement).toBeDefined();
|
expect(successElement).toBeDefined();
|
||||||
@@ -254,7 +252,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
+ 'This password reset link is invalid. It may have been used already. '
|
+ 'This password reset link is invalid. It may have been used already. '
|
||||||
+ 'Enter your email below to receive a new link.';
|
+ 'Enter your email below to receive a new link.';
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
const successElement = findByTextContent(container, successMessage);
|
const successElement = findByTextContent(container, successMessage);
|
||||||
|
|
||||||
expect(successElement).toBeDefined();
|
expect(successElement).toBeDefined();
|
||||||
@@ -262,7 +260,7 @@ describe('ForgotPasswordPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect onto login page', async () => {
|
it('should redirect onto login page', async () => {
|
||||||
const { container } = render(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ForgotPasswordPage {...props} />));
|
||||||
|
|
||||||
const navElement = container.querySelector('nav');
|
const navElement = container.querySelector('nav');
|
||||||
const anchorElement = navElement.querySelector('a');
|
const anchorElement = navElement.querySelector('a');
|
||||||
|
|||||||
@@ -1,27 +1,36 @@
|
|||||||
import 'core-js/stable';
|
import 'core-js/stable';
|
||||||
import 'regenerator-runtime/runtime';
|
import 'regenerator-runtime/runtime';
|
||||||
|
|
||||||
import React from 'react';
|
import React, { StrictMode } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
APP_INIT_ERROR, APP_READY, initialize, mergeConfig, subscribe,
|
APP_INIT_ERROR, APP_READY, initialize, mergeConfig, subscribe,
|
||||||
} from '@edx/frontend-platform';
|
} from '@edx/frontend-platform';
|
||||||
import { ErrorPage } from '@edx/frontend-platform/react';
|
import { ErrorPage } from '@edx/frontend-platform/react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import configuration from './config';
|
import configuration from './config';
|
||||||
import messages from './i18n';
|
import messages from './i18n';
|
||||||
import MainApp from './MainApp';
|
import MainApp from './MainApp';
|
||||||
|
|
||||||
subscribe(APP_READY, () => {
|
subscribe(APP_READY, () => {
|
||||||
ReactDOM.render(
|
const root = createRoot(document.getElementById('root'));
|
||||||
<MainApp />,
|
|
||||||
document.getElementById('root'),
|
root.render(
|
||||||
|
<StrictMode>
|
||||||
|
<MainApp />
|
||||||
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
subscribe(APP_INIT_ERROR, (error) => {
|
subscribe(APP_INIT_ERROR, (error) => {
|
||||||
ReactDOM.render(<ErrorPage message={error.message} />, document.getElementById('root'));
|
const root = createRoot(document.getElementById('root'));
|
||||||
|
|
||||||
|
root.render(
|
||||||
|
<StrictMode>
|
||||||
|
<ErrorPage message={error.message} />
|
||||||
|
</StrictMode>,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
initialize({
|
initialize({
|
||||||
|
|||||||
@@ -1,6 +1,2 @@
|
|||||||
@import "~@edx/brand/paragon/fonts";
|
@use "@openedx/paragon/styles/css/core/custom-media-breakpoints" as paragonCustomMediaBreakpoints;
|
||||||
@import "~@edx/brand/paragon/variables";
|
|
||||||
@import "~@openedx/paragon/scss/core/core";
|
|
||||||
@import "~@edx/brand/paragon/overrides";
|
|
||||||
|
|
||||||
@import "sass/style";
|
@import "sass/style";
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import { injectIntl, useIntl } from '@edx/frontend-platform/i18n';
|
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
Form, StatefulButton,
|
Form, StatefulButton,
|
||||||
} from '@openedx/paragon';
|
} from '@openedx/paragon';
|
||||||
@@ -365,4 +365,4 @@ export default connect(
|
|||||||
loginRequest,
|
loginRequest,
|
||||||
getTPADataFromBackend: getThirdPartyAuthContext,
|
getTPADataFromBackend: getThirdPartyAuthContext,
|
||||||
},
|
},
|
||||||
)(injectIntl(LoginPage));
|
)(LoginPage);
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { mergeConfig } from '@edx/frontend-platform';
|
import { mergeConfig } from '@edx/frontend-platform';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
render, screen,
|
render, screen,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -9,8 +7,6 @@ import {
|
|||||||
import AccountActivationMessage from '../AccountActivationMessage';
|
import AccountActivationMessage from '../AccountActivationMessage';
|
||||||
import { ACCOUNT_ACTIVATION_MESSAGE } from '../data/constants';
|
import { ACCOUNT_ACTIVATION_MESSAGE } from '../data/constants';
|
||||||
|
|
||||||
const IntlAccountActivationMessage = injectIntl(AccountActivationMessage);
|
|
||||||
|
|
||||||
describe('AccountActivationMessage', () => {
|
describe('AccountActivationMessage', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mergeConfig({
|
mergeConfig({
|
||||||
@@ -21,7 +17,7 @@ describe('AccountActivationMessage', () => {
|
|||||||
it('should match account already activated message', () => {
|
it('should match account already activated message', () => {
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
|
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -36,7 +32,7 @@ describe('AccountActivationMessage', () => {
|
|||||||
it('should match account activated success message', () => {
|
it('should match account activated success message', () => {
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
|
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -53,7 +49,7 @@ describe('AccountActivationMessage', () => {
|
|||||||
it('should match account activation error message', () => {
|
it('should match account activation error message', () => {
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
|
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -69,7 +65,7 @@ describe('AccountActivationMessage', () => {
|
|||||||
it('should not display anything for invalid message type', () => {
|
it('should not display anything for invalid message type', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType="invalid-message" />
|
<AccountActivationMessage messageType="invalid-message" />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -88,7 +84,7 @@ describe('EmailConfirmationMessage', () => {
|
|||||||
it('should match email already confirmed message', () => {
|
it('should match email already confirmed message', () => {
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
|
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.INFO} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -103,7 +99,7 @@ describe('EmailConfirmationMessage', () => {
|
|||||||
it('should match email confirmation success message', () => {
|
it('should match email confirmation success message', () => {
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
|
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.SUCCESS} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
const expectedMessage = 'Success! You have confirmed your email.Sign in to continue.';
|
const expectedMessage = 'Success! You have confirmed your email.Sign in to continue.';
|
||||||
@@ -117,7 +113,7 @@ describe('EmailConfirmationMessage', () => {
|
|||||||
it('should match email confirmation error message', () => {
|
it('should match email confirmation error message', () => {
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlAccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
|
<AccountActivationMessage messageType={ACCOUNT_ACTIVATION_MESSAGE.ERROR} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
const expectedMessage = 'Your email could not be confirmed'
|
const expectedMessage = 'Your email could not be confirmed'
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
fireEvent, render, screen,
|
fireEvent, render, screen,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -11,7 +9,6 @@ import { MemoryRouter } from 'react-router-dom';
|
|||||||
import { RESET_PAGE } from '../../data/constants';
|
import { RESET_PAGE } from '../../data/constants';
|
||||||
import ChangePasswordPrompt from '../ChangePasswordPrompt';
|
import ChangePasswordPrompt from '../ChangePasswordPrompt';
|
||||||
|
|
||||||
const IntlChangePasswordPrompt = injectIntl(ChangePasswordPrompt);
|
|
||||||
const mockedNavigator = jest.fn();
|
const mockedNavigator = jest.fn();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
jest.mock('react-router-dom', () => ({
|
||||||
@@ -44,7 +41,7 @@ describe('ChangePasswordPromptTests', () => {
|
|||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<IntlChangePasswordPrompt {...props} />
|
<ChangePasswordPrompt {...props} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
@@ -61,7 +58,7 @@ describe('ChangePasswordPromptTests', () => {
|
|||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<IntlChangePasswordPrompt {...props} />
|
<ChangePasswordPrompt {...props} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import React from 'react';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
|
||||||
import {
|
import {
|
||||||
render, screen,
|
render, screen,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -26,8 +24,6 @@ jest.mock('@edx/frontend-platform/auth', () => ({
|
|||||||
getAuthService: jest.fn(),
|
getAuthService: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlLoginFailureMessage = injectIntl(LoginFailureMessage);
|
|
||||||
|
|
||||||
describe('LoginFailureMessage', () => {
|
describe('LoginFailureMessage', () => {
|
||||||
let props = {};
|
let props = {};
|
||||||
|
|
||||||
@@ -48,7 +44,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -76,7 +72,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -106,7 +102,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -132,7 +128,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -152,7 +148,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -176,7 +172,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -196,7 +192,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -216,7 +212,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -236,7 +232,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -255,7 +251,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -275,7 +271,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -301,7 +297,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
@@ -327,7 +323,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
@@ -359,7 +355,7 @@ describe('LoginFailureMessage', () => {
|
|||||||
|
|
||||||
render(
|
render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlLoginFailureMessage {...props} />
|
<LoginFailureMessage {...props} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
fireEvent, render, screen, waitFor,
|
fireEvent, render, screen, waitFor,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -24,7 +23,6 @@ jest.mock('@edx/frontend-platform/auth', () => ({
|
|||||||
getAuthService: jest.fn(),
|
getAuthService: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlLoginPage = injectIntl(LoginPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
describe('LoginPage', () => {
|
describe('LoginPage', () => {
|
||||||
@@ -88,7 +86,7 @@ describe('LoginPage', () => {
|
|||||||
it('should submit form for valid input', () => {
|
it('should submit form for valid input', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
fireEvent.change(screen.getByText(
|
fireEvent.change(screen.getByText(
|
||||||
'',
|
'',
|
||||||
@@ -109,7 +107,7 @@ describe('LoginPage', () => {
|
|||||||
|
|
||||||
it('should not dispatch loginRequest on empty form submission', () => {
|
it('should not dispatch loginRequest on empty form submission', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
fireEvent.click(screen.getByText(
|
fireEvent.click(screen.getByText(
|
||||||
'',
|
'',
|
||||||
@@ -128,7 +126,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
fireEvent.click(screen.getByText(
|
fireEvent.click(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: '.btn-brand' },
|
{ selector: '.btn-brand' },
|
||||||
@@ -142,7 +140,7 @@ describe('LoginPage', () => {
|
|||||||
it('should match state for invalid email (less than 2 characters), on form submission', () => {
|
it('should match state for invalid email (less than 2 characters), on form submission', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
fireEvent.change(screen.getByText(
|
fireEvent.change(screen.getByText(
|
||||||
'',
|
'',
|
||||||
@@ -162,7 +160,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show error messages for required fields on empty form submission', () => {
|
it('should show error messages for required fields on empty form submission', () => {
|
||||||
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { container } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
fireEvent.click(screen.getByText(
|
fireEvent.click(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: '.btn-brand' },
|
{ selector: '.btn-brand' },
|
||||||
@@ -176,7 +174,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should run frontend validations for emailOrUsername field on form submission', () => {
|
it('should run frontend validations for emailOrUsername field on form submission', () => {
|
||||||
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { container } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
fireEvent.change(screen.getByText(
|
fireEvent.change(screen.getByText(
|
||||||
'',
|
'',
|
||||||
@@ -195,7 +193,7 @@ describe('LoginPage', () => {
|
|||||||
it('should reset field related error messages on onFocus event', async () => {
|
it('should reset field related error messages on onFocus event', async () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
// clicking submit button with empty fields to make the errors appear
|
// clicking submit button with empty fields to make the errors appear
|
||||||
@@ -224,7 +222,7 @@ describe('LoginPage', () => {
|
|||||||
// ******** test form buttons and links ********
|
// ******** test form buttons and links ********
|
||||||
|
|
||||||
it('should match default button state', () => {
|
it('should match default button state', () => {
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText('Sign in')).toBeDefined();
|
expect(screen.getByText('Sign in')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -237,7 +235,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'pending',
|
'pending',
|
||||||
@@ -245,7 +243,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show forgot password link', () => {
|
it('should show forgot password link', () => {
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'Forgot password',
|
'Forgot password',
|
||||||
@@ -265,7 +263,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: `#${ssoProvider.id}` },
|
{ selector: `#${ssoProvider.id}` },
|
||||||
@@ -287,7 +285,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Company or school credentials')).toBeNull();
|
expect(queryByText('Company or school credentials')).toBeNull();
|
||||||
expect(queryByText('Or sign in with:')).toBeNull();
|
expect(queryByText('Or sign in with:')).toBeNull();
|
||||||
expect(queryByText('Institution/campus credentials')).toBeNull();
|
expect(queryByText('Institution/campus credentials')).toBeNull();
|
||||||
@@ -307,7 +305,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Company or school credentials')).toBeNull();
|
expect(queryByText('Company or school credentials')).toBeNull();
|
||||||
expect(queryByText('Or sign in with:')).toBeNull();
|
expect(queryByText('Or sign in with:')).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -327,7 +325,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Or sign in with:')).toBeDefined();
|
expect(queryByText('Or sign in with:')).toBeDefined();
|
||||||
expect(queryByText('Company or school credentials')).toBeDefined();
|
expect(queryByText('Company or school credentials')).toBeDefined();
|
||||||
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
||||||
@@ -352,7 +350,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Or sign in with:')).toBeDefined();
|
expect(queryByText('Or sign in with:')).toBeDefined();
|
||||||
expect(queryByText('Company or school credentials')).toBeNull();
|
expect(queryByText('Company or school credentials')).toBeNull();
|
||||||
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
||||||
@@ -380,7 +378,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Or sign in with:')).toBeDefined();
|
expect(queryByText('Or sign in with:')).toBeDefined();
|
||||||
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
||||||
|
|
||||||
@@ -400,7 +398,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Or sign in with:')).toBeNull();
|
expect(queryByText('Or sign in with:')).toBeNull();
|
||||||
expect(queryByText('Institution/campus credentials')).toBeNull();
|
expect(queryByText('Institution/campus credentials')).toBeNull();
|
||||||
expect(queryByText('Company or school credentials')).toBeNull();
|
expect(queryByText('Company or school credentials')).toBeNull();
|
||||||
@@ -418,7 +416,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByText } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { queryByText } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(queryByText('Or sign in with:')).toBeDefined();
|
expect(queryByText('Or sign in with:')).toBeDefined();
|
||||||
expect(queryByText('Company or school credentials')).toBeNull();
|
expect(queryByText('Company or school credentials')).toBeNull();
|
||||||
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
expect(queryByText('Institution/campus credentials')).toBeDefined();
|
||||||
@@ -441,7 +439,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: '#login-failure-alert' },
|
{ selector: '#login-failure-alert' },
|
||||||
@@ -465,7 +463,7 @@ describe('LoginPage', () => {
|
|||||||
+ 'linked '}${ getConfig().SITE_NAME } account. To link your accounts, sign in now using your ${
|
+ 'linked '}${ getConfig().SITE_NAME } account. To link your accounts, sign in now using your ${
|
||||||
getConfig().SITE_NAME } password.`;
|
getConfig().SITE_NAME } password.`;
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: '#tpa-alert' },
|
{ selector: '#tpa-alert' },
|
||||||
@@ -484,7 +482,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: '#login-failure-alert' },
|
{ selector: '#login-failure-alert' },
|
||||||
@@ -501,7 +499,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: '#login-failure-alert' },
|
{ selector: '#login-failure-alert' },
|
||||||
@@ -525,7 +523,7 @@ describe('LoginPage', () => {
|
|||||||
|
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(window.location.href).toBe(dashboardURL);
|
expect(window.location.href).toBe(dashboardURL);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -552,7 +550,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
|
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -571,7 +569,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
|
|
||||||
fireEvent.click(screen.getByText(
|
fireEvent.click(screen.getByText(
|
||||||
'',
|
'',
|
||||||
@@ -600,7 +598,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + finishAuthUrl);
|
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + finishAuthUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -622,7 +620,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'',
|
'',
|
||||||
{ selector: `#${ssoProvider.id}` },
|
{ selector: `#${ssoProvider.id}` },
|
||||||
@@ -649,7 +647,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { container } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(container.querySelector('.react-loading-skeleton')).toBeTruthy();
|
expect(container.querySelector('.react-loading-skeleton')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -671,7 +669,7 @@ describe('LoginPage', () => {
|
|||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${secondaryProviders.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${secondaryProviders.id}` };
|
||||||
secondaryProviders.iconImage = null;
|
secondaryProviders.iconImage = null;
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(window.location.href).toEqual(getConfig().LMS_BASE_URL + secondaryProviders.loginUrl);
|
expect(window.location.href).toEqual(getConfig().LMS_BASE_URL + secondaryProviders.loginUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -691,7 +689,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: '?next=/dashboard&tpa_hint=invalid' };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: '?next=/dashboard&tpa_hint=invalid' };
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { container } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(container.querySelector(`#${ssoProvider.id}`).querySelector('#provider-name').textContent).toEqual(`${ssoProvider.name}`);
|
expect(container.querySelector(`#${ssoProvider.id}`).querySelector('#provider-name').textContent).toEqual(`${ssoProvider.name}`);
|
||||||
|
|
||||||
mergeConfig({
|
mergeConfig({
|
||||||
@@ -715,7 +713,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?tpa_hint=${ssoProvider.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?tpa_hint=${ssoProvider.id}` };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'Show me other ways to sign in or register',
|
'Show me other ways to sign in or register',
|
||||||
).textContent).toBeDefined();
|
).textContent).toBeDefined();
|
||||||
@@ -741,7 +739,7 @@ describe('LoginPage', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?tpa_hint=${ssoProvider.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?tpa_hint=${ssoProvider.id}` };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(screen.getByText(
|
expect(screen.getByText(
|
||||||
'Show me other ways to sign in',
|
'Show me other ways to sign in',
|
||||||
).textContent).toBeDefined();
|
).textContent).toBeDefined();
|
||||||
@@ -750,7 +748,7 @@ describe('LoginPage', () => {
|
|||||||
// ******** miscellaneous tests ********
|
// ******** miscellaneous tests ********
|
||||||
|
|
||||||
it('should send page event when login page is rendered', () => {
|
it('should send page event when login page is rendered', () => {
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'login');
|
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'login');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -764,7 +762,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(backupLoginFormBegin(
|
expect(store.dispatch).toHaveBeenCalledWith(backupLoginFormBegin(
|
||||||
{
|
{
|
||||||
formFields: {
|
formFields: {
|
||||||
@@ -778,7 +776,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should send track event when forgot password link is clicked', () => {
|
it('should send track event when forgot password link is clicked', () => {
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
fireEvent.click(screen.getByText(
|
fireEvent.click(screen.getByText(
|
||||||
'Forgot password',
|
'Forgot password',
|
||||||
{ selector: '#forgot-password' },
|
{ selector: '#forgot-password' },
|
||||||
@@ -797,7 +795,7 @@ describe('LoginPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(reduxWrapper(<IntlLoginPage {...props} />));
|
render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(backupLoginFormBegin(
|
expect(store.dispatch).toHaveBeenCalledWith(backupLoginFormBegin(
|
||||||
{
|
{
|
||||||
formFields: {
|
formFields: {
|
||||||
@@ -826,7 +824,7 @@ describe('LoginPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlLoginPage {...props} />));
|
const { container } = render(reduxWrapper(<LoginPage {...props} />));
|
||||||
expect(container.querySelector('input#emailOrUsername').value).toEqual('john_doe');
|
expect(container.querySelector('input#emailOrUsername').value).toEqual('john_doe');
|
||||||
expect(container.querySelector('input#password').value).toEqual('test-password');
|
expect(container.querySelector('input#password').value).toEqual('test-password');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render, screen } from '@testing-library/react';
|
import { fireEvent, render, screen } from '@testing-library/react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
@@ -23,7 +22,6 @@ jest.mock('@edx/frontend-platform/analytics', () => ({
|
|||||||
jest.mock('@edx/frontend-platform/auth');
|
jest.mock('@edx/frontend-platform/auth');
|
||||||
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
const IntlLogistration = injectIntl(Logistration);
|
|
||||||
|
|
||||||
describe('Logistration', () => {
|
describe('Logistration', () => {
|
||||||
let store = {};
|
let store = {};
|
||||||
@@ -95,7 +93,7 @@ describe('Logistration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should do nothing when user clicks on the same tab (login/register) again', () => {
|
it('should do nothing when user clicks on the same tab (login/register) again', () => {
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration />));
|
const { container } = render(reduxWrapper(<Logistration />));
|
||||||
// While staying on the registration form, clicking the register tab again
|
// While staying on the registration form, clicking the register tab again
|
||||||
fireEvent.click(container.querySelector('a[data-rb-event-key="/register"]'));
|
fireEvent.click(container.querySelector('a[data-rb-event-key="/register"]'));
|
||||||
|
|
||||||
@@ -107,14 +105,14 @@ describe('Logistration', () => {
|
|||||||
ALLOW_PUBLIC_ACCOUNT_CREATION: true,
|
ALLOW_PUBLIC_ACCOUNT_CREATION: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration />));
|
const { container } = render(reduxWrapper(<Logistration />));
|
||||||
|
|
||||||
expect(container.querySelector('RegistrationPage')).toBeDefined();
|
expect(container.querySelector('RegistrationPage')).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render login page', () => {
|
it('should render login page', () => {
|
||||||
const props = { selectedPage: LOGIN_PAGE };
|
const props = { selectedPage: LOGIN_PAGE };
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration {...props} />));
|
const { container } = render(reduxWrapper(<Logistration {...props} />));
|
||||||
|
|
||||||
expect(container.querySelector('LoginPage')).toBeDefined();
|
expect(container.querySelector('LoginPage')).toBeDefined();
|
||||||
});
|
});
|
||||||
@@ -125,7 +123,7 @@ describe('Logistration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let props = { selectedPage: LOGIN_PAGE };
|
let props = { selectedPage: LOGIN_PAGE };
|
||||||
const { rerender } = render(reduxWrapper(<IntlLogistration {...props} />));
|
const { rerender } = render(reduxWrapper(<Logistration {...props} />));
|
||||||
|
|
||||||
// verifying sign in heading
|
// verifying sign in heading
|
||||||
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Sign in');
|
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Sign in');
|
||||||
@@ -133,7 +131,7 @@ describe('Logistration', () => {
|
|||||||
// register page is still accessible when SHOW_REGISTRATION_LINKS is false
|
// register page is still accessible when SHOW_REGISTRATION_LINKS is false
|
||||||
// but it needs to be accessed directly
|
// but it needs to be accessed directly
|
||||||
props = { selectedPage: REGISTER_PAGE };
|
props = { selectedPage: REGISTER_PAGE };
|
||||||
rerender(reduxWrapper(<IntlLogistration {...props} />));
|
rerender(reduxWrapper(<Logistration {...props} />));
|
||||||
|
|
||||||
// verifying register heading
|
// verifying register heading
|
||||||
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Register');
|
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Register');
|
||||||
@@ -160,7 +158,7 @@ describe('Logistration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const props = { selectedPage: LOGIN_PAGE };
|
const props = { selectedPage: LOGIN_PAGE };
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration {...props} />));
|
const { container } = render(reduxWrapper(<Logistration {...props} />));
|
||||||
|
|
||||||
// verifying sign in heading for institution login false
|
// verifying sign in heading for institution login false
|
||||||
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Sign in');
|
expect(screen.getByRole('heading', { level: 3 }).textContent).toEqual('Sign in');
|
||||||
@@ -190,7 +188,7 @@ describe('Logistration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const props = { selectedPage: LOGIN_PAGE };
|
const props = { selectedPage: LOGIN_PAGE };
|
||||||
render(reduxWrapper(<IntlLogistration {...props} />));
|
render(reduxWrapper(<Logistration {...props} />));
|
||||||
expect(screen.getByText('Institution/campus credentials')).toBeDefined();
|
expect(screen.getByText('Institution/campus credentials')).toBeDefined();
|
||||||
|
|
||||||
// on clicking "Institution/campus credentials" button, it should display institution login page
|
// on clicking "Institution/campus credentials" button, it should display institution login page
|
||||||
@@ -221,7 +219,7 @@ describe('Logistration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const props = { selectedPage: LOGIN_PAGE };
|
const props = { selectedPage: LOGIN_PAGE };
|
||||||
render(reduxWrapper(<IntlLogistration {...props} />));
|
render(reduxWrapper(<Logistration {...props} />));
|
||||||
fireEvent.click(screen.getByText('Institution/campus credentials'));
|
fireEvent.click(screen.getByText('Institution/campus credentials'));
|
||||||
|
|
||||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
|
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
|
||||||
@@ -253,7 +251,7 @@ describe('Logistration', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { hostname: getConfig().SITE_NAME, href: getConfig().BASE_URL };
|
window.location = { hostname: getConfig().SITE_NAME, href: getConfig().BASE_URL };
|
||||||
|
|
||||||
render(reduxWrapper(<IntlLogistration />));
|
render(reduxWrapper(<Logistration />));
|
||||||
fireEvent.click(screen.getByText('Institution/campus credentials'));
|
fireEvent.click(screen.getByText('Institution/campus credentials'));
|
||||||
expect(screen.getByText('Test University')).toBeDefined();
|
expect(screen.getByText('Test University')).toBeDefined();
|
||||||
|
|
||||||
@@ -264,7 +262,7 @@ describe('Logistration', () => {
|
|||||||
|
|
||||||
it('should fire action to backup registration form on tab click', () => {
|
it('should fire action to backup registration form on tab click', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration />));
|
const { container } = render(reduxWrapper(<Logistration />));
|
||||||
fireEvent.click(container.querySelector('a[data-rb-event-key="/login"]'));
|
fireEvent.click(container.querySelector('a[data-rb-event-key="/login"]'));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationForm());
|
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationForm());
|
||||||
});
|
});
|
||||||
@@ -272,14 +270,14 @@ describe('Logistration', () => {
|
|||||||
it('should fire action to backup login form on tab click', () => {
|
it('should fire action to backup login form on tab click', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const props = { selectedPage: LOGIN_PAGE };
|
const props = { selectedPage: LOGIN_PAGE };
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration {...props} />));
|
const { container } = render(reduxWrapper(<Logistration {...props} />));
|
||||||
fireEvent.click(container.querySelector('a[data-rb-event-key="/register"]'));
|
fireEvent.click(container.querySelector('a[data-rb-event-key="/register"]'));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(backupLoginForm());
|
expect(store.dispatch).toHaveBeenCalledWith(backupLoginForm());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should clear tpa context errorMessage tab click', () => {
|
it('should clear tpa context errorMessage tab click', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { container } = render(reduxWrapper(<IntlLogistration />));
|
const { container } = render(reduxWrapper(<Logistration />));
|
||||||
fireEvent.click(container.querySelector('a[data-rb-event-key="/login"]'));
|
fireEvent.click(container.querySelector('a[data-rb-event-key="/login"]'));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(clearThirdPartyAuthContextErrorMessage());
|
expect(store.dispatch).toHaveBeenCalledWith(clearThirdPartyAuthContextErrorMessage());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||||
import { identifyAuthenticatedUser, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { identifyAuthenticatedUser, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
fireEvent, render, screen,
|
fireEvent, render, screen,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -22,7 +21,6 @@ import {
|
|||||||
import { saveUserProfile } from '../data/actions';
|
import { saveUserProfile } from '../data/actions';
|
||||||
import ProgressiveProfiling from '../ProgressiveProfiling';
|
import ProgressiveProfiling from '../ProgressiveProfiling';
|
||||||
|
|
||||||
const IntlProgressiveProfilingPage = injectIntl(ProgressiveProfiling);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('@edx/frontend-platform/analytics', () => ({
|
jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||||
@@ -114,7 +112,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
mergeConfig({
|
mergeConfig({
|
||||||
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: '',
|
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: '',
|
||||||
});
|
});
|
||||||
const { queryByRole } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { queryByRole } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
const button = queryByRole('button', { name: /learn more about how we use this information/i });
|
const button = queryByRole('button', { name: /learn more about how we use this information/i });
|
||||||
|
|
||||||
expect(button).toBeNull();
|
expect(button).toBeNull();
|
||||||
@@ -125,7 +123,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/support',
|
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/support',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { getByText } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { getByText } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const learnMoreButton = getByText('Learn more about how we use this information.');
|
const learnMoreButton = getByText('Learn more about how we use this information.');
|
||||||
|
|
||||||
@@ -135,7 +133,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
it('should open modal on pressing skip for now button', () => {
|
it('should open modal on pressing skip for now button', () => {
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
|
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
|
||||||
const { getByRole } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { getByRole } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const skipButton = getByRole('button', { name: /skip for now/i });
|
const skipButton = getByRole('button', { name: /skip for now/i });
|
||||||
fireEvent.click(skipButton);
|
fireEvent.click(skipButton);
|
||||||
@@ -150,7 +148,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
// ******** test event functionality ********
|
// ******** test event functionality ********
|
||||||
|
|
||||||
it('should make identify call to segment on progressive profiling page', () => {
|
it('should make identify call to segment on progressive profiling page', () => {
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
expect(identifyAuthenticatedUser).toHaveBeenCalledWith(3);
|
expect(identifyAuthenticatedUser).toHaveBeenCalledWith(3);
|
||||||
expect(identifyAuthenticatedUser).toHaveBeenCalled();
|
expect(identifyAuthenticatedUser).toHaveBeenCalled();
|
||||||
@@ -160,7 +158,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
mergeConfig({
|
mergeConfig({
|
||||||
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/support',
|
AUTHN_PROGRESSIVE_PROFILING_SUPPORT_LINK: 'http://localhost:1999/support',
|
||||||
});
|
});
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const supportLink = screen.getByRole('link', { name: /learn more about how we use this information/i });
|
const supportLink = screen.getByRole('link', { name: /learn more about how we use this information/i });
|
||||||
fireEvent.click(supportLink);
|
fireEvent.click(supportLink);
|
||||||
@@ -178,7 +176,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
};
|
};
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
|
window.location = { href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING) };
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const nextButton = screen.getByText('Next');
|
const nextButton = screen.getByText('Next');
|
||||||
fireEvent.click(nextButton);
|
fireEvent.click(nextButton);
|
||||||
@@ -194,7 +192,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
extended_profile: [{ field_name: 'company', field_value: 'test company' }],
|
extended_profile: [{ field_name: 'company', field_value: 'test company' }],
|
||||||
};
|
};
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, getByText } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { getByLabelText, getByText } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const genderSelect = getByLabelText('Gender');
|
const genderSelect = getByLabelText('Gender');
|
||||||
const companyInput = getByLabelText('Company');
|
const companyInput = getByLabelText('Company');
|
||||||
@@ -216,7 +214,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
const errorElement = container.querySelector('#pp-page-errors');
|
const errorElement = container.querySelector('#pp-page-errors');
|
||||||
|
|
||||||
expect(errorElement).toBeTruthy();
|
expect(errorElement).toBeTruthy();
|
||||||
@@ -232,7 +230,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
href: getConfig().BASE_URL,
|
href: getConfig().BASE_URL,
|
||||||
};
|
};
|
||||||
|
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
expect(window.location.href).toEqual(DASHBOARD_URL);
|
expect(window.location.href).toEqual(DASHBOARD_URL);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -250,7 +248,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
success: true,
|
success: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
const nextButton = container.querySelector('button.btn-brand');
|
const nextButton = container.querySelector('button.btn-brand');
|
||||||
expect(nextButton.textContent).toEqual('Next');
|
expect(nextButton.textContent).toEqual('Next');
|
||||||
|
|
||||||
@@ -277,7 +275,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
const nextButton = container.querySelector('button.btn-brand');
|
const nextButton = container.querySelector('button.btn-brand');
|
||||||
expect(nextButton.textContent).toEqual('Submit');
|
expect(nextButton.textContent).toEqual('Submit');
|
||||||
|
|
||||||
@@ -311,7 +309,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
|
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
|
||||||
search: `?host=${host}&variant=${EMBEDDED}`,
|
search: `?host=${host}&variant=${EMBEDDED}`,
|
||||||
};
|
};
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const skipLinkButton = screen.getByText('Skip for now');
|
const skipLinkButton = screen.getByText('Skip for now');
|
||||||
fireEvent.click(skipLinkButton);
|
fireEvent.click(skipLinkButton);
|
||||||
@@ -336,7 +334,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const tpaSpinnerElement = container.querySelector('#tpa-spinner');
|
const tpaSpinnerElement = container.querySelector('#tpa-spinner');
|
||||||
expect(tpaSpinnerElement).toBeTruthy();
|
expect(tpaSpinnerElement).toBeTruthy();
|
||||||
@@ -355,7 +353,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
|
href: getConfig().BASE_URL.concat(AUTHN_PROGRESSIVE_PROFILING),
|
||||||
search: `?host=${host}`,
|
search: `?host=${host}`,
|
||||||
};
|
};
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
const submitButton = screen.getByText('Next');
|
const submitButton = screen.getByText('Next');
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
|
|
||||||
@@ -370,7 +368,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
search: `?variant=${EMBEDDED}&host=${host}`,
|
search: `?variant=${EMBEDDED}&host=${host}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
const { container } = render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
|
|
||||||
const genderField = container.querySelector('#gender');
|
const genderField = container.querySelector('#gender');
|
||||||
expect(genderField).toBeTruthy();
|
expect(genderField).toBeTruthy();
|
||||||
@@ -391,7 +389,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
expect(window.location.href).toBe(DASHBOARD_URL);
|
expect(window.location.href).toBe(DASHBOARD_URL);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -419,7 +417,7 @@ describe('ProgressiveProfilingTests', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(reduxWrapper(<IntlProgressiveProfilingPage />));
|
render(reduxWrapper(<ProgressiveProfiling />));
|
||||||
const submitButton = screen.getByText('Submit');
|
const submitButton = screen.getByText('Submit');
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
expect(window.location.href).toBe(redirectUrl);
|
expect(window.location.href).toBe(redirectUrl);
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import React from 'react';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
import SmallLayout from './SmallLayout';
|
import SmallLayout from './SmallLayout';
|
||||||
import mockedRecommendedProducts from '../data/tests/mockedData';
|
import mockedRecommendedProducts from '../data/tests/mockedData';
|
||||||
|
|
||||||
const IntlRecommendationsSmallLayoutPage = injectIntl(SmallLayout);
|
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
jest.mock('react-router-dom', () => ({
|
||||||
...jest.requireActual('react-router-dom'),
|
...jest.requireActual('react-router-dom'),
|
||||||
useLocation: jest.fn(),
|
useLocation: jest.fn(),
|
||||||
@@ -36,7 +32,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should render recommendations when recommendations are not loading', () => {
|
it('should render recommendations when recommendations are not loading', () => {
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsSmallLayoutPage {...props} />));
|
const { container } = render(reduxWrapper(<SmallLayout {...props} />));
|
||||||
|
|
||||||
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
||||||
|
|
||||||
@@ -48,7 +44,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
...props,
|
...props,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
};
|
};
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsSmallLayoutPage {...props} />));
|
const { container } = render(reduxWrapper(<SmallLayout {...props} />));
|
||||||
|
|
||||||
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { renderHook } from '@testing-library/react-hooks';
|
import { renderHook } from '@testing-library/react';
|
||||||
import algoliasearchHelper from 'algoliasearch-helper';
|
import algoliasearchHelper from 'algoliasearch-helper';
|
||||||
|
|
||||||
import mockedRecommendedProducts from './mockedData';
|
import mockedRecommendedProducts from './mockedData';
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
|
|
||||||
import mockedProductData from './mockedData';
|
import mockedProductData from './mockedData';
|
||||||
import RecommendationList from '../RecommendationsList';
|
import RecommendationList from '../RecommendationsList';
|
||||||
|
|
||||||
const IntlRecommendationList = injectIntl(RecommendationList);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
describe('RecommendationsListTests', () => {
|
describe('RecommendationsListTests', () => {
|
||||||
@@ -25,7 +23,7 @@ describe('RecommendationsListTests', () => {
|
|||||||
userId: 1234567,
|
userId: 1234567,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationList {...props} />));
|
const { container } = render(reduxWrapper(<RecommendationList {...props} />));
|
||||||
|
|
||||||
const recommendationCards = container.querySelectorAll('.recommendation-card');
|
const recommendationCards = container.querySelectorAll('.recommendation-card');
|
||||||
expect(recommendationCards.length).toEqual(mockedProductData.length);
|
expect(recommendationCards.length).toEqual(mockedProductData.length);
|
||||||
@@ -37,7 +35,7 @@ describe('RecommendationsListTests', () => {
|
|||||||
userId: 1234567,
|
userId: 1234567,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getByText } = render(reduxWrapper(<IntlRecommendationList {...props} />));
|
const { getByText } = render(reduxWrapper(<RecommendationList {...props} />));
|
||||||
|
|
||||||
const firstFooterContent = getByText('1 Course');
|
const firstFooterContent = getByText('1 Course');
|
||||||
const secondFooterContent = getByText('2 Courses');
|
const secondFooterContent = getByText('2 Courses');
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { useMediaQuery } from '@openedx/paragon';
|
import { useMediaQuery } from '@openedx/paragon';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
@@ -16,7 +15,6 @@ import mockedRecommendedProducts from '../data/tests/mockedData';
|
|||||||
import RecommendationsPage from '../RecommendationsPage';
|
import RecommendationsPage from '../RecommendationsPage';
|
||||||
import { eventNames, getProductMapping } from '../track';
|
import { eventNames, getProductMapping } from '../track';
|
||||||
|
|
||||||
const IntlRecommendationsPage = injectIntl(RecommendationsPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('@edx/frontend-platform/analytics', () => ({
|
jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||||
@@ -77,7 +75,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect to dashboard if user is not coming from registration workflow', () => {
|
it('should redirect to dashboard if user is not coming from registration workflow', () => {
|
||||||
render(reduxWrapper(<IntlRecommendationsPage />));
|
render(reduxWrapper(<RecommendationsPage />));
|
||||||
expect(window.location.href).toEqual(dashboardUrl);
|
expect(window.location.href).toEqual(dashboardUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -86,14 +84,14 @@ describe('RecommendationsPageTests', () => {
|
|||||||
recommendations: [],
|
recommendations: [],
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
});
|
});
|
||||||
render(reduxWrapper(<IntlRecommendationsPage />));
|
render(reduxWrapper(<RecommendationsPage />));
|
||||||
expect(window.location.href).toEqual(dashboardUrl);
|
expect(window.location.href).toEqual(dashboardUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect user if they click "Skip for now" button', () => {
|
it('should redirect user if they click "Skip for now" button', () => {
|
||||||
mockUseLocation();
|
mockUseLocation();
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
|
const { container } = render(reduxWrapper(<RecommendationsPage />));
|
||||||
const skipButton = container.querySelector('.pgn__stateful-btn-state-default');
|
const skipButton = container.querySelector('.pgn__stateful-btn-state-default');
|
||||||
fireEvent.click(skipButton);
|
fireEvent.click(skipButton);
|
||||||
jest.advanceTimersByTime(300);
|
jest.advanceTimersByTime(300);
|
||||||
@@ -103,7 +101,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
it('should display recommendations small layout for small screen', () => {
|
it('should display recommendations small layout for small screen', () => {
|
||||||
mockUseLocation();
|
mockUseLocation();
|
||||||
useMediaQuery.mockReturnValue(true);
|
useMediaQuery.mockReturnValue(true);
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
|
const { container } = render(reduxWrapper(<RecommendationsPage />));
|
||||||
|
|
||||||
const recommendationsSmallLayout = container.querySelector('#recommendations-small-layout');
|
const recommendationsSmallLayout = container.querySelector('#recommendations-small-layout');
|
||||||
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
||||||
@@ -115,7 +113,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
it('should display recommendations large layout for large screen', () => {
|
it('should display recommendations large layout for large screen', () => {
|
||||||
mockUseLocation();
|
mockUseLocation();
|
||||||
useMediaQuery.mockReturnValue(false);
|
useMediaQuery.mockReturnValue(false);
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
|
const { container } = render(reduxWrapper(<RecommendationsPage />));
|
||||||
|
|
||||||
const pgnCollapsible = container.querySelector('.pgn_collapsible');
|
const pgnCollapsible = container.querySelector('.pgn_collapsible');
|
||||||
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
||||||
@@ -131,7 +129,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
recommendations: [],
|
recommendations: [],
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
});
|
});
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
|
const { container } = render(reduxWrapper(<RecommendationsPage />));
|
||||||
|
|
||||||
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
||||||
|
|
||||||
@@ -145,7 +143,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
recommendations: [],
|
recommendations: [],
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
});
|
});
|
||||||
const { container } = render(reduxWrapper(<IntlRecommendationsPage />));
|
const { container } = render(reduxWrapper(<RecommendationsPage />));
|
||||||
|
|
||||||
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
const reactLoadingSkeleton = container.querySelector('.react-loading-skeleton');
|
||||||
|
|
||||||
@@ -160,7 +158,7 @@ describe('RecommendationsPageTests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useMediaQuery.mockReturnValue(false);
|
useMediaQuery.mockReturnValue(false);
|
||||||
render(reduxWrapper(<IntlRecommendationsPage />));
|
render(reduxWrapper(<RecommendationsPage />));
|
||||||
|
|
||||||
expect(sendTrackEvent).toBeCalled();
|
expect(sendTrackEvent).toBeCalled();
|
||||||
expect(sendTrackEvent).toHaveBeenCalledWith(
|
expect(sendTrackEvent).toHaveBeenCalledWith(
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const CountryField = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getCountryList = () => countryList.map((country) => (
|
const getCountryList = () => countryList.map((country) => (
|
||||||
<FormAutosuggestOption key={country[COUNTRY_CODE_KEY]} id={country[COUNTRY_CODE_KEY]}>
|
<FormAutosuggestOption key={country[COUNTRY_DISPLAY_KEY]} id={country[COUNTRY_CODE_KEY]}>
|
||||||
{country[COUNTRY_DISPLAY_KEY]}
|
{country[COUNTRY_DISPLAY_KEY]}
|
||||||
</FormAutosuggestOption>
|
</FormAutosuggestOption>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { mergeConfig } from '@edx/frontend-platform';
|
import { mergeConfig } from '@edx/frontend-platform';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
@@ -10,7 +9,6 @@ import configureStore from 'redux-mock-store';
|
|||||||
import { COUNTRY_CODE_KEY, COUNTRY_DISPLAY_KEY } from './validator';
|
import { COUNTRY_CODE_KEY, COUNTRY_DISPLAY_KEY } from './validator';
|
||||||
import { CountryField } from '../index';
|
import { CountryField } from '../index';
|
||||||
|
|
||||||
const IntlCountryField = injectIntl(CountryField);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -82,7 +80,7 @@ describe('CountryField', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should run country field validation when onBlur is fired', () => {
|
it('should run country field validation when onBlur is fired', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
|
|
||||||
fireEvent.blur(countryInput, {
|
fireEvent.blur(countryInput, {
|
||||||
@@ -97,7 +95,7 @@ describe('CountryField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should run country field validation when country name is invalid', () => {
|
it('should run country field validation when country name is invalid', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
|
|
||||||
fireEvent.blur(countryInput, {
|
fireEvent.blur(countryInput, {
|
||||||
@@ -112,7 +110,7 @@ describe('CountryField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not run country field validation when onBlur is fired by drop-down arrow icon click', () => {
|
it('should not run country field validation when onBlur is fired by drop-down arrow icon click', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
const dropdownArrowIcon = container.querySelector('.btn-icon.pgn__form-autosuggest__icon-button');
|
const dropdownArrowIcon = container.querySelector('.btn-icon.pgn__form-autosuggest__icon-button');
|
||||||
|
|
||||||
@@ -125,7 +123,7 @@ describe('CountryField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update errors for frontend validations', () => {
|
it('should update errors for frontend validations', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
|
|
||||||
fireEvent.blur(countryInput, { target: { value: '', name: 'country' } });
|
fireEvent.blur(countryInput, { target: { value: '', name: 'country' } });
|
||||||
@@ -135,7 +133,7 @@ describe('CountryField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear error on focus', () => {
|
it('should clear error on focus', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
|
|
||||||
fireEvent.focus(countryInput);
|
fireEvent.focus(countryInput);
|
||||||
@@ -153,7 +151,7 @@ describe('CountryField', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
|
|
||||||
container.querySelector('input[name="country"]');
|
container.querySelector('input[name="country"]');
|
||||||
expect(props.onChangeHandler).toHaveBeenCalledTimes(1);
|
expect(props.onChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
@@ -164,7 +162,7 @@ describe('CountryField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set option on dropdown menu item click', () => {
|
it('should set option on dropdown menu item click', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
|
|
||||||
const dropdownButton = container.querySelector('.pgn__form-autosuggest__icon-button');
|
const dropdownButton = container.querySelector('.pgn__form-autosuggest__icon-button');
|
||||||
fireEvent.click(dropdownButton);
|
fireEvent.click(dropdownButton);
|
||||||
@@ -181,7 +179,7 @@ describe('CountryField', () => {
|
|||||||
|
|
||||||
it('should set value on change', () => {
|
it('should set value on change', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlCountryField {...props} />)),
|
routerWrapper(reduxWrapper(<CountryField {...props} />)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
@@ -200,7 +198,7 @@ describe('CountryField', () => {
|
|||||||
errorMessage: 'country error message',
|
errorMessage: 'country error message',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlCountryField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<CountryField {...props} />)));
|
||||||
|
|
||||||
const feedbackElement = container.querySelector('div[feedback-for="country"]');
|
const feedbackElement = container.querySelector('div[feedback-for="country"]');
|
||||||
expect(feedbackElement).toBeTruthy();
|
expect(feedbackElement).toBeTruthy();
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
@@ -10,7 +9,6 @@ import configureStore from 'redux-mock-store';
|
|||||||
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
|
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
|
||||||
import { EmailField } from '../index';
|
import { EmailField } from '../index';
|
||||||
|
|
||||||
const IntlEmailField = injectIntl(EmailField);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -80,7 +78,7 @@ describe('EmailField', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should run email field validation when onBlur is fired', () => {
|
it('should run email field validation when onBlur is fired', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: '', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: '', name: 'email' } });
|
||||||
@@ -92,7 +90,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update errors for frontend validations', () => {
|
it('should update errors for frontend validations', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'ab', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'ab', name: 'email' } });
|
||||||
@@ -105,7 +103,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear error on focus', () => {
|
it('should clear error on focus', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.focus(emailInput, { target: { value: '', name: 'email' } });
|
fireEvent.focus(emailInput, { target: { value: '', name: 'email' } });
|
||||||
@@ -119,7 +117,7 @@ describe('EmailField', () => {
|
|||||||
|
|
||||||
it('should call backend validation api on blur event, if frontend validations have passed', () => {
|
it('should call backend validation api on blur event, if frontend validations have passed', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
// Enter a valid email so that frontend validations are passed
|
// Enter a valid email so that frontend validations are passed
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
@@ -129,7 +127,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should give email suggestions for common service provider domain typos', () => {
|
it('should give email suggestions for common service provider domain typos', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
|
||||||
@@ -139,7 +137,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to click on email suggestions and set it as value', () => {
|
it('should be able to click on email suggestions and set it as value', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
|
||||||
@@ -154,7 +152,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should give error for common top level domain mistakes', () => {
|
it('should give error for common top level domain mistakes', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
|
||||||
@@ -164,7 +162,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should give error and suggestion for invalid email', () => {
|
it('should give error and suggestion for invalid email', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'john@gmail', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'john@gmail', name: 'email' } });
|
||||||
@@ -194,7 +192,7 @@ describe('EmailField', () => {
|
|||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.focus(emailInput, { target: { value: 'a@gmail.com', name: 'email' } });
|
fireEvent.focus(emailInput, { target: { value: 'a@gmail.com', name: 'email' } });
|
||||||
@@ -203,7 +201,7 @@ describe('EmailField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear email suggestions when close icon is clicked', () => {
|
it('should clear email suggestions when close icon is clicked', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
|
||||||
@@ -224,7 +222,7 @@ describe('EmailField', () => {
|
|||||||
confirmEmailValue: 'confirmEmail@yopmail.com',
|
confirmEmailValue: 'confirmEmail@yopmail.com',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlEmailField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
fireEvent.blur(emailInput, { target: { value: 'differentEmail@yopmail.com', name: 'email' } });
|
fireEvent.blur(emailInput, { target: { value: 'differentEmail@yopmail.com', name: 'email' } });
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
import { HonorCode } from '../index';
|
import { HonorCode } from '../index';
|
||||||
|
|
||||||
const IntlHonorCode = injectIntl(HonorCode);
|
|
||||||
|
|
||||||
describe('HonorCodeTest', () => {
|
describe('HonorCodeTest', () => {
|
||||||
mergeConfig({
|
mergeConfig({
|
||||||
PRIVACY_POLICY: 'http://privacy-policy.com',
|
PRIVACY_POLICY: 'http://privacy-policy.com',
|
||||||
@@ -28,7 +24,7 @@ describe('HonorCodeTest', () => {
|
|||||||
const errorMessage = `You must agree to the ${getConfig().SITE_NAME} Honor Code`;
|
const errorMessage = `You must agree to the ${getConfig().SITE_NAME} Honor Code`;
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlHonorCode
|
<HonorCode
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
onChangeHandler={changeHandler}
|
onChangeHandler={changeHandler}
|
||||||
/>
|
/>
|
||||||
@@ -43,7 +39,7 @@ describe('HonorCodeTest', () => {
|
|||||||
const expectedMsg = 'I agree to the Your Platform Name Here\u00a0Honor Codein a new tab';
|
const expectedMsg = 'I agree to the Your Platform Name Here\u00a0Honor Codein a new tab';
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlHonorCode onChangeHandler={changeHandler} />
|
<HonorCode onChangeHandler={changeHandler} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -56,7 +52,7 @@ describe('HonorCodeTest', () => {
|
|||||||
it('should render Terms of Service and Honor code field', () => {
|
it('should render Terms of Service and Honor code field', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlHonorCode fieldType="tos_and_honor_code" onChangeHandler={changeHandler} />
|
<HonorCode fieldType="tos_and_honor_code" onChangeHandler={changeHandler} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
const expectedMsg = 'By creating an account, you agree to the Terms of Service and Honor Code and you '
|
const expectedMsg = 'By creating an account, you agree to the Terms of Service and Honor Code and you '
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
@@ -9,7 +8,6 @@ import configureStore from 'redux-mock-store';
|
|||||||
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
|
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
|
||||||
import { NameField } from '../index';
|
import { NameField } from '../index';
|
||||||
|
|
||||||
const IntlNameField = injectIntl(NameField);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -69,7 +67,7 @@ describe('NameField', () => {
|
|||||||
const fieldValidation = { name: 'Enter your full name' };
|
const fieldValidation = { name: 'Enter your full name' };
|
||||||
|
|
||||||
it('should run name field validation when onBlur is fired', () => {
|
it('should run name field validation when onBlur is fired', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
|
||||||
|
|
||||||
const nameInput = container.querySelector('input#name');
|
const nameInput = container.querySelector('input#name');
|
||||||
fireEvent.blur(nameInput, { target: { value: '', name: 'name' } });
|
fireEvent.blur(nameInput, { target: { value: '', name: 'name' } });
|
||||||
@@ -82,7 +80,7 @@ describe('NameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update errors for frontend validations', () => {
|
it('should update errors for frontend validations', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
|
||||||
|
|
||||||
const nameInput = container.querySelector('input#name');
|
const nameInput = container.querySelector('input#name');
|
||||||
fireEvent.blur(nameInput, { target: { value: 'https://invalid-name.com', name: 'name' } });
|
fireEvent.blur(nameInput, { target: { value: 'https://invalid-name.com', name: 'name' } });
|
||||||
@@ -95,7 +93,7 @@ describe('NameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear error on focus', () => {
|
it('should clear error on focus', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
|
||||||
|
|
||||||
const nameInput = container.querySelector('input#name');
|
const nameInput = container.querySelector('input#name');
|
||||||
fireEvent.focus(nameInput, { target: { value: '', name: 'name' } });
|
fireEvent.focus(nameInput, { target: { value: '', name: 'name' } });
|
||||||
@@ -113,7 +111,7 @@ describe('NameField', () => {
|
|||||||
...props,
|
...props,
|
||||||
shouldFetchUsernameSuggestions: true,
|
shouldFetchUsernameSuggestions: true,
|
||||||
};
|
};
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
|
||||||
|
|
||||||
const nameInput = container.querySelector('input#name');
|
const nameInput = container.querySelector('input#name');
|
||||||
// Enter a valid name so that frontend validations are passed
|
// Enter a valid name so that frontend validations are passed
|
||||||
@@ -135,7 +133,7 @@ describe('NameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlNameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<NameField {...props} />)));
|
||||||
|
|
||||||
const nameInput = container.querySelector('input#name');
|
const nameInput = container.querySelector('input#name');
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
|
|
||||||
import { TermsOfService } from '../index';
|
import { TermsOfService } from '../index';
|
||||||
|
|
||||||
const IntlTermsOfService = injectIntl(TermsOfService);
|
|
||||||
|
|
||||||
describe('TermsOfServiceTest', () => {
|
describe('TermsOfServiceTest', () => {
|
||||||
let value = false;
|
let value = false;
|
||||||
|
|
||||||
@@ -23,7 +19,7 @@ describe('TermsOfServiceTest', () => {
|
|||||||
const errorMessage = `You must agree to the ${getConfig().SITE_NAME} Terms of Service`;
|
const errorMessage = `You must agree to the ${getConfig().SITE_NAME} Terms of Service`;
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlTermsOfService errorMessage={errorMessage} onChangeHandler={changeHandler} />
|
<TermsOfService errorMessage={errorMessage} onChangeHandler={changeHandler} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
const errorElement = container.querySelector('.form-text-size');
|
const errorElement = container.querySelector('.form-text-size');
|
||||||
@@ -33,7 +29,7 @@ describe('TermsOfServiceTest', () => {
|
|||||||
it('should render Terms of Service field', () => {
|
it('should render Terms of Service field', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlTermsOfService onChangeHandler={changeHandler} />
|
<TermsOfService onChangeHandler={changeHandler} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -48,7 +44,7 @@ describe('TermsOfServiceTest', () => {
|
|||||||
it('should change value when Terms of Service field is checked', () => {
|
it('should change value when Terms of Service field is checked', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<IntlProvider locale="en">
|
<IntlProvider locale="en">
|
||||||
<IntlTermsOfService onChangeHandler={changeHandler} />
|
<TermsOfService onChangeHandler={changeHandler} />
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
);
|
);
|
||||||
const field = container.querySelector('input#tos');
|
const field = container.querySelector('input#tos');
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ const UsernameField = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const suggestedUsernames = () => (
|
const suggestedUsernames = () => (
|
||||||
<div className={className}>
|
<div className={className} role="listbox">
|
||||||
<span className="text-gray username-suggestion--label">{formatMessage(messages['registration.username.suggestion.label'])}</span>
|
<span className="text-gray username-suggestion--label">{formatMessage(messages['registration.username.suggestion.label'])}</span>
|
||||||
<div className="username-scroll-suggested--form-field">
|
<div className="username-scroll-suggested--form-field">
|
||||||
{usernameSuggestions.map((username, index) => (
|
{usernameSuggestions.map((username, index) => (
|
||||||
@@ -112,7 +112,9 @@ const UsernameField = (props) => {
|
|||||||
className="username-suggestions--chip data-hj-suppress"
|
className="username-suggestions--chip data-hj-suppress"
|
||||||
autoComplete={props.autoComplete}
|
autoComplete={props.autoComplete}
|
||||||
key={`suggestion-${index.toString()}`}
|
key={`suggestion-${index.toString()}`}
|
||||||
|
tabIndex={0}
|
||||||
onClick={(e) => handleSuggestionClick(e, username)}
|
onClick={(e) => handleSuggestionClick(e, username)}
|
||||||
|
role="option"
|
||||||
>
|
>
|
||||||
{username}
|
{username}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -123,7 +125,7 @@ const UsernameField = (props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (usernameSuggestions.length > 0 && errorMessage && value === ' ') {
|
if (usernameSuggestions.length > 0 && errorMessage && value === ' ') {
|
||||||
className = 'username-suggestions__error';
|
className = 'username-suggestions';
|
||||||
iconButton = <IconButton src={Close} iconAs={Icon} alt="Close" onClick={() => handleUsernameSuggestionClose()} variant="black" size="sm" className="username-suggestions__close__button" />;
|
iconButton = <IconButton src={Close} iconAs={Icon} alt="Close" onClick={() => handleUsernameSuggestionClose()} variant="black" size="sm" className="username-suggestions__close__button" />;
|
||||||
suggestedUsernameDiv = suggestedUsernames();
|
suggestedUsernameDiv = suggestedUsernames();
|
||||||
} else if (usernameSuggestions.length > 0 && value === ' ') {
|
} else if (usernameSuggestions.length > 0 && value === ' ') {
|
||||||
@@ -134,14 +136,15 @@ const UsernameField = (props) => {
|
|||||||
suggestedUsernameDiv = suggestedUsernames();
|
suggestedUsernameDiv = suggestedUsernames();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<FormGroup
|
<div className="username__form-group-wrapper">
|
||||||
{...props}
|
|
||||||
handleChange={handleOnChange}
|
|
||||||
handleFocus={handleOnFocus}
|
|
||||||
handleBlur={handleOnBlur}
|
|
||||||
>
|
|
||||||
{suggestedUsernameDiv}
|
{suggestedUsernameDiv}
|
||||||
</FormGroup>
|
<FormGroup
|
||||||
|
{...props}
|
||||||
|
handleChange={handleOnChange}
|
||||||
|
handleFocus={handleOnFocus}
|
||||||
|
handleBlur={handleOnBlur}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
@@ -9,7 +8,6 @@ import configureStore from 'redux-mock-store';
|
|||||||
import { clearRegistrationBackendError, clearUsernameSuggestions, fetchRealtimeValidations } from '../../data/actions';
|
import { clearRegistrationBackendError, clearUsernameSuggestions, fetchRealtimeValidations } from '../../data/actions';
|
||||||
import { UsernameField } from '../index';
|
import { UsernameField } from '../index';
|
||||||
|
|
||||||
const IntlUsernameField = injectIntl(UsernameField);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -73,7 +71,7 @@ describe('UsernameField', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('should run username field validation when onBlur is fired', () => {
|
it('should run username field validation when onBlur is fired', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.blur(usernameField, { target: { value: '', name: 'username' } });
|
fireEvent.blur(usernameField, { target: { value: '', name: 'username' } });
|
||||||
@@ -86,7 +84,7 @@ describe('UsernameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update errors for frontend validations', () => {
|
it('should update errors for frontend validations', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.blur(usernameField, { target: { value: 'user#', name: 'username' } });
|
fireEvent.blur(usernameField, { target: { value: 'user#', name: 'username' } });
|
||||||
@@ -99,7 +97,7 @@ describe('UsernameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear error on focus', () => {
|
it('should clear error on focus', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.focus(usernameField, { target: { value: '', name: 'username' } });
|
fireEvent.focus(usernameField, { target: { value: '', name: 'username' } });
|
||||||
@@ -112,7 +110,7 @@ describe('UsernameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should remove space from field on focus if space exists', () => {
|
it('should remove space from field on focus if space exists', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.focus(usernameField, { target: { value: ' ', name: 'username' } });
|
fireEvent.focus(usernameField, { target: { value: ' ', name: 'username' } });
|
||||||
@@ -125,7 +123,7 @@ describe('UsernameField', () => {
|
|||||||
|
|
||||||
it('should call backend validation api on blur event, if frontend validations have passed', () => {
|
it('should call backend validation api on blur event, if frontend validations have passed', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
// Enter a valid username so that frontend validations are passed
|
// Enter a valid username so that frontend validations are passed
|
||||||
@@ -135,7 +133,7 @@ describe('UsernameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should remove space from the start of username on change', () => {
|
it('should remove space from the start of username on change', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.change(usernameField, { target: { value: ' test-user', name: 'username' } });
|
fireEvent.change(usernameField, { target: { value: ' test-user', name: 'username' } });
|
||||||
|
|
||||||
@@ -146,7 +144,7 @@ describe('UsernameField', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not set username if it is more than 30 character long', () => {
|
it('should not set username if it is more than 30 character long', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.change(usernameField, { target: { value: 'why_this_is_not_valid_username_', name: 'username' } });
|
fireEvent.change(usernameField, { target: { value: 'why_this_is_not_valid_username_', name: 'username' } });
|
||||||
@@ -157,7 +155,7 @@ describe('UsernameField', () => {
|
|||||||
it('should clear username suggestions when username field is focused in', () => {
|
it('should clear username suggestions when username field is focused in', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.focus(usernameField);
|
fireEvent.focus(usernameField);
|
||||||
@@ -179,7 +177,7 @@ describe('UsernameField', () => {
|
|||||||
errorMessage: 'It looks like this username is already taken',
|
errorMessage: 'It looks like this username is already taken',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
|
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
|
||||||
expect(usernameSuggestions.length).toEqual(3);
|
expect(usernameSuggestions.length).toEqual(3);
|
||||||
});
|
});
|
||||||
@@ -198,7 +196,7 @@ describe('UsernameField', () => {
|
|||||||
value: ' ',
|
value: ' ',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
|
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
|
||||||
expect(usernameSuggestions.length).toEqual(3);
|
expect(usernameSuggestions.length).toEqual(3);
|
||||||
});
|
});
|
||||||
@@ -218,7 +216,7 @@ describe('UsernameField', () => {
|
|||||||
errorMessage: 'username error',
|
errorMessage: 'username error',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
|
const usernameSuggestions = container.querySelectorAll('button.username-suggestions--chip');
|
||||||
expect(usernameSuggestions.length).toEqual(3);
|
expect(usernameSuggestions.length).toEqual(3);
|
||||||
});
|
});
|
||||||
@@ -232,7 +230,7 @@ describe('UsernameField', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
expect(props.handleChange).toHaveBeenCalledTimes(1);
|
expect(props.handleChange).toHaveBeenCalledTimes(1);
|
||||||
expect(props.handleChange).toHaveBeenCalledWith(
|
expect(props.handleChange).toHaveBeenCalledWith(
|
||||||
{ target: { name: 'username', value: ' ' } },
|
{ target: { name: 'username', value: ' ' } },
|
||||||
@@ -253,7 +251,7 @@ describe('UsernameField', () => {
|
|||||||
value: ' ',
|
value: ' ',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
const usernameSuggestion = container.querySelector('.username-suggestions--chip');
|
const usernameSuggestion = container.querySelector('.username-suggestions--chip');
|
||||||
fireEvent.click(usernameSuggestion);
|
fireEvent.click(usernameSuggestion);
|
||||||
expect(props.handleChange).toHaveBeenCalledTimes(1);
|
expect(props.handleChange).toHaveBeenCalledTimes(1);
|
||||||
@@ -277,7 +275,7 @@ describe('UsernameField', () => {
|
|||||||
value: ' ',
|
value: ' ',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
let closeButton = container.querySelector('button.username-suggestions__close__button');
|
let closeButton = container.querySelector('button.username-suggestions__close__button');
|
||||||
fireEvent.click(closeButton);
|
fireEvent.click(closeButton);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
|
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
|
||||||
@@ -287,7 +285,7 @@ describe('UsernameField', () => {
|
|||||||
errorMessage: 'username error',
|
errorMessage: 'username error',
|
||||||
};
|
};
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
closeButton = container.querySelector('button.username-suggestions__close__button');
|
closeButton = container.querySelector('button.username-suggestions__close__button');
|
||||||
fireEvent.click(closeButton);
|
fireEvent.click(closeButton);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
|
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
|
||||||
@@ -309,7 +307,7 @@ describe('UsernameField', () => {
|
|||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlUsernameField {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<UsernameField {...props} />)));
|
||||||
|
|
||||||
const usernameField = container.querySelector('input#username');
|
const usernameField = container.querySelector('input#username');
|
||||||
fireEvent.focus(usernameField, { target: { value: 'test', name: 'username' } });
|
fireEvent.focus(usernameField, { target: { value: 'test', name: 'username' } });
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ const RegistrationPage = (props) => {
|
|||||||
showConfigurableEdxFields: getConfig().SHOW_CONFIGURABLE_EDX_FIELDS,
|
showConfigurableEdxFields: getConfig().SHOW_CONFIGURABLE_EDX_FIELDS,
|
||||||
showConfigurableRegistrationFields: getConfig().ENABLE_DYNAMIC_REGISTRATION_FIELDS,
|
showConfigurableRegistrationFields: getConfig().ENABLE_DYNAMIC_REGISTRATION_FIELDS,
|
||||||
showMarketingEmailOptInCheckbox: getConfig().MARKETING_EMAILS_OPT_IN,
|
showMarketingEmailOptInCheckbox: getConfig().MARKETING_EMAILS_OPT_IN,
|
||||||
|
autoGeneratedUsernameEnabled: getConfig().ENABLE_AUTO_GENERATED_USERNAME,
|
||||||
};
|
};
|
||||||
const {
|
const {
|
||||||
handleInstitutionLogin,
|
handleInstitutionLogin,
|
||||||
@@ -215,6 +216,9 @@ const RegistrationPage = (props) => {
|
|||||||
delete payload.password;
|
delete payload.password;
|
||||||
payload.social_auth_provider = currentProvider;
|
payload.social_auth_provider = currentProvider;
|
||||||
}
|
}
|
||||||
|
if (flags.autoGeneratedUsernameEnabled) {
|
||||||
|
delete payload.username;
|
||||||
|
}
|
||||||
|
|
||||||
// Validating form data before submitting
|
// Validating form data before submitting
|
||||||
const { isValid, fieldErrors, emailSuggestion } = isFormValid(
|
const { isValid, fieldErrors, emailSuggestion } = isFormValid(
|
||||||
@@ -324,16 +328,18 @@ const RegistrationPage = (props) => {
|
|||||||
helpText={[formatMessage(messages['help.text.email'])]}
|
helpText={[formatMessage(messages['help.text.email'])]}
|
||||||
floatingLabel={formatMessage(messages['registration.email.label'])}
|
floatingLabel={formatMessage(messages['registration.email.label'])}
|
||||||
/>
|
/>
|
||||||
<UsernameField
|
{!flags.autoGeneratedUsernameEnabled && (
|
||||||
name="username"
|
<UsernameField
|
||||||
spellCheck="false"
|
name="username"
|
||||||
value={formFields.username}
|
spellCheck="false"
|
||||||
handleChange={handleOnChange}
|
value={formFields.username}
|
||||||
handleErrorChange={handleErrorChange}
|
handleChange={handleOnChange}
|
||||||
errorMessage={errors.username}
|
handleErrorChange={handleErrorChange}
|
||||||
helpText={[formatMessage(messages['help.text.username.1']), formatMessage(messages['help.text.username.2'])]}
|
errorMessage={errors.username}
|
||||||
floatingLabel={formatMessage(messages['registration.username.label'])}
|
helpText={[formatMessage(messages['help.text.username.1']), formatMessage(messages['help.text.username.2'])]}
|
||||||
/>
|
floatingLabel={formatMessage(messages['registration.username.label'])}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{!currentProvider && (
|
{!currentProvider && (
|
||||||
<PasswordField
|
<PasswordField
|
||||||
name="password"
|
name="password"
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||||
import {
|
import {
|
||||||
configure, getLocale, injectIntl, IntlProvider,
|
configure, getLocale, IntlProvider,
|
||||||
} from '@edx/frontend-platform/i18n';
|
} from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { mockNavigate, BrowserRouter as Router } from 'react-router-dom';
|
import { mockNavigate, BrowserRouter as Router } from 'react-router-dom';
|
||||||
@@ -31,7 +30,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
|||||||
getLocale: jest.fn(),
|
getLocale: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -134,9 +132,16 @@ describe('RegistrationPage', () => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
const populateRequiredFields = (getByLabelText, payload, isThirdPartyAuth = false) => {
|
const populateRequiredFields = (
|
||||||
|
getByLabelText,
|
||||||
|
payload,
|
||||||
|
isThirdPartyAuth = false,
|
||||||
|
autoGeneratedUsernameEnabled = false,
|
||||||
|
) => {
|
||||||
fireEvent.change(getByLabelText('Full name'), { target: { value: payload.name, name: 'name' } });
|
fireEvent.change(getByLabelText('Full name'), { target: { value: payload.name, name: 'name' } });
|
||||||
fireEvent.change(getByLabelText('Public username'), { target: { value: payload.username, name: 'username' } });
|
if (!autoGeneratedUsernameEnabled) {
|
||||||
|
fireEvent.change(getByLabelText('Public username'), { target: { value: payload.username, name: 'username' } });
|
||||||
|
}
|
||||||
fireEvent.change(getByLabelText('Email'), { target: { value: payload.email, name: 'email' } });
|
fireEvent.change(getByLabelText('Email'), { target: { value: payload.email, name: 'email' } });
|
||||||
|
|
||||||
fireEvent.change(getByLabelText('Country/Region'), { target: { value: payload.country, name: 'country' } });
|
fireEvent.change(getByLabelText('Country/Region'), { target: { value: payload.country, name: 'country' } });
|
||||||
@@ -176,12 +181,12 @@ describe('RegistrationPage', () => {
|
|||||||
password: 'password1',
|
password: 'password1',
|
||||||
country: 'Pakistan',
|
country: 'Pakistan',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
next: '/course/demo-course-url',
|
next: '/course/demo-course-url',
|
||||||
};
|
};
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
populateRequiredFields(getByLabelText, payload);
|
populateRequiredFields(getByLabelText, payload);
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
@@ -199,7 +204,7 @@ describe('RegistrationPage', () => {
|
|||||||
country: 'Pakistan',
|
country: 'Pakistan',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
social_auth_provider: 'Apple',
|
social_auth_provider: 'Apple',
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
store = mockStore({
|
store = mockStore({
|
||||||
@@ -213,7 +218,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
populateRequiredFields(getByLabelText, formPayload, true);
|
populateRequiredFields(getByLabelText, formPayload, true);
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
@@ -232,11 +237,11 @@ describe('RegistrationPage', () => {
|
|||||||
password: 'password1',
|
password: 'password1',
|
||||||
country: 'Ukraine',
|
country: 'Ukraine',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
populateRequiredFields(getByLabelText, formPayload, true);
|
populateRequiredFields(getByLabelText, formPayload, true);
|
||||||
|
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
@@ -257,11 +262,11 @@ describe('RegistrationPage', () => {
|
|||||||
password: 'password1',
|
password: 'password1',
|
||||||
country: 'Ukraine',
|
country: 'Ukraine',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
populateRequiredFields(getByLabelText, formPayload, true);
|
populateRequiredFields(getByLabelText, formPayload, true);
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
@@ -283,12 +288,12 @@ describe('RegistrationPage', () => {
|
|||||||
password: 'password1',
|
password: 'password1',
|
||||||
country: 'Pakistan',
|
country: 'Pakistan',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
marketing_emails_opt_in: true,
|
marketing_emails_opt_in: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
populateRequiredFields(getByLabelText, payload);
|
populateRequiredFields(getByLabelText, payload);
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
@@ -299,10 +304,48 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should submit form without UsernameField when autoGeneratedUsernameEnabled is true', () => {
|
||||||
|
mergeConfig({
|
||||||
|
ENABLE_AUTO_GENERATED_USERNAME: true,
|
||||||
|
});
|
||||||
|
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
|
||||||
|
const payload = {
|
||||||
|
name: 'John Doe',
|
||||||
|
email: 'john.doe@gmail.com',
|
||||||
|
password: 'password1',
|
||||||
|
country: 'Pakistan',
|
||||||
|
honor_code: true,
|
||||||
|
total_registration_time: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
populateRequiredFields(getByLabelText, payload, false, true);
|
||||||
|
const button = container.querySelector('button.btn-brand');
|
||||||
|
fireEvent.click(button);
|
||||||
|
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
|
||||||
|
mergeConfig({
|
||||||
|
ENABLE_AUTO_GENERATED_USERNAME: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display UsernameField when ENABLE_AUTO_GENERATED_USERNAME is true', () => {
|
||||||
|
mergeConfig({
|
||||||
|
ENABLE_AUTO_GENERATED_USERNAME: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryByLabelText } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
expect(queryByLabelText('Username')).toBeNull();
|
||||||
|
|
||||||
|
mergeConfig({
|
||||||
|
ENABLE_AUTO_GENERATED_USERNAME: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should not dispatch registerNewUser on empty form Submission', () => {
|
it('should not dispatch registerNewUser on empty form Submission', () => {
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
@@ -313,7 +356,7 @@ describe('RegistrationPage', () => {
|
|||||||
// ******** test registration form validations ********
|
// ******** test registration form validations ********
|
||||||
|
|
||||||
it('should show error messages for required fields on empty form submission', () => {
|
it('should show error messages for required fields on empty form submission', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
const button = container.querySelector('button.btn-brand');
|
const button = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
@@ -341,7 +384,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlProvider locale="en"><IntlRegistrationPage {...props} /></IntlProvider>)));
|
const { container } = render(routerWrapper(reduxWrapper(<IntlProvider locale="en"><RegistrationPage {...props} /></IntlProvider>)));
|
||||||
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
|
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
|
||||||
const emailFeedback = container.querySelector('div[feedback-for="email"]');
|
const emailFeedback = container.querySelector('div[feedback-for="email"]');
|
||||||
|
|
||||||
@@ -350,7 +393,7 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear error on focus', () => {
|
it('should clear error on focus', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
const submitButton = container.querySelector('button.btn-brand');
|
const submitButton = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
@@ -379,7 +422,7 @@ describe('RegistrationPage', () => {
|
|||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(
|
const { container } = render(routerWrapper(reduxWrapper(
|
||||||
<IntlRegistrationPage {...props} />,
|
<RegistrationPage {...props} />,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
const emailInput = container.querySelector('input#email');
|
const emailInput = container.querySelector('input#email');
|
||||||
@@ -390,7 +433,7 @@ describe('RegistrationPage', () => {
|
|||||||
// ******** test form buttons and fields ********
|
// ******** test form buttons and fields ********
|
||||||
|
|
||||||
it('should match default button state', () => {
|
it('should match default button state', () => {
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const button = container.querySelector('button[type="submit"] span');
|
const button = container.querySelector('button[type="submit"] span');
|
||||||
expect(button.textContent).toEqual('Create an account for free');
|
expect(button.textContent).toEqual('Create an account for free');
|
||||||
});
|
});
|
||||||
@@ -404,7 +447,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
const button = container.querySelector('button[type="submit"] span.sr-only');
|
const button = container.querySelector('button[type="submit"] span.sr-only');
|
||||||
expect(button.textContent).toEqual('pending');
|
expect(button.textContent).toEqual('pending');
|
||||||
@@ -415,7 +458,7 @@ describe('RegistrationPage', () => {
|
|||||||
MARKETING_EMAILS_OPT_IN: 'true',
|
MARKETING_EMAILS_OPT_IN: 'true',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const checkboxDivs = container.querySelectorAll('div.form-field--checkbox');
|
const checkboxDivs = container.querySelectorAll('div.form-field--checkbox');
|
||||||
expect(checkboxDivs.length).toEqual(1);
|
expect(checkboxDivs.length).toEqual(1);
|
||||||
|
|
||||||
@@ -428,7 +471,7 @@ describe('RegistrationPage', () => {
|
|||||||
const buttonLabel = 'Register';
|
const buttonLabel = 'Register';
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL, search: `?cta=${buttonLabel}` };
|
window.location = { href: getConfig().BASE_URL, search: `?cta=${buttonLabel}` };
|
||||||
const { container } = render(reduxWrapper(<IntlRegistrationPage {...props} />));
|
const { container } = render(reduxWrapper(<RegistrationPage {...props} />));
|
||||||
const button = container.querySelector('button[type="submit"] span');
|
const button = container.querySelector('button[type="submit"] span');
|
||||||
|
|
||||||
const buttonText = button.textContent;
|
const buttonText = button.textContent;
|
||||||
@@ -447,7 +490,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(document.cookie).toMatch(`${getConfig().USER_RETENTION_COOKIE_NAME}=true`);
|
expect(document.cookie).toMatch(`${getConfig().USER_RETENTION_COOKIE_NAME}=true`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -465,7 +508,7 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(window.location.href).toBe(dashboardURL);
|
expect(window.location.href).toBe(dashboardURL);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -492,7 +535,7 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(window.location.href).toBe(dashboardUrl);
|
expect(window.location.href).toBe(dashboardUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -523,7 +566,7 @@ describe('RegistrationPage', () => {
|
|||||||
|
|
||||||
render(reduxWrapper(
|
render(reduxWrapper(
|
||||||
<Router>
|
<Router>
|
||||||
<IntlRegistrationPage {...props} />
|
<RegistrationPage {...props} />
|
||||||
</Router>,
|
</Router>,
|
||||||
));
|
));
|
||||||
expect(mockNavigate).toHaveBeenCalledWith(AUTHN_PROGRESSIVE_PROFILING);
|
expect(mockNavigate).toHaveBeenCalledWith(AUTHN_PROGRESSIVE_PROFILING);
|
||||||
@@ -541,12 +584,12 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationFormBegin({ ...registrationFormData }));
|
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationFormBegin({ ...registrationFormData }));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should send page event when register page is rendered', () => {
|
it('should send page event when register page is rendered', () => {
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register');
|
expect(sendPageEvent).toHaveBeenCalledWith('login_and_registration', 'register');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -564,7 +607,7 @@ describe('RegistrationPage', () => {
|
|||||||
|
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', {});
|
expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.user.account.registered.client', {});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -590,7 +633,7 @@ describe('RegistrationPage', () => {
|
|||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { container } = render(reduxWrapper(
|
const { container } = render(reduxWrapper(
|
||||||
<Router>
|
<Router>
|
||||||
<IntlRegistrationPage {...props} />
|
<RegistrationPage {...props} />
|
||||||
</Router>,
|
</Router>,
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -613,7 +656,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const validationErrors = container.querySelector('div#validation-errors');
|
const validationErrors = container.querySelector('div#validation-errors');
|
||||||
expect(validationErrors.textContent).toContain(
|
expect(validationErrors.textContent).toContain(
|
||||||
'An error has occurred. Try refreshing the page, or check your internet connection.',
|
'An error has occurred. Try refreshing the page, or check your internet connection.',
|
||||||
@@ -640,7 +683,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
const fullNameInput = container.querySelector('input#name');
|
const fullNameInput = container.querySelector('input#name');
|
||||||
const usernameInput = container.querySelector('input#username');
|
const usernameInput = container.querySelector('input#username');
|
||||||
@@ -686,14 +729,14 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(window.parent.postMessage).toHaveBeenCalledTimes(2);
|
expect(window.parent.postMessage).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not display validations error on blur event when embedded variant is rendered', () => {
|
it('should not display validations error on blur event when embedded variant is rendered', () => {
|
||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: '?host=http://localhost/host-website' };
|
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: '?host=http://localhost/host-website' };
|
||||||
const { container } = render(reduxWrapper(<IntlRegistrationPage {...props} />));
|
const { container } = render(reduxWrapper(<RegistrationPage {...props} />));
|
||||||
|
|
||||||
const usernameInput = container.querySelector('input#username');
|
const usernameInput = container.querySelector('input#username');
|
||||||
fireEvent.blur(usernameInput, { target: { value: '', name: 'username' } });
|
fireEvent.blur(usernameInput, { target: { value: '', name: 'username' } });
|
||||||
@@ -721,7 +764,7 @@ describe('RegistrationPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { container } = render(routerWrapper(reduxWrapper(
|
const { container } = render(routerWrapper(reduxWrapper(
|
||||||
<IntlRegistrationPage {...props} />),
|
<RegistrationPage {...props} />),
|
||||||
));
|
));
|
||||||
|
|
||||||
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
|
const usernameFeedback = container.querySelector('div[feedback-for="username"]');
|
||||||
@@ -738,7 +781,7 @@ describe('RegistrationPage', () => {
|
|||||||
search: '?host=http://localhost/host-website',
|
search: '?host=http://localhost/host-website',
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const submitButton = container.querySelector('button.btn-brand');
|
const submitButton = container.querySelector('button.btn-brand');
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
|
|
||||||
@@ -779,7 +822,7 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const spinnerElement = container.querySelector('#tpa-spinner');
|
const spinnerElement = container.querySelector('#tpa-spinner');
|
||||||
const registrationFormElement = container.querySelector('#registration-form');
|
const registrationFormElement = container.querySelector('#registration-form');
|
||||||
|
|
||||||
@@ -830,14 +873,14 @@ describe('RegistrationPage', () => {
|
|||||||
});
|
});
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({
|
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({
|
||||||
name: 'John Doe',
|
name: 'John Doe',
|
||||||
username: 'john_doe',
|
username: 'john_doe',
|
||||||
email: 'john.doe@example.com',
|
email: 'john.doe@example.com',
|
||||||
country: 'PK',
|
country: 'PK',
|
||||||
social_auth_provider: 'Apple',
|
social_auth_provider: 'Apple',
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,7 +33,11 @@ const ConfigurableRegistrationForm = (props) => {
|
|||||||
autoSubmitRegistrationForm,
|
autoSubmitRegistrationForm,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const countryList = useMemo(() => getCountryList(getLocale()), []);
|
/** The reason for adding the entry 'United States' is that Chrome browser aut-fill the form with the 'Unites
|
||||||
|
States' instead of 'United States of America' which does not exist in country dropdown list and gets the user
|
||||||
|
confused and unable to create an account. So we added the United States entry in the dropdown list.
|
||||||
|
*/
|
||||||
|
const countryList = useMemo(() => getCountryList(getLocale()).concat([{ code: 'US', name: 'United States' }]), []);
|
||||||
|
|
||||||
let showTermsOfServiceAndHonorCode = false;
|
let showTermsOfServiceAndHonorCode = false;
|
||||||
let showCountryField = false;
|
let showCountryField = false;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { windowScrollTo } from '../../data/utils';
|
import { windowScrollTo } from '../../data/utils';
|
||||||
import {
|
import {
|
||||||
FORBIDDEN_REQUEST,
|
FORBIDDEN_REQUEST,
|
||||||
|
FORBIDDEN_USERNAME,
|
||||||
INTERNAL_SERVER_ERROR,
|
INTERNAL_SERVER_ERROR,
|
||||||
TPA_AUTHENTICATION_FAILURE,
|
TPA_AUTHENTICATION_FAILURE,
|
||||||
TPA_SESSION_EXPIRED,
|
TPA_SESSION_EXPIRED,
|
||||||
@@ -48,6 +49,9 @@ const RegistrationFailureMessage = (props) => {
|
|||||||
case TPA_SESSION_EXPIRED:
|
case TPA_SESSION_EXPIRED:
|
||||||
errorMessage = formatMessage(messages['registration.tpa.session.expired'], { provider: context.provider });
|
errorMessage = formatMessage(messages['registration.tpa.session.expired'], { provider: context.provider });
|
||||||
break;
|
break;
|
||||||
|
case FORBIDDEN_USERNAME:
|
||||||
|
errorMessage = formatMessage(messages['registration.forbidden.username']);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
errorMessage = formatMessage(messages['registration.empty.form.submission.error']);
|
errorMessage = formatMessage(messages['registration.empty.form.submission.error']);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { mergeConfig } from '@edx/frontend-platform';
|
import { mergeConfig } from '@edx/frontend-platform';
|
||||||
import {
|
import {
|
||||||
getLocale, injectIntl, IntlProvider,
|
getLocale, IntlProvider,
|
||||||
} from '@edx/frontend-platform/i18n';
|
} from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
@@ -23,8 +22,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
|||||||
getLocale: jest.fn(),
|
getLocale: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlConfigurableRegistrationForm = injectIntl(ConfigurableRegistrationForm);
|
|
||||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -158,7 +155,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(
|
render(routerWrapper(reduxWrapper(
|
||||||
<IntlConfigurableRegistrationForm {...props} />,
|
<ConfigurableRegistrationForm {...props} />,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
expect(document.querySelector('#profession')).toBeTruthy();
|
expect(document.querySelector('#profession')).toBeTruthy();
|
||||||
@@ -188,7 +185,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(
|
render(routerWrapper(reduxWrapper(
|
||||||
<IntlConfigurableRegistrationForm {...props} />,
|
<ConfigurableRegistrationForm {...props} />,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
expect(props.setFormFields).toHaveBeenCalledTimes(2);
|
expect(props.setFormFields).toHaveBeenCalledTimes(2);
|
||||||
@@ -215,7 +212,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(document.querySelector('#profession')).toBeTruthy();
|
expect(document.querySelector('#profession')).toBeTruthy();
|
||||||
expect(document.querySelector('#tos')).toBeTruthy();
|
expect(document.querySelector('#tos')).toBeTruthy();
|
||||||
});
|
});
|
||||||
@@ -245,11 +242,11 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
country: 'Pakistan',
|
country: 'Pakistan',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
profession: 'Engineer',
|
profession: 'Engineer',
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
populateRequiredFields(getByLabelText, payload);
|
populateRequiredFields(getByLabelText, payload);
|
||||||
|
|
||||||
@@ -284,7 +281,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const submitButton = container.querySelector('button.btn-brand');
|
const submitButton = container.querySelector('button.btn-brand');
|
||||||
|
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
@@ -310,7 +307,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const countryInput = container.querySelector('input[name="country"]');
|
const countryInput = container.querySelector('input[name="country"]');
|
||||||
fireEvent.change(countryInput, { target: { value: 'Pak', name: 'country' } });
|
fireEvent.change(countryInput, { target: { value: 'Pak', name: 'country' } });
|
||||||
fireEvent.blur(countryInput, { target: { value: 'Pak', name: 'country' } });
|
fireEvent.blur(countryInput, { target: { value: 'Pak', name: 'country' } });
|
||||||
@@ -335,7 +332,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
const emailInput = getByLabelText('Email');
|
const emailInput = getByLabelText('Email');
|
||||||
const confirmEmailInput = getByLabelText('Confirm Email');
|
const confirmEmailInput = getByLabelText('Confirm Email');
|
||||||
@@ -356,7 +353,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
password: 'password1',
|
password: 'password1',
|
||||||
country: 'Ukraine',
|
country: 'Ukraine',
|
||||||
honor_code: true,
|
honor_code: true,
|
||||||
totalRegistrationTime: 0,
|
total_registration_time: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
store = mockStore({
|
store = mockStore({
|
||||||
@@ -371,7 +368,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByLabelText, container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
|
|
||||||
populateRequiredFields(getByLabelText, formPayload, true);
|
populateRequiredFields(getByLabelText, formPayload, true);
|
||||||
fireEvent.change(
|
fireEvent.change(
|
||||||
@@ -406,7 +403,7 @@ describe('ConfigurableRegistrationForm', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { getByLabelText, container } = render(
|
const { getByLabelText, container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const professionInput = getByLabelText('Profession');
|
const professionInput = getByLabelText('Profession');
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { mergeConfig } from '@edx/frontend-platform';
|
import { mergeConfig } from '@edx/frontend-platform';
|
||||||
import {
|
import {
|
||||||
configure, getLocale, injectIntl, IntlProvider,
|
configure, getLocale, IntlProvider,
|
||||||
} from '@edx/frontend-platform/i18n';
|
} from '@edx/frontend-platform/i18n';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
@@ -24,8 +23,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
|||||||
getLocale: jest.fn(),
|
getLocale: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
|
||||||
const IntlRegistrationFailure = injectIntl(RegistrationFailureMessage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -137,7 +134,7 @@ describe('RegistrationFailure', () => {
|
|||||||
failureCount: 0,
|
failureCount: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
|
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
|
||||||
|
|
||||||
const alertHeading = container.querySelectorAll('div.alert-heading');
|
const alertHeading = container.querySelectorAll('div.alert-heading');
|
||||||
expect(alertHeading.length).toEqual(1);
|
expect(alertHeading.length).toEqual(1);
|
||||||
@@ -153,7 +150,7 @@ describe('RegistrationFailure', () => {
|
|||||||
failureCount: 0,
|
failureCount: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
|
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
|
||||||
|
|
||||||
const alertHeading = container.querySelectorAll('div.alert-heading');
|
const alertHeading = container.querySelectorAll('div.alert-heading');
|
||||||
expect(alertHeading.length).toEqual(1);
|
expect(alertHeading.length).toEqual(1);
|
||||||
@@ -172,7 +169,7 @@ describe('RegistrationFailure', () => {
|
|||||||
failureCount: 0,
|
failureCount: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
|
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
|
||||||
|
|
||||||
const alertHeading = container.querySelectorAll('div.alert-heading');
|
const alertHeading = container.querySelectorAll('div.alert-heading');
|
||||||
expect(alertHeading.length).toEqual(1);
|
expect(alertHeading.length).toEqual(1);
|
||||||
@@ -191,7 +188,7 @@ describe('RegistrationFailure', () => {
|
|||||||
failureCount: 0,
|
failureCount: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlRegistrationFailure {...props} />));
|
const { container } = render(reduxWrapper(<RegistrationFailureMessage {...props} />));
|
||||||
|
|
||||||
const alertHeading = container.querySelectorAll('div.alert-heading');
|
const alertHeading = container.querySelectorAll('div.alert-heading');
|
||||||
expect(alertHeading.length).toEqual(1);
|
expect(alertHeading.length).toEqual(1);
|
||||||
@@ -211,7 +208,7 @@ describe('RegistrationFailure', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const validationError = screen.queryByText('An error has occurred. Try refreshing the page, or check your internet connection.');
|
const validationError = screen.queryByText('An error has occurred. Try refreshing the page, or check your internet connection.');
|
||||||
|
|
||||||
expect(validationError).not.toBeNull();
|
expect(validationError).not.toBeNull();
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||||
import {
|
import {
|
||||||
configure, getLocale, injectIntl, IntlProvider,
|
configure, getLocale, IntlProvider,
|
||||||
} from '@edx/frontend-platform/i18n';
|
} from '@edx/frontend-platform/i18n';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
@@ -23,7 +22,6 @@ jest.mock('@edx/frontend-platform/i18n', () => ({
|
|||||||
getLocale: jest.fn(),
|
getLocale: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlRegistrationPage = injectIntl(RegistrationPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => {
|
jest.mock('react-router-dom', () => {
|
||||||
@@ -157,7 +155,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { queryByLabelText } = render(
|
const { queryByLabelText } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />, { store })),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />, { store })),
|
||||||
);
|
);
|
||||||
|
|
||||||
const passwordField = queryByLabelText('Password');
|
const passwordField = queryByLabelText('Password');
|
||||||
@@ -182,7 +180,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
|
||||||
);
|
);
|
||||||
const tpaButton = container.querySelector(`button#${ssoProvider.id}`);
|
const tpaButton = container.querySelector(`button#${ssoProvider.id}`);
|
||||||
|
|
||||||
@@ -207,7 +205,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
search: `?next=/dashboard&tpa_hint=${ssoProvider.id}`,
|
search: `?next=/dashboard&tpa_hint=${ssoProvider.id}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const skeletonElement = container.querySelector('.react-loading-skeleton');
|
const skeletonElement = container.querySelector('.react-loading-skeleton');
|
||||||
|
|
||||||
expect(skeletonElement).toBeTruthy();
|
expect(skeletonElement).toBeTruthy();
|
||||||
@@ -231,7 +229,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
|
||||||
ssoProvider.iconImage = null;
|
ssoProvider.iconImage = null;
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const iconElement = container.querySelector(`button#${ssoProvider.id} div span.pgn__icon`);
|
const iconElement = container.querySelector(`button#${ssoProvider.id} div span.pgn__icon`);
|
||||||
|
|
||||||
expect(iconElement).toBeTruthy();
|
expect(iconElement).toBeTruthy();
|
||||||
@@ -254,7 +252,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: `?next=/dashboard&tpa_hint=${secondaryProviders.id}` };
|
window.location = { href: getConfig().BASE_URL.concat(REGISTER_PAGE), search: `?next=/dashboard&tpa_hint=${secondaryProviders.id}` };
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(window.location.href).toEqual(getConfig().LMS_BASE_URL + secondaryProviders.registerUrl);
|
expect(window.location.href).toEqual(getConfig().LMS_BASE_URL + secondaryProviders.registerUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -275,7 +273,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: '?next=/dashboard&tpa_hint=invalid' };
|
window.location = { href: getConfig().BASE_URL.concat(LOGIN_PAGE), search: '?next=/dashboard&tpa_hint=invalid' };
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const providerButton = container.querySelector(`button#${ssoProvider.id} span#provider-name`);
|
const providerButton = container.querySelector(`button#${ssoProvider.id} span#provider-name`);
|
||||||
|
|
||||||
expect(providerButton.textContent).toEqual(expectedMessage);
|
expect(providerButton.textContent).toEqual(expectedMessage);
|
||||||
@@ -294,7 +292,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />, { store })),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />, { store })),
|
||||||
);
|
);
|
||||||
|
|
||||||
const buttonsWithId = container.querySelectorAll(`button#${ssoProvider.id}`);
|
const buttonsWithId = container.querySelectorAll(`button#${ssoProvider.id}`);
|
||||||
@@ -315,7 +313,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const buttonsWithId = container.querySelectorAll(`button#${ssoProvider.id}`);
|
const buttonsWithId = container.querySelectorAll(`button#${ssoProvider.id}`);
|
||||||
@@ -329,7 +327,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
institutionLogin: true,
|
institutionLogin: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { getByText } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { getByText } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const headingElement = getByText('Register with institution/campus credentials');
|
const headingElement = getByText('Register with institution/campus credentials');
|
||||||
expect(headingElement).toBeTruthy();
|
expect(headingElement).toBeTruthy();
|
||||||
});
|
});
|
||||||
@@ -354,7 +352,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const ssoButton = container.querySelector('button#oa2-apple-id');
|
const ssoButton = container.querySelector('button#oa2-apple-id');
|
||||||
@@ -385,7 +383,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
delete window.location;
|
delete window.location;
|
||||||
window.location = { href: getConfig().BASE_URL };
|
window.location = { href: getConfig().BASE_URL };
|
||||||
|
|
||||||
render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
|
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -406,7 +404,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
const expectedMessage = `${'You\'ve successfully signed into Apple! We just need a little more information before '
|
const expectedMessage = `${'You\'ve successfully signed into Apple! We just need a little more information before '
|
||||||
+ 'you start learning with '}${ getConfig().SITE_NAME }.`;
|
+ 'you start learning with '}${ getConfig().SITE_NAME }.`;
|
||||||
|
|
||||||
const { container } = render(routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)));
|
const { container } = render(routerWrapper(reduxWrapper(<RegistrationPage {...props} />)));
|
||||||
const tpaAlert = container.querySelector('#tpa-alert p');
|
const tpaAlert = container.querySelector('#tpa-alert p');
|
||||||
expect(tpaAlert.textContent).toEqual(expectedMessage);
|
expect(tpaAlert.textContent).toEqual(expectedMessage);
|
||||||
});
|
});
|
||||||
@@ -437,7 +435,7 @@ describe('ThirdPartyAuth', () => {
|
|||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
|
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
routerWrapper(reduxWrapper(<IntlRegistrationPage {...props} />)),
|
routerWrapper(reduxWrapper(<RegistrationPage {...props} />)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const alertHeading = container.querySelector('div.alert-heading');
|
const alertHeading = container.querySelector('div.alert-heading');
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ export const FORM_SUBMISSION_ERROR = 'form-submission-error';
|
|||||||
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
|
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
|
||||||
export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';
|
export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';
|
||||||
export const TPA_SESSION_EXPIRED = 'tpa-session-expired';
|
export const TPA_SESSION_EXPIRED = 'tpa-session-expired';
|
||||||
|
export const FORBIDDEN_USERNAME = 'forbidden-username';
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { camelCaseObject } from '@edx/frontend-platform';
|
import { camelCaseObject } from '@edx/frontend-platform';
|
||||||
import { logError, logInfo } from '@edx/frontend-platform/logging';
|
import { logError, logInfo } from '@edx/frontend-platform/logging';
|
||||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
import {
|
||||||
|
call, put, race, take, takeEvery,
|
||||||
|
} from 'redux-saga/effects';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
fetchRealtimeValidationsBegin,
|
fetchRealtimeValidationsBegin,
|
||||||
fetchRealtimeValidationsFailure,
|
fetchRealtimeValidationsFailure,
|
||||||
fetchRealtimeValidationsSuccess,
|
fetchRealtimeValidationsSuccess,
|
||||||
|
REGISTER_CLEAR_USERNAME_SUGGESTIONS,
|
||||||
REGISTER_FORM_VALIDATIONS,
|
REGISTER_FORM_VALIDATIONS,
|
||||||
REGISTER_NEW_USER,
|
REGISTER_NEW_USER,
|
||||||
registerNewUserBegin,
|
registerNewUserBegin,
|
||||||
@@ -41,9 +44,15 @@ export function* handleNewUserRegistration(action) {
|
|||||||
export function* fetchRealtimeValidations(action) {
|
export function* fetchRealtimeValidations(action) {
|
||||||
try {
|
try {
|
||||||
yield put(fetchRealtimeValidationsBegin());
|
yield put(fetchRealtimeValidationsBegin());
|
||||||
const { fieldValidations } = yield call(getFieldsValidations, action.payload.formPayload);
|
|
||||||
|
|
||||||
yield put(fetchRealtimeValidationsSuccess(camelCaseObject(fieldValidations)));
|
const { response } = yield race({
|
||||||
|
response: call(getFieldsValidations, action.payload.formPayload),
|
||||||
|
cancel: take(REGISTER_CLEAR_USERNAME_SUGGESTIONS),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
yield put(fetchRealtimeValidationsSuccess(camelCaseObject(response.fieldValidations)));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.response && e.response.status === 403) {
|
if (e.response && e.response.status === 403) {
|
||||||
yield put(fetchRealtimeValidationsFailure());
|
yield put(fetchRealtimeValidationsFailure());
|
||||||
|
|||||||
77
src/register/data/tests/utils.test.js
Normal file
77
src/register/data/tests/utils.test.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { isFormValid } from '../utils';
|
||||||
|
|
||||||
|
describe('Payload validation', () => {
|
||||||
|
let formatMessage;
|
||||||
|
let configurableFormFields;
|
||||||
|
let fieldDescriptions;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
formatMessage = jest.fn(msg => msg);
|
||||||
|
configurableFormFields = {
|
||||||
|
confirm_email: true,
|
||||||
|
};
|
||||||
|
fieldDescriptions = {};
|
||||||
|
});
|
||||||
|
|
||||||
|
test('validates name field correctly', () => {
|
||||||
|
const payload = { name: ' ' };
|
||||||
|
const errors = {};
|
||||||
|
const { isValid, fieldErrors } = isFormValid(
|
||||||
|
payload,
|
||||||
|
errors,
|
||||||
|
configurableFormFields,
|
||||||
|
fieldDescriptions,
|
||||||
|
formatMessage);
|
||||||
|
|
||||||
|
expect(fieldErrors.name).toBeDefined();
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('validates email field correctly', () => {
|
||||||
|
const payload = { email: 'invalid-email' };
|
||||||
|
const errors = {};
|
||||||
|
const { isValid, fieldErrors } = isFormValid(
|
||||||
|
payload, errors, configurableFormFields, fieldDescriptions, formatMessage);
|
||||||
|
|
||||||
|
expect(fieldErrors.email).toBeDefined();
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('validates username field correctly', () => {
|
||||||
|
const payload = { username: 'invalid username' };
|
||||||
|
const errors = {};
|
||||||
|
const { isValid, fieldErrors } = isFormValid(
|
||||||
|
payload, errors, configurableFormFields, fieldDescriptions, formatMessage);
|
||||||
|
|
||||||
|
expect(fieldErrors.username).toBeDefined();
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('validates password field correctly', () => {
|
||||||
|
const payload = { password: 'short' };
|
||||||
|
const errors = {};
|
||||||
|
const { isValid, fieldErrors } = isFormValid(
|
||||||
|
payload, errors, configurableFormFields, fieldDescriptions, formatMessage);
|
||||||
|
|
||||||
|
expect(fieldErrors.password).toBeDefined();
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('validates multiple fields correctly', () => {
|
||||||
|
const payload = {
|
||||||
|
name: 'InvalidName!',
|
||||||
|
email: 'invalid-email',
|
||||||
|
username: 'invalid username',
|
||||||
|
password: 'short',
|
||||||
|
};
|
||||||
|
const errors = {};
|
||||||
|
const { isValid, fieldErrors } = isFormValid(
|
||||||
|
payload, errors, configurableFormFields, fieldDescriptions, formatMessage);
|
||||||
|
|
||||||
|
expect(fieldErrors.name).toBeDefined();
|
||||||
|
expect(fieldErrors.email).toBeDefined();
|
||||||
|
expect(fieldErrors.username).toBeDefined();
|
||||||
|
expect(fieldErrors.password).toBeDefined();
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -43,30 +43,39 @@ export const isFormValid = (
|
|||||||
Object.keys(payload).forEach(key => {
|
Object.keys(payload).forEach(key => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'name':
|
case 'name':
|
||||||
fieldErrors.name = validateName(payload.name, formatMessage);
|
if (!fieldErrors.name) {
|
||||||
|
fieldErrors.name = validateName(payload.name, formatMessage);
|
||||||
|
}
|
||||||
if (fieldErrors.name) { isValid = false; }
|
if (fieldErrors.name) { isValid = false; }
|
||||||
break;
|
break;
|
||||||
case 'email': {
|
case 'email': {
|
||||||
const {
|
if (!fieldErrors.email) {
|
||||||
fieldError, confirmEmailError, suggestion,
|
const {
|
||||||
} = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
|
fieldError, confirmEmailError, suggestion,
|
||||||
if (fieldError) {
|
} = validateEmail(payload.email, configurableFormFields?.confirm_email, formatMessage);
|
||||||
fieldErrors.email = fieldError;
|
if (fieldError) {
|
||||||
isValid = false;
|
fieldErrors.email = fieldError;
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
if (confirmEmailError) {
|
||||||
|
fieldErrors.confirm_email = confirmEmailError;
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
emailSuggestion = suggestion;
|
||||||
}
|
}
|
||||||
if (confirmEmailError) {
|
if (fieldErrors.email) { isValid = false; }
|
||||||
fieldErrors.confirm_email = confirmEmailError;
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
emailSuggestion = suggestion;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'username':
|
case 'username':
|
||||||
fieldErrors.username = validateUsername(payload.username, formatMessage);
|
if (!fieldErrors.username) {
|
||||||
|
fieldErrors.username = validateUsername(payload.username, formatMessage);
|
||||||
|
}
|
||||||
if (fieldErrors.username) { isValid = false; }
|
if (fieldErrors.username) { isValid = false; }
|
||||||
break;
|
break;
|
||||||
case 'password':
|
case 'password':
|
||||||
fieldErrors.password = validatePasswordField(payload.password, formatMessage);
|
if (!fieldErrors.password) {
|
||||||
|
fieldErrors.password = validatePasswordField(payload.password, formatMessage);
|
||||||
|
}
|
||||||
if (fieldErrors.password) { isValid = false; }
|
if (fieldErrors.password) { isValid = false; }
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -125,8 +134,8 @@ export const prepareRegistrationPayload = (
|
|||||||
delete payload.marketingEmailsOptIn;
|
delete payload.marketingEmailsOptIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
payload = snakeCaseObject(payload);
|
|
||||||
payload.totalRegistrationTime = totalRegistrationTime;
|
payload.totalRegistrationTime = totalRegistrationTime;
|
||||||
|
payload = snakeCaseObject(payload);
|
||||||
|
|
||||||
// add query params to the payload
|
// add query params to the payload
|
||||||
payload = { ...payload, ...queryParams };
|
payload = { ...payload, ...queryParams };
|
||||||
|
|||||||
@@ -162,6 +162,11 @@ const messages = defineMessages({
|
|||||||
defaultMessage: 'Registration using {provider} has timed out.',
|
defaultMessage: 'Registration using {provider} has timed out.',
|
||||||
description: '',
|
description: '',
|
||||||
},
|
},
|
||||||
|
'registration.forbidden.username': {
|
||||||
|
id: 'registration.forbidden.username',
|
||||||
|
defaultMessage: 'Usernames can\'t include words that could be mistaken for course roles. Please choose a different username.',
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
'registration.tpa.authentication.failure': {
|
'registration.tpa.authentication.failure': {
|
||||||
id: 'registration.tpa.authentication.failure',
|
id: 'registration.tpa.authentication.failure',
|
||||||
defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '
|
defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
import { configure, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
fireEvent, render, screen,
|
fireEvent, render, screen,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
@@ -26,7 +25,6 @@ jest.mock('react-router-dom', () => ({
|
|||||||
useParams: jest.fn().mockReturnValue({ token }),
|
useParams: jest.fn().mockReturnValue({ token }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const IntlResetPasswordPage = injectIntl(ResetPasswordPage);
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
|
||||||
describe('ResetPasswordPage', () => {
|
describe('ResetPasswordPage', () => {
|
||||||
@@ -95,7 +93,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
store.dispatch = jest.fn(store.dispatch);
|
store.dispatch = jest.fn(store.dispatch);
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
const newPasswordInput = screen.getByLabelText('New password');
|
const newPasswordInput = screen.getByLabelText('New password');
|
||||||
const confirmPasswordInput = screen.getByLabelText('Confirm password');
|
const confirmPasswordInput = screen.getByLabelText('Confirm password');
|
||||||
|
|
||||||
@@ -120,7 +118,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
status: TOKEN_STATE.VALID,
|
status: TOKEN_STATE.VALID,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
const resetPasswordButton = screen.getByRole('button', { name: /Reset password/i, id: 'submit-new-password' });
|
const resetPasswordButton = screen.getByRole('button', { name: /Reset password/i, id: 'submit-new-password' });
|
||||||
fireEvent.click(resetPasswordButton);
|
fireEvent.click(resetPasswordButton);
|
||||||
|
|
||||||
@@ -144,7 +142,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
status: TOKEN_STATE.VALID,
|
status: TOKEN_STATE.VALID,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
const confirmPasswordInput = screen.getByLabelText('Confirm password');
|
const confirmPasswordInput = screen.getByLabelText('Confirm password');
|
||||||
fireEvent.change(confirmPasswordInput, { target: { value: 'password-mismatch' } });
|
fireEvent.change(confirmPasswordInput, { target: { value: 'password-mismatch' } });
|
||||||
|
|
||||||
@@ -163,7 +161,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
|
|
||||||
const alertElements = container.querySelectorAll('.alert-danger');
|
const alertElements = container.querySelectorAll('.alert-danger');
|
||||||
const rateLimitError = alertElements[0].textContent;
|
const rateLimitError = alertElements[0].textContent;
|
||||||
@@ -179,7 +177,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
const { container } = render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
const alertElements = container.querySelectorAll('.alert-danger');
|
const alertElements = container.querySelectorAll('.alert-danger');
|
||||||
const internalServerError = alertElements[0].textContent;
|
const internalServerError = alertElements[0].textContent;
|
||||||
expect(internalServerError).toBe(validationMessage);
|
expect(internalServerError).toBe(validationMessage);
|
||||||
@@ -188,7 +186,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
// ******** miscellaneous tests ********
|
// ******** miscellaneous tests ********
|
||||||
|
|
||||||
it('should call validation on password field when blur event fires', () => {
|
it('should call validation on password field when blur event fires', () => {
|
||||||
const resetPasswordPage = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
const resetPasswordPage = render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
const expectedText = 'Password criteria has not been metPassword must contain at least 8 characters, at least one letter, and at least one number';
|
const expectedText = 'Password criteria has not been metPassword must contain at least 8 characters, at least one letter, and at least one number';
|
||||||
const newPasswordInput = resetPasswordPage.container.querySelector('input#newPassword');
|
const newPasswordInput = resetPasswordPage.container.querySelector('input#newPassword');
|
||||||
newPasswordInput.value = 'test-password';
|
newPasswordInput.value = 'test-password';
|
||||||
@@ -207,7 +205,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
TOKEN_STATE.PENDING,
|
TOKEN_STATE.PENDING,
|
||||||
};
|
};
|
||||||
|
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
|
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(validateToken(token));
|
expect(store.dispatch).toHaveBeenCalledWith(validateToken(token));
|
||||||
});
|
});
|
||||||
@@ -216,19 +214,19 @@ describe('ResetPasswordPage', () => {
|
|||||||
status:
|
status:
|
||||||
PASSWORD_RESET_ERROR,
|
PASSWORD_RESET_ERROR,
|
||||||
};
|
};
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
expect(mockedNavigator).toHaveBeenCalledWith(RESET_PAGE);
|
expect(mockedNavigator).toHaveBeenCalledWith(RESET_PAGE);
|
||||||
});
|
});
|
||||||
it('should redirect the user to root url of the application ', async () => {
|
it('should redirect the user to root url of the application ', async () => {
|
||||||
props = {
|
props = {
|
||||||
status: SUCCESS,
|
status: SUCCESS,
|
||||||
};
|
};
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
expect(mockedNavigator).toHaveBeenCalledWith(LOGIN_PAGE);
|
expect(mockedNavigator).toHaveBeenCalledWith(LOGIN_PAGE);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows spinner during token validation', () => {
|
it('shows spinner during token validation', () => {
|
||||||
render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
const spinnerElement = document.getElementsByClassName('div.spinner-header');
|
const spinnerElement = document.getElementsByClassName('div.spinner-header');
|
||||||
|
|
||||||
expect(spinnerElement).toBeTruthy();
|
expect(spinnerElement).toBeTruthy();
|
||||||
@@ -237,7 +235,7 @@ describe('ResetPasswordPage', () => {
|
|||||||
// ******** redirection tests ********
|
// ******** redirection tests ********
|
||||||
|
|
||||||
it('by clicking on sign in tab should redirect onto login page', async () => {
|
it('by clicking on sign in tab should redirect onto login page', async () => {
|
||||||
const { getByText } = render(reduxWrapper(<IntlResetPasswordPage {...props} />));
|
const { getByText } = render(reduxWrapper(<ResetPasswordPage {...props} />));
|
||||||
|
|
||||||
const signInTab = getByText('Sign in');
|
const signInTab = getByText('Sign in');
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
.layout {
|
.layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
@include media-breakpoint-down('lg') {
|
@media (--pgn-size-breakpoint-max-width-lg) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up('xl') {
|
@media (--pgn-size-breakpoint-min-width-xl) {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@include media-breakpoint-up('xl') {
|
@media (--pgn-size-breakpoint-min-width-xl) {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 50vw;
|
width: 50vw;
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
|
||||||
@include media-breakpoint-down('xl') {
|
@media (--pgn-size-breakpoint-max-width-xl) {
|
||||||
font-size: 3.75rem;
|
font-size: 3.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
||||||
@include media-breakpoint-down('xl') {
|
@media (-pgn-size-breakpoint-max-width-xl) {
|
||||||
font-size: 1.375rem;
|
font-size: 1.375rem;
|
||||||
line-height: 1.75rem;
|
line-height: 1.75rem;
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.large-screen-left-container {
|
.large-screen-left-container {
|
||||||
@include media-breakpoint-down('xl') {
|
@media (-pgn-size-breakpoint-max-width-xl) {
|
||||||
flex: 0 0 25%;
|
flex: 0 0 25%;
|
||||||
max-width: 25%;
|
max-width: 25%;
|
||||||
}
|
}
|
||||||
@@ -87,43 +87,43 @@
|
|||||||
height: 0.25rem;
|
height: 0.25rem;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
102.02deg,
|
102.02deg,
|
||||||
$brand-700,
|
var(--pgn-color-brand-700),
|
||||||
$brand-700 20%,
|
var(--pgn-color-brand-700) 20%,
|
||||||
$brand 20%,
|
var(--pgn-color-brand-base) 20%,
|
||||||
);
|
);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-only('md') {
|
@media (--pgn-size-breakpoint-min-width-md) and (--pgn-size-breakpoint-max-width-md) {
|
||||||
.medium-screen-top-stripe {
|
.medium-screen-top-stripe {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 0.5rem;
|
height: 0.5rem;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
102.02deg,
|
102.02deg,
|
||||||
$brand-700,
|
var(--pgn-color-brand-700),
|
||||||
$brand-700 10%,
|
var(--pgn-color-brand-700) 10%,
|
||||||
$brand 10%,
|
var(--pgn-color-brand-base) 10%,
|
||||||
$brand 90%,
|
var(--pgn-color-brand-base) 90%,
|
||||||
$primary-700 90%,
|
var(--pgn-color-primary-700) 90%,
|
||||||
$primary-700 100%,
|
var(--pgn-color-primary-700) 100%,
|
||||||
);
|
);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-only('lg') {
|
@media (--pgn-size-breakpoint-min-width-lg) and (--pgn-size-breakpoint-max-width-lg){
|
||||||
.medium-screen-top-stripe {
|
.medium-screen-top-stripe {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 0.5rem;
|
height: 0.5rem;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
102.02deg,
|
102.02deg,
|
||||||
$brand-700 10%,
|
var(--pgn-color-brand-700) 10%,
|
||||||
$brand 10%,
|
var(--pgn-color-brand-base) 10%,
|
||||||
$brand 65%,
|
var(--pgn-color-brand-base) 65%,
|
||||||
$primary-700 65%,
|
var(--pgn-color-primary-700) 65%,
|
||||||
$primary-700 75%,
|
var(--pgn-color-primary-700) 75%,
|
||||||
$accent-a 75%,
|
var(--pgn-color-accent-a) 75%,
|
||||||
$accent-a 75%
|
var(--pgn-color-accent-a) 75%
|
||||||
);
|
);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
@@ -131,20 +131,20 @@
|
|||||||
|
|
||||||
.extra-large-screen-top-stripe { display: none; }
|
.extra-large-screen-top-stripe { display: none; }
|
||||||
|
|
||||||
@include media-breakpoint-up('xl') {
|
@media (--pgn-size-breakpoint-min-width-xl) {
|
||||||
.extra-large-screen-top-stripe {
|
.extra-large-screen-top-stripe {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 0.5rem;
|
height: 0.5rem;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
102.02deg,
|
102.02deg,
|
||||||
$brand-700 10%,
|
var(--pgn-color-brand-700) 10%,
|
||||||
$brand 10%,
|
var(--pgn-color-brand-base) 10%,
|
||||||
$brand 45%,
|
var(--pgn-color-brand-base) 45%,
|
||||||
$primary-700 45%,
|
var(--pgn-color-primary-700) 45%,
|
||||||
$primary-700 55%,
|
var(--pgn-color-primary-700) 55%,
|
||||||
$accent-a 55%,
|
var(--pgn-color-accent-a) 55%,
|
||||||
$accent-a 75%,
|
var(--pgn-color-accent-a) 75%,
|
||||||
$info-200 75%,
|
var(--pgn-color-info-200) 75%,
|
||||||
);
|
);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
@@ -152,24 +152,24 @@
|
|||||||
|
|
||||||
.large-screen-svg-light,
|
.large-screen-svg-light,
|
||||||
.large-screen-svg-primary {
|
.large-screen-svg-primary {
|
||||||
fill: $light-200;
|
fill: var(--pgn-color-light-200);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.large-screen-svg-primary {
|
.large-screen-svg-primary {
|
||||||
fill: $primary-400;
|
fill: var(--pgn-color-primary-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium-screen-svg-light,
|
.medium-screen-svg-light,
|
||||||
.medium-screen-svg-primary {
|
.medium-screen-svg-primary {
|
||||||
fill: $light-200;
|
fill: var(--pgn-color-light-200);
|
||||||
overflow: inherit;
|
overflow: inherit;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium-screen-svg-primary {
|
.medium-screen-svg-primary {
|
||||||
fill: $primary-400;
|
fill: var(--pgn-color-primary-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
[dir=rtl]{
|
[dir=rtl]{
|
||||||
@@ -184,20 +184,20 @@
|
|||||||
.small-yellow-line {
|
.small-yellow-line {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 0;
|
height: 0;
|
||||||
border: 2px solid $accent-b;
|
border: 2px solid var(--pgn-color-accent-b);
|
||||||
transform: rotate(102.02deg);
|
transform: rotate(102.02deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.medium-yellow-line {
|
.medium-yellow-line {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
height: 0;
|
height: 0;
|
||||||
border: 3px solid $accent-b;
|
border: 3px solid var(--pgn-color-accent-b);
|
||||||
transform: rotate(102.02deg);
|
transform: rotate(102.02deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.large-yellow-line {
|
.large-yellow-line {
|
||||||
width: 240px;
|
width: 240px;
|
||||||
height: 0;
|
height: 0;
|
||||||
border: 3px solid $accent-b;
|
border: 3px solid var(--pgn-color-accent-b);
|
||||||
transform: rotate(102.02deg);
|
transform: rotate(102.02deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
||||||
@include media-breakpoint-down('md') {
|
@media (--pgn-size-breakpoint-max-width-md) {
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,52 +64,52 @@ $header-height: 104px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.light {
|
&.light {
|
||||||
background-color: $white;
|
background-color: var(--pgn-color-white);
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: $black;
|
color: var(--pgn-color-black);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: $gray-700;
|
color: var(--pgn-color-gray-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
background-color: $light-500;
|
background-color: var(--pgn-color-light-500);
|
||||||
color: $black;
|
color: var(--pgn-color-black);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-content {
|
.footer-content {
|
||||||
color: $gray-700;
|
color: var(--pgn-color-gray-700);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
background-color: $primary-500;
|
background-color: var(--pgn-color-primary-500);
|
||||||
|
|
||||||
.pgn__card-header-title-md {
|
.pgn__card-header-title-md {
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pgn__card-header-subtitle-md {
|
.pgn__card-header-subtitle-md {
|
||||||
color: $light-200;
|
color: var(--pgn-color-light-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: $light-200;
|
color: var(--pgn-color-light-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
background-color: $dark-200;
|
background-color: var(--pgn-color-dark-200);
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-content {
|
.footer-content {
|
||||||
color: $light-200;
|
color: var(--pgn-color-light-200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ $card-gap: 24px;
|
|||||||
.recommendations-container__card-list {
|
.recommendations-container__card-list {
|
||||||
gap: $card-gap $card-gap;
|
gap: $card-gap $card-gap;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@media (-pgn-size-breakpoint-max-width-sm) {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,15 +11,15 @@ $card-gap: 24px;
|
|||||||
flex: 0 1 100%;
|
flex: 0 1 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@media (--pgn-size-breakpoint-min-width-sm) {
|
||||||
flex: 0 1 calc(50% - #{$card-gap - 12});
|
flex: 0 1 calc(50% - #{$card-gap - 12});
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@media (--pgn-size-breakpoint-min-width-md) {
|
||||||
flex: 0 1 calc(33.333% - #{$card-gap - 8});
|
flex: 0 1 calc(33.333% - #{$card-gap - 8});
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
@media (--pgn-size-breakpoint-min-width-lg) {
|
||||||
flex: 0 1 calc(25% - #{$card-gap - 6});
|
flex: 0 1 calc(25% - #{$card-gap - 6});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,21 +23,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.alert-link {
|
.alert-link {
|
||||||
color: $primary !important;
|
color: var(--pgn-color-primary-base) !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: $info-700 !important;
|
color: var(--pgn-color-info-700) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-suggestion-alert-warning {
|
.email-suggestion-alert-warning {
|
||||||
color: $info-500 !important;
|
color: var(--pgn-color-info-500) !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: $info-700 !important;
|
color: var(--pgn-color-info-700) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: $primary-700;
|
color: var(--pgn-color-primary-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.username-suggestion--label {
|
.username-suggestion--label {
|
||||||
@@ -65,10 +65,15 @@
|
|||||||
margin-right: 0.25rem;
|
margin-right: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.username-suggestions {
|
.username__form-group-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: -2.5rem;
|
}
|
||||||
margin-left: 15px;
|
|
||||||
|
.username-suggestions {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
padding-left: 15px;
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.username-suggestions__close__button {
|
.username-suggestions__close__button {
|
||||||
@@ -76,13 +81,6 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.username-suggestions__error {
|
|
||||||
position: relative;
|
|
||||||
margin-top: -13.7%;
|
|
||||||
margin-bottom: 11%;
|
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.username-scroll-suggested--form-field {
|
.username-scroll-suggested--form-field {
|
||||||
width: 20rem;
|
width: 20rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -99,7 +97,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: map-get($grid-breakpoints, "sm")) {
|
@media (--pgn-size-breakpoint-max-width-sm) {
|
||||||
.username-scroll-suggested--form-field {
|
.username-scroll-suggested--form-field {
|
||||||
width: 15rem;
|
width: 15rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
@extend .pt-4;
|
padding-top: calc(var(--pgn-spacing-spacer-base) * 1.5) !important;
|
||||||
min-width: 464px !important;
|
min-width: 464px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,15 +80,15 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
.alert-link {
|
.alert-link {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: $info-300 !important;
|
color: var(--pgn-color-info-300) !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $info-500 !important;
|
color: var(--pgn-color-info-500) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control {
|
||||||
background-color: $white !important;
|
background-color: var(--pgn-color-white) !important;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
height: 2.75rem;
|
height: 2.75rem;
|
||||||
@@ -103,11 +103,11 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
background-color: $white;
|
background-color: var(--pgn-color-white);
|
||||||
border: 1px solid $primary;
|
border: 1px solid var(--pgn-color-primary-base);
|
||||||
width: 224px;
|
width: 224px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
color: $primary;
|
color: var(--pgn-color-primary-base);
|
||||||
|
|
||||||
.btn-tpa__image-icon{
|
.btn-tpa__image-icon{
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@@ -132,8 +132,8 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-tpa__font-container {
|
.btn-tpa__font-container {
|
||||||
background-color: $primary;
|
background-color: var(--pgn-color-primary-base);
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
|
||||||
margin-left: -6px;
|
margin-left: -6px;
|
||||||
@@ -143,7 +143,7 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-oa2-facebook {
|
.btn-oa2-facebook {
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
border-color: $facebook-blue;
|
border-color: $facebook-blue;
|
||||||
background-color: $facebook-blue;
|
background-color: $facebook-blue;
|
||||||
|
|
||||||
@@ -151,12 +151,12 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
&:focus {
|
&:focus {
|
||||||
background-color: $facebook-focus-blue;
|
background-color: $facebook-focus-blue;
|
||||||
border: 1px solid $facebook-focus-blue;
|
border: 1px solid $facebook-focus-blue;
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-oa2-google-oauth2 {
|
.btn-oa2-google-oauth2 {
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
border-color: $google-blue;
|
border-color: $google-blue;
|
||||||
background-color: $google-blue;
|
background-color: $google-blue;
|
||||||
|
|
||||||
@@ -171,12 +171,12 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
&:focus {
|
&:focus {
|
||||||
background-color: $google-focus-blue;
|
background-color: $google-focus-blue;
|
||||||
border: 1px solid $google-focus-blue;
|
border: 1px solid $google-focus-blue;
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-oa2-apple-id {
|
.btn-oa2-apple-id {
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
border-color: $apple-black;
|
border-color: $apple-black;
|
||||||
background-color: $apple-black;
|
background-color: $apple-black;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -190,12 +190,12 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
&:focus {
|
&:focus {
|
||||||
background-color: $apple-focus-black;
|
background-color: $apple-focus-black;
|
||||||
border: 1px solid $apple-focus-black;
|
border: 1px solid $apple-focus-black;
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-oa2-azuread-oauth2 {
|
.btn-oa2-azuread-oauth2 {
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
border-color: $microsoft-black;
|
border-color: $microsoft-black;
|
||||||
background-color: $microsoft-black;
|
background-color: $microsoft-black;
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
&:focus {
|
&:focus {
|
||||||
background-color: $microsoft-focus-black;
|
background-color: $microsoft-focus-black;
|
||||||
border: 1px solid $microsoft-focus-black;
|
border: 1px solid $microsoft-focus-black;
|
||||||
color: $white;
|
color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,9 +214,8 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.institute-icon {
|
.institute-icon {
|
||||||
@extend .mr-1;
|
margin: calc(var(--pgn-spacing-spacer-base) * 0.25) !important;
|
||||||
@extend .text-gray;
|
color: var(--pgn-color-gray-base) !important;
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
@@ -232,7 +231,7 @@ $elevation-level-2-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.15);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.invalid-feedback {
|
.invalid-feedback {
|
||||||
color: $red;
|
color: var(--pgn-color-red);
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-vertical-height {
|
.full-vertical-height {
|
||||||
@@ -290,22 +289,22 @@ select.form-control {
|
|||||||
|
|
||||||
#password-requirement-left {
|
#password-requirement-left {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@extend .x-small;
|
font-size: var(--pgn-typography-font-size-xs) !important;
|
||||||
filter: drop-shadow($elevation-level-2-shadow) drop-shadow($elevation-level-2-shadow) !important;
|
filter: drop-shadow($elevation-level-2-shadow) drop-shadow($elevation-level-2-shadow) !important;
|
||||||
right: 0.2rem !important;
|
right: 0.2rem !important;
|
||||||
.tooltip-inner {
|
.tooltip-inner {
|
||||||
background: $white;
|
background: var(--pgn-color-white);
|
||||||
display: block;
|
display: block;
|
||||||
color: $gray-500;
|
color: var(--pgn-color-gray-500);
|
||||||
}
|
}
|
||||||
.arrow::before {
|
.arrow::before {
|
||||||
border-left-color: $white;
|
border-left-color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#password-requirement-top {
|
#password-requirement-top {
|
||||||
@extend .x-small;
|
font-size: var(--pgn-typography-font-size-xs) !important;
|
||||||
filter: drop-shadow($elevation-level-2-shadow) drop-shadow($elevation-level-2-shadow) !important;
|
filter: drop-shadow(var(--pgn-elevation-box-shadow-level-2)) drop-shadow(var(--pgn-elevation-box-shadow-level-2)) !important;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
bottom: 10px !important;
|
bottom: 10px !important;
|
||||||
@@ -314,30 +313,30 @@ select.form-control {
|
|||||||
|
|
||||||
.tooltip-inner {
|
.tooltip-inner {
|
||||||
min-width: 464px !important;
|
min-width: 464px !important;
|
||||||
background: $white;
|
background: var(--pgn-color-white);
|
||||||
display: block;
|
display: block;
|
||||||
color: $gray-500;
|
color: var(--pgn-color-gray-500);
|
||||||
}
|
}
|
||||||
.arrow::before {
|
.arrow::before {
|
||||||
border-top-color: $white;
|
border-top-color: var(--pgn-color-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.yellow-border {
|
.yellow-border {
|
||||||
border: 2px solid $accent-b;
|
border: 2px solid var(--pgn-color-accent-b);
|
||||||
}
|
}
|
||||||
|
|
||||||
.institutions__heading {
|
.institutions__heading {
|
||||||
color: $primary-700;
|
color: var(--pgn-color-primary-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.logistration-button {
|
.logistration-button {
|
||||||
color: $gray-700;
|
color: var(--pgn-color-gray-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.logistration-button:hover{
|
.logistration-button:hover{
|
||||||
color: $gray-700;
|
color: var(--pgn-color-gray-700);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +351,7 @@ select.form-control {
|
|||||||
width: 2.3rem;
|
width: 2.3rem;
|
||||||
}
|
}
|
||||||
.has-floating-label {
|
.has-floating-label {
|
||||||
color: $gray-500;
|
color: var(--pgn-color-gray-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pgn__form-control-floating-label .pgn__form-control-floating-label-content {
|
.pgn__form-control-floating-label .pgn__form-control-floating-label-content {
|
||||||
@@ -366,7 +365,7 @@ select.form-control {
|
|||||||
|
|
||||||
.form-group__form-field .form-control:focus ~ .pgn__form-control-floating-label .pgn__form-control-floating-label-content {
|
.form-group__form-field .form-control:focus ~ .pgn__form-control-floating-label .pgn__form-control-floating-label-content {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: $primary-700;
|
color: var(--pgn-color-primary-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group__form-field .form-control:not([value='']):not(:focus) ~
|
.form-group__form-field .form-control:not([value='']):not(:focus) ~
|
||||||
@@ -444,14 +443,14 @@ select.form-control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table-striped tbody tr:nth-of-type(odd) {
|
.table-striped tbody tr:nth-of-type(odd) {
|
||||||
background-color: $light-200;
|
background-color: var(--pgn-color-light-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
.institutions--provider-link {
|
.institutions--provider-link {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
color: $primary-700
|
color: var(--pgn-color-primary-700)
|
||||||
}
|
}
|
||||||
|
|
||||||
.pgn__form-control-decorator-trailing {
|
.pgn__form-control-decorator-trailing {
|
||||||
|
|||||||
Reference in New Issue
Block a user