diff --git a/package-lock.json b/package-lock.json index 94e32a4a4..b73ae471c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "codemirror": "^6.0.0", "fast-xml-parser": "^4.0.10", "lodash-es": "^4.17.21", + "moment": "^2.29.4", "moment-shortformat": "^2.1.0", "react-redux": "^7.2.8", "react-responsive": "8.2.0", @@ -42,6 +43,7 @@ "@edx/paragon": "^20.28.0", "@edx/reactifex": "^2.1.1", "@testing-library/dom": "^8.13.0", + "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^12.1.1", "@testing-library/user-event": "^13.5.0", "codecov": "3.8.3", @@ -67,6 +69,12 @@ "react-dom": "^16.14.0" } }, + "node_modules/@adobe/css-tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", + "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==", + "dev": true + }, "node_modules/@babel/cli": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.16.0.tgz", @@ -5018,6 +5026,47 @@ "node": ">=8" } }, + "node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@lezer/common": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", @@ -5417,6 +5466,12 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true + }, "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", @@ -6405,6 +6460,41 @@ "node": ">=12" } }, + "node_modules/@testing-library/jest-dom": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@testing-library/react": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.1.tgz", @@ -6544,6 +6634,57 @@ "@types/istanbul-lib-coverage": "*" } }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.1.tgz", + "integrity": "sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -6616,6 +6757,21 @@ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.5", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", + "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", + "dev": true, + "dependencies": { + "@types/jest": "*" + } + }, "node_modules/@types/uglify-js": { "version": "3.17.1", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.1.tgz", @@ -6645,6 +6801,15 @@ "node": ">= 8" } }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, "node_modules/@types/yargs-parser": { "version": "21.0.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", @@ -6895,18 +7060,6 @@ "node": ">= 8" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -8465,15 +8618,6 @@ "@types/node": "*" } }, - "node_modules/babel-jest/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, "node_modules/babel-jest/node_modules/@types/yargs": { "version": "15.0.14", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", @@ -11443,6 +11587,12 @@ "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==" }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, "node_modules/cssnano": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.12.tgz", @@ -12383,6 +12533,15 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -14267,6 +14426,22 @@ "node": ">= 0.6" } }, + "node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", @@ -22394,6 +22569,170 @@ "node": ">= 10.14.2" } }, + "node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", @@ -22411,6 +22750,38 @@ } } }, + "node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/jest/node_modules/@babel/generator": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", @@ -22873,15 +23244,6 @@ "@types/node": "*" } }, - "node_modules/jest/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, "node_modules/jest/node_modules/@types/normalize-package-data": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", @@ -22894,12 +23256,6 @@ "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", "dev": true }, - "node_modules/jest/node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, "node_modules/jest/node_modules/@types/yargs": { "version": "15.0.14", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", @@ -23231,15 +23587,6 @@ "node": ">=8" } }, - "node_modules/jest/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest/node_modules/escodegen": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", @@ -25136,18 +25483,6 @@ "source-map": "^0.6.0" } }, - "node_modules/jest/node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest/node_modules/static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -25956,18 +26291,6 @@ "node": ">=8" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -26009,6 +26332,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/mini-css-extract-plugin": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz", @@ -26154,7 +26486,6 @@ "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "peer": true, "engines": { "node": "*" } @@ -27834,6 +28165,18 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -29204,16 +29547,17 @@ "node": ">=8.10.0" } }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, - "engines": { - "node": ">=8.6" + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=8" } }, "node_modules/redux": { @@ -30256,6 +30600,27 @@ "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", "dev": true }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -30751,6 +31116,18 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -34569,6 +34946,12 @@ } }, "dependencies": { + "@adobe/css-tools": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", + "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==", + "dev": true + }, "@babel/cli": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.16.0.tgz", @@ -38218,6 +38601,38 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "requires": { + "jest-get-type": "^29.4.3" + } + }, + "@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.25.16" + } + }, + "@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, "@lezer/common": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", @@ -38538,6 +38953,12 @@ } } }, + "@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true + }, "@svgr/babel-plugin-remove-jsx-attribute": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", @@ -39210,6 +39631,35 @@ "pretty-format": "^27.0.2" } }, + "@testing-library/jest-dom": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, "@testing-library/react": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.1.tgz", @@ -39331,6 +39781,50 @@ "@types/istanbul-lib-coverage": "*" } }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.5.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.1.tgz", + "integrity": "sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -39403,6 +39897,21 @@ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/testing-library__jest-dom": { + "version": "5.14.5", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", + "integrity": "sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==", + "dev": true, + "requires": { + "@types/jest": "*" + } + }, "@types/uglify-js": { "version": "3.17.1", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.1.tgz", @@ -39431,6 +39940,15 @@ } } }, + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "@types/yargs-parser": { "version": "21.0.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", @@ -39631,14 +40149,6 @@ "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" - }, - "dependencies": { - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - } } }, "aproba": { @@ -40772,15 +41282,6 @@ "@types/node": "*" } }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, "@types/yargs": { "version": "15.0.14", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", @@ -43125,6 +43626,12 @@ "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==" }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, "cssnano": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.12.tgz", @@ -43767,6 +44274,12 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -45221,6 +45734,19 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, + "expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + } + }, "ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", @@ -52013,15 +52539,6 @@ "@types/node": "*" } }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, "@types/normalize-package-data": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", @@ -52034,12 +52551,6 @@ "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", "dev": true }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, "@types/yargs": { "version": "15.0.14", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", @@ -52311,12 +52822,6 @@ } } }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, "escodegen": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", @@ -53821,15 +54326,6 @@ "source-map": "^0.6.0" } }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -54117,6 +54613,134 @@ } } }, + "jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, + "jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, "jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", @@ -54124,6 +54748,28 @@ "dev": true, "requires": {} }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true + } + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -54500,12 +55146,6 @@ "requires": { "fill-range": "^7.0.1" } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true } } }, @@ -54535,6 +55175,12 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "mini-css-extract-plugin": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz", @@ -54643,8 +55289,7 @@ "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "peer": true + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "moment-shortformat": { "version": "2.1.0", @@ -55881,6 +56526,12 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -56942,14 +57593,16 @@ "dev": true, "requires": { "picomatch": "^2.2.1" - }, - "dependencies": { - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - } + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" } }, "redux": { @@ -57744,6 +58397,23 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -58107,6 +58777,15 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", diff --git a/package.json b/package.json index 2c8ac4800..828bfd45a 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@edx/paragon": "^20.28.0", "@edx/reactifex": "^2.1.1", "@testing-library/dom": "^8.13.0", + "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^12.1.1", "@testing-library/user-event": "^13.5.0", "codecov": "3.8.3", @@ -69,6 +70,7 @@ "codemirror": "^6.0.0", "fast-xml-parser": "^4.0.10", "lodash-es": "^4.17.21", + "moment": "^2.29.4", "moment-shortformat": "^2.1.0", "react-redux": "^7.2.8", "react-responsive": "8.2.0", diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.jsx index cef3d4ed5..178da1e86 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.jsx @@ -11,6 +11,11 @@ jest.mock('../../../../../data/redux', () => ({ settings: jest.fn(state => ({ question: state })), }, }, + thunkActions: { + video: { + importTranscript: jest.fn(), + }, + }, })); jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({ diff --git a/src/editors/containers/VideoGallery/hooks.test.js b/src/editors/containers/VideoGallery/hooks.test.js index 8508404fa..43d0b77f0 100644 --- a/src/editors/containers/VideoGallery/hooks.test.js +++ b/src/editors/containers/VideoGallery/hooks.test.js @@ -28,6 +28,15 @@ describe('VideoGallery hooks', () => { beforeEach(() => { jest.clearAllMocks(); }); + describe('state hooks', () => { + state.testGetter(state.keys.highlighted); + state.testGetter(state.keys.searchString); + state.testGetter(state.keys.showSelectVideoError); + state.testGetter(state.keys.showSizeError); + state.testGetter(state.keys.sortBy); + state.testGetter(state.keys.filertBy); + state.testGetter(state.keys.hideSelectedVideos); + }); describe('using state', () => { beforeEach(() => { state.mock(); }); afterEach(() => { state.restore(); }); @@ -77,9 +86,79 @@ describe('VideoGallery hooks', () => { notMatching.forEach(val => expect(filterCb({ displayName: val })).toEqual(false)); }); }); - describe('imgListHooks outputs', () => { + describe('buildVideos', () => { + const rawVideos = [ + { + edx_video_id: 'id_1', + client_video_id: 'client_id_1', + course_video_image_url: 'course_video_image_url_1', + created: 'created_1', + status: 'status_1', + duration: 1, + transcripts: [], + }, + { + edx_video_id: 'id_2', + client_video_id: 'client_id_2', + course_video_image_url: 'course_video_image_url_2', + created: 'created_2', + status: 'status_2', + duration: 2, + transcripts: [], + }, + ]; + const expectedValues = [ + { + id: 'id_1', + displayName: 'client_id_1', + externalUrl: 'course_video_image_url_1', + dateAdded: 'created_1', + locked: false, + thumbnail: 'course_video_image_url_1', + status: 'status_1', + statusBadgeVariant: null, + duration: 1, + transcripts: [], + }, + { + id: 'id_2', + displayName: 'client_id_2', + externalUrl: 'course_video_image_url_2', + dateAdded: 'created_2', + locked: false, + thumbnail: 'course_video_image_url_2', + status: 'status_2', + statusBadgeVariant: null, + duration: 2, + transcripts: [], + }, + ]; + test('return the expected values', () => { + const values = hooks.buildVideos({ rawVideos }); + expect(values).toEqual(expectedValues); + }); + }); + describe('getstatusBadgeVariant', () => { + test('return the expected values', () => { + let value = hooks.getstatusBadgeVariant({ status: filterKeys.failed }); + expect(value).toEqual('danger'); + value = hooks.getstatusBadgeVariant({ status: filterKeys.uploading }); + expect(value).toEqual('light'); + value = hooks.getstatusBadgeVariant({ status: filterKeys.processing }); + expect(value).toEqual('light'); + value = hooks.getstatusBadgeVariant({ status: filterKeys.videoStatus }); + expect(value).toBeNull(); + value = hooks.getstatusBadgeVariant({ status: filterKeys.ready }); + expect(value).toBeNull(); + }); + }); + describe('videoListHooks outputs', () => { const props = { - searchSortProps: { searchString: 'Es', sortBy: sortKeys.dateNewest, filterBy: filterKeys.videoStatus }, + searchSortProps: { + searchString: 'Es', + sortBy: sortKeys.dateNewest, + filterBy: filterKeys.videoStatus, + }, videos: [ { displayName: 'sOmEuiMAge', @@ -131,4 +210,44 @@ describe('VideoGallery hooks', () => { }); }); }); + describe('videoHooks', () => { + const videoListHooks = { + galleryProps: 'some gallery props', + selectBtnProps: 'some select btn props', + }; + const searchAndSortHooks = { search: 'props' }; + const fileInputHooks = { file: 'input hooks' }; + const videos = { video: { staTICUrl: '/assets/sOmEuiMAge' } }; + const spies = {}; + beforeEach(() => { + spies.videoList = jest.spyOn(hooks, hookKeys.videoListHooks) + .mockReturnValueOnce(videoListHooks); + spies.search = jest.spyOn(hooks, hookKeys.searchAndSortHooks) + .mockReturnValueOnce(searchAndSortHooks); + spies.file = jest.spyOn(hooks, hookKeys.fileInputHooks) + .mockReturnValueOnce(fileInputHooks); + hook = hooks.videoHooks({ videos }); + }); + it('forwards fileInputHooks as fileInput', () => { + expect(hook.fileInput).toEqual(fileInputHooks); + expect(spies.file.mock.calls.length).toEqual(1); + expect(spies.file).toHaveBeenCalled(); + }); + it('initializes videoListHooks', () => { + expect(spies.videoList.mock.calls.length).toEqual(1); + expect(spies.videoList).toHaveBeenCalledWith({ + searchSortProps: searchAndSortHooks, + videos, + }); + }); + it('forwards searchAndSortHooks as searchSortProps', () => { + expect(hook.searchSortProps).toEqual(searchAndSortHooks); + expect(spies.search.mock.calls.length).toEqual(1); + expect(spies.search).toHaveBeenCalled(); + }); + it('forwards galleryProps and selectBtnProps from the video list hooks', () => { + expect(hook.galleryProps).toEqual(videoListHooks.galleryProps); + expect(hook.selectBtnProps).toEqual(videoListHooks.selectBtnProps); + }); + }); }); diff --git a/src/editors/containers/VideoGallery/messages.js b/src/editors/containers/VideoGallery/messages.js index d351cd751..a846b3956 100644 --- a/src/editors/containers/VideoGallery/messages.js +++ b/src/editors/containers/VideoGallery/messages.js @@ -3,7 +3,7 @@ export const messages = { emptyGalleryLabel: { id: 'authoring.selectvideomodal.emptyGalleryLabel', defaultMessage: - 'No videos found in your gallery. Please upload a video using the button below.', + 'No results found.', description: 'Label for when video gallery is empty.', }, selectVideoButtonlabel: { diff --git a/src/editors/containers/VideoGallery/utils.test.js b/src/editors/containers/VideoGallery/utils.test.js new file mode 100644 index 000000000..ef9818833 --- /dev/null +++ b/src/editors/containers/VideoGallery/utils.test.js @@ -0,0 +1,62 @@ +import { sortFunctions } from './utils'; + +describe('VideGallery utils', () => { + describe('sortFunctions', () => { + const dateA = { + dateAdded: new Date('2023-03-30'), + }; + const dateB = { + dateAdded: new Date('2023-03-31'), + }; + const nameA = { + displayName: 'This is the Name A', + dateAdded: new Date('2023-03-30'), + }; + const nameB = { + displayName: 'Hello World', + dateAdded: new Date('2023-03-30'), + }; + const nameC = { + displayName: 'Hello World', + dateAdded: new Date('2023-03-31'), + }; + const durationA = { + duration: 10, + }; + const durationB = { + duration: 100, + }; + test('correct functionality of dateNewest', () => { + expect(sortFunctions.dateNewest(dateA, dateB)).toBeGreaterThan(0); + expect(sortFunctions.dateNewest(dateB, dateA)).toBeLessThan(0); + expect(sortFunctions.dateNewest(dateA, dateA)).toEqual(0); + }); + test('correct functionality of dateOldest', () => { + expect(sortFunctions.dateOldest(dateA, dateB)).toBeLessThan(0); + expect(sortFunctions.dateOldest(dateB, dateA)).toBeGreaterThan(0); + expect(sortFunctions.dateOldest(dateA, dateA)).toEqual(0); + }); + test('correct functionality of nameAscending', () => { + expect(sortFunctions.nameAscending(nameA, nameB)).toEqual(1); + expect(sortFunctions.nameAscending(nameB, nameA)).toEqual(-1); + expect(sortFunctions.nameAscending(nameA, nameA)).toEqual(0); + expect(sortFunctions.nameAscending(nameB, nameC)).toBeGreaterThan(0); + }); + test('correct functionality of nameDescending', () => { + expect(sortFunctions.nameDescending(nameA, nameB)).toEqual(-1); + expect(sortFunctions.nameDescending(nameB, nameA)).toEqual(1); + expect(sortFunctions.nameDescending(nameA, nameA)).toEqual(0); + expect(sortFunctions.nameDescending(nameB, nameC)).toBeGreaterThan(0); + }); + test('correct functionality of durationShortest', () => { + expect(sortFunctions.durationShortest(durationA, durationB)).toBeLessThan(0); + expect(sortFunctions.durationShortest(durationB, durationA)).toBeGreaterThan(0); + expect(sortFunctions.durationShortest(durationA, durationA)).toEqual(0); + }); + test('correct functionality of durationLongest', () => { + expect(sortFunctions.durationLongest(durationA, durationB)).toBeGreaterThan(0); + expect(sortFunctions.durationLongest(durationB, durationA)).toBeLessThan(0); + expect(sortFunctions.durationLongest(durationA, durationA)).toEqual(0); + }); + }); +}); diff --git a/src/editors/data/redux/app/reducer.test.js b/src/editors/data/redux/app/reducer.test.js index 09b1bccdb..f23e8c14c 100644 --- a/src/editors/data/redux/app/reducer.test.js +++ b/src/editors/data/redux/app/reducer.test.js @@ -48,6 +48,7 @@ describe('app reducer', () => { ['setBlockTitle', 'blockTitle'], ['setSaveResponse', 'saveResponse'], ['setAssets', 'assets'], + ['setVideos', 'videos'], ['setCourseDetails', 'courseDetails'], ].map(args => setterTest(...args)); describe('setBlockValue', () => { diff --git a/src/editors/data/redux/app/selectors.test.js b/src/editors/data/redux/app/selectors.test.js index d2fb44f28..ac7cc400a 100644 --- a/src/editors/data/redux/app/selectors.test.js +++ b/src/editors/data/redux/app/selectors.test.js @@ -48,6 +48,7 @@ describe('app selectors unit tests', () => { simpleKeys.blockTitle, simpleKeys.studioView, simpleKeys.assets, + simpleKeys.videos, ].map(testSimpleSelector); }); }); diff --git a/src/editors/data/redux/thunkActions/app.test.js b/src/editors/data/redux/thunkActions/app.test.js index 8a2621f6f..f6ee54837 100644 --- a/src/editors/data/redux/thunkActions/app.test.js +++ b/src/editors/data/redux/thunkActions/app.test.js @@ -166,6 +166,15 @@ describe('app thunkActions', () => { expect(dispatch).toHaveBeenCalledWith(actions.app.setAssets(response)); }); }); + describe('fetchVideos', () => { + it('dispatches fetchVideos action with setVideos for onSuccess param', () => { + const response = { data: { videos: 'testRESPONSE' } }; + thunkActions.fetchVideos()(dispatch); + const [[dispatchCall]] = dispatch.mock.calls; + dispatchCall.fetchVideos.onSuccess(response); + expect(dispatch).toHaveBeenCalledWith(actions.app.setVideos(response.data.videos)); + }); + }); describe('uploadImage', () => { const setSelection = jest.fn(); beforeEach(() => { diff --git a/src/editors/data/redux/thunkActions/requests.test.js b/src/editors/data/redux/thunkActions/requests.test.js index ea77e5d81..e2b3c548a 100644 --- a/src/editors/data/redux/thunkActions/requests.test.js +++ b/src/editors/data/redux/thunkActions/requests.test.js @@ -27,6 +27,7 @@ jest.mock('../../services/cms/api', () => ({ fetchCourseDetails: (args) => args, saveBlock: (args) => args, fetchAssets: ({ id, url }) => ({ id, url }), + fetchVideos: ({ id, url }) => ({ id, url }), uploadAsset: (args) => args, loadImages: jest.fn(), uploadThumbnail: (args) => args, @@ -265,6 +266,32 @@ describe('requests thunkActions module', () => { expect(loadImages).toHaveBeenCalledWith({ fetchAssets: expectedArgs }); }); }); + describe('fetchVideos', () => { + const expectedArgs = { + studioEndpointUrl: selectors.app.studioEndpointUrl(testState), + learningContextId: selectors.app.learningContextId(testState), + }; + let fetchVideos; + let dispatchedAction; + beforeEach(() => { + fetchVideos = jest.fn((args) => new Promise((resolve) => { + resolve({ data: { videos: { fetchVideos: args } } }); + })); + jest.spyOn(api, apiKeys.fetchVideos).mockImplementationOnce(fetchVideos); + requests.fetchVideos({ ...fetchParams, onSuccess, onFailure })(dispatch, () => testState); + [[dispatchedAction]] = dispatch.mock.calls; + }); + it('dispatches networkRequest', () => { + expect(dispatchedAction.networkRequest).not.toEqual(undefined); + }); + test('forwards onSuccess and onFailure', () => { + expect(dispatchedAction.networkRequest.onSuccess).toEqual(onSuccess); + expect(dispatchedAction.networkRequest.onFailure).toEqual(onFailure); + }); + test('api.fetchVideos promise called with studioEndpointUrl and learningContextId', () => { + expect(fetchVideos).toHaveBeenCalledWith(expectedArgs); + }); + }); describe('saveBlock', () => { const content = 'SoME HtMl CoNtent As String'; testNetworkRequestAction({ diff --git a/src/editors/data/services/cms/api.test.js b/src/editors/data/services/cms/api.test.js index b2a97fa7f..6e94bb8e0 100644 --- a/src/editors/data/services/cms/api.test.js +++ b/src/editors/data/services/cms/api.test.js @@ -21,8 +21,11 @@ jest.mock('./urls', () => ({ allowThumbnailUpload: jest.fn().mockName('urls.allowThumbnailUpload'), thumbnailUpload: jest.fn().mockName('urls.thumbnailUpload'), checkTranscriptsForImport: jest.fn().mockName('urls.checkTranscriptsForImport'), + courseDetailsUrl: jest.fn().mockName('urls.courseDetailsUrl'), + courseAdvanceSettings: jest.fn().mockName('urls.courseAdvanceSettings'), replaceTranscript: jest.fn().mockName('urls.replaceTranscript'), videoFeatures: jest.fn().mockName('urls.videoFeatures'), + courseVideos: jest.fn().mockName('urls.courseVideos'), })); jest.mock('./utils', () => ({ @@ -73,6 +76,27 @@ describe('cms api', () => { }); }); + describe('fetchCourseDetails', () => { + it('should call get with url.courseDetailsUrl', () => { + apiMethods.fetchCourseDetails({ learningContextId, studioEndpointUrl }); + expect(get).toHaveBeenCalledWith(urls.courseDetailsUrl({ studioEndpointUrl, learningContextId })); + }); + }); + + describe('fetchVideos', () => { + it('should call get with url.courseVideos', () => { + apiMethods.fetchVideos({ learningContextId, studioEndpointUrl }); + expect(get).toHaveBeenCalledWith(urls.courseVideos({ studioEndpointUrl, learningContextId })); + }); + }); + + describe('fetchAdvancedSettings', () => { + it('should call get with url.courseAdvanceSettings', () => { + apiMethods.fetchAdvancedSettings({ learningContextId, studioEndpointUrl }); + expect(get).toHaveBeenCalledWith(urls.courseAdvanceSettings({ studioEndpointUrl, learningContextId })); + }); + }); + describe('normalizeContent', () => { test('return value for blockType: html', () => { const content = 'Im baby palo santo ugh celiac fashion axe. La croix lo-fi venmo whatever. Beard man braid migas single-origin coffee forage ramps.'; diff --git a/src/editors/data/services/cms/urls.test.js b/src/editors/data/services/cms/urls.test.js index 9f5282a37..47dbd5cff 100644 --- a/src/editors/data/services/cms/urls.test.js +++ b/src/editors/data/services/cms/urls.test.js @@ -13,7 +13,9 @@ import { courseDetailsUrl, checkTranscriptsForImport, replaceTranscript, + courseAdvanceSettings, videoFeatures, + courseVideos, } from './urls'; describe('cms url methods', () => { @@ -125,10 +127,22 @@ describe('cms url methods', () => { .toEqual(`${studioEndpointUrl}/transcripts/replace?data=${parameters}`); }); }); + describe('courseAdvanceSettings', () => { + it('returns url with studioEndpointUrl and learningContextId', () => { + expect(courseAdvanceSettings({ studioEndpointUrl, learningContextId })) + .toEqual(`${studioEndpointUrl}/api/contentstore/v0/advanced_settings/${learningContextId}`); + }); + }); describe('videoFeatures', () => { it('returns url with studioEndpointUrl and learningContextId', () => { expect(videoFeatures({ studioEndpointUrl, learningContextId })) .toEqual(`${studioEndpointUrl}/video_features/${learningContextId}`); }); }); + describe('courseVideos', () => { + it('returns url with studioEndpointUrl and learningContextId', () => { + expect(courseVideos({ studioEndpointUrl, learningContextId })) + .toEqual(`${studioEndpointUrl}/videos/${learningContextId}`); + }); + }); }); diff --git a/src/editors/sharedComponents/ErrorAlerts/ErrorAlert.jsx b/src/editors/sharedComponents/ErrorAlerts/ErrorAlert.jsx index fe73eb053..40a813e89 100644 --- a/src/editors/sharedComponents/ErrorAlerts/ErrorAlert.jsx +++ b/src/editors/sharedComponents/ErrorAlerts/ErrorAlert.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Alert } from '@edx/paragon'; -import { Outline } from '@edx/paragon/icons'; +import { Error } from '@edx/paragon/icons'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; import messages from './messages'; @@ -42,7 +42,7 @@ export const ErrorAlert = ({ return ( diff --git a/src/editors/sharedComponents/SelectionModal/Gallery.jsx b/src/editors/sharedComponents/SelectionModal/Gallery.jsx index 69eafb5c2..e497a40c2 100644 --- a/src/editors/sharedComponents/SelectionModal/Gallery.jsx +++ b/src/editors/sharedComponents/SelectionModal/Gallery.jsx @@ -15,6 +15,7 @@ import messages from './messages'; import GalleryCard from './GalleryCard'; export const Gallery = ({ + show, galleryIsEmpty, searchIsEmpty, displayList, @@ -27,13 +28,24 @@ export const Gallery = ({ // injected intl, }) => { + if (!show) { + return null; + } if (!isLoaded) { return ( - +
+ +
); } if (galleryIsEmpty) { @@ -71,8 +83,10 @@ Gallery.defaultProps = { highlighted: '', showIdsOnCards: false, height: '375px', + show: true, }; Gallery.propTypes = { + show: PropTypes.bool, isLoaded: PropTypes.bool.isRequired, galleryIsEmpty: PropTypes.bool.isRequired, searchIsEmpty: PropTypes.bool.isRequired, diff --git a/src/editors/sharedComponents/SelectionModal/Gallery.test.jsx b/src/editors/sharedComponents/SelectionModal/Gallery.test.jsx index f9904889b..eafa533df 100644 --- a/src/editors/sharedComponents/SelectionModal/Gallery.test.jsx +++ b/src/editors/sharedComponents/SelectionModal/Gallery.test.jsx @@ -37,5 +37,9 @@ describe('TextEditor Image Gallery component', () => { test('snapshot: loaded, show gallery', () => { expect(shallow()).toMatchSnapshot(); }); + test('snapshot: not shot gallery', () => { + const wrapper = shallow(); + expect(wrapper.type()).toBeNull(); + }); }); }); diff --git a/src/editors/sharedComponents/SelectionModal/SearchSort.test.jsx b/src/editors/sharedComponents/SelectionModal/SearchSort.test.jsx index dbb5e9de9..ccf8d36c8 100644 --- a/src/editors/sharedComponents/SelectionModal/SearchSort.test.jsx +++ b/src/editors/sharedComponents/SelectionModal/SearchSort.test.jsx @@ -6,20 +6,21 @@ import { FormattedMessage } from '@edx/frontend-platform/i18n'; import { formatMessage } from '../../../testUtils'; import { sortKeys, sortMessages } from '../ImageUploadModal/SelectImageModal/utils'; +import { filterKeys, filterMessages } from '../../containers/VideoGallery/utils'; import { SearchSort } from './SearchSort'; describe('SearchSort component', () => { - const props = { - searchString: 'props.searchString', - onSearchChange: jest.fn().mockName('props.onSearchChange'), - clearSearchString: jest.fn().mockName('props.clearSearchString'), - sortBy: sortKeys.dateOldest, - sortKeys, - sortMessages, - onSortClick: jest.fn().mockName('props.onSortClick'), - intl: { formatMessage }, - }; - describe('snapshots', () => { + describe('snapshots without filterKeys', () => { + const props = { + searchString: 'props.searchString', + onSearchChange: jest.fn().mockName('props.onSearchChange'), + clearSearchString: jest.fn().mockName('props.clearSearchString'), + sortBy: sortKeys.dateOldest, + sortKeys, + sortMessages, + onSortClick: jest.fn().mockName('props.onSortClick'), + intl: { formatMessage }, + }; test('with search string (close button)', () => { expect(shallow()).toMatchSnapshot(); }); @@ -42,4 +43,59 @@ describe('SearchSort component', () => { )).toEqual(true); }); }); + describe('snapshots with filterKeys', () => { + const props = { + searchString: 'props.searchString', + onSearchChange: jest.fn().mockName('props.onSearchChange'), + clearSearchString: jest.fn().mockName('props.clearSearchString'), + sortBy: sortKeys.dateOldest, + sortKeys, + sortMessages, + filterKeys, + filterMessages, + showSwitch: true, + onSortClick: jest.fn().mockName('props.onSortClick'), + onFilterClick: jest.fn().mockName('props.onFilterClick'), + intl: { formatMessage }, + }; + test('with search string (close button)', () => { + expect(shallow()).toMatchSnapshot(); + }); + test('without search string (search icon)', () => { + expect(shallow()).toMatchSnapshot(); + }); + test('adds a sort option for each sortKey', () => { + const el = shallow(); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + }); + test('adds a filter option for each filterKet', () => { + const el = shallow(); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + expect(el.find(Dropdown).containsMatchingElement( + , + )).toEqual(true); + }); + }); }); diff --git a/src/editors/sharedComponents/SelectionModal/__snapshots__/Gallery.test.jsx.snap b/src/editors/sharedComponents/SelectionModal/__snapshots__/Gallery.test.jsx.snap index 380b58307..9c2eacf95 100644 --- a/src/editors/sharedComponents/SelectionModal/__snapshots__/Gallery.test.jsx.snap +++ b/src/editors/sharedComponents/SelectionModal/__snapshots__/Gallery.test.jsx.snap @@ -85,9 +85,20 @@ exports[`TextEditor Image Gallery component component snapshot: loaded, show gal `; exports[`TextEditor Image Gallery component component snapshot: not loaded, show spinner 1`] = ` - +
+ +
`; diff --git a/src/editors/sharedComponents/SelectionModal/__snapshots__/SearchSort.test.jsx.snap b/src/editors/sharedComponents/SelectionModal/__snapshots__/SearchSort.test.jsx.snap index a48329e45..1f3156ab8 100644 --- a/src/editors/sharedComponents/SelectionModal/__snapshots__/SearchSort.test.jsx.snap +++ b/src/editors/sharedComponents/SelectionModal/__snapshots__/SearchSort.test.jsx.snap @@ -1,6 +1,291 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`SearchSort component snapshots with search string (close button) 1`] = ` +exports[`SearchSort component snapshots with filterKeys with search string (close button) 1`] = ` + + + + } + value="props.searchString" + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`SearchSort component snapshots with filterKeys without search string (search icon) 1`] = ` + + + } + value="" + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`SearchSort component snapshots without filterKeys with search string (close button) 1`] = ` `; -exports[`SearchSort component snapshots without search string (search icon) 1`] = ` +exports[`SearchSort component snapshots without filterKeys without search string (search icon) 1`] = ` - - -`; - -exports[`Selection Modal snapshots rendering with props to null 1`] = ` - - - -`; diff --git a/src/editors/sharedComponents/SelectionModal/index.jsx b/src/editors/sharedComponents/SelectionModal/index.jsx index b0d868383..19218edd3 100644 --- a/src/editors/sharedComponents/SelectionModal/index.jsx +++ b/src/editors/sharedComponents/SelectionModal/index.jsx @@ -43,8 +43,18 @@ export const SelectionModal = ({ fetchError, uploadError, } = modalMessages; + + let background = '#FFFFFF'; + let showGallery = true; + if (isLoaded && !isFetchError && !isUploadError && !inputError.show) { + background = '#EBEBEB'; + } else if (isLoaded) { + showGallery = false; + } + const galleryPropsValues = { isLoaded, + show: showGallery, ...galleryProps, }; return ( @@ -64,7 +74,7 @@ export const SelectionModal = ({ )} title={intl.formatMessage(titleMsg)} - bodyStyle={{ background: '#EBEBEB' }} + bodyStyle={{ background, padding: '24px' }} headerComponent={(
diff --git a/src/editors/sharedComponents/SelectionModal/index.test.jsx b/src/editors/sharedComponents/SelectionModal/index.test.jsx index a77669a8c..2f9389059 100644 --- a/src/editors/sharedComponents/SelectionModal/index.test.jsx +++ b/src/editors/sharedComponents/SelectionModal/index.test.jsx @@ -1,7 +1,9 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { render, screen } from '@testing-library/react'; import { formatMessage } from '../../../testUtils'; import SelectionModal from '.'; +import '@testing-library/jest-dom'; const props = { isOpen: jest.fn(), @@ -69,7 +71,7 @@ const props = { jest.mock('../BaseModal', () => 'BaseModal'); jest.mock('./SearchSort', () => 'SearchSort'); -jest.mock('./Gallery', () => 'Gallery'); +jest.mock('./Gallery', () => () => 'Gallery'); jest.mock('../FileInput', () => 'FileInput'); jest.mock('../ErrorAlerts/ErrorAlert', () => 'ErrorAlert'); jest.mock('../ErrorAlerts/FetchErrorAlert', () => 'FetchErrorAlert'); @@ -77,11 +79,13 @@ jest.mock('../ErrorAlerts/UploadErrorAlert', () => 'UploadErrorAlert'); describe('Selection Modal', () => { describe('snapshots', () => { - test('rendering correctly with expected Input', () => { - expect(shallow()).toMatchSnapshot(); - }); - test('rendering with props to null', () => { - expect(shallow()).toMatchSnapshot(); + test('rendering correctly with expected Input', async () => { + render( + + + , + ); + expect(screen.getByText('Gallery')).toBeInTheDocument(); }); }); }); diff --git a/src/editors/utils/formatDuration.js b/src/editors/utils/formatDuration.js index 83008b7d7..8458f51fc 100644 --- a/src/editors/utils/formatDuration.js +++ b/src/editors/utils/formatDuration.js @@ -2,7 +2,7 @@ import * as moment from 'moment-shortformat'; const formatDuration = (duration) => { const d = moment.duration(duration, 'seconds'); - if (d.hours > 0) { + if (d.hours() > 0) { return ( `${d.hours().toString().padStart(2, '0')}:` + `${d.minutes().toString().padStart(2, '0')}:` diff --git a/src/editors/utils/formatDuration.test.js b/src/editors/utils/formatDuration.test.js new file mode 100644 index 000000000..6720130d7 --- /dev/null +++ b/src/editors/utils/formatDuration.test.js @@ -0,0 +1,12 @@ +import formatDuration from './formatDuration'; + +describe('formatDuration', () => { + test.each([ + [60, '01:00'], + [35, '00:35'], + [60 * 10 + 15, '10:15'], + [60 * 60 + 60 * 15 + 13, '01:15:13'], + ])('correct functionality of formatDuration with duration as %p', (duration, expected) => { + expect(formatDuration(duration)).toEqual(expected); + }); +});