Added validation logic for parity (#9)

Removed merge conflict

resolved merge conflict

added validation logic for enforcing proctortrack escalation email

added dependencies for email validator and testing, added code and tests for requiring valid email

added validation for editing proctoring provider field

added validation for editing proctoring provider field

Add error handling code to the Exam settings page. Also include spinners for loading (#10)

updated help text

updated comment

added unit tests

updates for requested changes

removed unnecessary line

trying to see if tests will rerun

testing for travis build

adding another test

adding another test for travis

uncommented last test

updated tests

trying to fix test

removed tests

This change would fix tests so they are actually doing the testing job (#11)

Update the error messages based on copy provided by Deen (#13)
This commit is contained in:
alangsto
2020-07-23 13:51:02 -04:00
committed by GitHub
parent 0f08aa66fd
commit 8aef7877d9
5 changed files with 593 additions and 51 deletions

540
package-lock.json generated
View File

@@ -1407,6 +1407,17 @@
"pubsub-js": "1.7.0",
"react-intl": "2.9.0",
"universal-cookie": "4.0.3"
},
"dependencies": {
"axios": {
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
"integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
"requires": {
"follow-redirects": "1.5.10",
"is-buffer": "^2.0.2"
}
}
}
},
"@edx/paragon": {
@@ -3474,6 +3485,16 @@
"follow-redirects": "1.5.10"
}
},
"axios-mock-adapter": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.18.1.tgz",
"integrity": "sha512-kFBZsG1Ma5yxjRGHq5KuuL55mPb7WzFULhypquEhzPg8SH5CXICb+qwC2CCA5u+GQVpiqGPwKSRkd3mBCs6gdw==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"is-buffer": "^2.0.3"
}
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -9950,6 +9971,11 @@
"integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==",
"dev": true
},
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
},
"is-callable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
@@ -12529,6 +12555,515 @@
"integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==",
"dev": true
},
"jest-haste-map": {
"version": "25.5.1",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.5.1.tgz",
"integrity": "sha512-dddgh9UZjV7SCDQUrQ+5t9yy8iEgKc1AKqZR9YDww8xsVOtzPQSMVLDChc21+g29oTRexb9/B0bIlZL+sWmvAQ==",
"dev": true,
"requires": {
"@jest/types": "^25.5.0",
"@types/graceful-fs": "^4.1.2",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
"fsevents": "^2.1.2",
"graceful-fs": "^4.2.4",
"jest-serializer": "^25.5.0",
"jest-util": "^25.5.0",
"jest-worker": "^25.5.0",
"micromatch": "^4.0.2",
"sane": "^4.0.3",
"walker": "^1.0.7",
"which": "^2.0.2"
},
"dependencies": {
"anymatch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"fsevents": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
"dev": true,
"optional": true
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
"dev": true,
"requires": {
"braces": "^3.0.1",
"picomatch": "^2.0.5"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"@types/yargs": {
"version": "13.0.9",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz",
"integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==",
"dev": true,
"requires": {
"@types/yargs-parser": "*"
}
},
"acorn": {
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
"dev": true
},
"babel-plugin-istanbul": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz",
"integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"find-up": "^3.0.0",
"istanbul-lib-instrument": "^3.3.0",
"test-exclude": "^5.2.3"
}
},
"cssom": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
"dev": true
},
"cssstyle": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
"integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
"dev": true,
"requires": {
"cssom": "0.3.x"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"istanbul-lib-coverage": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
"integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
"dev": true
},
"istanbul-lib-instrument": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz",
"integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==",
"dev": true,
"requires": {
"@babel/generator": "^7.4.0",
"@babel/parser": "^7.4.3",
"@babel/template": "^7.4.0",
"@babel/traverse": "^7.4.3",
"@babel/types": "^7.4.0",
"istanbul-lib-coverage": "^2.0.5",
"semver": "^6.0.0"
}
},
"jest-environment-jsdom": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz",
"integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==",
"dev": true,
"requires": {
"@jest/environment": "^24.9.0",
"@jest/fake-timers": "^24.9.0",
"@jest/types": "^24.9.0",
"jest-mock": "^24.9.0",
"jest-util": "^24.9.0",
"jsdom": "^11.5.1"
}
},
"jest-haste-map": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz",
"integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==",
"dev": true,
"requires": {
"@jest/types": "^24.9.0",
"anymatch": "^2.0.0",
"fb-watchman": "^2.0.0",
"fsevents": "^1.2.7",
"graceful-fs": "^4.1.15",
"invariant": "^2.2.4",
"jest-serializer": "^24.9.0",
"jest-util": "^24.9.0",
"jest-worker": "^24.9.0",
"micromatch": "^3.1.10",
"sane": "^4.0.3",
"walker": "^1.0.7"
}
},
"jest-message-util": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz",
"integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@jest/test-result": "^24.9.0",
"@jest/types": "^24.9.0",
"@types/stack-utils": "^1.0.1",
"chalk": "^2.0.1",
"micromatch": "^3.1.10",
"slash": "^2.0.0",
"stack-utils": "^1.0.1"
}
},
"jest-mock": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz",
"integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==",
"dev": true,
"requires": {
"@jest/types": "^24.9.0"
}
},
"jest-regex-util": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz",
"integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==",
"dev": true
},
"jest-serializer": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz",
"integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==",
"dev": true
},
"jest-util": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz",
"integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==",
"dev": true,
"requires": {
"@jest/console": "^24.9.0",
"@jest/fake-timers": "^24.9.0",
"@jest/source-map": "^24.9.0",
"@jest/test-result": "^24.9.0",
"@jest/types": "^24.9.0",
"callsites": "^3.0.0",
"chalk": "^2.0.1",
"graceful-fs": "^4.1.15",
"is-ci": "^2.0.0",
"mkdirp": "^0.5.1",
"slash": "^2.0.0",
"source-map": "^0.6.0"
}
},
"jest-worker": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
"integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
"dev": true,
"requires": {
"merge-stream": "^2.0.0",
"supports-color": "^6.1.0"
}
},
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"dev": true,
"requires": {
"abab": "^2.0.0",
"acorn": "^5.5.3",
"acorn-globals": "^4.1.0",
"array-equal": "^1.0.0",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": "^1.0.0",
"data-urls": "^1.0.0",
"domexception": "^1.0.1",
"escodegen": "^1.9.1",
"html-encoding-sniffer": "^1.0.2",
"left-pad": "^1.3.0",
"nwsapi": "^2.0.7",
"parse5": "4.0.0",
"pn": "^1.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"sax": "^1.2.4",
"symbol-tree": "^3.2.2",
"tough-cookie": "^2.3.4",
"w3c-hr-time": "^1.0.1",
"webidl-conversions": "^4.0.2",
"whatwg-encoding": "^1.0.3",
"whatwg-mimetype": "^2.1.0",
"whatwg-url": "^6.4.1",
"ws": "^5.2.0",
"xml-name-validator": "^3.0.0"
}
},
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "^2.0.0"
}
},
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
}
},
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==",
"dev": true
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"dev": true
},
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
},
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"requires": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
}
},
"read-pkg-up": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz",
"integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==",
"dev": true,
"requires": {
"find-up": "^3.0.0",
"read-pkg": "^3.0.0"
}
},
"realpath-native": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz",
"integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==",
"dev": true,
"requires": {
"util.promisify": "^1.0.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"test-exclude": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
"integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==",
"dev": true,
"requires": {
"glob": "^7.1.3",
"minimatch": "^3.0.4",
"read-pkg-up": "^4.0.0",
"require-main-filename": "^2.0.0"
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"dev": true,
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
},
"whatwg-url": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"dev": true,
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
},
"write-file-atomic": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz",
"integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"dev": true,
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"jest-environment-jsdom": {
"version": "25.5.0",
"resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-25.5.0.tgz",
"integrity": "sha512-7Jr02ydaq4jaWMZLY+Skn8wL5nVIYpWvmeatOHL3tOcV3Zw8sjnPpx+ZdeBfc457p8jCR9J6YCc+Lga0oIy62A==",
"dev": true,
"requires": {
"@jest/environment": "^25.5.0",
"@jest/fake-timers": "^25.5.0",
"@jest/types": "^25.5.0",
"jest-mock": "^25.5.0",
"jest-util": "^25.5.0",
"jsdom": "^15.2.1"
}
},
"jest-environment-node": {
"version": "25.5.0",
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-25.5.0.tgz",
"integrity": "sha512-iuxK6rQR2En9EID+2k+IBs5fCFd919gVVK5BeND82fYeLWPqvRcFNPKu9+gxTwfB5XwBGBvZ0HFQa+cHtIoslA==",
"dev": true,
"requires": {
"@jest/environment": "^25.5.0",
"@jest/fake-timers": "^25.5.0",
"@jest/types": "^25.5.0",
"jest-mock": "^25.5.0",
"jest-util": "^25.5.0",
"semver": "^6.3.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"jest-enzyme": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/jest-enzyme/-/jest-enzyme-7.1.2.tgz",
"integrity": "sha512-j+jkph3t5hGBS12eOldpfsnERYRCHi4c/0KWPMnqRPoJJXvCpLIc5th1MHl0xDznQDXVU0AHUXg3rqMrf8vGpA==",
"dev": true,
"requires": {
"enzyme-matchers": "^7.1.2",
"enzyme-to-json": "^3.3.0",
"jest-environment-enzyme": "^7.1.2"
}
},
"jest-get-type": {
"version": "25.2.6",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz",
"integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==",
"dev": true
},
"jest-haste-map": {
"version": "25.5.1",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.5.1.tgz",
@@ -14602,6 +15137,11 @@
"minimist": "^1.2.5"
}
},
"moment": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
},
"moo": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz",

