Compare commits
192 Commits
open-relea
...
release/te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4825c3d68c | ||
|
|
4e27a35e10 | ||
|
|
ad0e2af8c8 | ||
|
|
d03e7c40d8 | ||
|
|
5a7063c123 | ||
|
|
9348c4bb4c | ||
|
|
5c5ff1190b | ||
|
|
7aee8562a8 | ||
|
|
ebca59a38f | ||
|
|
f87d521bc0 | ||
|
|
5280cef554 | ||
|
|
08430571ed | ||
|
|
3de6821c5d | ||
|
|
fb06133a27 | ||
|
|
12f1c72b7e | ||
|
|
ca8d08c8a0 | ||
|
|
30a4ca17ac | ||
|
|
25d76c0e59 | ||
|
|
6527f505f1 | ||
|
|
400950cff8 | ||
|
|
0219f5cd25 | ||
|
|
fdcab456e8 | ||
|
|
5283e7c7c6 | ||
|
|
e39533c56a | ||
|
|
212014fed9 | ||
|
|
9600301a62 | ||
|
|
1d5f64e1db | ||
|
|
f5208c58aa | ||
|
|
c15680cb8c | ||
|
|
76f41439e9 | ||
|
|
4581cf8698 | ||
|
|
95fa32eaaa | ||
|
|
1f729becbe | ||
|
|
7ad1df8bd0 | ||
|
|
c9d0abe968 | ||
|
|
91e33748ab | ||
|
|
8809f4cf16 | ||
|
|
7482765aa4 | ||
|
|
7003b6102d | ||
|
|
d608daccb1 | ||
|
|
2208737a69 | ||
|
|
567a020061 | ||
|
|
c5d9bfb2f6 | ||
|
|
f433d33f9d | ||
|
|
c0816e0818 | ||
|
|
c83e86bf06 | ||
|
|
b6f1a9739e | ||
|
|
f2b6cd4cac | ||
|
|
3092bd3980 | ||
|
|
20dc736278 | ||
|
|
d72beeb2d4 | ||
|
|
64b57df976 | ||
|
|
346b371ba2 | ||
|
|
650d708a1c | ||
|
|
1d924b4812 | ||
|
|
31ed9410a4 | ||
|
|
0ba3cac532 | ||
|
|
b23effdb7f | ||
|
|
5bcb6fe6f3 | ||
|
|
a67f201f4d | ||
|
|
9cfab58663 | ||
|
|
59a7d0751b | ||
|
|
9d673e803e | ||
|
|
8438915f72 | ||
|
|
cc6dd20f12 | ||
|
|
f67ffdd480 | ||
|
|
836df49829 | ||
|
|
5bed90b659 | ||
|
|
3b39c79fbf | ||
|
|
df7a189bcd | ||
|
|
08c51b6492 | ||
|
|
3bb3d90f3a | ||
|
|
2f48cc5767 | ||
|
|
ea43ebb031 | ||
|
|
4a708da50c | ||
|
|
f135f9a111 | ||
|
|
44d6dc616c | ||
|
|
a9771fbf49 | ||
|
|
8f58b72919 | ||
|
|
8da2a60b37 | ||
|
|
ff3e56c3f7 | ||
|
|
204586e79b | ||
|
|
31be6daac3 | ||
|
|
9f1c950080 | ||
|
|
66b793a1d4 | ||
|
|
72db51b65c | ||
|
|
9121b3f1e7 | ||
|
|
f7e51fd1d0 | ||
|
|
77b4f9b47e | ||
|
|
3ef24a626b | ||
|
|
d810913038 | ||
|
|
a6436997bb | ||
|
|
7959a39267 | ||
|
|
3a1dbfdee5 | ||
|
|
9b326f1ee8 | ||
|
|
3a87ebda1a | ||
|
|
25389ff296 | ||
|
|
80f782b87f | ||
|
|
8a2d767263 | ||
|
|
264bed987e | ||
|
|
738d460505 | ||
|
|
b8f43b92a1 | ||
|
|
7afffa4509 | ||
|
|
b9ad13e354 | ||
|
|
8ceb9e308f | ||
|
|
b58cab1249 | ||
|
|
f6d8c324d9 | ||
|
|
0c8d2017db | ||
|
|
c644da3dcc | ||
|
|
cc11ce0f81 | ||
|
|
549252038f | ||
|
|
192c8b4601 | ||
|
|
70e13eccfa | ||
|
|
e25a5a9549 | ||
|
|
358263de3c | ||
|
|
dc7fc94ab5 | ||
|
|
b643afd1b8 | ||
|
|
5ac1868d30 | ||
|
|
65063df731 | ||
|
|
9aee97dccb | ||
|
|
be1ce502c8 | ||
|
|
19e2f35522 | ||
|
|
d24ab3358b | ||
|
|
56803fb874 | ||
|
|
b7b94531aa | ||
|
|
78ada8ce34 | ||
|
|
194e61380c | ||
|
|
fa36e20de9 | ||
|
|
61cf386ee6 | ||
|
|
445cd15d9a | ||
|
|
db1cf48257 | ||
|
|
942d471097 | ||
|
|
1a769a4e70 | ||
|
|
b5cb2af513 | ||
|
|
6666c0df83 | ||
|
|
fa60d7d234 | ||
|
|
78cce21f10 | ||
|
|
e21c2a63e7 | ||
|
|
514792786d | ||
|
|
5ef2f1ba4f | ||
|
|
b986849c85 | ||
|
|
f8565c30d1 | ||
|
|
3a7e103317 | ||
|
|
f977e14ea6 | ||
|
|
ab4f1864f2 | ||
|
|
6e4d4c479c | ||
|
|
d74532f988 | ||
|
|
d577bc79f7 | ||
|
|
43ab328545 | ||
|
|
3ddfdf34d0 | ||
|
|
b751d41caf | ||
|
|
4f4b28e6f5 | ||
|
|
038bd117e1 | ||
|
|
7bb31a9aa0 | ||
|
|
b2f59fc3a1 | ||
|
|
60b63944bd | ||
|
|
2893a9e698 | ||
|
|
de4d0fb7f2 | ||
|
|
ca7254c3b0 | ||
|
|
6095869271 | ||
|
|
8fe67f918f | ||
|
|
b28e58e7cd | ||
|
|
a1436c3266 | ||
|
|
9b5e85a236 | ||
|
|
fe1388666a | ||
|
|
a07d6f9b80 | ||
|
|
3e685be116 | ||
|
|
0bb5f50917 | ||
|
|
49357a4e87 | ||
|
|
33ba1cdd08 | ||
|
|
7012fa82c9 | ||
|
|
7b418ff6e3 | ||
|
|
cc349faeb2 | ||
|
|
455ca15af9 | ||
|
|
f992331bf4 | ||
|
|
4158231d7a | ||
|
|
2fa46ab00e | ||
|
|
adade6e48d | ||
|
|
06aea1ff68 | ||
|
|
054304902f | ||
|
|
ba9bddbda1 | ||
|
|
706d69aeca | ||
|
|
6d3ed03cac | ||
|
|
21a35cde82 | ||
|
|
66f85ee17e | ||
|
|
140cfc1639 | ||
|
|
26906d45f7 | ||
|
|
a753170cb7 | ||
|
|
690140ce46 | ||
|
|
6764a9766c | ||
|
|
c646b88543 | ||
|
|
b1d11119db |
3
.env
3
.env
@@ -30,3 +30,6 @@ ENTERPRISE_MARKETING_URL=''
|
|||||||
ENTERPRISE_MARKETING_UTM_SOURCE=''
|
ENTERPRISE_MARKETING_UTM_SOURCE=''
|
||||||
ENTERPRISE_MARKETING_UTM_CAMPAIGN=''
|
ENTERPRISE_MARKETING_UTM_CAMPAIGN=''
|
||||||
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM=''
|
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM=''
|
||||||
|
APP_ID=''
|
||||||
|
MFE_CONFIG_API_URL=''
|
||||||
|
ACCOUNT_SETTINGS_URL=''
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ LOGOUT_URL='http://localhost:18000/logout'
|
|||||||
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
|
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
|
||||||
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
|
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
|
||||||
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
|
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
|
||||||
LOGO_POWERED_BY_OPEN_EDX_URL_SVG=https://edx-cdn.org/v3/stage/open-edx-tag.svg
|
|
||||||
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
|
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
|
||||||
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
|
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
|
||||||
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
|
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
|
||||||
@@ -36,3 +35,6 @@ ENTERPRISE_MARKETING_URL='http://example.com'
|
|||||||
ENTERPRISE_MARKETING_UTM_SOURCE='example.com'
|
ENTERPRISE_MARKETING_UTM_SOURCE='example.com'
|
||||||
ENTERPRISE_MARKETING_UTM_CAMPAIGN='example.com Referral'
|
ENTERPRISE_MARKETING_UTM_CAMPAIGN='example.com Referral'
|
||||||
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM='Footer'
|
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM='Footer'
|
||||||
|
APP_ID=''
|
||||||
|
MFE_CONFIG_API_URL=''
|
||||||
|
ACCOUNT_SETTINGS_URL=http://localhost:1997
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ LOGOUT_URL='http://localhost:18000/logout'
|
|||||||
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
|
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
|
||||||
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
|
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
|
||||||
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
|
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
|
||||||
LOGO_POWERED_BY_OPEN_EDX_URL_SVG=https://edx-cdn.org/v3/stage/open-edx-tag.svg
|
|
||||||
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
|
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
|
||||||
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
|
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
|
||||||
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
|
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
|
||||||
@@ -36,3 +35,4 @@ ENTERPRISE_MARKETING_URL='http://example.com'
|
|||||||
ENTERPRISE_MARKETING_UTM_SOURCE='example.com'
|
ENTERPRISE_MARKETING_UTM_SOURCE='example.com'
|
||||||
ENTERPRISE_MARKETING_UTM_CAMPAIGN='example.com Referral'
|
ENTERPRISE_MARKETING_UTM_CAMPAIGN='example.com Referral'
|
||||||
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM='Footer'
|
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM='Footer'
|
||||||
|
ACCOUNT_SETTINGS_URL=http://localhost:1997
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
const { createConfig } = require('@edx/frontend-build');
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
const { createConfig } = require('@openedx/frontend-build');
|
||||||
|
|
||||||
const config = createConfig('eslint', {
|
const config = createConfig('eslint', {
|
||||||
rules: {
|
rules: {
|
||||||
'import/no-named-as-default': 'off',
|
'import/no-named-as-default': 'off',
|
||||||
'import/no-named-as-default-member': 'off',
|
'import/no-named-as-default-member': 'off',
|
||||||
|
'import/no-import-module-exports': 'off',
|
||||||
'import/no-self-import': 'off',
|
'import/no-self-import': 'off',
|
||||||
'spaced-comment': ['error', 'always', { 'block': { 'exceptions': ['*'] } }],
|
'spaced-comment': ['error', 'always', { 'block': { 'exceptions': ['*'] } }],
|
||||||
'react-hooks/rules-of-hooks': 'off',
|
'react-hooks/rules-of-hooks': 'off',
|
||||||
|
"react/forbid-prop-types": ["error", { "forbid": ["any", "array"] }], // arguable object proptype is use when I do not care about the shape of the object
|
||||||
|
'no-import-assign': 'off',
|
||||||
|
'no-promise-executor-return': 'off',
|
||||||
|
'import/no-cycle': 'off',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
6
.github/CODEOWNERS
vendored
Normal file
6
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Code owners for frontend-app-ora-grading
|
||||||
|
|
||||||
|
# These owners will be the default owners for everything in
|
||||||
|
# the repo. Unless a later match takes precedence, they will
|
||||||
|
# be requested for review when someone opens a pull request.
|
||||||
|
* @edx/content-aurora
|
||||||
19
.github/workflows/add-depr-ticket-to-depr-board.yml
vendored
Normal file
19
.github/workflows/add-depr-ticket-to-depr-board.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Run the workflow that adds new tickets that are either:
|
||||||
|
# - labelled "DEPR"
|
||||||
|
# - title starts with "[DEPR]"
|
||||||
|
# - body starts with "Proposal Date" (this is the first template field)
|
||||||
|
# to the org-wide DEPR project board
|
||||||
|
|
||||||
|
name: Add newly created DEPR issues to the DEPR project board
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
routeissue:
|
||||||
|
uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
|
||||||
|
secrets:
|
||||||
|
GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
|
||||||
|
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
|
||||||
|
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}
|
||||||
20
.github/workflows/add-remove-label-on-comment.yml
vendored
Normal file
20
.github/workflows/add-remove-label-on-comment.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# This workflow runs when a comment is made on the ticket
|
||||||
|
# If the comment starts with "label: " it tries to apply
|
||||||
|
# the label indicated in rest of comment.
|
||||||
|
# If the comment starts with "remove label: ", it tries
|
||||||
|
# to remove the indicated label.
|
||||||
|
# Note: Labels are allowed to have spaces and this script does
|
||||||
|
# not parse spaces (as often a space is legitimate), so the command
|
||||||
|
# "label: really long lots of words label" will apply the
|
||||||
|
# label "really long lots of words label"
|
||||||
|
|
||||||
|
name: Allows for the adding and removing of labels via comment
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
add_remove_labels:
|
||||||
|
uses: openedx/.github/.github/workflows/add-remove-label-on-comment.yml@master
|
||||||
|
|
||||||
21
.github/workflows/ci.yml
vendored
21
.github/workflows/ci.yml
vendored
@@ -10,18 +10,18 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node: [12, 14, 16]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup Nodejs Env
|
||||||
|
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
|
||||||
- name: Setup Nodejs
|
- name: Setup Nodejs
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v4
|
||||||
|
# Because of node 18 bug (https://github.com/nodejs/node/issues/47563), Pinning node version 18.15 until the next release of node
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -39,7 +39,10 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Run Coverage
|
- name: Run Coverage
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
fail_ci_if_error: true
|
||||||
|
|
||||||
- name: Send failure notification
|
- name: Send failure notification
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
|||||||
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/lockfileversion-check.yml@master
|
uses: openedx/.github/.github/workflows/lockfileversion-check-v3.yml@master
|
||||||
|
|||||||
32
.github/workflows/npm-publish.yml
vendored
32
.github/workflows/npm-publish.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Release CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Release
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 12
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Create Build
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Release Package
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }}
|
|
||||||
NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_NPM_TOKEN }}
|
|
||||||
run: npm semantic-release
|
|
||||||
12
.github/workflows/self-assign-issue.yml
vendored
Normal file
12
.github/workflows/self-assign-issue.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This workflow runs when a comment is made on the ticket
|
||||||
|
# If the comment starts with "assign me" it assigns the author to the
|
||||||
|
# ticket (case insensitive)
|
||||||
|
|
||||||
|
name: Assign comment author to ticket if they say "assign me"
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
self_assign_by_comment:
|
||||||
|
uses: openedx/.github/.github/workflows/self-assign-issue.yml@master
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,3 +25,5 @@ module.config.js
|
|||||||
### transifex ###
|
### transifex ###
|
||||||
src/i18n/transifex_input.json
|
src/i18n/transifex_input.json
|
||||||
temp
|
temp
|
||||||
|
|
||||||
|
src/i18n/messages
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npm run lint
|
|
||||||
27
.releaserc
27
.releaserc
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"branch": "master",
|
|
||||||
"tagFormat": "v${version}",
|
|
||||||
"verifyConditions": [
|
|
||||||
"@semantic-release/npm",
|
|
||||||
{
|
|
||||||
"path": "@semantic-release/github",
|
|
||||||
"assets": {
|
|
||||||
"path": "dist/*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"analyzeCommits": "@semantic-release/commit-analyzer",
|
|
||||||
"generateNotes": "@semantic-release/release-notes-generator",
|
|
||||||
"prepare": "@semantic-release/npm",
|
|
||||||
"publish": [
|
|
||||||
"@semantic-release/npm",
|
|
||||||
{
|
|
||||||
"path": "@semantic-release/github",
|
|
||||||
"assets": {
|
|
||||||
"path": "dist/*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"success": [],
|
|
||||||
"fail": []
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
[main]
|
|
||||||
host = https://www.transifex.com
|
|
||||||
|
|
||||||
[o:open-edx:p:edx-platform:r:frontend-app-ora-grading]
|
|
||||||
file_filter = src/i18n/messages/<lang>.json
|
|
||||||
source_file = src/i18n/transifex_input.json
|
|
||||||
source_lang = en
|
|
||||||
type = KEYVALUEJSON
|
|
||||||
|
|
||||||
34
Makefile
34
Makefile
@@ -2,19 +2,15 @@ npm-install-%: ## install specified % npm package
|
|||||||
npm install $* --save-dev
|
npm install $* --save-dev
|
||||||
git add package.json
|
git add package.json
|
||||||
|
|
||||||
transifex_resource = frontend-app-ora-grading
|
intl_imports = ./node_modules/.bin/intl-imports.js
|
||||||
transifex_langs = "ar,fr,es_419,zh_CN"
|
|
||||||
|
|
||||||
transifex_utils = ./node_modules/.bin/transifex-utils.js
|
transifex_utils = ./node_modules/.bin/transifex-utils.js
|
||||||
i18n = ./src/i18n
|
i18n = ./src/i18n
|
||||||
transifex_input = $(i18n)/transifex_input.json
|
transifex_input = $(i18n)/transifex_input.json
|
||||||
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/translation/en/strings/
|
|
||||||
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
|
|
||||||
|
|
||||||
# This directory must match .babelrc .
|
# This directory must match .babelrc .
|
||||||
transifex_temp = ./temp/babel-plugin-react-intl
|
transifex_temp = ./temp/babel-plugin-formatjs
|
||||||
|
|
||||||
NPM_TESTS=build i18n_extract lint test is-es5
|
NPM_TESTS=build i18n_extract lint test
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: $(addprefix test.npm.,$(NPM_TESTS)) ## validate ci suite
|
test: $(addprefix test.npm.,$(NPM_TESTS)) ## validate ci suite
|
||||||
@@ -44,20 +40,18 @@ detect_changed_source_translations:
|
|||||||
# Checking for changed translations...
|
# Checking for changed translations...
|
||||||
git diff --exit-code $(i18n)
|
git diff --exit-code $(i18n)
|
||||||
|
|
||||||
# Pushes translations to Transifex. You must run make extract_translations first.
|
|
||||||
push_translations:
|
|
||||||
# Pushing strings to Transifex...
|
|
||||||
tx push -s
|
|
||||||
# Fetching hashes from Transifex...
|
|
||||||
./node_modules/reactifex/bash_scripts/get_hashed_strings.sh $(tx_url1)
|
|
||||||
# Writing out comments to file...
|
|
||||||
$(transifex_utils) $(transifex_temp) --comments
|
|
||||||
# Pushing comments to Transifex...
|
|
||||||
./node_modules/reactifex/bash_scripts/put_comments.sh $(tx_url2)
|
|
||||||
|
|
||||||
# Pulls translations from Transifex.
|
|
||||||
pull_translations:
|
pull_translations:
|
||||||
tx pull -f --mode reviewed --languages=$(transifex_langs)
|
rm -rf src/i18n/messages
|
||||||
|
mkdir src/i18n/messages
|
||||||
|
cd src/i18n/messages \
|
||||||
|
&& atlas pull $(ATLAS_OPTIONS) \
|
||||||
|
translations/frontend-component-footer/src/i18n/messages:frontend-component-footer \
|
||||||
|
translations/frontend-component-header/src/i18n/messages:frontend-component-header \
|
||||||
|
translations/frontend-platform/src/i18n/messages:frontend-platform \
|
||||||
|
translations/paragon/src/i18n/messages:paragon \
|
||||||
|
translations/frontend-app-ora-grading/src/i18n/messages:frontend-app-ora-grading
|
||||||
|
|
||||||
|
$(intl_imports) frontend-component-footer frontend-component-header frontend-platform paragon frontend-app-ora-grading
|
||||||
|
|
||||||
# This target is used by CI.
|
# This target is used by CI.
|
||||||
validate-no-uncommitted-package-lock-changes:
|
validate-no-uncommitted-package-lock-changes:
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -1,21 +0,0 @@
|
|||||||
# frontend-app-ora-grading
|
|
||||||
|
|
||||||
The ORA Staff Grading App is a microfrontend (MFE) staff grading experience for Open Response Assessments (ORAs). This experience was designed to streamline the grading process and enable richer previews of submission content.
|
|
||||||
|
|
||||||
When enabled, ORAs with a staff grading step will link to this new MFE when clicking "Grade Available Responses" from the ORA or link in the instructor dashboard.
|
|
||||||
|
|
||||||
## Quickstart
|
|
||||||
|
|
||||||
To start the MFE and enable the feature in LMS:
|
|
||||||
|
|
||||||
1. Start the MFE with `npm run start`. Take a note of the path/port (defaults to `http://localhost:1993`).
|
|
||||||
|
|
||||||
2. Add the route root to `edx-platform` settings: In `edx-platform/lms/envs/private.py` or similar, add `ORA_GRADING_MICROFRONTEND_URL = 'http://localhost:1993'`
|
|
||||||
|
|
||||||
3. Enable the feature: In Django Admin go to django-waffle > Flags and add/enable a new flag called `openresponseassessment.enhanced_staff_grader`.
|
|
||||||
|
|
||||||
From there, visit the new experience by going to the Instructor Dashboard > Open Responses or an ORA with a Staff Graded Step and click a link to begin grading.
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
See the [ORA Staff Grading](https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/open_response_assessments/ORA_Staff_Grading.html#ora-staff-grading) section on ReadTheDocs for usage information.
|
|
||||||
239
README.rst
Normal file
239
README.rst
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
frontend-app-ora-grading
|
||||||
|
#############################
|
||||||
|
|
||||||
|
|license-badge| |status-badge| |ci-badge| |codecov-badge|
|
||||||
|
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
*******
|
||||||
|
|
||||||
|
The ORA Staff Grading App is a micro-frontend (MFE) staff grading experience
|
||||||
|
for Open Response Assessments (ORAs). This experience was designed to
|
||||||
|
streamline the grading process and enable richer previews of submission content
|
||||||
|
and, eventually, replace on-platform grading workflows for ORA.
|
||||||
|
|
||||||
|
When enabled, ORAs with a staff grading step will link to this new MFE when
|
||||||
|
clicking "Grade Available Responses" from the ORA or link in the instructor
|
||||||
|
dashboard.
|
||||||
|
|
||||||
|
The ORA Staff Grader depends on the `lms/djangoapps/ora_staff_grader
|
||||||
|
<https://github.com/openedx/edx-platform/tree/master/lms/djangoapps/ora_staff_grader>`_
|
||||||
|
app in ``edx-platform``.
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
***************
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
=============
|
||||||
|
|
||||||
|
The `devstack`_ is currently recommended as a development environment for your
|
||||||
|
new MFE. If you start it with ``make dev.up.lms`` that should give you
|
||||||
|
everything you need as a companion to this frontend.
|
||||||
|
|
||||||
|
Note that it is also possible to use `Tutor`_ to develop an MFE. You can refer
|
||||||
|
to the `relevant tutor-mfe documentation`_ to get started using it.
|
||||||
|
|
||||||
|
.. _Devstack: https://github.com/openedx/devstack
|
||||||
|
|
||||||
|
.. _Tutor: https://github.com/overhangio/tutor
|
||||||
|
|
||||||
|
.. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe#mfe-development
|
||||||
|
|
||||||
|
Plugins
|
||||||
|
=======
|
||||||
|
This MFE can be customized using `Frontend Plugin Framework <https://github.com/openedx/frontend-plugin-framework>`_.
|
||||||
|
|
||||||
|
The parts of this MFE that can be customized in that manner are documented `here </src/plugin-slots>`_.
|
||||||
|
|
||||||
|
Developing
|
||||||
|
==========
|
||||||
|
|
||||||
|
Cloning and Startup
|
||||||
|
--------------
|
||||||
|
|
||||||
|
First, clone the repo, install code prerequisites, and start the app.
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
|
||||||
|
1. Clone your new repo:
|
||||||
|
|
||||||
|
``git clone git@github.com:openedx/frontend-app-ora-grading.git``
|
||||||
|
|
||||||
|
2. Use node v18.x.
|
||||||
|
|
||||||
|
The current version of the micro-frontend build scripts support node 18.
|
||||||
|
Using other major versions of node *may* work, but this is unsupported. For
|
||||||
|
convenience, this repository includes an .nvmrc file to help in setting the
|
||||||
|
correct node version via `nvm <https://github.com/nvm-sh/nvm>`_.
|
||||||
|
|
||||||
|
3. Install npm dependencies:
|
||||||
|
|
||||||
|
``cd frontend-app-ora-grading && npm install``
|
||||||
|
|
||||||
|
4. Update the application port to use for local development:
|
||||||
|
|
||||||
|
Default port is 1993. If this does not work for you, update the line
|
||||||
|
`PORT=1993` to your port in all .env.* files
|
||||||
|
|
||||||
|
5. Start the dev server:
|
||||||
|
|
||||||
|
``npm start``
|
||||||
|
|
||||||
|
The app will, by default, run on `http://localhost:1993` unless otherwise
|
||||||
|
specified in ``.env.development:PORT`` and ``.env.development:BASE_URL``.
|
||||||
|
|
||||||
|
Next, enable the ORA Grading micro-frontend in `edx-platform`
|
||||||
|
|
||||||
|
#. Add the path to the ORA Grading app in `edx-platform`:
|
||||||
|
|
||||||
|
#. Go to your environment settings (e.g. `edx-platform/lms/envs/private.py`)
|
||||||
|
|
||||||
|
#. Add the environment variable, ``ORA_GRADING_MICROFRONTEND_URL`` pointing
|
||||||
|
to the ORA Grading app location (e.g. ``http://localhost:1993``).
|
||||||
|
|
||||||
|
#. Start / restart the ``edx-platform`` ``lms``.
|
||||||
|
|
||||||
|
#. Enable the ORA Grading feature in Django Admin.
|
||||||
|
|
||||||
|
#. Go to Django Admin (`{lms-root}/admin`)
|
||||||
|
|
||||||
|
#. Navigate to ``django-waffle`` > ``Flags`` and click ``add/enable a new
|
||||||
|
flag``.
|
||||||
|
|
||||||
|
#. Add a new flag called ``openresponseassessment.enhanced_staff_grader``
|
||||||
|
and enable it.
|
||||||
|
|
||||||
|
From there, visit an Open Response Assessment with a Staff Graded Step and
|
||||||
|
click the "View and grade responses" button to begin grading in the ORA Staff
|
||||||
|
Grader experience.
|
||||||
|
|
||||||
|
|
||||||
|
Making Changes
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Get / install the latest code:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
# Grab the latest code
|
||||||
|
git checkout master
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# Install/update the dev requirements
|
||||||
|
npm install
|
||||||
|
|
||||||
|
|
||||||
|
Before committing:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
# Make a new branch for your changes
|
||||||
|
git checkout -b <your_github_username>/<short_description>
|
||||||
|
|
||||||
|
# Using your favorite editor, edit the code to make your change.
|
||||||
|
|
||||||
|
# Run your new tests
|
||||||
|
npm test
|
||||||
|
|
||||||
|
# Commit all your changes
|
||||||
|
git commit ...
|
||||||
|
git push
|
||||||
|
|
||||||
|
# Open a PR and ask for review.
|
||||||
|
|
||||||
|
Deploying
|
||||||
|
=========
|
||||||
|
|
||||||
|
This component follows the standard deploy process for MFEs. For details, see
|
||||||
|
the `MFE production deployment guide`_
|
||||||
|
|
||||||
|
.. _MFE production deployment guide: https://openedx.github.io/frontend-platform/#production-deployment-strategy
|
||||||
|
|
||||||
|
Internationalization
|
||||||
|
====================
|
||||||
|
|
||||||
|
Please see refer to the `frontend-platform i18n howto`_ for documentation on
|
||||||
|
internationalization.
|
||||||
|
|
||||||
|
.. _frontend-platform i18n howto: https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst
|
||||||
|
|
||||||
|
Getting Help
|
||||||
|
************
|
||||||
|
|
||||||
|
If you're having trouble, we have discussion forums at
|
||||||
|
https://discuss.openedx.org where you can connect with others in the community.
|
||||||
|
|
||||||
|
Our real-time conversations are on Slack. You can request a `Slack
|
||||||
|
invitation`_, then join our `community Slack workspace`_. Because this is a
|
||||||
|
frontend repository, the best place to discuss it would be in the `#wg-frontend
|
||||||
|
channel`_.
|
||||||
|
|
||||||
|
For anything non-trivial, the best path is to open an issue in this repository
|
||||||
|
with as many details about the issue you are facing as you can provide.
|
||||||
|
|
||||||
|
https://github.com/openedx/frontend-app-ora-grading/issues
|
||||||
|
|
||||||
|
For more information about these options, see the `Getting Help`_ page.
|
||||||
|
|
||||||
|
.. _Slack invitation: https://openedx.org/slack
|
||||||
|
.. _community Slack workspace: https://openedx.slack.com/
|
||||||
|
.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6
|
||||||
|
.. _Getting Help: https://openedx.org/community/connect
|
||||||
|
|
||||||
|
License
|
||||||
|
*******
|
||||||
|
|
||||||
|
The code in this repository is licensed under the AGPLv3 unless otherwise
|
||||||
|
noted.
|
||||||
|
|
||||||
|
Please see `LICENSE <LICENSE>`_ for details.
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
************
|
||||||
|
|
||||||
|
Contributions are very welcome. Please read `How To Contribute`_ for details.
|
||||||
|
|
||||||
|
.. _How To Contribute: https://openedx.org/r/how-to-contribute
|
||||||
|
|
||||||
|
This project is currently accepting all types of contributions, bug fixes,
|
||||||
|
security fixes, maintenance work, or new features. However, please make sure
|
||||||
|
to have a discussion about your new feature idea with the maintainers prior to
|
||||||
|
beginning development to maximize the chances of your change being accepted.
|
||||||
|
You can start a conversation by creating a new issue on this repo summarizing
|
||||||
|
your idea.
|
||||||
|
|
||||||
|
The Open edX Code of Conduct
|
||||||
|
****************************
|
||||||
|
|
||||||
|
All community members are expected to follow the `Open edX Code of Conduct`_.
|
||||||
|
|
||||||
|
.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/
|
||||||
|
|
||||||
|
People
|
||||||
|
******
|
||||||
|
|
||||||
|
The assigned maintainers for this component and other project details may be
|
||||||
|
found in `Backstage`_. Backstage pulls this data from the ``catalog-info.yaml``
|
||||||
|
file in this repo.
|
||||||
|
|
||||||
|
.. _Backstage: https://open-edx-backstage.herokuapp.com/catalog/default/component/frontend-app-ora-grading
|
||||||
|
|
||||||
|
Reporting Security Issues
|
||||||
|
*************************
|
||||||
|
|
||||||
|
Please do not report security issues in public, and email security@openedx.org instead.
|
||||||
|
|
||||||
|
.. |license-badge| image:: https://img.shields.io/github/license/openedx/frontend-app-ora-grading.svg
|
||||||
|
:target: https://github.com/openedx/frontend-app-ora-grading/blob/master/LICENSE
|
||||||
|
:alt: License
|
||||||
|
|
||||||
|
.. |status-badge| image:: https://img.shields.io/badge/Status-Maintained-brightgreen
|
||||||
|
|
||||||
|
.. |ci-badge| image:: https://github.com/openedx/frontend-app-ora-grading/actions/workflows/ci.yml/badge.svg
|
||||||
|
:target: https://github.com/openedx/frontend-app-ora-grading/actions/workflows/ci.yml
|
||||||
|
:alt: Continuous Integration
|
||||||
|
|
||||||
|
.. |codecov-badge| image:: https://codecov.io/github/openedx/frontend-app-ora-grading/coverage.svg?branch=master
|
||||||
|
:target: https://codecov.io/github/openedx/frontend-app-ora-grading?branch=master
|
||||||
|
:alt: Codecov
|
||||||
21
catalog-info.yaml
Normal file
21
catalog-info.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# This file records information about this repo. Its use is described in OEP-55:
|
||||||
|
# https://open-edx-proposals.readthedocs.io/en/latest/processes/oep-0055-proc-project-maintainers.html
|
||||||
|
|
||||||
|
apiVersion: backstage.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: 'frontend-app-ora-grading'
|
||||||
|
description: "Frontend grading experience for Open Response Assessments (ORAs)"
|
||||||
|
links:
|
||||||
|
- url: "https://ora-grading.edx.org"
|
||||||
|
title: "Production Site"
|
||||||
|
icon: "Web"
|
||||||
|
- url: "https://ora-grading.stage.edx.org"
|
||||||
|
title: "Stage Site"
|
||||||
|
icon: "Web"
|
||||||
|
annotations:
|
||||||
|
openedx.org/release: "master"
|
||||||
|
spec:
|
||||||
|
owner: "user:codewithemad"
|
||||||
|
type: 'website'
|
||||||
|
lifecycle: 'production'
|
||||||
@@ -26,4 +26,3 @@ There are only two requirements for a good `make target` name
|
|||||||
What `make validate-no-uncommitted-package-lock-changes` does is `git diff`s for any `package-lock.json` file changes in your project.
|
What `make validate-no-uncommitted-package-lock-changes` does is `git diff`s for any `package-lock.json` file changes in your project.
|
||||||
|
|
||||||
This is important because `npm` uses the pinned dependencies in your `package-lock.json` file to build the `node_modules` directory. However, the dependencies defined within the `package.json` file can be modified manually, for example, to become misaligned with the dependencies defined within the `package-lock.json`. So when `npm install` executes, the `package-lock.json` file will be updated to mirror the modified `package.json` changes.
|
This is important because `npm` uses the pinned dependencies in your `package-lock.json` file to build the `node_modules` directory. However, the dependencies defined within the `package.json` file can be modified manually, for example, to become misaligned with the dependencies defined within the `package-lock.json`. So when `npm install` executes, the `package-lock.json` file will be updated to mirror the modified `package.json` changes.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { createConfig } = require('@edx/frontend-build');
|
const { createConfig } = require('@openedx/frontend-build');
|
||||||
|
|
||||||
module.exports = createConfig('jest', {
|
module.exports = createConfig('jest', {
|
||||||
setupFilesAfterEnv: [
|
setupFilesAfterEnv: [
|
||||||
@@ -6,9 +6,6 @@ module.exports = createConfig('jest', {
|
|||||||
'<rootDir>/src/setupTest.js',
|
'<rootDir>/src/setupTest.js',
|
||||||
],
|
],
|
||||||
modulePaths: ['<rootDir>/src/'],
|
modulePaths: ['<rootDir>/src/'],
|
||||||
snapshotSerializers: [
|
|
||||||
'enzyme-to-json/serializer',
|
|
||||||
],
|
|
||||||
coveragePathIgnorePatterns: [
|
coveragePathIgnorePatterns: [
|
||||||
'src/segment.js',
|
'src/segment.js',
|
||||||
'src/postcss.config.js',
|
'src/postcss.config.js',
|
||||||
|
|||||||
@@ -1,9 +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
|
|
||||||
|
|
||||||
tags:
|
|
||||||
- frontend-app
|
|
||||||
- masters
|
|
||||||
oeps:
|
|
||||||
oep-2: true # Repository metadata
|
|
||||||
openedx-release: {ref: master}
|
|
||||||
62117
package-lock.json
generated
62117
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@@ -6,18 +6,19 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/edx/frontend-app-ora-grading.git"
|
"url": "git+https://github.com/edx/frontend-app-ora-grading.git"
|
||||||
},
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"extends @edx/browserslist-config"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "fedx-scripts webpack",
|
"build": "fedx-scripts webpack",
|
||||||
"coveralls": "cat ./coverage/lcov.info | coveralls",
|
"i18n_extract": "fedx-scripts formatjs extract",
|
||||||
"is-es5": "es-check es5 ./dist/*.js",
|
|
||||||
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
|
|
||||||
"lint": "fedx-scripts eslint --ext .jsx,.js src/",
|
"lint": "fedx-scripts eslint --ext .jsx,.js src/",
|
||||||
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
|
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
|
||||||
"semantic-release": "semantic-release",
|
"semantic-release": "semantic-release",
|
||||||
"start": "fedx-scripts webpack-dev-server --progress",
|
"start": "fedx-scripts webpack-dev-server --progress",
|
||||||
|
"dev": "PUBLIC_PATH=/ora-grading/ MFE_CONFIG_API_URL='http://localhost:8000/api/mfe_config/v1' fedx-scripts webpack-dev-server --progress --host apps.local.openedx.io",
|
||||||
"test": "TZ=GMT fedx-scripts jest --coverage --passWithNoTests",
|
"test": "TZ=GMT fedx-scripts jest --coverage --passWithNoTests",
|
||||||
"watch-tests": "jest --watch",
|
"watch-tests": "jest --watch"
|
||||||
"prepare": "husky install"
|
|
||||||
},
|
},
|
||||||
"author": "edX",
|
"author": "edX",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
@@ -26,70 +27,69 @@
|
|||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/brand": "npm:@edx/brand-edx.org@^2.0.3",
|
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||||
"@edx/frontend-component-footer": "^11.1.1",
|
"@edx/frontend-component-footer": "^14.6.0",
|
||||||
"@edx/frontend-component-header": "^3.1.1",
|
"@edx/frontend-component-header": "^6.2.0",
|
||||||
"@edx/frontend-platform": "^2.4.0",
|
"@edx/frontend-platform": "^8.3.1",
|
||||||
"@edx/paragon": "^19.9.0",
|
"@edx/openedx-atlas": "^0.6.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
|
"@openedx/paragon": "^22.16.0",
|
||||||
"@redux-beacon/segment": "^1.1.0",
|
"@redux-beacon/segment": "^1.1.0",
|
||||||
|
"@redux-devtools/extension": "3.0.0",
|
||||||
"@reduxjs/toolkit": "^1.6.1",
|
"@reduxjs/toolkit": "^1.6.1",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^14.0.0",
|
||||||
"@zip.js/zip.js": "^2.4.6",
|
"@zip.js/zip.js": "^2.4.6",
|
||||||
"axios": "^0.21.4",
|
"axios": "^0.28.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"core-js": "3.16.2",
|
"core-js": "3.35.1",
|
||||||
"dompurify": "^2.3.1",
|
"dompurify": "^2.3.1",
|
||||||
"email-prop-type": "^3.0.1",
|
"email-prop-type": "^3.0.1",
|
||||||
"enzyme": "^3.11.0",
|
|
||||||
"enzyme-to-json": "^3.6.2",
|
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"filesize": "^8.0.6",
|
"filesize": "^8.0.6",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"history": "5.0.1",
|
"history": "5.3.0",
|
||||||
"html-react-parser": "^1.3.0",
|
"html-react-parser": "^1.3.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.3",
|
||||||
"prop-types": "15.7.2",
|
"prop-types": "15.8.1",
|
||||||
"query-string": "7.0.1",
|
"query-string": "7.1.3",
|
||||||
"react": "^16.14.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-intl": "^5.20.9",
|
"react-helmet": "^6.1.0",
|
||||||
"react-pdf": "^5.5.0",
|
"react-intl": "6.4.7",
|
||||||
"react-redux": "^7.2.4",
|
"react-pdf": "^7.0.0",
|
||||||
"react-router": "5.2.0",
|
"react-redux": "^7.2.9",
|
||||||
"react-router-dom": "5.2.0",
|
"react-router": "6.21.3",
|
||||||
|
"react-router-dom": "6.21.3",
|
||||||
"react-router-redux": "^5.0.0-alpha.9",
|
"react-router-redux": "^5.0.0-alpha.9",
|
||||||
"redux": "4.1.1",
|
"redux": "4.2.1",
|
||||||
"redux-beacon": "^2.1.0",
|
"redux-beacon": "^2.1.0",
|
||||||
"redux-devtools-extension": "2.13.9",
|
|
||||||
"redux-logger": "3.0.6",
|
"redux-logger": "3.0.6",
|
||||||
"redux-thunk": "2.3.0",
|
"redux-thunk": "2.4.2",
|
||||||
"regenerator-runtime": "^0.13.9",
|
"regenerator-runtime": "^0.14.0",
|
||||||
"reselect": "^4.0.0",
|
"reselect": "^4.0.0",
|
||||||
"util": "^0.12.4",
|
"util": "^0.12.4",
|
||||||
"whatwg-fetch": "^3.6.2"
|
"whatwg-fetch": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@edx/frontend-build": "^11.0.2",
|
"@edx/browserslist-config": "^1.3.0",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@edx/react-unit-test-utils": "^4.0.0",
|
||||||
"@testing-library/react": "^12.1.0",
|
"@edx/reactifex": "^2.1.1",
|
||||||
|
"@openedx/frontend-build": "^14.3.3",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"@testing-library/react": "^16.2.0",
|
||||||
"axios-mock-adapter": "^1.20.0",
|
"axios-mock-adapter": "^1.20.0",
|
||||||
"codecov": "^3.8.3",
|
|
||||||
"enzyme-adapter-react-16": "^1.15.6",
|
|
||||||
"es-check": "^6.0.0",
|
|
||||||
"fetch-mock": "^9.11.0",
|
"fetch-mock": "^9.11.0",
|
||||||
"husky": "^7.0.0",
|
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "27.0.6",
|
"jest": "29.7.0",
|
||||||
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"jest-expect-message": "^1.0.2",
|
"jest-expect-message": "^1.0.2",
|
||||||
"react-dev-utils": "^12.0.1",
|
"react-dev-utils": "^12.0.1",
|
||||||
"react-test-renderer": "^16.14.0",
|
"react-test-renderer": "^18.3.1",
|
||||||
"reactifex": "1.1.1",
|
"reactifex": "1.1.1",
|
||||||
"redux-mock-store": "^1.5.4",
|
"redux-mock-store": "^1.5.5"
|
||||||
"semantic-release": "^19.0.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
renovate.json
Normal file
34
renovate.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"config:base",
|
||||||
|
"schedule:weekly",
|
||||||
|
":automergeLinters",
|
||||||
|
":automergeMinor",
|
||||||
|
":automergeTesters",
|
||||||
|
":enableVulnerabilityAlerts",
|
||||||
|
":rebaseStalePrs",
|
||||||
|
":semanticCommits",
|
||||||
|
":updateNotScheduled"
|
||||||
|
],
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchDepTypes": [
|
||||||
|
"devDependencies"
|
||||||
|
],
|
||||||
|
"matchUpdateTypes": [
|
||||||
|
"lockFileMaintenance",
|
||||||
|
"minor",
|
||||||
|
"patch",
|
||||||
|
"pin"
|
||||||
|
],
|
||||||
|
"automerge": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchPackagePatterns": ["@edx", "@openedx"],
|
||||||
|
"matchUpdateTypes": ["minor", "patch"],
|
||||||
|
"automerge": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timezone": "America/New_York",
|
||||||
|
"schedule": ["before 11pm"]
|
||||||
|
}
|
||||||
13
src/App.jsx
13
src/App.jsx
@@ -3,31 +3,34 @@ import PropTypes from 'prop-types';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
|
||||||
import Footer from '@edx/frontend-component-footer';
|
import { FooterSlot } from '@edx/frontend-component-footer';
|
||||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
|
|
||||||
import DemoWarning from 'containers/DemoWarning';
|
import DemoWarning from 'containers/DemoWarning';
|
||||||
import CTA from 'containers/CTA';
|
import NotificationsBanner from 'containers/NotificationsBanner';
|
||||||
import ListView from 'containers/ListView';
|
import ListView from 'containers/ListView';
|
||||||
|
|
||||||
import './App.scss';
|
import './App.scss';
|
||||||
|
import Head from './components/Head';
|
||||||
|
|
||||||
export const App = ({ courseMetadata, isEnabled }) => (
|
export const App = ({ courseMetadata, isEnabled }) => (
|
||||||
<Router>
|
<Router>
|
||||||
<div>
|
<div>
|
||||||
|
<Head />
|
||||||
<Header
|
<Header
|
||||||
courseTitle={courseMetadata.title}
|
courseTitle={courseMetadata.title}
|
||||||
courseNumber={courseMetadata.number}
|
courseNumber={courseMetadata.number}
|
||||||
courseOrg={courseMetadata.org}
|
courseOrg={courseMetadata.org}
|
||||||
|
data-testid="header"
|
||||||
/>
|
/>
|
||||||
{!isEnabled && <DemoWarning />}
|
{!isEnabled && <DemoWarning />}
|
||||||
<CTA />
|
<NotificationsBanner />
|
||||||
<main>
|
<main data-testid="main">
|
||||||
<ListView />
|
<ListView />
|
||||||
</main>
|
</main>
|
||||||
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
|
<FooterSlot />
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// frontend-app-*/src/index.scss
|
// frontend-app-*/src/index.scss
|
||||||
@import "~@edx/brand/paragon/fonts";
|
@import "~@edx/brand/paragon/fonts";
|
||||||
@import "~@edx/brand/paragon/variables";
|
@import "~@edx/brand/paragon/variables";
|
||||||
@import "~@edx/paragon/scss/core/core";
|
@import "~@openedx/paragon/scss/core/core";
|
||||||
@import "~@edx/brand/paragon/overrides";
|
@import "~@edx/brand/paragon/overrides";
|
||||||
|
|
||||||
$fa-font-path: "~font-awesome/fonts";
|
$fa-font-path: "~font-awesome/fonts";
|
||||||
@@ -10,6 +10,7 @@ $fa-font-path: "~font-awesome/fonts";
|
|||||||
$input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4.0.0 to work
|
$input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4.0.0 to work
|
||||||
|
|
||||||
@import "~@edx/frontend-component-footer/dist/_footer";
|
@import "~@edx/frontend-component-footer/dist/_footer";
|
||||||
|
@import "~@edx/frontend-component-header/dist/index";
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import Footer from '@edx/frontend-component-footer';
|
|
||||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
|
||||||
|
|
||||||
import ListView from 'containers/ListView';
|
|
||||||
|
|
||||||
import { App } from './App';
|
import { App } from './App';
|
||||||
|
|
||||||
@@ -20,15 +15,13 @@ jest.mock('data/redux', () => ({
|
|||||||
jest.mock('@edx/frontend-component-header', () => ({
|
jest.mock('@edx/frontend-component-header', () => ({
|
||||||
LearningHeader: 'Header',
|
LearningHeader: 'Header',
|
||||||
}));
|
}));
|
||||||
jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
jest.mock('@edx/frontend-component-footer', () => ({ FooterSlot: 'FooterSlot' }));
|
||||||
|
|
||||||
jest.mock('containers/DemoWarning', () => 'DemoWarning');
|
jest.mock('containers/DemoWarning', () => 'DemoWarning');
|
||||||
jest.mock('containers/CTA', () => 'CTA');
|
|
||||||
jest.mock('containers/ListView', () => 'ListView');
|
jest.mock('containers/ListView', () => 'ListView');
|
||||||
|
jest.mock('components/Head', () => 'Head');
|
||||||
|
|
||||||
const logo = 'fakeLogo.png';
|
|
||||||
let el;
|
let el;
|
||||||
let router;
|
|
||||||
|
|
||||||
describe('App router component', () => {
|
describe('App router component', () => {
|
||||||
const props = {
|
const props = {
|
||||||
@@ -40,34 +33,28 @@ describe('App router component', () => {
|
|||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
};
|
};
|
||||||
test('snapshot: enabled', () => {
|
test('snapshot: enabled', () => {
|
||||||
expect(shallow(<App {...props} />)).toMatchSnapshot();
|
expect(shallow(<App {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('snapshot: disabled (show demo warning)', () => {
|
test('snapshot: disabled (show demo warning)', () => {
|
||||||
expect(shallow(<App {...props} isEnabled={false} />)).toMatchSnapshot();
|
expect(shallow(<App {...props} isEnabled={false} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
describe('component', () => {
|
describe('component', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
|
|
||||||
el = shallow(<App {...props} />);
|
el = shallow(<App {...props} />);
|
||||||
router = el.childAt(0);
|
|
||||||
});
|
});
|
||||||
describe('Router', () => {
|
describe('Router', () => {
|
||||||
test('Routing - ListView is only route', () => {
|
test('Routing - ListView is only route', () => {
|
||||||
expect(router.find('main')).toEqual(shallow(
|
expect(el.instance.findByTestId('main')[0].children).toHaveLength(1);
|
||||||
<main><ListView /></main>,
|
expect(el.instance.findByTestId('main')[0].children[0].type).toBe('ListView');
|
||||||
));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
test('Footer logo drawn from env variable', () => {
|
|
||||||
expect(router.find(Footer).props().logo).toEqual(logo);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Header to use courseMetadata props', () => {
|
test('Header to use courseMetadata props', () => {
|
||||||
const {
|
const {
|
||||||
courseTitle,
|
courseTitle,
|
||||||
courseNumber,
|
courseNumber,
|
||||||
courseOrg,
|
courseOrg,
|
||||||
} = router.find(Header).props();
|
} = el.instance.findByTestId('header')[0].props;
|
||||||
expect(courseTitle).toEqual(props.courseMetadata.title);
|
expect(courseTitle).toEqual(props.courseMetadata.title);
|
||||||
expect(courseNumber).toEqual(props.courseMetadata.number);
|
expect(courseNumber).toEqual(props.courseMetadata.number);
|
||||||
expect(courseOrg).toEqual(props.courseMetadata.org);
|
expect(courseOrg).toEqual(props.courseMetadata.org);
|
||||||
|
|||||||
@@ -3,19 +3,21 @@
|
|||||||
exports[`App router component snapshot: disabled (show demo warning) 1`] = `
|
exports[`App router component snapshot: disabled (show demo warning) 1`] = `
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<div>
|
<div>
|
||||||
|
<Head />
|
||||||
<Header
|
<Header
|
||||||
courseNumber="course-number"
|
courseNumber="course-number"
|
||||||
courseOrg="course-org"
|
courseOrg="course-org"
|
||||||
courseTitle="course-title"
|
courseTitle="course-title"
|
||||||
|
data-testid="header"
|
||||||
/>
|
/>
|
||||||
<DemoWarning />
|
<DemoWarning />
|
||||||
<CTA />
|
<NotificationsBanner />
|
||||||
<main>
|
<main
|
||||||
|
data-testid="main"
|
||||||
|
>
|
||||||
<ListView />
|
<ListView />
|
||||||
</main>
|
</main>
|
||||||
<Footer
|
<FooterSlot />
|
||||||
logo="https://edx-cdn.org/v3/stage/open-edx-tag.svg"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
`;
|
`;
|
||||||
@@ -23,18 +25,20 @@ exports[`App router component snapshot: disabled (show demo warning) 1`] = `
|
|||||||
exports[`App router component snapshot: enabled 1`] = `
|
exports[`App router component snapshot: enabled 1`] = `
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<div>
|
<div>
|
||||||
|
<Head />
|
||||||
<Header
|
<Header
|
||||||
courseNumber="course-number"
|
courseNumber="course-number"
|
||||||
courseOrg="course-org"
|
courseOrg="course-org"
|
||||||
courseTitle="course-title"
|
courseTitle="course-title"
|
||||||
|
data-testid="header"
|
||||||
/>
|
/>
|
||||||
<CTA />
|
<NotificationsBanner />
|
||||||
<main>
|
<main
|
||||||
|
data-testid="main"
|
||||||
|
>
|
||||||
<ListView />
|
<ListView />
|
||||||
</main>
|
</main>
|
||||||
<Footer
|
<FooterSlot />
|
||||||
logo="https://edx-cdn.org/v3/stage/open-edx-tag.svg"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,26 +1,18 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`app registry subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element 1`] = `
|
exports[`app registry subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element 1`] = `
|
||||||
<ErrorPage
|
<React Strict Mode>
|
||||||
message="test-error-message"
|
<ErrorPage
|
||||||
/>
|
message="test-error-message"
|
||||||
|
/>
|
||||||
|
</React Strict Mode>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
||||||
<IntlProvider
|
<React Strict Mode>
|
||||||
defaultFormats={Object {}}
|
|
||||||
defaultLocale="en"
|
|
||||||
fallbackOnEmptyString={true}
|
|
||||||
formats={Object {}}
|
|
||||||
locale="en"
|
|
||||||
messages={Object {}}
|
|
||||||
onError={[Function]}
|
|
||||||
onWarn={[Function]}
|
|
||||||
textComponent={Symbol(react.fragment)}
|
|
||||||
>
|
|
||||||
<AppProvider
|
<AppProvider
|
||||||
store={
|
store={
|
||||||
Object {
|
{
|
||||||
"dispatch": [Function],
|
"dispatch": [Function],
|
||||||
"getState": [Function],
|
"getState": [Function],
|
||||||
"replaceReducer": [Function],
|
"replaceReducer": [Function],
|
||||||
@@ -28,8 +20,9 @@ exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
|||||||
Symbol(Symbol.observable): [Function],
|
Symbol(Symbol.observable): [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wrapWithRouter={false}
|
||||||
>
|
>
|
||||||
<App />
|
<App />
|
||||||
</AppProvider>
|
</AppProvider>
|
||||||
</IntlProvider>
|
</React Strict Mode>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { AlertModal, ActionRow, Button } from '@edx/paragon';
|
import { AlertModal, ActionRow, Button } from '@openedx/paragon';
|
||||||
import { nullMethod } from 'hooks';
|
import { nullMethod } from 'hooks';
|
||||||
|
|
||||||
export const ConfirmModal = ({
|
export const ConfirmModal = ({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { ConfirmModal } from './ConfirmModal';
|
import { ConfirmModal } from './ConfirmModal';
|
||||||
|
|
||||||
@@ -13,9 +13,9 @@ describe('ConfirmModal', () => {
|
|||||||
onConfirm: jest.fn().mockName('this.props.onConfirm'),
|
onConfirm: jest.fn().mockName('this.props.onConfirm'),
|
||||||
};
|
};
|
||||||
test('snapshot: closed', () => {
|
test('snapshot: closed', () => {
|
||||||
expect(shallow(<ConfirmModal {...props} />)).toMatchSnapshot();
|
expect(shallow(<ConfirmModal {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('snapshot: open', () => {
|
test('snapshot: open', () => {
|
||||||
expect(shallow(<ConfirmModal {...props} isOpen />)).toMatchSnapshot();
|
expect(shallow(<ConfirmModal {...props} isOpen />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
ActionRow,
|
ActionRow,
|
||||||
AlertModal,
|
AlertModal,
|
||||||
Button,
|
Button,
|
||||||
} from '@edx/paragon';
|
} from '@openedx/paragon';
|
||||||
|
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { formatMessage } from 'testUtils';
|
import { formatMessage } from 'testUtils';
|
||||||
import { DemoAlert } from '.';
|
import { DemoAlert } from '.';
|
||||||
@@ -11,6 +11,6 @@ describe('DemoAlert component', () => {
|
|||||||
isOpen: true,
|
isOpen: true,
|
||||||
onClose: jest.fn().mockName('props.onClose'),
|
onClose: jest.fn().mockName('props.onClose'),
|
||||||
};
|
};
|
||||||
expect(shallow(<DemoAlert {...props} />)).toMatchSnapshot();
|
expect(shallow(<DemoAlert {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import filesize from 'filesize';
|
import filesize from 'filesize';
|
||||||
import FilePopoverContent from '.';
|
import FilePopoverContent from '.';
|
||||||
@@ -19,20 +19,19 @@ describe('FilePopoverContent', () => {
|
|||||||
el = shallow(<FilePopoverContent {...props} />);
|
el = shallow(<FilePopoverContent {...props} />);
|
||||||
});
|
});
|
||||||
describe('snapshot', () => {
|
describe('snapshot', () => {
|
||||||
test('default', () => expect(el).toMatchSnapshot());
|
test('default', () => expect(el.snapshot).toMatchSnapshot());
|
||||||
test('invalid size', () => {
|
test('invalid size', () => {
|
||||||
el.setProps({
|
el = shallow(<FilePopoverContent {...props} size={null} />);
|
||||||
size: null,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
|
||||||
expect(el).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('behavior', () => {
|
describe('behavior', () => {
|
||||||
test('content', () => {
|
test('content', () => {
|
||||||
expect(el.text()).toContain(props.name);
|
const childElements = el.instance.children;
|
||||||
expect(el.text()).toContain(props.description);
|
expect(childElements[0].children[2].el).toContain(props.name);
|
||||||
expect(el.text()).toContain(filesize(props.size));
|
expect(childElements[1].children[2].el).toContain(props.description);
|
||||||
|
expect(childElements[2].children[2].el).toContain(filesize(props.size));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { Alert, Button } from '@edx/paragon';
|
import { Alert, Button } from '@openedx/paragon';
|
||||||
import { Info } from '@edx/paragon/icons';
|
import { Info } from '@openedx/paragon/icons';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
const messageShape = PropTypes.shape({
|
const messageShape = PropTypes.shape({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import ErrorBanner from './ErrorBanner';
|
import ErrorBanner from './ErrorBanner';
|
||||||
|
|
||||||
@@ -31,16 +31,20 @@ describe('Error Banner component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('component', () => {
|
describe('component', () => {
|
||||||
test('children node', () => {
|
test('children node', () => {
|
||||||
expect(el.containsMatchingElement(children)).toEqual(true);
|
const childElement = el.instance.children[1];
|
||||||
|
const child = shallow(children);
|
||||||
|
|
||||||
|
expect(childElement.type).toEqual(child.type);
|
||||||
|
expect(childElement.children[0].el).toEqual(child.children[0].el);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verify actions', () => {
|
test('verify actions', () => {
|
||||||
const actions = el.find('Alert').prop('actions');
|
const { actions } = el.instance.findByType('Alert')[0].props;
|
||||||
expect(actions).toHaveLength(props.actions.length);
|
expect(actions).toHaveLength(props.actions.length);
|
||||||
|
|
||||||
actions.forEach((action, index) => {
|
actions.forEach((action, index) => {
|
||||||
@@ -52,8 +56,8 @@ describe('Error Banner component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('verify heading', () => {
|
test('verify heading', () => {
|
||||||
const heading = el.find('FormattedMessage');
|
const heading = el.instance.findByType('FormattedMessage')[0];
|
||||||
expect(heading.props()).toEqual(props.headingMessage);
|
expect(heading.props).toEqual(props.headingMessage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Alert, Spinner } from '@edx/paragon';
|
import { Alert, Spinner } from '@openedx/paragon';
|
||||||
|
|
||||||
export const LoadingBanner = () => (
|
export const LoadingBanner = () => (
|
||||||
<Alert variant="info">
|
<Alert variant="info">
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import LoadingBanner from './LoadingBanner';
|
import LoadingBanner from './LoadingBanner';
|
||||||
|
|
||||||
describe('Loading Banner component', () => {
|
describe('Loading Banner component', () => {
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
const el = shallow(<LoadingBanner />);
|
const el = shallow(<LoadingBanner />);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
exports[`Error Banner component snapshot 1`] = `
|
exports[`Error Banner component snapshot 1`] = `
|
||||||
<Alert
|
<Alert
|
||||||
actions={
|
actions={
|
||||||
Array [
|
[
|
||||||
<Button
|
<Button
|
||||||
onClick={[MockFunction action1.onClick]}
|
onClick={[MockFunction action1.onClick]}
|
||||||
variant="outline-primary"
|
variant="outline-primary"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import ImageRenderer from './ImageRenderer';
|
import ImageRenderer from './ImageRenderer';
|
||||||
|
|
||||||
@@ -16,6 +16,6 @@ describe('Image Renderer Component', () => {
|
|||||||
el = shallow(<ImageRenderer {...props} />);
|
el = shallow(<ImageRenderer {...props} />);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { Document, Page, pdfjs } from 'react-pdf';
|
||||||
import { pdfjs, Document, Page } from 'react-pdf';
|
|
||||||
import {
|
import {
|
||||||
Icon, Form, ActionRow, IconButton,
|
Icon, Form, ActionRow, IconButton,
|
||||||
} from '@edx/paragon';
|
} from '@openedx/paragon';
|
||||||
import { ChevronLeft, ChevronRight } from '@edx/paragon/icons';
|
import { ChevronLeft, ChevronRight } from '@openedx/paragon/icons';
|
||||||
import pdfjsWorker from 'react-pdf/dist/esm/pdf.worker.entry';
|
|
||||||
|
|
||||||
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||||
import { rendererHooks } from './pdfHooks';
|
import { rendererHooks } from './pdfHooks';
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <PDFRenderer />
|
* <PDFRenderer />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import PDFRenderer from './PDFRenderer';
|
import PDFRenderer from './PDFRenderer';
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ describe('PDF Renderer Component', () => {
|
|||||||
describe('snapshots', () => {
|
describe('snapshots', () => {
|
||||||
test('first page, prev is disabled', () => {
|
test('first page, prev is disabled', () => {
|
||||||
hooks.rendererHooks.mockReturnValue(hookProps);
|
hooks.rendererHooks.mockReturnValue(hookProps);
|
||||||
expect(shallow(<PDFRenderer {...props} />)).toMatchSnapshot();
|
expect(shallow(<PDFRenderer {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('on last page, next is disabled', () => {
|
test('on last page, next is disabled', () => {
|
||||||
hooks.rendererHooks.mockReturnValue({
|
hooks.rendererHooks.mockReturnValue({
|
||||||
@@ -51,7 +51,7 @@ describe('PDF Renderer Component', () => {
|
|||||||
hasNext: false,
|
hasNext: false,
|
||||||
hasPrev: true,
|
hasPrev: true,
|
||||||
});
|
});
|
||||||
expect(shallow(<PDFRenderer {...props} />)).toMatchSnapshot();
|
expect(shallow(<PDFRenderer {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import TXTRenderer from './TXTRenderer';
|
import TXTRenderer from './TXTRenderer';
|
||||||
|
|
||||||
@@ -18,6 +18,6 @@ describe('TXT Renderer Component', () => {
|
|||||||
onSuccess: jest.fn().mockName('this.props.onSuccess'),
|
onSuccess: jest.fn().mockName('this.props.onSuccess'),
|
||||||
};
|
};
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(shallow(<TXTRenderer {...props} />)).toMatchSnapshot();
|
expect(shallow(<TXTRenderer {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ exports[`PDF Renderer Component snapshots first page, prev is disabled 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="page-wrapper"
|
className="page-wrapper"
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"height": 200,
|
"height": 200,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ exports[`PDF Renderer Component snapshots on last page, next is disabled 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="page-wrapper"
|
className="page-wrapper"
|
||||||
style={
|
style={
|
||||||
Object {
|
{
|
||||||
"height": 200,
|
"height": 200,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
|
|
||||||
import { pdfjs } from 'react-pdf';
|
|
||||||
import pdfjsWorker from 'react-pdf/dist/esm/pdf.worker.entry';
|
|
||||||
|
|
||||||
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||||
|
|
||||||
import { ErrorStatuses } from 'data/constants/requests';
|
import { ErrorStatuses } from 'data/constants/requests';
|
||||||
import { StrictDict } from 'utils';
|
import { StrictDict } from 'utils';
|
||||||
import * as module from './pdfHooks';
|
import * as module from './pdfHooks';
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
||||||
|
|
||||||
export const errors = StrictDict({
|
export const errors = StrictDict({
|
||||||
missingPDF: 'MissingPDFException',
|
missingPDF: 'MissingPDFException',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,13 +81,12 @@ describe('Text file preview hooks', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('onError', () => {
|
describe('onError', () => {
|
||||||
it('calls get on the passed url when it changes', async (done) => {
|
it('calls get on the passed url when it changes', async () => {
|
||||||
axios.get.mockReturnValueOnce(Promise.reject(
|
axios.get.mockReturnValueOnce(Promise.reject(
|
||||||
{ response: { status: testValue } },
|
{ response: { status: testValue } },
|
||||||
));
|
));
|
||||||
await hooks.fetchFile({ ...props, setContent: state.setState.content });
|
await hooks.fetchFile({ ...props, setContent: state.setState.content });
|
||||||
expect(props.onError).toHaveBeenCalledWith(testValue);
|
expect(props.onError).toHaveBeenCalledWith(testValue);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { Card, Collapsible } from '@edx/paragon';
|
import { Card, Collapsible } from '@openedx/paragon';
|
||||||
import FilePopoverContent from 'components/FilePopoverContent';
|
import FilePopoverContent from 'components/FilePopoverContent';
|
||||||
import FileInfo from './FileInfo';
|
import FileInfo from './FileInfo';
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ export const FileCard = ({ file, children }) => (
|
|||||||
defaultOpen
|
defaultOpen
|
||||||
title={<h3 className="file-card-title">{file.name}</h3>}
|
title={<h3 className="file-card-title">{file.name}</h3>}
|
||||||
>
|
>
|
||||||
<div className="preview-panel">
|
<div className="preview-panel" data-testid="preview-panel">
|
||||||
<FileInfo><FilePopoverContent {...file} /></FileInfo>
|
<FileInfo><FilePopoverContent {...file} /></FileInfo>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import "@edx/paragon/scss/core/core";
|
@import "@openedx/paragon/scss/core/core";
|
||||||
|
|
||||||
.file-card {
|
.file-card {
|
||||||
margin: map-get($spacers, 1) 0;
|
margin: map-get($spacers, 1) 0;
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
.file-card-title {
|
.file-card-title {
|
||||||
width: map-get($container-max-widths, "sm")/2;
|
width: calc(map-get($container-max-widths, "sm")/2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { Collapsible } from '@edx/paragon';
|
import { Collapsible } from '@openedx/paragon';
|
||||||
|
|
||||||
import FilePopoverContent from 'components/FilePopoverContent';
|
import FilePopoverContent from 'components/FilePopoverContent';
|
||||||
import FileInfo from './FileInfo';
|
import FileInfo from './FileInfo';
|
||||||
@@ -24,19 +24,19 @@ describe('File Preview Card component', () => {
|
|||||||
el = shallow(<FileCard {...props}>{children}</FileCard>);
|
el = shallow(<FileCard {...props}>{children}</FileCard>);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
describe('Component', () => {
|
describe('Component', () => {
|
||||||
test('collapsible title is name header', () => {
|
test('collapsible title is name header', () => {
|
||||||
const title = el.find(Collapsible).prop('title');
|
const { title } = el.instance.findByType(Collapsible)[0].props;
|
||||||
expect(title).toEqual(<h3 className="file-card-title">{props.file.name}</h3>);
|
expect(title).toEqual(<h3 className="file-card-title">{props.file.name}</h3>);
|
||||||
});
|
});
|
||||||
test('forwards children into preview-panel', () => {
|
test('forwards children into preview-panel', () => {
|
||||||
const previewPanelChildren = el.find('.preview-panel').children();
|
const previewPanelChildren = el.instance.findByTestId('preview-panel')[0].children;
|
||||||
expect(previewPanelChildren.at(0).equals(
|
expect(previewPanelChildren[0].matches(
|
||||||
<FileInfo><FilePopoverContent file={props.file} /></FileInfo>,
|
<FileInfo><FilePopoverContent file={props.file} /></FileInfo>,
|
||||||
));
|
));
|
||||||
expect(previewPanelChildren.at(1).equals(children)).toEqual(true);
|
expect(previewPanelChildren[1].matches(shallow(children))).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
OverlayTrigger,
|
OverlayTrigger,
|
||||||
Popover,
|
Popover,
|
||||||
} from '@edx/paragon';
|
} from '@openedx/paragon';
|
||||||
import { InfoOutline } from '@edx/paragon/icons';
|
import { InfoOutline } from '@openedx/paragon/icons';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
import { nullMethod } from 'hooks';
|
import { nullMethod } from 'hooks';
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
@@ -26,7 +26,7 @@ export const FileInfo = ({ onClick, children }) => (
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="sm"
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
iconAfter={InfoOutline}
|
iconAfter={InfoOutline}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { Popover } from '@edx/paragon';
|
import { Popover } from '@openedx/paragon';
|
||||||
|
|
||||||
import FileInfo from './FileInfo';
|
import FileInfo from './FileInfo';
|
||||||
|
|
||||||
@@ -13,11 +13,11 @@ describe('File Preview Card component', () => {
|
|||||||
el = shallow(<FileInfo {...props}>{children}</FileInfo>);
|
el = shallow(<FileInfo {...props}>{children}</FileInfo>);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
describe('Component', () => {
|
describe('Component', () => {
|
||||||
test('overlay with passed children', () => {
|
test('overlay with passed children', () => {
|
||||||
const { overlay } = el.at(0).props();
|
const { overlay } = el.instance.props;
|
||||||
expect(overlay.type).toEqual(Popover);
|
expect(overlay.type).toEqual(Popover);
|
||||||
expect(overlay.props.children).toEqual(<Popover.Content>{children}</Popover.Content>);
|
expect(overlay.props.children).toEqual(<Popover.Content>{children}</Popover.Content>);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { formatMessage } from 'testUtils';
|
import { formatMessage } from 'testUtils';
|
||||||
import { keyStore } from 'utils';
|
import { keyStore } from 'utils';
|
||||||
@@ -35,7 +35,7 @@ describe('FileRenderer', () => {
|
|||||||
rendererProps: { prop: 'hooks.rendererProps' },
|
rendererProps: { prop: 'hooks.rendererProps' },
|
||||||
};
|
};
|
||||||
jest.spyOn(hooks, hookKeys.renderHooks).mockReturnValueOnce(hookProps);
|
jest.spyOn(hooks, hookKeys.renderHooks).mockReturnValueOnce(hookProps);
|
||||||
expect(shallow(<FileRenderer {...props} />)).toMatchSnapshot();
|
expect(shallow(<FileRenderer {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('is not loading, with error', () => {
|
test('is not loading, with error', () => {
|
||||||
const hookProps = {
|
const hookProps = {
|
||||||
@@ -46,7 +46,7 @@ describe('FileRenderer', () => {
|
|||||||
rendererProps: { prop: 'hooks.rendererProps' },
|
rendererProps: { prop: 'hooks.rendererProps' },
|
||||||
};
|
};
|
||||||
jest.spyOn(hooks, hookKeys.renderHooks).mockReturnValueOnce(hookProps);
|
jest.spyOn(hooks, hookKeys.renderHooks).mockReturnValueOnce(hookProps);
|
||||||
expect(shallow(<FileRenderer {...props} />)).toMatchSnapshot();
|
expect(shallow(<FileRenderer {...props} />).snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ exports[`File Preview Card component snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="preview-panel"
|
className="preview-panel"
|
||||||
|
data-testid="preview-panel"
|
||||||
>
|
>
|
||||||
<FileInfo>
|
<FileInfo>
|
||||||
<FilePopoverContent
|
<FilePopoverContent
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ exports[`File Preview Card component snapshot 1`] = `
|
|||||||
<Button
|
<Button
|
||||||
iconAfter={[MockFunction icons.InfoOutline]}
|
iconAfter={[MockFunction icons.InfoOutline]}
|
||||||
onClick={[MockFunction this.props.onClick]}
|
onClick={[MockFunction this.props.onClick]}
|
||||||
size="small"
|
size="sm"
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
exports[`FileRenderer component snapshot is not loading, with error 1`] = `
|
exports[`FileRenderer component snapshot is not loading, with error 1`] = `
|
||||||
<FileCard
|
<FileCard
|
||||||
file={
|
file={
|
||||||
Object {
|
{
|
||||||
"downloadUrl": "file download url",
|
"downloadUrl": "file download url",
|
||||||
"name": "filename.txt",
|
"name": "filename.txt",
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ exports[`FileRenderer component snapshot is not loading, with error 1`] = `
|
|||||||
exports[`FileRenderer component snapshot isLoading, no Error 1`] = `
|
exports[`FileRenderer component snapshot isLoading, no Error 1`] = `
|
||||||
<FileCard
|
<FileCard
|
||||||
file={
|
file={
|
||||||
Object {
|
{
|
||||||
"downloadUrl": "file download url",
|
"downloadUrl": "file download url",
|
||||||
"name": "filename.txt",
|
"name": "filename.txt",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export const renderHooks = ({
|
|||||||
message: messages.retryButton,
|
message: messages.retryButton,
|
||||||
};
|
};
|
||||||
const error = {
|
const error = {
|
||||||
headerMessage: errorMessage,
|
headingMessage: errorMessage,
|
||||||
children: intl.formatMessage(errorMessage),
|
children: intl.formatMessage(errorMessage),
|
||||||
actions: [errorAction],
|
actions: [errorAction],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ describe('FilePreview hooks', () => {
|
|||||||
});
|
});
|
||||||
describe('error', () => {
|
describe('error', () => {
|
||||||
it('loads message from current error status, if valid, else from serverError', () => {
|
it('loads message from current error status, if valid, else from serverError', () => {
|
||||||
expect(hook.error.headerMessage).toEqual(
|
expect(hook.error.headingMessage).toEqual(
|
||||||
hooks.ERROR_STATUSES[ErrorStatuses.serverError],
|
hooks.ERROR_STATUSES[ErrorStatuses.serverError],
|
||||||
);
|
);
|
||||||
expect(hook.error.children).toEqual(
|
expect(hook.error.children).toEqual(
|
||||||
@@ -63,7 +63,7 @@ describe('FilePreview hooks', () => {
|
|||||||
);
|
);
|
||||||
state.mockVal(state.keys.errorStatus, ErrorStatuses.notFound);
|
state.mockVal(state.keys.errorStatus, ErrorStatuses.notFound);
|
||||||
hook = hooks.renderHooks({ intl: { formatMessage }, file });
|
hook = hooks.renderHooks({ intl: { formatMessage }, file });
|
||||||
expect(hook.error.headerMessage).toEqual(
|
expect(hook.error.headingMessage).toEqual(
|
||||||
hooks.ERROR_STATUSES[ErrorStatuses.notFound],
|
hooks.ERROR_STATUSES[ErrorStatuses.notFound],
|
||||||
);
|
);
|
||||||
expect(hook.error.children).toEqual(
|
expect(hook.error.children).toEqual(
|
||||||
|
|||||||
14
src/components/Head/__snapshots__/index.test.jsx.snap
Normal file
14
src/components/Head/__snapshots__/index.test.jsx.snap
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Head snapshot 1`] = `
|
||||||
|
<Helmet>
|
||||||
|
<title>
|
||||||
|
ORA staff grading | site-name
|
||||||
|
</title>
|
||||||
|
<link
|
||||||
|
href="favicon-url"
|
||||||
|
rel="shortcut icon"
|
||||||
|
type="image/x-icon"
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
|
`;
|
||||||
20
src/components/Head/index.jsx
Normal file
20
src/components/Head/index.jsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||||
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
|
|
||||||
|
import messages from './messages';
|
||||||
|
|
||||||
|
const Head = () => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
return (
|
||||||
|
<Helmet>
|
||||||
|
<title>
|
||||||
|
{formatMessage(messages.PageTitle, { siteName: getConfig().SITE_NAME })}
|
||||||
|
</title>
|
||||||
|
<link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
|
||||||
|
</Helmet>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Head;
|
||||||
25
src/components/Head/index.test.jsx
Normal file
25
src/components/Head/index.test.jsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
import Head from '.';
|
||||||
|
|
||||||
|
jest.mock('react-helmet', () => ({
|
||||||
|
Helmet: 'Helmet',
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('@edx/frontend-platform', () => ({
|
||||||
|
getConfig: () => ({
|
||||||
|
SITE_NAME: 'site-name',
|
||||||
|
FAVICON_URL: 'favicon-url',
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('Head', () => {
|
||||||
|
it('snapshot', () => {
|
||||||
|
const el = shallow(<Head />);
|
||||||
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
|
|
||||||
|
expect(el.instance.findByType('title')[0].el.children[0]).toContain(getConfig().SITE_NAME);
|
||||||
|
expect(el.instance.findByType('link')[0].props.href).toEqual(getConfig().FAVICON_URL);
|
||||||
|
});
|
||||||
|
});
|
||||||
11
src/components/Head/messages.js
Normal file
11
src/components/Head/messages.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
PageTitle: {
|
||||||
|
id: 'PageTitle',
|
||||||
|
defaultMessage: 'ORA staff grading | {siteName}',
|
||||||
|
description: 'Title tag',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default messages;
|
||||||
@@ -21,6 +21,7 @@ exports[`Info Popover Component snapshot 1`] = `
|
|||||||
<IconButton
|
<IconButton
|
||||||
alt="Display more info"
|
alt="Display more info"
|
||||||
className="esg-help-icon"
|
className="esg-help-icon"
|
||||||
|
data-testid="esg-help-icon"
|
||||||
iconAs="Icon"
|
iconAs="Icon"
|
||||||
onClick={[MockFunction this.props.onClick]}
|
onClick={[MockFunction this.props.onClick]}
|
||||||
src={[MockFunction icons.InfoOutline]}
|
src={[MockFunction icons.InfoOutline]}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
Popover,
|
Popover,
|
||||||
Icon,
|
Icon,
|
||||||
IconButton,
|
IconButton,
|
||||||
} from '@edx/paragon';
|
} from '@openedx/paragon';
|
||||||
import { InfoOutline } from '@edx/paragon/icons';
|
import { InfoOutline } from '@openedx/paragon/icons';
|
||||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { nullMethod } from 'hooks';
|
import { nullMethod } from 'hooks';
|
||||||
@@ -30,6 +30,7 @@ export const InfoPopover = ({ onClick, children, intl }) => (
|
|||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
className="esg-help-icon"
|
className="esg-help-icon"
|
||||||
|
data-testid="esg-help-icon"
|
||||||
src={InfoOutline}
|
src={InfoOutline}
|
||||||
alt={intl.formatMessage(messages.altText)}
|
alt={intl.formatMessage(messages.altText)}
|
||||||
iconAs={Icon}
|
iconAs={Icon}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { formatMessage } from 'testUtils';
|
import { formatMessage } from 'testUtils';
|
||||||
import { InfoPopover } from '.';
|
import { InfoPopover } from '.';
|
||||||
@@ -12,12 +12,12 @@ describe('Info Popover Component', () => {
|
|||||||
el = shallow(<InfoPopover onClick={onClick} intl={{ formatMessage }}>{child}</InfoPopover>);
|
el = shallow(<InfoPopover onClick={onClick} intl={{ formatMessage }}>{child}</InfoPopover>);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
describe('Component', () => {
|
describe('Component', () => {
|
||||||
test('Test component render', () => {
|
test('Test component render', () => {
|
||||||
expect(el.length).toEqual(1);
|
expect(el.instance.children.length).toEqual(1);
|
||||||
expect(el.find('.esg-help-icon').length).toEqual(1);
|
expect(el.instance.findByTestId('esg-help-icon').length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { Spinner } from '@edx/paragon';
|
import { Spinner } from '@openedx/paragon';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { Badge } from '@edx/paragon';
|
import { Badge } from '@openedx/paragon';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { StrictDict } from 'utils';
|
import { StrictDict } from 'utils';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { gradingStatuses } from 'data/services/lms/constants';
|
import { gradingStatuses } from 'data/services/lms/constants';
|
||||||
import { StatusBadge } from './StatusBadge';
|
import { StatusBadge } from './StatusBadge';
|
||||||
@@ -10,25 +10,25 @@ describe('StatusBadge component', () => {
|
|||||||
describe('behavior', () => {
|
describe('behavior', () => {
|
||||||
it('does not render if status does not have configured variant', () => {
|
it('does not render if status does not have configured variant', () => {
|
||||||
const el = render('arbitrary');
|
const el = render('arbitrary');
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
expect(el.isEmptyRender()).toEqual(true);
|
expect(el.isEmptyRender()).toEqual(true);
|
||||||
});
|
});
|
||||||
describe('status snapshots: loads badge with configured variant and message.', () => {
|
describe('status snapshots: loads badge with configured variant and message.', () => {
|
||||||
test('`ungraded` shows primary button variant and message', () => {
|
test('`ungraded` shows primary button variant and message', () => {
|
||||||
const el = render(gradingStatuses.ungraded);
|
const el = render(gradingStatuses.ungraded);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('`locked` shows light button variant and message', () => {
|
test('`locked` shows light button variant and message', () => {
|
||||||
const el = render(gradingStatuses.locked);
|
const el = render(gradingStatuses.locked);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('`graded` shows success button variant and message', () => {
|
test('`graded` shows success button variant and message', () => {
|
||||||
const el = render(gradingStatuses.graded);
|
const el = render(gradingStatuses.graded);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('`inProgress` shows warning button variant and message', () => {
|
test('`inProgress` shows warning button variant and message', () => {
|
||||||
const el = render(gradingStatuses.inProgress);
|
const el = render(gradingStatuses.inProgress);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`StatusBadge component behavior does not render if status does not have configured variant 1`] = `""`;
|
exports[`StatusBadge component behavior does not render if status does not have configured variant 1`] = `null`;
|
||||||
|
|
||||||
exports[`StatusBadge component behavior status snapshots: loads badge with configured variant and message. \`graded\` shows success button variant and message 1`] = `
|
exports[`StatusBadge component behavior status snapshots: loads badge with configured variant and message. \`graded\` shows success button variant and message 1`] = `
|
||||||
<Badge
|
<Badge
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
const configuration = {
|
|
||||||
// BASE_URL: process.env.BASE_URL,
|
|
||||||
LMS_BASE_URL: process.env.LMS_BASE_URL,
|
|
||||||
// LOGIN_URL: process.env.LOGIN_URL,
|
|
||||||
// LOGOUT_URL: process.env.LOGOUT_URL,
|
|
||||||
// CSRF_TOKEN_API_PATH: process.env.CSRF_TOKEN_API_PATH,
|
|
||||||
// REFRESH_ACCESS_TOKEN_ENDPOINT: process.env.REFRESH_ACCESS_TOKEN_ENDPOINT,
|
|
||||||
// DATA_API_BASE_URL: process.env.DATA_API_BASE_URL,
|
|
||||||
// SECURE_COOKIES: process.env.NODE_ENV !== 'development',
|
|
||||||
// SEGMENT_KEY: process.env.SEGMENT_KEY,
|
|
||||||
// ACCESS_TOKEN_COOKIE_NAME: process.env.ACCESS_TOKEN_COOKIE_NAME,
|
|
||||||
};
|
|
||||||
|
|
||||||
const features = {};
|
|
||||||
|
|
||||||
export { configuration, features };
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { shallow } from 'enzyme';
|
|
||||||
|
|
||||||
import { CTA } from '.';
|
|
||||||
|
|
||||||
describe('CTA component', () => {
|
|
||||||
test('snapshots', () => {
|
|
||||||
const el = shallow(<CTA hide />);
|
|
||||||
expect(el).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`CTA component snapshots 1`] = `
|
|
||||||
<PageBanner>
|
|
||||||
<span>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Thanks for using the new ORA staff grading experience. "
|
|
||||||
description="Thank user for using ora and ask for feed back"
|
|
||||||
id="ora-grading.CTA.feedbackMessage"
|
|
||||||
/>
|
|
||||||
<Hyperlink
|
|
||||||
destination="https://docs.google.com/forms/d/1Hu1rgJcCHl5_EtDb5Up3hiZ40sSUtkZQfRHJ3fWOvfQ/edit"
|
|
||||||
isInline={true}
|
|
||||||
showLaunchIcon={false}
|
|
||||||
target="_blank"
|
|
||||||
variant="muted"
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Provide some feedback"
|
|
||||||
description="placeholder for the feedback anchor link"
|
|
||||||
id="ora-grading.CTA.linkMessage"
|
|
||||||
/>
|
|
||||||
</Hyperlink>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage=" and let us know what you think!"
|
|
||||||
description="inform user to provide feedback"
|
|
||||||
id="ora-grading.CTA.letUsKnowMessage"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</PageBanner>
|
|
||||||
`;
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
|
||||||
import { PageBanner, Hyperlink } from '@edx/paragon';
|
|
||||||
|
|
||||||
import messages from './messages';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <CTA />
|
|
||||||
*/
|
|
||||||
export const CTA = () => (
|
|
||||||
<PageBanner>
|
|
||||||
<span>
|
|
||||||
<FormattedMessage {...messages.ctaFeedbackMessage} />
|
|
||||||
<Hyperlink
|
|
||||||
isInline
|
|
||||||
variant="muted"
|
|
||||||
destination="https://docs.google.com/forms/d/1Hu1rgJcCHl5_EtDb5Up3hiZ40sSUtkZQfRHJ3fWOvfQ/edit"
|
|
||||||
target="_blank"
|
|
||||||
showLaunchIcon={false}
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.ctaLinkMessage} />
|
|
||||||
</Hyperlink>
|
|
||||||
<FormattedMessage {...messages.ctaLetUsKnowMessage} />
|
|
||||||
</span>
|
|
||||||
</PageBanner>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default CTA;
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable quotes */
|
|
||||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
|
||||||
import { StrictDict } from 'utils';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
ctaFeedbackMessage: {
|
|
||||||
id: 'ora-grading.CTA.feedbackMessage',
|
|
||||||
defaultMessage: 'Thanks for using the new ORA staff grading experience. ',
|
|
||||||
description: 'Thank user for using ora and ask for feed back',
|
|
||||||
},
|
|
||||||
ctaLinkMessage: {
|
|
||||||
id: 'ora-grading.CTA.linkMessage',
|
|
||||||
defaultMessage: 'Provide some feedback',
|
|
||||||
description: 'placeholder for the feedback anchor link',
|
|
||||||
},
|
|
||||||
ctaLetUsKnowMessage: {
|
|
||||||
id: 'ora-grading.CTA.letUsKnowMessage',
|
|
||||||
defaultMessage: ' and let us know what you think!',
|
|
||||||
description: 'inform user to provide feedback',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default StrictDict(messages);
|
|
||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Form } from '@edx/paragon';
|
import { Form } from '@openedx/paragon';
|
||||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { feedbackRequirement } from 'data/services/lms/constants';
|
import { feedbackRequirement } from 'data/services/lms/constants';
|
||||||
@@ -51,13 +51,14 @@ export class CriterionFeedback extends React.Component {
|
|||||||
<Form.Control
|
<Form.Control
|
||||||
as="textarea"
|
as="textarea"
|
||||||
className="criterion-feedback feedback-input"
|
className="criterion-feedback feedback-input"
|
||||||
|
data-testid="criterion-feedback-input"
|
||||||
floatingLabel={this.commentMessage}
|
floatingLabel={this.commentMessage}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
disabled={!isGrading}
|
disabled={!isGrading}
|
||||||
/>
|
/>
|
||||||
{isInvalid && (
|
{isInvalid && (
|
||||||
<Form.Control.Feedback type="invalid" className="feedback-error-msg">
|
<Form.Control.Feedback type="invalid" className="feedback-error-msg" data-testid="criterion-feedback-error-msg">
|
||||||
{this.translate(messages.criterionFeedbackError)}
|
{this.translate(messages.criterionFeedbackError)}
|
||||||
</Form.Control.Feedback>
|
</Form.Control.Feedback>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { actions, selectors } from 'data/redux';
|
import { actions, selectors } from 'data/redux';
|
||||||
import {
|
import {
|
||||||
@@ -48,34 +48,27 @@ describe('Criterion Feedback', () => {
|
|||||||
let el;
|
let el;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
el = shallow(<CriterionFeedback {...props} />);
|
el = shallow(<CriterionFeedback {...props} />);
|
||||||
el.instance().onChange = jest.fn().mockName('this.onChange');
|
el.instance.onChange = jest.fn().mockName('this.onChange');
|
||||||
});
|
});
|
||||||
describe('snapshot', () => {
|
describe('snapshot', () => {
|
||||||
test('is grading', () => {
|
test('is grading', () => {
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is graded', () => {
|
test('is graded', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionFeedback {...props} isGrading={false} gradeStatus={gradeStatuses.graded} />);
|
||||||
isGrading: false,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
gradeStatus: gradeStatuses.graded,
|
|
||||||
});
|
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('feedback value is invalid', () => {
|
test('feedback value is invalid', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionFeedback {...props} isInvalid />);
|
||||||
isInvalid: true,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.values(feedbackRequirement).forEach((requirement) => {
|
Object.values(feedbackRequirement).forEach((requirement) => {
|
||||||
test(`feedback is configured to ${requirement}`, () => {
|
test(`feedback is configured to ${requirement}`, () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionFeedback {...props} config={requirement} />);
|
||||||
config: requirement,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -84,33 +77,23 @@ describe('Criterion Feedback', () => {
|
|||||||
describe('render', () => {
|
describe('render', () => {
|
||||||
test('is grading (the feedback input is not disabled)', () => {
|
test('is grading (the feedback input is not disabled)', () => {
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
expect(el.instance().props.value).toEqual(props.value);
|
const controlEl = el.instance.findByTestId('criterion-feedback-input')[0];
|
||||||
const controlEl = el.find('.feedback-input');
|
expect(controlEl.props.disabled).toEqual(false);
|
||||||
expect(controlEl.prop('disabled')).toEqual(false);
|
expect(controlEl.props.value).toEqual(props.value);
|
||||||
expect(controlEl.prop('value')).toEqual(props.value);
|
|
||||||
});
|
});
|
||||||
test('is graded (the input is disabled)', () => {
|
test('is graded (the input is disabled)', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionFeedback {...props} isGrading={false} gradeStatus={gradeStatuses.graded} />);
|
||||||
isGrading: false,
|
const controlEl = el.instance.findByTestId('criterion-feedback-input')[0];
|
||||||
gradeStatus: gradeStatuses.graded,
|
expect(controlEl.props.disabled).toEqual(true);
|
||||||
});
|
expect(controlEl.props.value).toEqual(props.value);
|
||||||
expect(el.instance().props.value).toEqual(props.value);
|
|
||||||
const controlEl = el.find('.feedback-input');
|
|
||||||
expect(controlEl.prop('disabled')).toEqual(true);
|
|
||||||
expect(controlEl.prop('value')).toEqual(props.value);
|
|
||||||
});
|
});
|
||||||
test('is having invalid feedback (feedback get render)', () => {
|
test('is having invalid feedback (feedback get render)', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionFeedback {...props} isInvalid />);
|
||||||
isInvalid: true,
|
const feedbackErrorEl = el.instance.findByTestId('criterion-feedback-error-msg');
|
||||||
});
|
|
||||||
const feedbackErrorEl = el.find('.feedback-error-msg');
|
|
||||||
expect(el.instance().props.isInvalid).toEqual(true);
|
|
||||||
expect(feedbackErrorEl).toBeDefined();
|
expect(feedbackErrorEl).toBeDefined();
|
||||||
});
|
});
|
||||||
test('is configure to disabled (the input does not get render)', () => {
|
test('is configure to disabled (the input does not get render)', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionFeedback {...props} config={feedbackRequirement.disabled} />);
|
||||||
config: feedbackRequirement.disabled,
|
|
||||||
});
|
|
||||||
expect(el.isEmptyRender()).toEqual(true);
|
expect(el.isEmptyRender()).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -118,7 +101,7 @@ describe('Criterion Feedback', () => {
|
|||||||
describe('behavior', () => {
|
describe('behavior', () => {
|
||||||
test('onChange call set value', () => {
|
test('onChange call set value', () => {
|
||||||
el = shallow(<CriterionFeedback {...props} />);
|
el = shallow(<CriterionFeedback {...props} />);
|
||||||
el.instance().onChange({
|
el.instance.findByTestId('criterion-feedback-input')[0].props.onChange({
|
||||||
target: {
|
target: {
|
||||||
value: 'some value',
|
value: 'some value',
|
||||||
},
|
},
|
||||||
@@ -129,33 +112,41 @@ describe('Criterion Feedback', () => {
|
|||||||
|
|
||||||
describe('getter commentMessage', () => {
|
describe('getter commentMessage', () => {
|
||||||
test('is grading', () => {
|
test('is grading', () => {
|
||||||
el.setProps({ config: feedbackRequirement.optional, isGrading: true });
|
let commentMessage;
|
||||||
expect(el.instance().commentMessage).toContain(
|
|
||||||
|
el = shallow(<CriterionFeedback {...props} isGrading config={feedbackRequirement.optional} />);
|
||||||
|
commentMessage = el.instance.findByTestId('criterion-feedback-input')[0].props.floatingLabel;
|
||||||
|
expect(commentMessage).toContain(
|
||||||
messages.optional.defaultMessage,
|
messages.optional.defaultMessage,
|
||||||
);
|
);
|
||||||
|
|
||||||
el.setProps({ config: feedbackRequirement.required });
|
el = shallow(<CriterionFeedback {...props} config={feedbackRequirement.required} />);
|
||||||
expect(el.instance().commentMessage).not.toContain(
|
commentMessage = el.instance.findByTestId('criterion-feedback-input')[0].props.floatingLabel;
|
||||||
|
expect(commentMessage).not.toContain(
|
||||||
messages.optional.defaultMessage,
|
messages.optional.defaultMessage,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(el.instance().commentMessage).toContain(
|
expect(commentMessage).toContain(
|
||||||
messages.addComments.defaultMessage,
|
messages.addComments.defaultMessage,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is not grading', () => {
|
test('is not grading', () => {
|
||||||
el.setProps({ config: feedbackRequirement.optional, isGrading: false });
|
let commentMessage;
|
||||||
expect(el.instance().commentMessage).toContain(
|
|
||||||
|
el = shallow(<CriterionFeedback {...props} isGrading={false} config={feedbackRequirement.optional} />);
|
||||||
|
commentMessage = el.instance.findByTestId('criterion-feedback-input')[0].props.floatingLabel;
|
||||||
|
expect(commentMessage).toContain(
|
||||||
messages.optional.defaultMessage,
|
messages.optional.defaultMessage,
|
||||||
);
|
);
|
||||||
|
|
||||||
el.setProps({ config: feedbackRequirement.required });
|
el = shallow(<CriterionFeedback {...props} isGrading={false} config={feedbackRequirement.required} />);
|
||||||
expect(el.instance().commentMessage).not.toContain(
|
commentMessage = el.instance.findByTestId('criterion-feedback-input')[0].props.floatingLabel;
|
||||||
|
expect(commentMessage).not.toContain(
|
||||||
messages.optional.defaultMessage,
|
messages.optional.defaultMessage,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(el.instance().commentMessage).toContain(
|
expect(commentMessage).toContain(
|
||||||
messages.comments.defaultMessage,
|
messages.comments.defaultMessage,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -163,7 +154,7 @@ describe('Criterion Feedback', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('mapStateToProps', () => {
|
describe('mapStateToProps', () => {
|
||||||
const testState = { abitaryState: 'some data' };
|
const testState = { arbitraryState: 'some data' };
|
||||||
const ownProps = { orderNum: props.orderNum };
|
const ownProps = { orderNum: props.orderNum };
|
||||||
let mapped;
|
let mapped;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Form } from '@edx/paragon';
|
import { Form } from '@openedx/paragon';
|
||||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { actions, selectors } from 'data/redux';
|
import { actions, selectors } from 'data/redux';
|
||||||
@@ -33,27 +33,26 @@ export class RadioCriterion extends React.Component {
|
|||||||
isInvalid,
|
isInvalid,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<>
|
<Form.RadioSet name={config.name} value={data}>
|
||||||
<Form.RadioSet name={config.name} value={data}>
|
{config.options.map((option) => (
|
||||||
{config.options.map((option) => (
|
<Form.Radio
|
||||||
<Form.Radio
|
className="criteria-option align-items-center"
|
||||||
className="criteria-option"
|
key={option.name}
|
||||||
key={option.name}
|
value={option.name}
|
||||||
value={option.name}
|
description={intl.formatMessage(messages.optionPoints, { points: option.points })}
|
||||||
description={intl.formatMessage(messages.optionPoints, { points: option.points })}
|
onChange={this.onChange}
|
||||||
onChange={this.onChange}
|
disabled={!isGrading}
|
||||||
disabled={!isGrading}
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
{option.label}
|
{option.label}
|
||||||
</Form.Radio>
|
</Form.Radio>
|
||||||
))}
|
))}
|
||||||
{isInvalid && (
|
{isInvalid && (
|
||||||
<Form.Control.Feedback type="invalid" className="feedback-error-msg">
|
<Form.Control.Feedback type="invalid" className="feedback-error-msg">
|
||||||
{intl.formatMessage(messages.rubricSelectedError)}
|
{intl.formatMessage(messages.rubricSelectedError)}
|
||||||
</Form.Control.Feedback>
|
</Form.Control.Feedback>
|
||||||
)}
|
)}
|
||||||
</Form.RadioSet>
|
</Form.RadioSet>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { actions, selectors } from 'data/redux';
|
import { actions, selectors } from 'data/redux';
|
||||||
import { formatMessage } from 'testUtils';
|
import { formatMessage } from 'testUtils';
|
||||||
@@ -40,14 +40,14 @@ describe('Radio Criterion Container', () => {
|
|||||||
feedback: 'feedback mock',
|
feedback: 'feedback mock',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
explanation: 'explaination',
|
explanation: 'explanation',
|
||||||
feedback: 'option feedback',
|
feedback: 'option feedback',
|
||||||
label: 'this label',
|
label: 'this label',
|
||||||
name: 'option name',
|
name: 'option name',
|
||||||
points: 1,
|
points: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
explanation: 'explaination 2',
|
explanation: 'explanation 2',
|
||||||
feedback: 'option feedback 2',
|
feedback: 'option feedback 2',
|
||||||
label: 'this label 2',
|
label: 'this label 2',
|
||||||
name: 'option name 2',
|
name: 'option name 2',
|
||||||
@@ -63,25 +63,21 @@ describe('Radio Criterion Container', () => {
|
|||||||
let el;
|
let el;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
el = shallow(<RadioCriterion {...props} />);
|
el = shallow(<RadioCriterion {...props} />);
|
||||||
el.instance().onChange = jest.fn().mockName('this.onChange');
|
el.instance.onChange = jest.fn().mockName('this.onChange');
|
||||||
});
|
});
|
||||||
describe('snapshot', () => {
|
describe('snapshot', () => {
|
||||||
test('is grading', () => {
|
test('is grading', () => {
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is not grading', () => {
|
test('is not grading', () => {
|
||||||
el.setProps({
|
el = shallow(<RadioCriterion {...props} isGrading={false} />);
|
||||||
isGrading: false,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('radio contain invalid response', () => {
|
test('radio contain invalid response', () => {
|
||||||
el.setProps({
|
el = shallow(<RadioCriterion {...props} isInvalid />);
|
||||||
isInvalid: true,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
|
||||||
expect(el.instance().render()).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -89,36 +85,33 @@ describe('Radio Criterion Container', () => {
|
|||||||
describe('rendering', () => {
|
describe('rendering', () => {
|
||||||
test('is grading (all options are not disabled)', () => {
|
test('is grading (all options are not disabled)', () => {
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
const optionsEl = el.find('.criteria-option');
|
const optionsEl = el.instance.children;
|
||||||
expect(optionsEl.length).toEqual(props.config.options.length);
|
expect(optionsEl.length).toEqual(props.config.options.length);
|
||||||
optionsEl.forEach((optionEl) => expect(optionEl.prop('disabled')).toEqual(false));
|
optionsEl.forEach((optionEl) => expect(optionEl.props.disabled).toEqual(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is not grading (all options are disabled)', () => {
|
test('is not grading (all options are disabled)', () => {
|
||||||
el.setProps({
|
el = shallow(<RadioCriterion {...props} isGrading={false} />);
|
||||||
isGrading: false,
|
|
||||||
});
|
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
const optionsEl = el.find('.criteria-option');
|
const optionsEl = el.instance.children;
|
||||||
expect(optionsEl.length).toEqual(props.config.options.length);
|
expect(optionsEl.length).toEqual(props.config.options.length);
|
||||||
optionsEl.forEach((optionEl) => expect(optionEl.prop('disabled')).toEqual(true));
|
optionsEl.forEach((optionEl) => expect(optionEl.props.disabled).toEqual(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('radio contain invalid response (error response get render)', () => {
|
test('radio contain invalid response (error response get render)', () => {
|
||||||
el.setProps({
|
el = shallow(<RadioCriterion {...props} isInvalid />);
|
||||||
isInvalid: true,
|
|
||||||
});
|
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
const radioErrorEl = el.find('.feedback-error-msg');
|
const radioErrorEl = el.instance.children[2];
|
||||||
expect(el.instance().props.isInvalid).toEqual(true);
|
expect(radioErrorEl.props.type).toBe('invalid');
|
||||||
expect(radioErrorEl).toBeDefined();
|
expect(radioErrorEl.props.className).toBe('feedback-error-msg');
|
||||||
|
expect(radioErrorEl).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('behavior', () => {
|
describe('behavior', () => {
|
||||||
test('onChange call set crition option', () => {
|
test('onChange call set crition option', () => {
|
||||||
el = shallow(<RadioCriterion {...props} />);
|
el = shallow(<RadioCriterion {...props} />);
|
||||||
el.instance().onChange({
|
el.instance.children[0].props.onChange({
|
||||||
target: {
|
target: {
|
||||||
value: 'some value',
|
value: 'some value',
|
||||||
},
|
},
|
||||||
@@ -129,7 +122,7 @@ describe('Radio Criterion Container', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('mapStateToProps', () => {
|
describe('mapStateToProps', () => {
|
||||||
const testState = { arbitary: 'some data' };
|
const testState = { arbitrary: 'some data' };
|
||||||
const ownProps = { orderNum: props.orderNum };
|
const ownProps = { orderNum: props.orderNum };
|
||||||
let mapped;
|
let mapped;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Form, FormControlFeedback } from '@edx/paragon';
|
import { Form, FormControlFeedback } from '@openedx/paragon';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
@@ -14,10 +14,10 @@ import messages from './messages';
|
|||||||
export const ReviewCriterion = ({ config }) => (
|
export const ReviewCriterion = ({ config }) => (
|
||||||
<div className="review-criterion">
|
<div className="review-criterion">
|
||||||
{config.options.map((option) => (
|
{config.options.map((option) => (
|
||||||
<div key={option.name} className="criteria-option">
|
<div key={option.name} className="criteria-option" data-testid="criteria-option">
|
||||||
<div>
|
<div>
|
||||||
<Form.Label className="option-label">{option.label}</Form.Label>
|
<Form.Label className="option-label" data-testid="option-label">{option.label}</Form.Label>
|
||||||
<FormControlFeedback className="option-points">
|
<FormControlFeedback className="option-points" data-testid="option-points">
|
||||||
<FormattedMessage {...messages.optionPoints} values={{ points: option.points }} />
|
<FormattedMessage {...messages.optionPoints} values={{ points: option.points }} />
|
||||||
</FormControlFeedback>
|
</FormControlFeedback>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
import { ReviewCriterion, mapStateToProps } from './ReviewCriterion';
|
import { ReviewCriterion, mapStateToProps } from './ReviewCriterion';
|
||||||
@@ -29,14 +29,14 @@ describe('Review Crition Container', () => {
|
|||||||
feedback: 'feedback mock',
|
feedback: 'feedback mock',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
explanation: 'explaination',
|
explanation: 'explanation',
|
||||||
feedback: 'option feedback',
|
feedback: 'option feedback',
|
||||||
label: 'this label',
|
label: 'this label',
|
||||||
name: 'option name',
|
name: 'option name',
|
||||||
points: 1,
|
points: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
explanation: 'explaination 2',
|
explanation: 'explanation 2',
|
||||||
feedback: 'option feedback 2',
|
feedback: 'option feedback 2',
|
||||||
label: 'this label 2',
|
label: 'this label 2',
|
||||||
name: 'option name 2',
|
name: 'option name 2',
|
||||||
@@ -55,21 +55,21 @@ describe('Review Crition Container', () => {
|
|||||||
el = shallow(<ReviewCriterion {...props} />);
|
el = shallow(<ReviewCriterion {...props} />);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('component', () => {
|
describe('component', () => {
|
||||||
test('rendering (everything show up)', () => {
|
test('rendering (everything show up)', () => {
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
const optionsEl = el.find('.criteria-option');
|
const optionsEl = el.instance.findByTestId('criteria-option');
|
||||||
expect(optionsEl.length).toEqual(props.config.options.length);
|
expect(optionsEl.length).toEqual(props.config.options.length);
|
||||||
optionsEl.forEach((optionEl, i) => {
|
optionsEl.forEach((optionEl, i) => {
|
||||||
const option = props.config.options[i];
|
const option = props.config.options[i];
|
||||||
expect(optionEl.key()).toEqual(option.name);
|
expect(optionEl.props.key).toEqual(option.name);
|
||||||
expect(optionEl.find('.option-label').childAt(0).text()).toEqual(
|
expect(optionEl.findByTestId('option-label')[0].children[0].el).toEqual(
|
||||||
option.label,
|
option.label,
|
||||||
);
|
);
|
||||||
expect(optionEl.find('.option-points').childAt(0).props()).toEqual({
|
expect(optionEl.findByTestId('option-points')[0].children[0].props).toEqual({
|
||||||
...messages.optionPoints,
|
...messages.optionPoints,
|
||||||
values: { points: option.points },
|
values: { points: option.points },
|
||||||
});
|
});
|
||||||
@@ -78,7 +78,7 @@ describe('Review Crition Container', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('mapStateToProps', () => {
|
describe('mapStateToProps', () => {
|
||||||
const testState = { arbitary: 'some data' };
|
const testState = { arbitrary: 'some data' };
|
||||||
const ownProps = { orderNum: props.orderNum };
|
const ownProps = { orderNum: props.orderNum };
|
||||||
let mapped;
|
let mapped;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ exports[`Criterion Feedback snapshot feedback is configured to optional 1`] = `
|
|||||||
<Form.Control
|
<Form.Control
|
||||||
as="textarea"
|
as="textarea"
|
||||||
className="criterion-feedback feedback-input"
|
className="criterion-feedback feedback-input"
|
||||||
|
data-testid="criterion-feedback-input"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
floatingLabel="Add comments (Optional)"
|
floatingLabel="Add comments (Optional)"
|
||||||
onChange={[MockFunction this.onChange]}
|
onChange={[Function]}
|
||||||
value="criterion value"
|
value="criterion value"
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
@@ -20,9 +21,10 @@ exports[`Criterion Feedback snapshot feedback is configured to required 1`] = `
|
|||||||
<Form.Control
|
<Form.Control
|
||||||
as="textarea"
|
as="textarea"
|
||||||
className="criterion-feedback feedback-input"
|
className="criterion-feedback feedback-input"
|
||||||
|
data-testid="criterion-feedback-input"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
floatingLabel="Add comments"
|
floatingLabel="Add comments"
|
||||||
onChange={[MockFunction this.onChange]}
|
onChange={[Function]}
|
||||||
value="criterion value"
|
value="criterion value"
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
@@ -33,13 +35,15 @@ exports[`Criterion Feedback snapshot feedback value is invalid 1`] = `
|
|||||||
<Form.Control
|
<Form.Control
|
||||||
as="textarea"
|
as="textarea"
|
||||||
className="criterion-feedback feedback-input"
|
className="criterion-feedback feedback-input"
|
||||||
|
data-testid="criterion-feedback-input"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
floatingLabel="Add comments"
|
floatingLabel="Add comments"
|
||||||
onChange={[MockFunction this.onChange]}
|
onChange={[Function]}
|
||||||
value="criterion value"
|
value="criterion value"
|
||||||
/>
|
/>
|
||||||
<Form.Control.Feedback
|
<Form.Control.Feedback
|
||||||
className="feedback-error-msg"
|
className="feedback-error-msg"
|
||||||
|
data-testid="criterion-feedback-error-msg"
|
||||||
type="invalid"
|
type="invalid"
|
||||||
>
|
>
|
||||||
The feedback is required
|
The feedback is required
|
||||||
@@ -52,9 +56,10 @@ exports[`Criterion Feedback snapshot is graded 1`] = `
|
|||||||
<Form.Control
|
<Form.Control
|
||||||
as="textarea"
|
as="textarea"
|
||||||
className="criterion-feedback feedback-input"
|
className="criterion-feedback feedback-input"
|
||||||
|
data-testid="criterion-feedback-input"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
floatingLabel="Comments"
|
floatingLabel="Comments"
|
||||||
onChange={[MockFunction this.onChange]}
|
onChange={[Function]}
|
||||||
value="criterion value"
|
value="criterion value"
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
@@ -65,9 +70,10 @@ exports[`Criterion Feedback snapshot is grading 1`] = `
|
|||||||
<Form.Control
|
<Form.Control
|
||||||
as="textarea"
|
as="textarea"
|
||||||
className="criterion-feedback feedback-input"
|
className="criterion-feedback feedback-input"
|
||||||
|
data-testid="criterion-feedback-input"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
floatingLabel="Add comments"
|
floatingLabel="Add comments"
|
||||||
onChange={[MockFunction this.onChange]}
|
onChange={[Function]}
|
||||||
value="criterion value"
|
value="criterion value"
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|||||||
@@ -1,91 +1,121 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Radio Criterion Container snapshot is grading 1`] = `
|
exports[`Radio Criterion Container snapshot is grading 1`] = `
|
||||||
<React.Fragment>
|
<Form.RadioSet
|
||||||
<Form.RadioSet
|
name="random name"
|
||||||
name="random name"
|
value="selected radio option"
|
||||||
value="selected radio option"
|
>
|
||||||
|
<Form.Radio
|
||||||
|
className="criteria-option align-items-center"
|
||||||
|
description="1 points"
|
||||||
|
disabled={false}
|
||||||
|
key="option name"
|
||||||
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value="option name"
|
||||||
>
|
>
|
||||||
<Form.Radio
|
this label
|
||||||
className="criteria-option"
|
</Form.Radio>
|
||||||
description="1 points"
|
<Form.Radio
|
||||||
disabled={false}
|
className="criteria-option align-items-center"
|
||||||
onChange={[MockFunction this.onChange]}
|
description="2 points"
|
||||||
value="option name"
|
disabled={false}
|
||||||
>
|
key="option name 2"
|
||||||
this label
|
onChange={[Function]}
|
||||||
</Form.Radio>
|
style={
|
||||||
<Form.Radio
|
{
|
||||||
className="criteria-option"
|
"flexShrink": 0,
|
||||||
description="2 points"
|
}
|
||||||
disabled={false}
|
}
|
||||||
onChange={[MockFunction this.onChange]}
|
value="option name 2"
|
||||||
value="option name 2"
|
>
|
||||||
>
|
this label 2
|
||||||
this label 2
|
</Form.Radio>
|
||||||
</Form.Radio>
|
</Form.RadioSet>
|
||||||
</Form.RadioSet>
|
|
||||||
</React.Fragment>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Radio Criterion Container snapshot is not grading 1`] = `
|
exports[`Radio Criterion Container snapshot is not grading 1`] = `
|
||||||
<React.Fragment>
|
<Form.RadioSet
|
||||||
<Form.RadioSet
|
name="random name"
|
||||||
name="random name"
|
value="selected radio option"
|
||||||
value="selected radio option"
|
>
|
||||||
|
<Form.Radio
|
||||||
|
className="criteria-option align-items-center"
|
||||||
|
description="1 points"
|
||||||
|
disabled={true}
|
||||||
|
key="option name"
|
||||||
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value="option name"
|
||||||
>
|
>
|
||||||
<Form.Radio
|
this label
|
||||||
className="criteria-option"
|
</Form.Radio>
|
||||||
description="1 points"
|
<Form.Radio
|
||||||
disabled={true}
|
className="criteria-option align-items-center"
|
||||||
onChange={[MockFunction this.onChange]}
|
description="2 points"
|
||||||
value="option name"
|
disabled={true}
|
||||||
>
|
key="option name 2"
|
||||||
this label
|
onChange={[Function]}
|
||||||
</Form.Radio>
|
style={
|
||||||
<Form.Radio
|
{
|
||||||
className="criteria-option"
|
"flexShrink": 0,
|
||||||
description="2 points"
|
}
|
||||||
disabled={true}
|
}
|
||||||
onChange={[MockFunction this.onChange]}
|
value="option name 2"
|
||||||
value="option name 2"
|
>
|
||||||
>
|
this label 2
|
||||||
this label 2
|
</Form.Radio>
|
||||||
</Form.Radio>
|
</Form.RadioSet>
|
||||||
</Form.RadioSet>
|
|
||||||
</React.Fragment>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Radio Criterion Container snapshot radio contain invalid response 1`] = `
|
exports[`Radio Criterion Container snapshot radio contain invalid response 1`] = `
|
||||||
<React.Fragment>
|
<Form.RadioSet
|
||||||
<Form.RadioSet
|
name="random name"
|
||||||
name="random name"
|
value="selected radio option"
|
||||||
value="selected radio option"
|
>
|
||||||
|
<Form.Radio
|
||||||
|
className="criteria-option align-items-center"
|
||||||
|
description="1 points"
|
||||||
|
disabled={false}
|
||||||
|
key="option name"
|
||||||
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value="option name"
|
||||||
>
|
>
|
||||||
<Form.Radio
|
this label
|
||||||
className="criteria-option"
|
</Form.Radio>
|
||||||
description="1 points"
|
<Form.Radio
|
||||||
disabled={false}
|
className="criteria-option align-items-center"
|
||||||
onChange={[MockFunction this.onChange]}
|
description="2 points"
|
||||||
value="option name"
|
disabled={false}
|
||||||
>
|
key="option name 2"
|
||||||
this label
|
onChange={[Function]}
|
||||||
</Form.Radio>
|
style={
|
||||||
<Form.Radio
|
{
|
||||||
className="criteria-option"
|
"flexShrink": 0,
|
||||||
description="2 points"
|
}
|
||||||
disabled={false}
|
}
|
||||||
onChange={[MockFunction this.onChange]}
|
value="option name 2"
|
||||||
value="option name 2"
|
>
|
||||||
>
|
this label 2
|
||||||
this label 2
|
</Form.Radio>
|
||||||
</Form.Radio>
|
<Form.Control.Feedback
|
||||||
<Form.Control.Feedback
|
className="feedback-error-msg"
|
||||||
className="feedback-error-msg"
|
type="invalid"
|
||||||
type="invalid"
|
>
|
||||||
>
|
Rubric selection is required
|
||||||
Rubric selection is required
|
</Form.Control.Feedback>
|
||||||
</Form.Control.Feedback>
|
</Form.RadioSet>
|
||||||
</Form.RadioSet>
|
|
||||||
</React.Fragment>
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -6,23 +6,26 @@ exports[`Review Crition Container snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="criteria-option"
|
className="criteria-option"
|
||||||
|
data-testid="criteria-option"
|
||||||
key="option name"
|
key="option name"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Form.Label
|
<Form.Label
|
||||||
className="option-label"
|
className="option-label"
|
||||||
|
data-testid="option-label"
|
||||||
>
|
>
|
||||||
this label
|
this label
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<FormControlFeedback
|
<FormControlFeedback
|
||||||
className="option-points"
|
className="option-points"
|
||||||
|
data-testid="option-points"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="{points} points"
|
defaultMessage="{points} points"
|
||||||
description="criterion option point value display"
|
description="criterion option point value display"
|
||||||
id="ora-grading.RadioCriterion.optionPoints"
|
id="ora-grading.RadioCriterion.optionPoints"
|
||||||
values={
|
values={
|
||||||
Object {
|
{
|
||||||
"points": 1,
|
"points": 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,23 +35,26 @@ exports[`Review Crition Container snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="criteria-option"
|
className="criteria-option"
|
||||||
|
data-testid="criteria-option"
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Form.Label
|
<Form.Label
|
||||||
className="option-label"
|
className="option-label"
|
||||||
|
data-testid="option-label"
|
||||||
>
|
>
|
||||||
this label 2
|
this label 2
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<FormControlFeedback
|
<FormControlFeedback
|
||||||
className="option-points"
|
className="option-points"
|
||||||
|
data-testid="option-points"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="{points} points"
|
defaultMessage="{points} points"
|
||||||
description="criterion option point value display"
|
description="criterion option point value display"
|
||||||
id="ora-grading.RadioCriterion.optionPoints"
|
id="ora-grading.RadioCriterion.optionPoints"
|
||||||
values={
|
values={
|
||||||
Object {
|
{
|
||||||
"points": 2,
|
"points": 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,28 +13,31 @@ exports[`Criterion Container snapshot is graded and is not grading 1`] = `
|
|||||||
<InfoPopover>
|
<InfoPopover>
|
||||||
<div
|
<div
|
||||||
className="help-popover-option"
|
className="help-popover-option"
|
||||||
|
data-testid="help-popover-option"
|
||||||
key="option name"
|
key="option name"
|
||||||
>
|
>
|
||||||
<strong>
|
<strong>
|
||||||
this label
|
this label
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
explaination
|
explanation
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="help-popover-option"
|
className="help-popover-option"
|
||||||
|
data-testid="help-popover-option"
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
>
|
>
|
||||||
<strong>
|
<strong>
|
||||||
this label 2
|
this label 2
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
explaination 2
|
explanation 2
|
||||||
</div>
|
</div>
|
||||||
</InfoPopover>
|
</InfoPopover>
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<div
|
<div
|
||||||
className="rubric-criteria"
|
className="rubric-criteria"
|
||||||
|
data-testid="rubric-criteria"
|
||||||
>
|
>
|
||||||
<RadioCriterion
|
<RadioCriterion
|
||||||
isGrading={false}
|
isGrading={false}
|
||||||
@@ -61,28 +64,31 @@ exports[`Criterion Container snapshot is ungraded and is grading 1`] = `
|
|||||||
<InfoPopover>
|
<InfoPopover>
|
||||||
<div
|
<div
|
||||||
className="help-popover-option"
|
className="help-popover-option"
|
||||||
|
data-testid="help-popover-option"
|
||||||
key="option name"
|
key="option name"
|
||||||
>
|
>
|
||||||
<strong>
|
<strong>
|
||||||
this label
|
this label
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
explaination
|
explanation
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="help-popover-option"
|
className="help-popover-option"
|
||||||
|
data-testid="help-popover-option"
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
>
|
>
|
||||||
<strong>
|
<strong>
|
||||||
this label 2
|
this label 2
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
explaination 2
|
explanation 2
|
||||||
</div>
|
</div>
|
||||||
</InfoPopover>
|
</InfoPopover>
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<div
|
<div
|
||||||
className="rubric-criteria"
|
className="rubric-criteria"
|
||||||
|
data-testid="rubric-criteria"
|
||||||
>
|
>
|
||||||
<RadioCriterion
|
<RadioCriterion
|
||||||
isGrading={true}
|
isGrading={true}
|
||||||
@@ -109,28 +115,31 @@ exports[`Criterion Container snapshot is ungraded and is not grading 1`] = `
|
|||||||
<InfoPopover>
|
<InfoPopover>
|
||||||
<div
|
<div
|
||||||
className="help-popover-option"
|
className="help-popover-option"
|
||||||
|
data-testid="help-popover-option"
|
||||||
key="option name"
|
key="option name"
|
||||||
>
|
>
|
||||||
<strong>
|
<strong>
|
||||||
this label
|
this label
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
explaination
|
explanation
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="help-popover-option"
|
className="help-popover-option"
|
||||||
|
data-testid="help-popover-option"
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
>
|
>
|
||||||
<strong>
|
<strong>
|
||||||
this label 2
|
this label 2
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
explaination 2
|
explanation 2
|
||||||
</div>
|
</div>
|
||||||
</InfoPopover>
|
</InfoPopover>
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<div
|
<div
|
||||||
className="rubric-criteria"
|
className="rubric-criteria"
|
||||||
|
data-testid="rubric-criteria"
|
||||||
>
|
>
|
||||||
<ReviewCriterion
|
<ReviewCriterion
|
||||||
orderNum={1}
|
orderNum={1}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Form } from '@edx/paragon';
|
import { Form } from '@openedx/paragon';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
import { gradeStatuses } from 'data/services/lms/constants';
|
import { gradeStatuses } from 'data/services/lms/constants';
|
||||||
@@ -25,7 +25,7 @@ export const CriterionContainer = (props) => {
|
|||||||
<span className="criteria-title">{config.prompt}</span>
|
<span className="criteria-title">{config.prompt}</span>
|
||||||
<InfoPopover>
|
<InfoPopover>
|
||||||
{config.options.map((option) => (
|
{config.options.map((option) => (
|
||||||
<div key={option.name} className="help-popover-option">
|
<div key={option.name} className="help-popover-option" data-testid="help-popover-option">
|
||||||
<strong>{option.label}</strong>
|
<strong>{option.label}</strong>
|
||||||
<br />
|
<br />
|
||||||
{option.explanation}
|
{option.explanation}
|
||||||
@@ -33,7 +33,7 @@ export const CriterionContainer = (props) => {
|
|||||||
))}
|
))}
|
||||||
</InfoPopover>
|
</InfoPopover>
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
<div className="rubric-criteria">
|
<div className="rubric-criteria" data-testid="rubric-criteria">
|
||||||
{isGrading || gradeStatus === gradeStatuses.graded ? (
|
{isGrading || gradeStatus === gradeStatuses.graded ? (
|
||||||
<RadioCriterion orderNum={orderNum} isGrading={isGrading} />
|
<RadioCriterion orderNum={orderNum} isGrading={isGrading} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
import { gradeStatuses } from 'data/services/lms/constants';
|
import { gradeStatuses } from 'data/services/lms/constants';
|
||||||
@@ -34,14 +34,14 @@ describe('Criterion Container', () => {
|
|||||||
feedback: 'feedback mock',
|
feedback: 'feedback mock',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
explanation: 'explaination',
|
explanation: 'explanation',
|
||||||
feedback: 'option feedback',
|
feedback: 'option feedback',
|
||||||
label: 'this label',
|
label: 'this label',
|
||||||
name: 'option name',
|
name: 'option name',
|
||||||
points: 2,
|
points: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
explanation: 'explaination 2',
|
explanation: 'explanation 2',
|
||||||
feedback: 'option feedback 2',
|
feedback: 'option feedback 2',
|
||||||
label: 'this label 2',
|
label: 'this label 2',
|
||||||
name: 'option name 2',
|
name: 'option name 2',
|
||||||
@@ -58,61 +58,51 @@ describe('Criterion Container', () => {
|
|||||||
|
|
||||||
describe('snapshot', () => {
|
describe('snapshot', () => {
|
||||||
test('is ungraded and is grading', () => {
|
test('is ungraded and is grading', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is ungraded and is not grading', () => {
|
test('is ungraded and is not grading', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionContainer {...props} isGrading={false} />);
|
||||||
isGrading: false,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
|
||||||
expect(el).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is graded and is not grading', () => {
|
test('is graded and is not grading', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionContainer {...props} isGrading={false} gradeStatus={gradeStatuses.graded} />);
|
||||||
isGrading: false,
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
gradeStatus: gradeStatuses.graded,
|
|
||||||
});
|
|
||||||
expect(el).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('component', () => {
|
describe('component', () => {
|
||||||
test('rendering and all of the option show up', () => {
|
test('rendering and all of the option show up', () => {
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
const optionsEl = el.find('.help-popover-option');
|
const optionsEl = el.instance.findByTestId('help-popover-option');
|
||||||
expect(optionsEl.length).toEqual(props.config.options.length);
|
expect(optionsEl.length).toEqual(props.config.options.length);
|
||||||
optionsEl.forEach((optionEl, i) => {
|
optionsEl.forEach((optionEl, i) => {
|
||||||
expect(optionEl.key()).toEqual(props.config.options[i].name);
|
expect(optionEl.props.key).toEqual(props.config.options[i].name);
|
||||||
expect(optionEl.text()).toContain(props.config.options[i].explanation);
|
expect(optionEl.children[2].el).toContain(props.config.options[i].explanation);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is ungraded and is grading (Radio criterion get render)', () => {
|
test('is ungraded and is grading (Radio criterion get render)', () => {
|
||||||
const rubricCritera = el.find('.rubric-criteria');
|
const rubricCriteria = el.instance.findByTestId('rubric-criteria')[0];
|
||||||
expect(rubricCritera.children(0).name()).toEqual('RadioCriterion');
|
expect(rubricCriteria.children[0].el.type).toEqual('RadioCriterion');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is ungraded and is not grading (Review criterion get render)', () => {
|
test('is ungraded and is not grading (Review criterion get render)', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionContainer {...props} isGrading={false} />);
|
||||||
isGrading: false,
|
const rubricCriteria = el.instance.findByTestId('rubric-criteria')[0];
|
||||||
});
|
expect(rubricCriteria.children[0].el.type).toEqual('ReviewCriterion');
|
||||||
const rubricCritera = el.find('.rubric-criteria');
|
|
||||||
expect(rubricCritera.children(0).name()).toEqual('ReviewCriterion');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('is graded and is not grading (Radio criterion get render)', () => {
|
test('is graded and is not grading (Radio criterion get render)', () => {
|
||||||
el.setProps({
|
el = shallow(<CriterionContainer {...props} isGrading={false} gradeStatus={gradeStatuses.graded} />);
|
||||||
isGrading: false,
|
const rubricCriteria = el.instance.findByTestId('rubric-criteria')[0];
|
||||||
gradeStatus: gradeStatuses.graded,
|
expect(rubricCriteria.children[0].el.type).toEqual('RadioCriterion');
|
||||||
});
|
|
||||||
const rubricCritera = el.find('.rubric-criteria');
|
|
||||||
expect(rubricCritera.children(0).name()).toEqual('RadioCriterion');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('mapStateToProps', () => {
|
describe('mapStateToProps', () => {
|
||||||
const testState = { abitaryState: 'some data' };
|
const testState = { arbitraryState: 'some data' };
|
||||||
const ownProps = { orderNum: props.orderNum };
|
const ownProps = { orderNum: props.orderNum };
|
||||||
let mapped;
|
let mapped;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const messages = defineMessages({
|
|||||||
optional: {
|
optional: {
|
||||||
id: 'ora-grading.CriterionFeedback.optional',
|
id: 'ora-grading.CriterionFeedback.optional',
|
||||||
defaultMessage: '(Optional)',
|
defaultMessage: '(Optional)',
|
||||||
description: 'addtional label for optional feedback field',
|
description: 'additional label for optional feedback field',
|
||||||
},
|
},
|
||||||
optionPoints: {
|
optionPoints: {
|
||||||
id: 'ora-grading.RadioCriterion.optionPoints',
|
id: 'ora-grading.RadioCriterion.optionPoints',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
import { DemoWarning, mapStateToProps } from '.';
|
import { DemoWarning, mapStateToProps } from '.';
|
||||||
@@ -16,12 +16,12 @@ describe('DemoWarning component', () => {
|
|||||||
describe('snapshots', () => {
|
describe('snapshots', () => {
|
||||||
test('does not render if disabled flag is missing', () => {
|
test('does not render if disabled flag is missing', () => {
|
||||||
el = shallow(<DemoWarning hide />);
|
el = shallow(<DemoWarning hide />);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
expect(el.isEmptyRender()).toEqual(true);
|
expect(el.isEmptyRender()).toEqual(true);
|
||||||
});
|
});
|
||||||
test('snapshot: disabled flag is present', () => {
|
test('snapshot: disabled flag is present', () => {
|
||||||
el = shallow(<DemoWarning hide={false} />);
|
el = shallow(<DemoWarning hide={false} />);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
expect(el.isEmptyRender()).toEqual(false);
|
expect(el.isEmptyRender()).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`DemoWarning component snapshots does not render if disabled flag is missing 1`] = `""`;
|
exports[`DemoWarning component snapshots does not render if disabled flag is missing 1`] = `null`;
|
||||||
|
|
||||||
exports[`DemoWarning component snapshots snapshot: disabled flag is present 1`] = `
|
exports[`DemoWarning component snapshots snapshot: disabled flag is present 1`] = `
|
||||||
<Alert
|
<Alert
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { connect } from 'react-redux';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
import { Alert } from '@edx/paragon';
|
import { Alert } from '@openedx/paragon';
|
||||||
import { Info } from '@edx/paragon/icons';
|
import { Info } from '@openedx/paragon/icons';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
import { Hyperlink, Button } from '@edx/paragon';
|
import { Hyperlink, Button } from '@openedx/paragon';
|
||||||
|
|
||||||
import urls from 'data/services/lms/urls';
|
import urls from 'data/services/lms/urls';
|
||||||
import emptyStateSVG from './assets/empty-state.svg';
|
import emptyStateSVG from './assets/empty-state.svg';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { Hyperlink } from '@edx/paragon';
|
import { Hyperlink } from '@openedx/paragon';
|
||||||
|
|
||||||
import urls from 'data/services/lms/urls';
|
import urls from 'data/services/lms/urls';
|
||||||
|
|
||||||
@@ -22,11 +22,11 @@ describe('EmptySubmission component', () => {
|
|||||||
el = shallow(<EmptySubmission {...props} />);
|
el = shallow(<EmptySubmission {...props} />);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('openResponse destination', () => {
|
test('openResponse destination', () => {
|
||||||
expect(
|
expect(
|
||||||
el.find(Hyperlink).at(0).props().destination,
|
el.instance.findByType(Hyperlink)[0].props.destination,
|
||||||
).toEqual(urls.openResponse(props.courseId));
|
).toEqual(urls.openResponse(props.courseId));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, DataTableContext } from '@edx/paragon';
|
import { Button, DataTableContext } from '@openedx/paragon';
|
||||||
|
|
||||||
import * as module from './FilterStatusComponent';
|
import * as module from './FilterStatusComponent';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import * as module from './FilterStatusComponent';
|
import * as module from './FilterStatusComponent';
|
||||||
|
|
||||||
@@ -71,20 +71,20 @@ describe('FilterStatusComponent component', () => {
|
|||||||
test('showFilteredFields', () => {
|
test('showFilteredFields', () => {
|
||||||
mockHooks(hookProps);
|
mockHooks(hookProps);
|
||||||
const el = shallow(<FilterStatusComponent {...props} />);
|
const el = shallow(<FilterStatusComponent {...props} />);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('showFilteredFields=false - hide filterTexts', () => {
|
test('showFilteredFields=false - hide filterTexts', () => {
|
||||||
mockHooks(hookProps);
|
mockHooks(hookProps);
|
||||||
const el = shallow(
|
const el = shallow(
|
||||||
<FilterStatusComponent {...props} showFilteredFields={false} />,
|
<FilterStatusComponent {...props} showFilteredFields={false} />,
|
||||||
);
|
);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
test('without filters', () => {
|
test('without filters', () => {
|
||||||
mockHooks({});
|
mockHooks({});
|
||||||
const el = shallow(<FilterStatusComponent {...props} />);
|
const el = shallow(<FilterStatusComponent {...props} />);
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
expect(el.isEmptyRender()).toEqual(true);
|
expect(el.isEmptyRender()).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
Alert,
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
Hyperlink,
|
Hyperlink,
|
||||||
} from '@edx/paragon';
|
} from '@openedx/paragon';
|
||||||
import { Info } from '@edx/paragon/icons';
|
import { Info } from '@openedx/paragon/icons';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import urls from 'data/services/lms/urls';
|
import urls from 'data/services/lms/urls';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { selectors, thunkActions } from 'data/redux';
|
import { selectors, thunkActions } from 'data/redux';
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ describe('ListError component', () => {
|
|||||||
el = shallow(<ListError {...props} />);
|
el = shallow(<ListError {...props} />);
|
||||||
});
|
});
|
||||||
test('snapshot', () => {
|
test('snapshot', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@import "@edx/paragon/scss/core/core";
|
@import "@openedx/paragon/scss/core/core";
|
||||||
|
|
||||||
span.pgn__icon.breadcrumb-arrow {
|
span.pgn__icon.breadcrumb-arrow {
|
||||||
width: 16px !important;
|
width: 16px !important;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { ArrowBack, Launch } from '@edx/paragon/icons';
|
import { ArrowBack, Launch } from '@openedx/paragon/icons';
|
||||||
import { Hyperlink, Icon } from '@edx/paragon';
|
import { Hyperlink, Icon } from '@openedx/paragon';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
@@ -22,7 +22,7 @@ export const ListViewBreadcrumb = ({ courseId, oraName }) => (
|
|||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
<p className="py-4">
|
<p className="py-4">
|
||||||
<span className="h3">{oraName}</span>
|
<span className="h3">{oraName}</span>
|
||||||
<Hyperlink className="align-middle" destination={urls.ora(courseId, locationId)}>
|
<Hyperlink className="align-middle" destination={urls.ora(courseId, locationId())}>
|
||||||
<Icon src={Launch} className="d-inline-block" />
|
<Icon src={Launch} className="d-inline-block" />
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
|
||||||
import { Hyperlink } from '@edx/paragon';
|
import { Hyperlink } from '@openedx/paragon';
|
||||||
|
|
||||||
import * as constants from 'data/constants/app';
|
import * as constants from 'data/constants/app';
|
||||||
import urls from 'data/services/lms/urls';
|
import urls from 'data/services/lms/urls';
|
||||||
@@ -40,17 +40,17 @@ describe('ListViewBreadcrumb component', () => {
|
|||||||
el = shallow(<ListViewBreadcrumb {...props} />);
|
el = shallow(<ListViewBreadcrumb {...props} />);
|
||||||
});
|
});
|
||||||
test('snapshot: empty (no list data)', () => {
|
test('snapshot: empty (no list data)', () => {
|
||||||
expect(el).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('openResponse destination', () => {
|
test('openResponse destination', () => {
|
||||||
expect(
|
expect(
|
||||||
el.find(Hyperlink).at(0).props().destination,
|
el.instance.findByType(Hyperlink)[0].props.destination,
|
||||||
).toEqual(urls.openResponse(props.courseId));
|
).toEqual(urls.openResponse(props.courseId));
|
||||||
});
|
});
|
||||||
test('ora destination', () => {
|
test('ora destination', () => {
|
||||||
expect(
|
expect(
|
||||||
el.find(Hyperlink).at(1).props().destination,
|
el.instance.findByType(Hyperlink)[1].props.destination,
|
||||||
).toEqual(urls.ora(props.courseId, constants.locationId));
|
).toEqual(urls.ora(props.courseId, constants.locationId()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('mapStateToProps', () => {
|
describe('mapStateToProps', () => {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user