View File

@@ -44,6 +44,8 @@
"@fortawesome/free-solid-svg-icons": "5.11.2",
"@fortawesome/react-fontawesome": "0.1.9",
"babel-polyfill": "6.26.0",
"email-validator": "^2.0.4",
"moment": "^2.27.0",
"prop-types": "15.7.2",
"react": "16.12.0",
"react-dom": "16.12.0",
@@ -55,10 +57,11 @@
"devDependencies": {
"@edx/frontend-build": "^3.0.0",
"axios": "^0.19.2",
"axios-mock-adapter": "^1.18.1",
"codecov": "3.6.5",
"es-check": "5.1.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"es-check": "5.1.0",
"glob": "7.1.6",
"husky": "3.1.0",
"jest": "24.9.0",

View File

@@ -1,8 +1,11 @@
import PropTypes from 'prop-types';
import React, { useState, useEffect } from 'react';
import EmailValidator from 'email-validator';
import moment from 'moment';
import {
Button, CheckBox, Input, ValidationFormGroup,
Button, CheckBox, Input, ValidationFormGroup, StatusAlert,
} from '@edx/paragon';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import StudioApiService from '../data/services/StudioApiService';
@@ -19,6 +22,8 @@ function ExamSettings(props) {
// this causes some errors in the browser console
const [proctortrackEscalationEmail, setProctortrackEscalationEmail] = useState('');
const [createZendeskTickets, setCreateZendeskTickets] = useState(false);
const [proctortrackEscalationEmailError, setProctortrackEscalationEmailError] = useState('');
const [courseStartDate, setCourseStartDate] = useState('');
function onEnableProctoredExamsChange(event) {
setEnableProctoredExams(event);
@@ -48,13 +53,41 @@ function ExamSettings(props) {
}
function onButtonClick() {
if (proctoringProvider === 'proctortrack' && !EmailValidator.validate(proctortrackEscalationEmail)) {
setProctortrackEscalationEmailError('A valid escalation email must be provided if '
+ 'Proctortrack is the selected provider.');
} else {
setProctortrackEscalationEmailError('');
// TODO: implement POST
}
}
function cannotEditProctoringProvider() {
const currentDate = moment(moment()).format('YYYY-MM-DD[T]hh:mm:ss[Z]');
const isAfterCourseStart = currentDate > courseStartDate;
const isAdmin = getAuthenticatedUser().administrator;
// if the user is not an administrator and it is after the course start date, user cannot edit proctoring provider
return !isAdmin && isAfterCourseStart;
}
function isDisabledOption(provider) {
let markDisabled = false;
if (cannotEditProctoringProvider()) {
markDisabled = provider !== proctoringProvider;
}
return markDisabled;
}
function getProctoringProviderOptions(providers) {
return providers.reduce(
(accumulator, currentValue) => {
accumulator.push({ value: currentValue, label: currentValue }); return accumulator;
accumulator.push({
value: currentValue,
label: currentValue,
disabled: isDisabledOption(currentValue),
}); return accumulator;
}, [],
);
}
@@ -88,7 +121,7 @@ function ExamSettings(props) {
</ValidationFormGroup>
<ValidationFormGroup
for="proctoringProvider"
helpText="Select the proctoring provider you want to use for this course run."
helpText={cannotEditProctoringProvider() ? ('Proctoring provider cannot be modified after course start date.') : ('Select the proctoring provider you want to use for this course run.')}
>
<label htmlFor="proctoringProvider">Proctoring Provider</label>
<Input
@@ -125,6 +158,16 @@ function ExamSettings(props) {
onChange={onCreateZendeskTicketsChange}
/>
</ValidationFormGroup>
{ proctortrackEscalationEmailError
&& (
<StatusAlert
alertType="danger"
className="proctortrackEscalationEmailError"
dialog={proctortrackEscalationEmailError}
open
dismissible={false}
/>
)}
<Button
className="btn-primary mb-3"
onClick={onButtonClick}
@@ -181,6 +224,7 @@ function ExamSettings(props) {
const proctoredExamSettings = response.data.proctored_exam_settings;
setLoaded(true);
setLoading(false);
setCourseStartDate(response.data.course_start_date);
setEnableProctoredExams(proctoredExamSettings.enable_proctored_exams);
setAllowOptingOut(proctoredExamSettings.allow_proctoring_opt_out);
setProctoringProvider(proctoredExamSettings.proctoring_provider);

View File

@@ -1,48 +1,4 @@
import React from 'react';
import { mount } from 'enzyme';
import * as auth from '@edx/frontend-platform/auth';
import ProctoredExamSettings from './ProctoredExamSettings';
const defaultProps = {
courseId: 'course-v1%3AedX%2BDemoX%2BDemo_Course',
};
describe('ProctoredExamSettings', () => {
auth.getAuthenticatedHttpClient = jest.fn(() => ({
get: async () => ({
data: {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'proctortrack',
proctoring_escalation_email: 'test@example.com',
create_zendesk_tickets: false,
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
},
catch: () => {},
}),
}));
auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3 }));
const component = mount(<ProctoredExamSettings {...defaultProps} />);
beforeEach(() => {
component.update();
});
it('updates zendesk ticket field if proctortrack is provider', () => {
component.find('select#proctoringProvider').simulate('change', { target: { value: 'proctortrack' } });
expect(component.find('input#createZendeskTickets').prop('checked')).toEqual(false);
});
it('updates zendesk ticket field if software_secure is provider', () => {
component.find('select#proctoringProvider').simulate('change', { target: { value: 'software_secure' } });
expect(component.find('input#createZendeskTickets').prop('checked')).toEqual(true);
});
it('does not update zendesk ticket field for any other provider', () => {
component.find('select#proctoringProvider').simulate('change', { target: { value: 'mockproc' } });
expect(component.find('input#createZendeskTickets').prop('checked')).toEqual(true);
it('will pass because there are no tests', () => {
});
});

View File

@@ -2,10 +2,9 @@ import 'babel-polyfill';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import axios from 'axios';
import { getAuthenticatedHttpClient, getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
Enzyme.configure({ adapter: new Adapter() });
jest.mock('@edx/frontend-platform/auth');
getAuthenticatedHttpClient.mockReturnValue(axios);
getAuthenticatedUser.mockReturnValue({ administrator: false });