From 8c15f0014501ddb200e3aca4236cfd95f10f4b90 Mon Sep 17 00:00:00 2001 From: Michael Roytman Date: Tue, 15 May 2018 13:49:54 -0400 Subject: [PATCH] fix(editimagemodal): add remaining tests --- package-lock.json | 603 ++++-- .../AssetsClearFiltersButton.test.jsx | 2 +- .../AssetsClearSearchButton.test.jsx | 2 +- .../AssetsDropZone/AssetsDropZone.test.jsx | 2 +- src/components/AssetsList/AssetsList.test.jsx | 2 +- src/components/AssetsPage/AssetsPage.test.jsx | 2 +- src/components/AssetsPage/index.jsx | 20 +- .../AssetsTable/AssetsTable.test.jsx | 2 +- .../EditImageModal/EditImageModal.test.jsx | 1892 ++++++++++------- .../EditImageModal/displayMessages.jsx | 40 +- src/components/EditImageModal/index.jsx | 13 +- src/components/Pagination/Pagination.test.jsx | 2 +- src/data/i18n/default/transifex_input.json | 8 +- src/utils/testConstants.jsx | 4 +- 14 files changed, 1601 insertions(+), 993 deletions(-) diff --git a/package-lock.json b/package-lock.json index b14f49b8..43c99a0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -239,7 +239,7 @@ "@edx/edx-bootstrap": "1.0.0", "babel-polyfill": "6.26.0", "classnames": "2.2.5", - "email-prop-type": "1.1.6", + "email-prop-type": "1.1.7", "font-awesome": "4.7.0", "mailto-link": "1.0.0", "prop-types": "15.6.1", @@ -277,9 +277,9 @@ "dev": true }, "@octokit/rest": { - "version": "15.6.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.6.0.tgz", - "integrity": "sha512-POCEmRrow+NhEh8cs6aFAXwgExWQ9uNwmZTKr48bgr0czyqgNLcdImHhhMfSV2xHa1wTqj+AdWbrkr+1EpOL+A==", + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.6.1.tgz", + "integrity": "sha512-KpyRdr7ie62wTmc3NQEG7jKm7ke6VxHJvRby/dMKtdllrBtXZikigVAbXsqBSP/yMxpayE2f6AwsQfm4XnX1xw==", "dev": true, "requires": { "before-after-hook": "1.1.0", @@ -355,10 +355,10 @@ "integrity": "sha512-SuaBvUf7l3RwqdxBKyRSPZnSckEMB0EqBu6658x41hivJXn7KdJnH/EcKNzMeKu8zFJ6a8DrXTY71APVKE3wHg==", "dev": true, "requires": { - "@octokit/rest": "15.6.0", + "@octokit/rest": "15.6.1", "@semantic-release/error": "2.2.0", "aggregate-error": "1.0.0", - "bottleneck": "2.3.0", + "bottleneck": "2.3.1", "debug": "3.1.0", "fs-extra": "6.0.1", "globby": "8.0.1", @@ -398,18 +398,21 @@ } }, "@semantic-release/npm": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-3.2.5.tgz", - "integrity": "sha512-I40tCW1S3QY4hStrg5PGnRI7Y8N5XVnsG9grEkEKSZmcuBPWC1ag5YcSPxnlsOzbsb94wRPwJTKuzNo7/nA2iQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-3.3.0.tgz", + "integrity": "sha512-XuVXsZ8JkRLjoAsknfD4YXwhJqWRL5IDq77k1uZBXlQlGhVE2MRQ0Vtl3fUMThYPs7RlJfzQNJvY3TZm0zsTOg==", "dev": true, "requires": { "@semantic-release/error": "2.2.0", "aggregate-error": "1.0.0", + "detect-indent": "5.0.0", + "detect-newline": "2.1.0", "execa": "0.10.0", "fs-extra": "6.0.1", "lodash": "4.17.10", "nerf-dart": "1.0.0", "normalize-url": "2.0.1", + "parse-json": "4.0.0", "read-pkg": "3.0.0", "registry-auth-token": "3.3.2" }, @@ -427,6 +430,12 @@ "which": "1.3.0" } }, + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true + }, "execa": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", @@ -526,9 +535,9 @@ "dev": true }, "@types/node": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.1.0.tgz", - "integrity": "sha512-sELcX/cJHwRp8kn4hYSvBxKGJ+ubl3MvS8VJQe5gz/sp7CifYxsiCxIJ35wMIYyGVMgfO2AzRa8UcVReAcJRlw==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.1.2.tgz", + "integrity": "sha512-bjk1RIeZBCe/WukrFToIVegOf91Pebr8cXYBwLBIsfiGWVQ+ifwWsT59H3RxrWzWrzd1l/Amk1/ioY5Fq3/bpA==", "dev": true }, "@types/tapable": { @@ -552,7 +561,7 @@ "integrity": "sha512-Q8ro/vCAyE8piwBvRgzeerrVkGy3XBmK2O2bk5g+NBHDqR0R2qZGwpBsz+js5mBH9PvvenQCojqB9nZC9Gz4MQ==", "dev": true, "requires": { - "@types/node": "10.1.0", + "@types/node": "10.1.2", "@types/tapable": "0.2.5", "@types/uglify-js": "3.0.2", "source-map": "0.6.1" @@ -1188,9 +1197,9 @@ "dev": true }, "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { "lodash": "4.17.10" @@ -1241,7 +1250,7 @@ "dev": true, "requires": { "browserslist": "2.11.3", - "caniuse-lite": "1.0.30000841", + "caniuse-lite": "1.0.30000844", "normalize-range": "0.1.2", "num2fraction": "1.2.2", "postcss": "6.0.22", @@ -2155,19 +2164,19 @@ "babel-plugin-transform-es2015-unicode-regex": "6.24.1", "babel-plugin-transform-exponentiation-operator": "6.24.1", "babel-plugin-transform-regenerator": "6.26.0", - "browserslist": "3.2.7", + "browserslist": "3.2.8", "invariant": "2.2.4", "semver": "5.5.0" }, "dependencies": { "browserslist": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.7.tgz", - "integrity": "sha512-oYVLxFVqpX9uMhOIQBLtZL+CX4uY8ZpWcjNTaxyWl5rO8yA9SSNikFnAfvk8J3P/7z3BZwNmEqFKaJoYltj3MQ==", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000841", - "electron-to-chromium": "1.3.46" + "caniuse-lite": "1.0.30000844", + "electron-to-chromium": "1.3.47" } } } @@ -2558,9 +2567,9 @@ "integrity": "sha512-gulJE5dGFo6Q61V/whS6VM4WIyrlydXfCgkE+Gxe5hjrJ8rXLLZlALq7zq2RPhOc45PSwQpJkrTnc2KgD6cvmA==" }, "bottleneck": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.3.0.tgz", - "integrity": "sha512-Zxhe8FRIiFp5/uGRxIt/s26f6bm0Z87BWzPbUUZZGLkXOldRse1I/pqASYKjcth+6D1NOpVjaqD1X6aEqH+GCw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.3.1.tgz", + "integrity": "sha512-6Ktg80l6qMLlNeRpJjtBsBT8UqYXK7ei4eMwUwk9Q4xOEhmP/MTvmjrd+kQ+EMgLiQFkV4HbZp4cUkMn/Yl0nw==", "dev": true }, "brace-expansion": { @@ -2688,8 +2697,8 @@ "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000841", - "electron-to-chromium": "1.3.46" + "caniuse-lite": "1.0.30000844", + "electron-to-chromium": "1.3.47" } }, "bser": { @@ -2931,7 +2940,7 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000841", + "caniuse-db": "1.0.30000844", "lodash.memoize": "4.1.2", "lodash.uniq": "4.5.0" }, @@ -2942,22 +2951,22 @@ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "dev": true, "requires": { - "caniuse-db": "1.0.30000841", - "electron-to-chromium": "1.3.46" + "caniuse-db": "1.0.30000844", + "electron-to-chromium": "1.3.47" } } } }, "caniuse-db": { - "version": "1.0.30000841", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000841.tgz", - "integrity": "sha1-26QAiVmQNI4t47cXlaUOg38Ts/Y=", + "version": "1.0.30000844", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000844.tgz", + "integrity": "sha1-vKV5jNoraTHWgQDC1p5V+zOMu0E=", "dev": true }, "caniuse-lite": { - "version": "1.0.30000841", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000841.tgz", - "integrity": "sha512-LeOGLEY4hl6xZc/xMYOrVmSrHOybyHWNShFN51qCmDXo69nEGKHTJTfe6jdWe4hLxSJcwEIYtKHFFh93fF/kNA==", + "version": "1.0.30000844", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000844.tgz", + "integrity": "sha512-UpKQE7y6dLHhlv75UyBCRiun34Q+bmxyX3zS+ve9M07YG52tRafOvop9N9d5jC+sikKuG7UMweJKJNts4FVehA==", "dev": true }, "capture-exit": { @@ -3632,6 +3641,49 @@ "semver": "5.5.0", "split": "1.0.1", "through2": "2.0.3" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "meow": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.0.tgz", + "integrity": "sha512-Me/kel335m6vMKmEmA6c87Z6DUFW3JqkINRnxkbC+A/PUm0D5Fl2dEBQrPKnqCL9Te/CIa1MUt/0InMJhuC/sw==", + "dev": true, + "requires": { + "camelcase-keys": "4.2.0", + "decamelize-keys": "1.1.0", + "loud-rejection": "1.6.0", + "minimist": "1.2.0", + "minimist-options": "3.0.2", + "normalize-package-data": "2.4.0", + "read-pkg-up": "3.0.0", + "redent": "2.0.0", + "trim-newlines": "2.0.0" + }, + "dependencies": { + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "1.2.0", + "map-obj": "1.0.1" + } + } + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, "conventional-commits-filter": { @@ -3657,6 +3709,49 @@ "split2": "2.2.0", "through2": "2.0.3", "trim-off-newlines": "1.0.1" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "meow": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.0.tgz", + "integrity": "sha512-Me/kel335m6vMKmEmA6c87Z6DUFW3JqkINRnxkbC+A/PUm0D5Fl2dEBQrPKnqCL9Te/CIa1MUt/0InMJhuC/sw==", + "dev": true, + "requires": { + "camelcase-keys": "4.2.0", + "decamelize-keys": "1.1.0", + "loud-rejection": "1.6.0", + "minimist": "1.2.0", + "minimist-options": "3.0.2", + "normalize-package-data": "2.4.0", + "read-pkg-up": "3.0.0", + "redent": "2.0.0", + "trim-newlines": "2.0.0" + }, + "dependencies": { + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "1.2.0", + "map-obj": "1.0.1" + } + } + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, "convert-source-map": { @@ -3872,7 +3967,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -3995,7 +4090,7 @@ "dev": true, "requires": { "browserslist": "1.7.7", - "caniuse-db": "1.0.30000841", + "caniuse-db": "1.0.30000844", "normalize-range": "0.1.2", "num2fraction": "1.2.2", "postcss": "5.2.18", @@ -4008,8 +4103,8 @@ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "dev": true, "requires": { - "caniuse-db": "1.0.30000841", - "electron-to-chromium": "1.3.46" + "caniuse-db": "1.0.30000844", + "electron-to-chromium": "1.3.47" } }, "chalk": { @@ -4046,7 +4141,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -4669,9 +4764,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.46", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.46.tgz", - "integrity": "sha1-AOheIidUFaiHUF5KtJc3GU8YubA=", + "version": "1.3.47", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.47.tgz", + "integrity": "sha1-dk6IfKkQTQGgrI6r7n38DizhQQQ=", "dev": true }, "elegant-spinner": { @@ -4696,9 +4791,9 @@ } }, "email-prop-type": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/email-prop-type/-/email-prop-type-1.1.6.tgz", - "integrity": "sha512-ZMo+5GT+9bpsFQSR9fPe8ozaZ0AbgAPTqei1/MS9N9rikIpQyj2wVOMcrqZ/a6cKWMe7ttl5aNZ9HiqlQCB03A==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/email-prop-type/-/email-prop-type-1.1.7.tgz", + "integrity": "sha512-5dhzRyH20+oooO5ZN4xJBSKuXj5gVg523gYGlj/bADXXx6ZsiB8x0XgPGLWOeZee9sURjgtyVc0RoBkfh0AfaA==", "requires": { "email-validator": "2.0.3" } @@ -5107,7 +5202,7 @@ "eslint": "4.19.1", "eslint-config-airbnb": "15.1.0", "eslint-plugin-dollar-sign": "1.0.1", - "eslint-plugin-import": "2.11.0", + "eslint-plugin-import": "2.12.0", "eslint-plugin-jsx-a11y": "5.1.1", "eslint-plugin-react": "7.8.2" } @@ -5169,9 +5264,9 @@ "dev": true }, "eslint-plugin-import": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz", - "integrity": "sha1-Fa7qN6Z0mdhI6OmBgG1GJ7VQOBY=", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz", + "integrity": "sha1-2tMXgSktZmSyUxf9BJ0uKy8CIF0=", "dev": true, "requires": { "contains-path": "0.1.0", @@ -5598,7 +5693,7 @@ "integrity": "sha512-Hypkn9jUTnFr0DpekNam53X47tXn3ucY08BQumv7kdGgeVUBLq3DJHJTi6HNxv4jl9W+Skxjz9+RnK0sJyqqjA==", "dev": true, "requires": { - "async": "2.6.0", + "async": "2.6.1", "loader-utils": "1.1.0", "schema-utils": "0.4.5", "webpack-sources": "1.1.0" @@ -6153,9 +6248,9 @@ } }, "follow-redirects": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", - "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz", + "integrity": "sha512-fdrt472/9qQ6Kgjvb935ig6vJCuofpBUD14f9Vb+SLlm7xIe4Qva5gey8EKtv8lp7ahE1wilg3xL1znpVGtZIA==", "dev": true, "requires": { "debug": "3.1.0" @@ -6883,9 +6978,9 @@ } }, "gaze": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", - "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, "requires": { "globule": "1.2.0" @@ -7041,6 +7136,49 @@ "meow": "4.0.0", "split2": "2.2.0", "through2": "2.0.3" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "meow": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.0.tgz", + "integrity": "sha512-Me/kel335m6vMKmEmA6c87Z6DUFW3JqkINRnxkbC+A/PUm0D5Fl2dEBQrPKnqCL9Te/CIa1MUt/0InMJhuC/sw==", + "dev": true, + "requires": { + "camelcase-keys": "4.2.0", + "decamelize-keys": "1.1.0", + "loud-rejection": "1.6.0", + "minimist": "1.2.0", + "minimist-options": "3.0.2", + "normalize-package-data": "2.4.0", + "read-pkg-up": "3.0.0", + "redent": "2.0.0", + "trim-newlines": "2.0.0" + }, + "dependencies": { + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "1.2.0", + "map-obj": "1.0.1" + } + } + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, "git-up": { @@ -7632,9 +7770,9 @@ "dev": true }, "html-minifier": { - "version": "3.5.15", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.15.tgz", - "integrity": "sha512-OZa4rfb6tZOZ3Z8Xf0jKxXkiDcFWldQePGYFDcgKqES2sXeWaEv9y6QQvWUtX3ySI3feApQi5uCsHLINQ6NoAw==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.16.tgz", + "integrity": "sha512-zP5EfLSpiLRp0aAgud4CQXPQZm9kXwWjR/cF0PfdOj+jjWnOaCgeZcll4kYXSvIBPeUMmyaSc7mM4IDtA+kboA==", "dev": true, "requires": { "camel-case": "3.0.0", @@ -7643,7 +7781,7 @@ "he": "1.1.1", "param-case": "2.1.1", "relateurl": "0.2.7", - "uglify-js": "3.3.25" + "uglify-js": "3.3.26" } }, "html-webpack-harddisk-plugin": { @@ -7662,7 +7800,7 @@ "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "dev": true, "requires": { - "html-minifier": "3.5.15", + "html-minifier": "3.5.16", "loader-utils": "0.2.17", "lodash": "4.17.10", "pretty-error": "2.1.1", @@ -7736,7 +7874,7 @@ "dev": true, "requires": { "eventemitter3": "3.1.0", - "follow-redirects": "1.4.1", + "follow-redirects": "1.5.0", "requires-port": "1.0.0" } }, @@ -8585,8 +8723,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-builtin-module": { "version": "1.0.0", @@ -9034,7 +9171,7 @@ "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", "dev": true, "requires": { - "async": "2.6.0", + "async": "2.6.1", "compare-versions": "3.2.1", "fileset": "2.0.3", "istanbul-lib-coverage": "1.2.0", @@ -9204,13 +9341,13 @@ "dev": true }, "jest": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-22.4.3.tgz", - "integrity": "sha512-FFCdU/pXOEASfHxFDOWUysI/+FFoqiXJADEIXgDKuZyqSmBD3tZ4BEGH7+M79v7czj7bbkhwtd2LaEDcJiM/GQ==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-22.4.4.tgz", + "integrity": "sha512-eBhhW8OS/UuX3HxgzNBSVEVhSuRDh39Z1kdYkQVWna+scpgsrD7vSeBI7tmEvsguPDMnfJodW28YBnhv/BzSew==", "dev": true, "requires": { "import-local": "1.0.0", - "jest-cli": "22.4.3" + "jest-cli": "22.4.4" }, "dependencies": { "ansi-regex": { @@ -9220,9 +9357,9 @@ "dev": true }, "jest-cli": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-22.4.3.tgz", - "integrity": "sha512-IiHybF0DJNqZPsbjn4Cy4vcqcmImpoFwNFnkehzVw8lTUSl4axZh5DHewu5bdpZF2Y5gUqFKYzH0FH4Qx2k+UA==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-22.4.4.tgz", + "integrity": "sha512-I9dsgkeyjVEEZj9wrGrqlH+8OlNob9Iptyl+6L5+ToOLJmHm4JwOPatin1b2Bzp5R5YRQJ+oiedx7o1H7wJzhA==", "dev": true, "requires": { "ansi-escapes": "3.1.0", @@ -9237,18 +9374,18 @@ "istanbul-lib-instrument": "1.10.1", "istanbul-lib-source-maps": "1.2.3", "jest-changed-files": "22.4.3", - "jest-config": "22.4.3", + "jest-config": "22.4.4", "jest-environment-jsdom": "22.4.3", "jest-get-type": "22.4.3", "jest-haste-map": "22.4.3", "jest-message-util": "22.4.3", "jest-regex-util": "22.4.3", "jest-resolve-dependencies": "22.4.3", - "jest-runner": "22.4.3", - "jest-runtime": "22.4.3", + "jest-runner": "22.4.4", + "jest-runtime": "22.4.4", "jest-snapshot": "22.4.3", "jest-util": "22.4.3", - "jest-validate": "22.4.3", + "jest-validate": "22.4.4", "jest-worker": "22.4.3", "micromatch": "2.3.11", "node-notifier": "5.2.1", @@ -9282,9 +9419,9 @@ } }, "jest-config": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-22.4.3.tgz", - "integrity": "sha512-KSg3EOToCgkX+lIvenKY7J8s426h6ahXxaUFJxvGoEk0562Z6inWj1TnKoGycTASwiLD+6kSYFALcjdosq9KIQ==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-22.4.4.tgz", + "integrity": "sha512-9CKfo1GC4zrXSoMLcNeDvQBfgtqGTB1uP8iDIZ97oB26RCUb886KkKWhVcpyxVDOUxbhN+uzcBCeFe7w+Iem4A==", "dev": true, "requires": { "chalk": "2.4.1", @@ -9292,11 +9429,11 @@ "jest-environment-jsdom": "22.4.3", "jest-environment-node": "22.4.3", "jest-get-type": "22.4.3", - "jest-jasmine2": "22.4.3", + "jest-jasmine2": "22.4.4", "jest-regex-util": "22.4.3", "jest-resolve": "22.4.3", "jest-util": "22.4.3", - "jest-validate": "22.4.3", + "jest-validate": "22.4.4", "pretty-format": "22.4.3" } }, @@ -9364,9 +9501,9 @@ } }, "jest-jasmine2": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-22.4.3.tgz", - "integrity": "sha512-yZCPCJUcEY6R5KJB/VReo1AYI2b+5Ky+C+JA1v34jndJsRcLpU4IZX4rFJn7yDTtdNbO/nNqg+3SDIPNH2ecnw==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-22.4.4.tgz", + "integrity": "sha512-nK3vdUl50MuH7vj/8at7EQVjPGWCi3d5+6aCi7Gxy/XMWdOdbH1qtO/LjKbqD8+8dUAEH+BVVh7HkjpCWC1CSw==", "dev": true, "requires": { "chalk": "2.4.1", @@ -9459,43 +9596,43 @@ } }, "jest-runner": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-22.4.3.tgz", - "integrity": "sha512-U7PLlQPRlWNbvOHWOrrVay9sqhBJmiKeAdKIkvX4n1G2tsvzLlf77nBD28GL1N6tGv4RmuTfI8R8JrkvCa+IBg==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-22.4.4.tgz", + "integrity": "sha512-5S/OpB51igQW9xnkM5Tgd/7ZjiAuIoiJAVtvVTBcEBiXBIFzWM3BAMPBM19FX68gRV0KWyFuGKj0EY3M3aceeQ==", "dev": true, "requires": { "exit": "0.1.2", - "jest-config": "22.4.3", + "jest-config": "22.4.4", "jest-docblock": "22.4.3", "jest-haste-map": "22.4.3", - "jest-jasmine2": "22.4.3", + "jest-jasmine2": "22.4.4", "jest-leak-detector": "22.4.3", "jest-message-util": "22.4.3", - "jest-runtime": "22.4.3", + "jest-runtime": "22.4.4", "jest-util": "22.4.3", "jest-worker": "22.4.3", "throat": "4.1.0" } }, "jest-runtime": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-22.4.3.tgz", - "integrity": "sha512-Eat/esQjevhx9BgJEC8udye+FfoJ2qvxAZfOAWshYGS22HydHn5BgsvPdTtt9cp0fSl5LxYOFA1Pja9Iz2Zt8g==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-22.4.4.tgz", + "integrity": "sha512-WRTj9m///npte1YjuphCYX7GRY/c2YvJImU9t7qOwFcqHr4YMzmX6evP/3Sehz5DKW2Vi8ONYPCFWe36JVXxfw==", "dev": true, "requires": { "babel-core": "6.26.3", - "babel-jest": "22.4.3", + "babel-jest": "22.4.4", "babel-plugin-istanbul": "4.1.6", "chalk": "2.4.1", "convert-source-map": "1.5.1", "exit": "0.1.2", "graceful-fs": "4.1.11", - "jest-config": "22.4.3", + "jest-config": "22.4.4", "jest-haste-map": "22.4.3", "jest-regex-util": "22.4.3", "jest-resolve": "22.4.3", "jest-util": "22.4.3", - "jest-validate": "22.4.3", + "jest-validate": "22.4.4", "json-stable-stringify": "1.0.1", "micromatch": "2.3.11", "realpath-native": "1.0.0", @@ -9506,28 +9643,28 @@ }, "dependencies": { "babel-jest": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.3.tgz", - "integrity": "sha512-BgSjmtl3mW3i+VeVHEr9d2zFSAT66G++pJcHQiUjd00pkW+voYXFctIm/indcqOWWXw5a1nUpR1XWszD9fJ1qg==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz", + "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==", "dev": true, "requires": { "babel-plugin-istanbul": "4.1.6", - "babel-preset-jest": "22.4.3" + "babel-preset-jest": "22.4.4" } }, "babel-plugin-jest-hoist": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz", - "integrity": "sha512-zhvv4f6OTWy2bYevcJftwGCWXMFe7pqoz41IhMi4xna7xNsX5NygdagsrE0y6kkfuXq8UalwvPwKTyAxME2E/g==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz", + "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==", "dev": true }, "babel-preset-jest": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.3.tgz", - "integrity": "sha512-a+M3LTEXTq3gxv0uBN9Qm6ahUl7a8pj923nFbCUdqFUSsf3YrX8Uc+C3MEwji5Af3LiQjSC7w4ooYewlz8HRTA==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz", + "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "22.4.3", + "babel-plugin-jest-hoist": "22.4.4", "babel-plugin-syntax-object-rest-spread": "6.13.0" } } @@ -9577,13 +9714,13 @@ } }, "jest-validate": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-22.4.3.tgz", - "integrity": "sha512-CfFM18W3GSP/xgmA4UouIx0ljdtfD2mjeBC6c89Gg17E44D4tQhAcTrZmf9djvipwU30kSTnk6CzcxdCCeSXfA==", + "version": "22.4.4", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-22.4.4.tgz", + "integrity": "sha512-dmlf4CIZRGvkaVg3fa0uetepcua44DHtktHm6rcoNVtYlpwe6fEJRkMFsaUVcFHLzbuBJ2cPw9Gl9TKfnzMVwg==", "dev": true, "requires": { "chalk": "2.4.1", - "jest-config": "22.4.3", + "jest-config": "22.4.4", "jest-get-type": "22.4.3", "leven": "2.1.0", "pretty-format": "22.4.3" @@ -9604,9 +9741,9 @@ "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" }, "js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz", + "integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==", "dev": true }, "js-cookie": { @@ -9737,7 +9874,7 @@ "nwmatcher": "1.4.4", "parse5": "4.0.0", "pn": "1.1.0", - "request": "2.86.0", + "request": "2.87.0", "request-promise-native": "1.0.5", "sax": "1.2.4", "symbol-tree": "3.2.2", @@ -9767,7 +9904,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "dev": true, "requires": { "hoek": "4.2.1" } @@ -9782,7 +9918,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "dev": true, "requires": { "boom": "5.2.0" }, @@ -9791,7 +9926,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "dev": true, "requires": { "hoek": "4.2.1" } @@ -9823,7 +9957,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "dev": true, "requires": { "boom": "4.3.1", "cryptiles": "3.1.2", @@ -9834,8 +9967,7 @@ "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "dev": true + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" }, "http-signature": { "version": "1.2.0", @@ -9861,9 +9993,9 @@ "dev": true }, "request": { - "version": "2.86.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.86.0.tgz", - "integrity": "sha512-BQZih67o9r+Ys94tcIW4S7Uu8pthjrQVxhsZ/weOwHbDfACxvIyvnAbzFQxjy1jMtvFSzv5zf4my6cZsJBbVzw==", + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "dev": true, "requires": { "aws-sign2": "0.7.0", @@ -9874,7 +10006,6 @@ "forever-agent": "0.6.1", "form-data": "2.3.2", "har-validator": "5.0.3", - "hawk": "6.0.2", "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", @@ -9893,7 +10024,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "dev": true, "requires": { "hoek": "4.2.1" } @@ -10703,15 +10833,15 @@ } }, "marked": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", - "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz", + "integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==", "dev": true }, "marked-terminal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-2.0.0.tgz", - "integrity": "sha1-Xq9Wi+ZvaGVBr6UqVYKAMQox3i0=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-3.0.0.tgz", + "integrity": "sha512-7gWHPxQlWNeqjVgW72gwxLeJBj0T/RmurVs2qHPm90f7kuu7CMcZVTmtqk1dogourkAtopZNnp2DUpTIJZKZ4w==", "dev": true, "requires": { "cardinal": "1.0.0", @@ -10840,8 +10970,21 @@ "ignore": "3.3.8", "pify": "3.0.0", "slash": "1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, "replace-ext": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", @@ -10891,11 +11034,48 @@ "trim-newlines": "2.0.0" }, "dependencies": { + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "map-obj": "2.0.0", + "quick-lru": "1.1.0" + } + }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "3.0.0" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "3.2.0", + "strip-indent": "2.0.0" + } + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true } } }, @@ -11376,7 +11556,7 @@ "async-foreach": "0.1.3", "chalk": "1.1.3", "cross-spawn": "3.0.1", - "gaze": "1.1.2", + "gaze": "1.1.3", "get-stdin": "4.0.1", "glob": "7.1.2", "in-publish": "2.0.0", @@ -11595,7 +11775,7 @@ "mime-types": "2.1.18", "oauth-sign": "0.8.2", "qs": "6.3.2", - "stringstream": "0.0.5", + "stringstream": "0.0.6", "tough-cookie": "2.3.4", "tunnel-agent": "0.4.3", "uuid": "3.2.1" @@ -12083,6 +12263,18 @@ "dev": true, "requires": { "url-parse": "1.4.0" + }, + "dependencies": { + "url-parse": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.0.tgz", + "integrity": "sha512-ERuGxDiQ6Xw/agN4tuoCRbmwRuZP0cJ1lJxJubXr5Q/5cDa78+Dc4wfvtxzhzhkm5VvmW6Mf8EVj9SPGN4l8Lg==", + "dev": true, + "requires": { + "querystringify": "2.0.0", + "requires-port": "1.0.0" + } + } } }, "os-browserify": { @@ -12343,7 +12535,7 @@ "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", "dev": true, "requires": { - "@types/node": "10.1.0" + "@types/node": "10.1.2" } }, "parseurl": { @@ -12570,7 +12762,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -12643,7 +12835,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -12715,7 +12907,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -12786,7 +12978,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -12857,7 +13049,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -12928,7 +13120,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -12999,7 +13191,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13071,7 +13263,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13143,7 +13335,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13384,7 +13576,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13455,7 +13647,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13502,8 +13694,8 @@ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", "dev": true, "requires": { - "caniuse-db": "1.0.30000841", - "electron-to-chromium": "1.3.46" + "caniuse-db": "1.0.30000844", + "electron-to-chromium": "1.3.47" } }, "chalk": { @@ -13540,7 +13732,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13619,7 +13811,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13691,7 +13883,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13765,7 +13957,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13839,7 +14031,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -13949,7 +14141,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14023,7 +14215,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14095,7 +14287,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14166,7 +14358,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14248,7 +14440,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14319,7 +14511,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14392,7 +14584,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14486,7 +14678,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14559,7 +14751,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14638,7 +14830,7 @@ "dev": true, "requires": { "chalk": "1.1.3", - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.5.7", "supports-color": "3.2.3" } @@ -14918,7 +15110,17 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true + "dev": true, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + } + } }, "kind-of": { "version": "6.0.2", @@ -15643,7 +15845,7 @@ "node-uuid": "1.4.8", "oauth-sign": "0.8.2", "qs": "6.3.2", - "stringstream": "0.0.5", + "stringstream": "0.0.6", "tough-cookie": "2.3.4", "tunnel-agent": "0.4.3" } @@ -16478,7 +16680,7 @@ "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "dev": true, "requires": { - "js-base64": "2.4.3", + "js-base64": "2.4.5", "source-map": "0.4.4" }, "dependencies": { @@ -16509,19 +16711,19 @@ } }, "semantic-release": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-15.4.1.tgz", - "integrity": "sha512-mUAjrB39e/D720kDZFPrKEHukwsUnr8kLgXQXexjGbsmTt3RheBOIeIH7j4yKqyn/gDJb6MxMLfeU6Yu22z92w==", + "version": "15.4.4", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-15.4.4.tgz", + "integrity": "sha512-6NJjFwrZ8xpgz43EOqDkVxZVyI5MelWmzwdgdoLuklkRbUCL91+KAvIrU0nA4iuanYlXFJVFIsFdL5W0e2m/EA==", "dev": true, "requires": { "@semantic-release/commit-analyzer": "5.0.3", "@semantic-release/error": "2.2.0", "@semantic-release/github": "4.2.16", - "@semantic-release/npm": "3.2.5", + "@semantic-release/npm": "3.3.0", "@semantic-release/release-notes-generator": "6.0.10", "aggregate-error": "1.0.0", "chalk": "2.4.1", - "cosmiconfig": "5.0.3", + "cosmiconfig": "5.0.4", "debug": "3.1.0", "env-ci": "2.1.0", "execa": "0.10.0", @@ -16531,8 +16733,8 @@ "hook-std": "0.4.0", "hosted-git-info": "2.6.0", "lodash": "4.17.10", - "marked": "0.3.19", - "marked-terminal": "2.0.0", + "marked": "0.4.0", + "marked-terminal": "3.0.0", "p-locate": "2.0.0", "p-reduce": "1.0.0", "read-pkg-up": "3.0.0", @@ -16559,9 +16761,9 @@ } }, "cosmiconfig": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.3.tgz", - "integrity": "sha512-x7vMpNH5favpvFjxwSzfQkB5ozdxikcmWzxah9aOh8BCOKeR+j6TM6PxQ2zyMm3+EDZcSajQrzzPKrsVqbsUDA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.4.tgz", + "integrity": "sha512-AmWciHfzwEOUI+4jeXJap/E3Apebr7FZIGBqjzkID+lnIPTMMSNN6WM4o6q4EX1u+5fgcP7G3rEzxSe0FTqtIw==", "dev": true, "requires": { "is-directory": "0.3.1", @@ -17395,9 +17597,9 @@ } }, "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", "dev": true }, "strip-ansi": { @@ -18213,9 +18415,9 @@ "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==" }, "uglify-js": { - "version": "3.3.25", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.25.tgz", - "integrity": "sha512-hobogryjDV36VrLK3Y69ou4REyrTApzUblVFmdQOYRe8cYaSmFJXMb4dR9McdvYDSbeNdzUgYr2YVukJaErJcA==", + "version": "3.3.26", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.26.tgz", + "integrity": "sha512-XHxutZNxbx0UnqNUrjL/wvABLxirEYpbAnjCWGakPfQRJbbAGF2dI+YYw300F5mYKm7zBtgYiw3kOiQFobzglQ==", "dev": true, "requires": { "commander": "2.15.1", @@ -18408,9 +18610,9 @@ } }, "untildify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", - "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", "dev": true }, "upath": { @@ -18480,6 +18682,14 @@ "requires": { "querystringify": "2.0.0", "requires-port": "1.0.0" + }, + "dependencies": { + "querystringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", + "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", + "dev": true + } } }, "url-parse-lax": { @@ -20512,7 +20722,7 @@ "mem-fs": "1.1.3", "strip-ansi": "4.0.0", "text-table": "0.2.0", - "untildify": "3.0.2" + "untildify": "3.0.3" }, "dependencies": { "ansi-regex": { @@ -20556,6 +20766,14 @@ "ignore": "3.3.8", "pify": "3.0.0", "slash": "1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "inquirer": { @@ -20579,6 +20797,11 @@ "through": "2.3.8" } }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -20596,7 +20819,7 @@ "integrity": "sha512-rV6tJ8oYzm4mmdF2T3wjY+Q42jKF2YiiD0VKfJ8/0ZYwmhCKC9Xs2346HVLPj/xE13i68psnFJv7iS6gWRkeAg==", "dev": true, "requires": { - "async": "2.6.0", + "async": "2.6.1", "chalk": "2.4.1", "cli-table": "0.3.1", "cross-spawn": "6.0.5", diff --git a/src/components/AssetsClearFiltersButton/AssetsClearFiltersButton.test.jsx b/src/components/AssetsClearFiltersButton/AssetsClearFiltersButton.test.jsx index 0c4d84ac..d9249402 100644 --- a/src/components/AssetsClearFiltersButton/AssetsClearFiltersButton.test.jsx +++ b/src/components/AssetsClearFiltersButton/AssetsClearFiltersButton.test.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { Button } from '@edx/paragon'; import AssetsClearFiltersButton from './index'; -import courseDetails from '../../utils/testConstants'; +import { courseDetails } from '../../utils/testConstants'; import { shallowWithIntl } from '../../utils/i18n/enzymeHelper'; import WrappedMessage from '../../utils/i18n/formattedMessageWrapper'; import messages from './displayMessages'; diff --git a/src/components/AssetsClearSearchButton/AssetsClearSearchButton.test.jsx b/src/components/AssetsClearSearchButton/AssetsClearSearchButton.test.jsx index 694fe393..b235a826 100644 --- a/src/components/AssetsClearSearchButton/AssetsClearSearchButton.test.jsx +++ b/src/components/AssetsClearSearchButton/AssetsClearSearchButton.test.jsx @@ -2,7 +2,7 @@ import { Button } from '@edx/paragon'; import React from 'react'; import AssetsClearSearchButton from './index'; -import courseDetails from '../../utils/testConstants'; +import { courseDetails } from '../../utils/testConstants'; import messages from './displayMessages'; import { shallowWithIntl } from '../../utils/i18n/enzymeHelper'; import WrappedMessage from '../../utils/i18n/formattedMessageWrapper'; diff --git a/src/components/AssetsDropZone/AssetsDropZone.test.jsx b/src/components/AssetsDropZone/AssetsDropZone.test.jsx index 3cdbcf43..109865a4 100644 --- a/src/components/AssetsDropZone/AssetsDropZone.test.jsx +++ b/src/components/AssetsDropZone/AssetsDropZone.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; import AssetsDropZone from './index'; -import courseDetails from '../../utils/testConstants'; +import { courseDetails } from '../../utils/testConstants'; import { mountWithIntl } from '../../utils/i18n/enzymeHelper'; const defaultProps = { diff --git a/src/components/AssetsList/AssetsList.test.jsx b/src/components/AssetsList/AssetsList.test.jsx index 69a1233a..aba734db 100644 --- a/src/components/AssetsList/AssetsList.test.jsx +++ b/src/components/AssetsList/AssetsList.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; import AssetsList from './index'; -import courseDetails, { testAssetsList } from '../../utils/testConstants'; +import { courseDetails, testAssetsList } from '../../utils/testConstants'; import messages from './displayMessages'; import { mountWithIntl } from '../../utils/i18n/enzymeHelper'; import { paginationInitial, selectInitial } from '../../data/reducers/assets'; diff --git a/src/components/AssetsPage/AssetsPage.test.jsx b/src/components/AssetsPage/AssetsPage.test.jsx index 110198be..9f39bda5 100644 --- a/src/components/AssetsPage/AssetsPage.test.jsx +++ b/src/components/AssetsPage/AssetsPage.test.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { assetActions } from '../../data/constants/actionTypes'; import AssetsPage, { TABLE_CONTENTS_ID } from './index'; -import courseDetails, { testAssetsList } from '../../utils/testConstants'; +import { courseDetails, testAssetsList } from '../../utils/testConstants'; import messages from './displayMessages'; import { pageTypes } from '../../utils/getAssetsPageType'; import { shallowWithIntl } from '../../utils/i18n/enzymeHelper'; diff --git a/src/components/AssetsPage/index.jsx b/src/components/AssetsPage/index.jsx index 3e907d1d..e4185f35 100644 --- a/src/components/AssetsPage/index.jsx +++ b/src/components/AssetsPage/index.jsx @@ -114,11 +114,11 @@ export default class AssetsPage extends React.Component { > - { this.renderAssetsDropZone() } + {this.renderAssetsDropZone()}
- { this.renderAssetsFilters() } + {this.renderAssetsFilters()}
@@ -143,10 +143,10 @@ export default class AssetsPage extends React.Component { renderNoAssetsPage = () => (
- { this.renderAssetsDropZone() } + {this.renderAssetsDropZone()}
- { this.renderNoAssetsBody() } + {this.renderNoAssetsBody()}
); @@ -161,11 +161,11 @@ export default class AssetsPage extends React.Component { renderNoResultsPage = () => (
- { this.renderAssetsDropZone() } - { this.renderAssetsFilters() } + {this.renderAssetsDropZone()} + {this.renderAssetsFilters()}
- { this.renderNoResultsBody() } + {this.renderNoResultsBody()}
); @@ -173,8 +173,8 @@ export default class AssetsPage extends React.Component { renderSkeletonPage = () => (
- { this.renderAssetsDropZone() } - { this.renderAssetsFilters() } + {this.renderAssetsDropZone()} + {this.renderAssetsFilters()}
); @@ -200,7 +200,7 @@ export default class AssetsPage extends React.Component {
)} - { this.getPage(this.state.pageType) } + {this.getPage(this.state.pageType)} ); diff --git a/src/components/AssetsTable/AssetsTable.test.jsx b/src/components/AssetsTable/AssetsTable.test.jsx index 8018e7d8..4e6f8ac1 100644 --- a/src/components/AssetsTable/AssetsTable.test.jsx +++ b/src/components/AssetsTable/AssetsTable.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; import AssetsTable from './index'; -import courseDetails, { testAssetsList } from '../../utils/testConstants'; +import { courseDetails, testAssetsList } from '../../utils/testConstants'; import { assetActions } from '../../data/constants/actionTypes'; import { assetLoading } from '../../data/constants/loadingTypes'; import mockQuerySelector from '../../utils/mockQuerySelector'; diff --git a/src/components/EditImageModal/EditImageModal.test.jsx b/src/components/EditImageModal/EditImageModal.test.jsx index 5a0d20e8..8f999811 100644 --- a/src/components/EditImageModal/EditImageModal.test.jsx +++ b/src/components/EditImageModal/EditImageModal.test.jsx @@ -1,14 +1,15 @@ -import { Button, CheckBox, Fieldset, Modal, InputText, StatusAlert } from '@edx/paragon'; +import { Button, CheckBox, Fieldset, Modal, InputText, StatusAlert, Variant } from '@edx/paragon'; import { IntlProvider, FormattedMessage } from 'react-intl'; import { Provider } from 'react-redux'; import React from 'react'; -import EditImageModal from './index'; import { assetActions } from '../../data/constants/actionTypes'; -import { getMockStore } from '../../utils/testConstants'; +import { courseDetails, getMockStore, testAssetsList } from '../../utils/testConstants'; +import EditImageModal from './index'; import messages from './displayMessages'; import mockModalPortal from '../../utils/mockModalPortal'; import mockQuerySelector from '../../utils/mockQuerySelector'; +import { pageTypes } from '../../utils/getAssetsPageType'; import rewriteStaticLinks from '../../utils/rewriteStaticLinks'; import { shallowWithIntl } from '../../utils/i18n/enzymeHelper'; import WrappedEditImageModal from './container'; @@ -27,9 +28,11 @@ const { intl } = intlProvider.getChildContext(); const getEditImageModal = wrapper => (wrapper.find('Connect(EditImageModal)').dive({ context: { store, intl } }).find(EditImageModal).dive({ context: { store, intl } })); -const getModal = editImageModal => (editImageModal.find(Modal).dive({ context: { store, intl } })); -const getModalBody = editImageModal => (getModal(editImageModal).find('.modal-body')); -const getModalFooter = editImageModal => (getModal(editImageModal).find('.modal-footer')); +const getModal = editImageModal => (editImageModal.find(Modal)); +const getModalContent = editImageModal => + (getModal(editImageModal).dive({ context: { store, intl } })); +const getModalBody = editImageModal => (getModalContent(editImageModal).find('.modal-body')); +const getModalFooter = editImageModal => (getModalContent(editImageModal).find('.modal-footer')); const getFormContainer = editImageModal => (getModalBody(editImageModal).find('div.col form')); const getStatusAlert = editImageModal => (getModalBody(editImageModal).find(StatusAlert)); const getCloseStatusAlertButton = editImageModal => @@ -59,6 +62,8 @@ const getImageDimensionsHeightInput = editImageModal => const getImageDimensionsCheckBox = editImageModal => (getImageDimensionsFieldset(editImageModal).dive({ context: { store, intl } }).find(CheckBox)); +const getNextPageButton = editImageModal => (getModalFooter(editImageModal).find(Button).first()); + const wrapper = shallowWithIntl( @@ -89,238 +94,505 @@ describe('EditImageModal', () => { mockQuerySelector.reset(); }); - describe('page 1 renders', () => { - describe('a modal with', () => { - it('a closed modal by default', () => { - const modal = getModal(editImageModal); - expect(modal.find('.modal')).toHaveLength(1); - expect(modal.find('.modal.show')).toHaveLength(0); - expect(modal.find('.modal-backdrop.show')).toHaveLength(0); - }); - - it('an open modal when this.state.isModalOpen is true', () => { - editImageModal.setState({ isModalOpen: true }); - const modal = getModal(editImageModal); + describe('renders', () => { + describe('page 1', () => { + describe('a modal with', () => { + it('correct initial props', () => { + const modal = getModal(editImageModal); + expect(modal.prop('open')).toEqual(false); + expect(shallowWithIntl(modal.prop('title')).find(WrappedMessage).prop('message')).toEqual(messages.editImageModalInsertTitle); + expect(shallowWithIntl(modal.prop('closeText')).prop('message')).toEqual(messages.editImageModalCancelButton); + }); - expect(modal.find('.modal')).toHaveLength(1); - expect(modal.find('.modal.show')).toHaveLength(1); - expect(modal.find('.modal-backdrop.show')).toHaveLength(1); - }); + describe('buttons', () => { + Object.values(pageTypes).forEach((type) => { + beforeEach(() => { + editImageModal.setState({ + assetsPageType: type, + }); + }); - it('modal title text', () => { - const modalTitle = getModal(editImageModal).find('.modal-title').find(WrappedMessage); - expect(modalTitle.prop('message')).toEqual(messages.editImageModalInsertTitle); - }); + it('a Next page button', () => { + expect(getNextPageButton(editImageModal)).toHaveLength(1); + }); - it('a Next page button', () => { - const nextPageButton = getModal(editImageModal).find('.modal-footer').find(Button).first(); - expect(nextPageButton).toHaveLength(1); + it('a Next page button with correct label', () => { + const nextPageButton = getNextPageButton(editImageModal); - const nextPageButtonText = nextPageButton - .dive({ context: { store, intl } }).find(WrappedMessage); - expect(nextPageButtonText.prop('message')).toEqual(messages.editImageModalNextPageButton); - }); - }); + const nextPageButtonText = shallowWithIntl(nextPageButton.prop('label')); + expect(nextPageButtonText.prop('message')).toEqual(messages.editImageModalNextPageButton); + }); - describe('a modal body with', () => { - describe('a status alert with', () => { - it('a status alert', () => { - expect(getStatusAlert(editImageModal)).toHaveLength(1); - }); + it('a disabled Next page button', () => { + const nextPageButton = getNextPageButton(editImageModal); - it('a status alert with danger alertType', () => { - expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); - }); - }); - }); - }); + expect(nextPageButton.prop('disabled')).toEqual(true); + }); - describe('page 2 renders', () => { - beforeEach(() => { - editImageModal.setState({ - open: true, - pageNumber: 2, - shouldShowPreviousButton: true, - }); - }); + it('a not disabled Next page button when asset selected', () => { + editImageModal.setProps({ + selectedAsset: testAssetsList[0], + }); - describe('a modal with', () => { - it('modal title text', () => { - const modalTitle = getModal(editImageModal).find('.modal-title').find(WrappedMessage); - expect(modalTitle.prop('message')).toEqual(messages.editImageModalEditTitle); - }); + const nextPageButton = getNextPageButton(editImageModal); - it('an Insert Image button', () => { - const insertImageButton = getInsertImageButton(editImageModal); - expect(insertImageButton).toHaveLength(1); + expect(nextPageButton.prop('disabled')).toEqual(false); + }); + }); + }); - const insertImageButtonText = insertImageButton.dive({ context: { store, intl } }) - .find(WrappedMessage); - expect(insertImageButtonText.prop('message')).toEqual(messages.editImageModalInsertImageButton); - }); - }); + describe('body', () => { + it('getImageSelectionModalBodyAssetsList throws an Error for an unknown page type', () => { + expect(() => editImageModal.instance().getImageSelectionModalBodyAssetsList(sampleText)) + .toThrow(Error); + expect(() => editImageModal.instance().getImageSelectionModalBodyAssetsList(sampleText)) + .toThrow(`Unknown pageType ${sampleText}.`); + }); - describe('a modal body with', () => { - describe('a status alert with', () => { - it('a status alert', () => { - expect(getStatusAlert(editImageModal)).toHaveLength(1); - }); + describe('skeleton page view with', () => { + it('a StatusAlert component', () => { + expect(getStatusAlert(editImageModal)).toHaveLength(1); + }); - it('a status alert with danger alertType', () => { - expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); - }); - }); - }); + it('a StatusAlert component with danger alertType prop', () => { + expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); + }); - describe('a form with', () => { - it('a form', () => { - expect(getFormContainer(editImageModal)).toHaveLength(1); - }); + it('an AssetsDropZone component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsDropZone)')).toHaveLength(1); + }); - describe('an imageDescription Fieldset with', () => { - it('a fieldset', () => { - expect(getImageDescriptionFieldset(editImageModal)).toHaveLength(1); - }); + it('a header', () => { + const header = getModalBody(editImageModal).find(WrappedMessage).filterWhere(message => message.prop('tagName') === 'h3'); + expect(header).toHaveLength(1); + expect(header.prop('message')).toEqual(messages.editImageModalInsertHeader); + }); - it('a legend', () => { - const imageDescriptionFieldsetLegend = getImageDescriptionFieldset(editImageModal).prop('legend'); - expect(imageDescriptionFieldsetLegend.props.message) - .toEqual(messages.editImageModalImageDescriptionLegend); - }); + it('a loading spinner', () => { + const loadingSpinnerRegion = getModalBody(editImageModal).find('.text-center .mt-3'); + expect(loadingSpinnerRegion).toHaveLength(1); - it('an InputText', () => { - expect(getImageDescriptionInput(editImageModal)).toHaveLength(1); - }); + const loadingSpinner = loadingSpinnerRegion.find('.fa-icon-spacing'); + expect(loadingSpinner).toHaveLength(1); + expect(loadingSpinner.prop('aria-hidden')).toEqual(true); - describe('an imageDescription input with', () => { - it('a label', () => { - const imageDescriptionInputLabel = getImageDescriptionInput(editImageModal).prop('label'); - expect(imageDescriptionInputLabel.props.message) - .toEqual(messages.editImageModalImageDescriptionLabel); - }); + const loadingSpinnerIcon = loadingSpinner.children().find('span'); + expect(loadingSpinnerIcon.hasClass('fa')).toEqual(true); + expect(loadingSpinnerIcon.hasClass('fa-spinner')).toEqual(true); + expect(loadingSpinnerIcon.hasClass('fa-spin')).toEqual(true); - it('a description', () => { - const imageDescriptionInputDescription = getImageDescriptionInput(editImageModal).prop('description'); + expect(loadingSpinnerRegion.find(WrappedMessage).prop('message')).toEqual(messages.editImageModalAssetsListLoadingSpinner); + }); - expect(imageDescriptionInputDescription.props.children[0].props.message) - .toEqual(messages.editImageModalImageDescriptionDescription); - expect(imageDescriptionInputDescription.props.children[1]).toEqual(' '); - expect(imageDescriptionInputDescription.props.children[2].props.message) - .toEqual(messages.editImageModalLearnMore); - }); + it('no AssetsList component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsList)')).toHaveLength(0); + }); - it('a Learn More link', () => { - const imageDescriptionInputDescription = getImageDescriptionInput(editImageModal).prop('description'); - expect(imageDescriptionInputDescription.props.children[2].props.children().type).toEqual('a'); - expect(imageDescriptionInputDescription.props.message).toEqual(messages.learnMoreLink); - }); + it('no AssetsSearch component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsSearch)')).toHaveLength(0); + }); - it('a correct InputText props', () => { - const imageDescriptionInput = getImageDescriptionInput(editImageModal); - expect(imageDescriptionInput.prop('type')).toEqual('text'); - expect(imageDescriptionInput.prop('id')).toEqual('imageDescription'); - }); - }); + it('no AssetsResultsCount component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsResultsCount)')).toHaveLength(0); + }); - describe('a CheckBox with', () => { - it('a CheckBox', () => { - expect(getImageDescriptionInputCheckBox(editImageModal)).toHaveLength(1); - }); - it('correct CheckBox props', () => { - const imageDescriptionInputCheckBox = getImageDescriptionInputCheckBox(editImageModal); - expect(imageDescriptionInputCheckBox.prop('id')).toEqual('isDecorative'); - expect(imageDescriptionInputCheckBox.prop('name')).toEqual('isDecorative'); + it('no Pagination component', () => { + expect(getModalBody(editImageModal).find('Connect(Pagination)')).toHaveLength(0); + }); }); - it('a label', () => { - const imageDescriptionInputCheckBoxLabel = getImageDescriptionInputCheckBox(editImageModal).prop('label'); - expect(imageDescriptionInputCheckBoxLabel.props.message) - .toEqual(messages.editImageModalImageIsDecorativeCheckboxLabel); + describe('a normal page view with', () => { + beforeEach(() => { + editImageModal.setProps({ + assetsList: testAssetsList, + }); + }); + + it('a StatusAlert component', () => { + expect(getStatusAlert(editImageModal)).toHaveLength(1); + }); + + it('a StatusAlert component with danger alertType prop', () => { + expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); + }); + + it('an AssetsDropZone component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsDropZone)')).toHaveLength(1); + }); + + it('a header', () => { + const header = getModalBody(editImageModal).find(WrappedMessage).filterWhere(message => message.prop('tagName') === 'h3'); + expect(header).toHaveLength(1); + expect(header.prop('message')).toEqual(messages.editImageModalInsertHeader); + }); + + it('an AssetsList component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsList)')).toHaveLength(1); + }); + + it('an AssetsSearch component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsSearch)')).toHaveLength(1); + }); + + it('no AssetsClearSearchButton component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsClearSearchButton)')).toHaveLength(0); + }); + + it('a AssetsResultsCount component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsResultsCount)')).toHaveLength(1); + }); + + it('a Pagination component', () => { + expect(getModalBody(editImageModal).find('Connect(Pagination)')).toHaveLength(1); + }); }); - it('a description', () => { - const imageDescriptionInputCheckBoxDescription = getImageDescriptionInputCheckBox(editImageModal).prop('description'); - expect(imageDescriptionInputCheckBoxDescription.props.children[0].props.message) - .toEqual(messages.editImageModalImageIsDecorativeCheckboxDescription); - expect(imageDescriptionInputCheckBoxDescription.props.children[1]).toEqual(' '); - expect(imageDescriptionInputCheckBoxDescription.props.children[2].props.message) - .toEqual(messages.editImageModalLearnMore); + describe('no results page view with', () => { + beforeEach(() => { + editImageModal.setState({ + assetsPageType: pageTypes.NO_RESULTS, + }); + }); + it('a StatusAlert component', () => { + expect(getStatusAlert(editImageModal)).toHaveLength(1); + }); + + it('a StatusAlert component with danger alertType prop', () => { + expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); + }); + + it('an AssetsDropZone component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsDropZone)')).toHaveLength(1); + }); + + it('a header', () => { + const header = getModalBody(editImageModal).find(WrappedMessage).filterWhere(message => message.prop('tagName') === 'h3').at(0); + expect(header).toHaveLength(1); + expect(header.prop('message')).toEqual(messages.editImageModalInsertHeader); + }); + + it('a no results message', () => { + expect(getModalBody(editImageModal).find(WrappedMessage).filterWhere(message => message.prop('tagName') === 'h3').at(1) + .prop('message')).toEqual(messages.editImageModalAssetsListNoResultsMessage); + }); + + it('no AssetsList component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsList)')).toHaveLength(0); + }); + + it('an AssetsSearch component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsSearch)')).toHaveLength(1); + }); + + it('an AssetsClearSearchButton component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsClearSearchButton)')).toHaveLength(1); + }); + + it('no AssetsResultsCount component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsResultsCount)')).toHaveLength(0); + }); + + it('no Pagination component', () => { + expect(getModalBody(editImageModal).find('Connect(Pagination)')).toHaveLength(0); + }); }); - it('a "Learn more." link', () => { - const imageDescriptionInputCheckBoxDescription = getImageDescriptionInputCheckBox(editImageModal).prop('description'); - expect(imageDescriptionInputCheckBoxDescription.props.children[2].props.children().type).toEqual('a'); - expect(imageDescriptionInputCheckBoxDescription.props.message) - .toEqual(messages.learnMoreLink); + describe('no assets page view with', () => { + beforeEach(() => { + editImageModal.setState({ + assetsPageType: pageTypes.NO_ASSETS, + }); + }); + + it('a StatusAlert component', () => { + expect(getStatusAlert(editImageModal)).toHaveLength(1); + }); + + it('a StatusAlert component with danger alertType prop', () => { + expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); + }); + + it('an AssetsDropZone component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsDropZone)')); + }); + + it('a header', () => { + const header = getModalBody(editImageModal).find(WrappedMessage).filterWhere(message => message.prop('tagName') === 'h3').at(0); + expect(header).toHaveLength(1); + expect(header.prop('message')).toEqual(messages.editImageModalInsertHeader); + }); + + it('a no assets message', () => { + expect(getModalBody(editImageModal).find(WrappedMessage).filterWhere(message => message.prop('tagName') === 'h3').at(1) + .prop('message')).toEqual(messages.editImageModalAssetsListNoAssetsMessage); + }); + + it('no AssetsList component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsList)')).toHaveLength(0); + }); + + it('no AssetsSearch component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsSearch)')).toHaveLength(0); + }); + + it('no AssetsClearSearchButton component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsClearSearchButton)')).toHaveLength(0); + }); + + it('no AssetsResultsCount component', () => { + expect(getModalBody(editImageModal).find('Connect(AssetsResultsCount)')).toHaveLength(0); + }); + + it('no Pagination component', () => { + expect(getModalBody(editImageModal).find('Connect(Pagination)')).toHaveLength(0); + }); }); }); }); + }); - describe('an imageDimensions Fieldset with', () => { - it('a fieldset', () => { - expect(getImageDimensionsFieldset(editImageModal)).toHaveLength(1); + describe('page 2', () => { + describe('a modal with', () => { + beforeEach(() => { + editImageModal.setState({ + open: true, + pageNumber: 2, + shouldShowPreviousButton: true, + }); }); - it('a legend', () => { - const imageDimensionsFieldsetLegend = getImageDimensionsFieldset(editImageModal).prop('legend'); - expect(imageDimensionsFieldsetLegend.props.message) - .toEqual(messages.editImageModalDimensionsLegend); - }); + it('correct initial props', () => { + editImageModal.setState({ + open: false, + }); - it('a form-row', () => { - expect(getImageDimensionsFieldset(editImageModal).find('div.form-row')).toHaveLength(1); - }); + const modal = getModal(editImageModal); - describe('an imageDimensionsWidth input with', () => { - it('a width InputText', () => { - expect(getImageDimensionsWidthInput(editImageModal)).toHaveLength(1); - }); + expect(modal.prop('open')).toEqual(false); + expect(shallowWithIntl(modal.prop('title')).find(WrappedMessage).prop('message')).toEqual(messages.editImageModalEditTitle); + expect(shallowWithIntl(modal.prop('closeText')).prop('message')).toEqual(messages.editImageModalCancelButton); + }); - it('a width label', () => { - const imageWidthInputLabel = getImageDimensionsWidthInput(editImageModal).prop('label'); - expect(imageWidthInputLabel.props.message) - .toEqual(messages.editImageModalImageWidthLabel); + describe('buttons', () => { + it('an Insert Image button', () => { + expect(getInsertImageButton(editImageModal)).toHaveLength(1); }); - it('correct width InputText props', () => { - const imageDimensionsWidthInput = getImageDimensionsWidthInput(editImageModal); - expect(imageDimensionsWidthInput.prop('type')).toEqual('number'); - expect(imageDimensionsWidthInput.prop('id')).toEqual('imageWidth'); + it('an Insert Image button with correct label', () => { + expect(shallowWithIntl(getInsertImageButton(editImageModal).prop('label')).prop('message')).toEqual(messages.editImageModalInsertImageButton); }); }); - describe('an imageDimensionsHeight input with', () => { - it('a height InputText', () => { - expect(getImageDimensionsHeightInput(editImageModal)).toHaveLength(1); + describe('body', () => { + it('a StatusAlert component', () => { + expect(getStatusAlert(editImageModal)).toHaveLength(1); }); - it('a height label', () => { - const imageHeightInputLabel = getImageDimensionsHeightInput(editImageModal).prop('label'); - expect(imageHeightInputLabel.props.message) - .toEqual(messages.editImageModalImageHeightLabel); + it('a StatusAlert component with correct initial props', () => { + expect(getStatusAlert(editImageModal).prop('alertType')).toEqual('danger'); + const statusAlertDialog = shallowWithIntl(getStatusAlert(editImageModal).prop('dialog')).find(WrappedMessage).at(0); + expect(statusAlertDialog.prop('message')).toEqual(messages.editImageModalFormErrorMissingFields); + expect(getStatusAlert(editImageModal).prop('open')).toEqual(false); }); - it('correct height InputText props', () => { - const imageDimensionsHeightInput = getImageDimensionsHeightInput(editImageModal); - expect(imageDimensionsHeightInput.prop('type')).toEqual('number'); - expect(imageDimensionsHeightInput.prop('id')).toEqual('imageHeight'); + it('a previous page button when this.state.shouldShowPreviousButton', () => { + expect(getModalBody(editImageModal).find(Button)).toHaveLength(1); }); - }); - describe('an imageDimensionsHeight input with', () => { - it('a CheckBox', () => { - expect(getImageDimensionsCheckBox(editImageModal)).toHaveLength(1); + it('a previous page button with correct props', () => { + const previousButton = getModalBody(editImageModal).find(Button); + expect(previousButton).toHaveLength(1); + expect(shallowWithIntl(previousButton.prop('label')).prop('message')).toEqual(messages.editImageModalPreviousPageButton); + expect(previousButton.prop('buttonType')).toEqual('link'); }); - it('correct CheckBox props', () => { - const imageDimensionsInputCheckBox = getImageDimensionsCheckBox(editImageModal); - expect(imageDimensionsInputCheckBox.prop('id')).toEqual('lockProportions'); - expect(imageDimensionsInputCheckBox.prop('name')).toEqual('lockProportions'); + + it('no previous page button when not this.state.shouldShowPreviousButton', () => { + editImageModal.setState({ + shouldShowPreviousButton: false, + }); + + expect(getModalBody(editImageModal).find(Button)).toHaveLength(0); }); - it('a label', () => { - const imageDimensionsInputCheckBoxLabel = getImageDimensionsCheckBox(editImageModal).prop('label'); - expect(imageDimensionsInputCheckBoxLabel.props.message) - .toEqual(messages.editImageModalLockImageProportionsCheckboxLabel); + + describe('a form with', () => { + it('a form', () => { + expect(getFormContainer(editImageModal)).toHaveLength(1); + }); + + describe('an imageDescription Fieldset with', () => { + describe('a Fieldset with', () => { + it('a Fieldset', () => { + expect(getImageDescriptionFieldset(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDescriptionFieldset = getImageDescriptionFieldset(editImageModal); + + expect(shallowWithIntl(imageDescriptionFieldset.prop('legend')).prop('message')) + .toEqual(messages.editImageModalImageDescriptionLegend); + expect(imageDescriptionFieldset.prop('id')).toEqual('imageDescriptionFieldset'); + expect(shallowWithIntl(imageDescriptionFieldset.prop('invalidMessage')).prop('message')).toEqual(messages.editImageModalFormValidImageDescription); + expect(imageDescriptionFieldset.prop('isValid')).toEqual(true); + expect(imageDescriptionFieldset.prop('variant')).toEqual({ status: Variant.status.DANGER }); + expect(shallowWithIntl(imageDescriptionFieldset.prop('variantIconDescription')).prop('message')).toEqual(messages.editImageModalFormError); + }); + }); + + describe('an imageDescription TextInput with', () => { + it('an InputText', () => { + expect(getImageDescriptionInput(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDescriptionInput = getImageDescriptionInput(editImageModal); + + expect(imageDescriptionInput.prop('name')).toEqual('imageDescription'); + /* + Due to Enzyme issue #1213, we must wrap React Fragments in a div in order + to succesfully shallow them. Once Enzyme introduces support for React Fragments, + we can remove the extraneous div. + */ + expect(shallowWithIntl(
{imageDescriptionInput.prop('label')}
).find(WrappedMessage).prop('message')) + .toEqual(messages.editImageModalImageDescriptionLabel); + expect(imageDescriptionInput.prop('describedBy')).toEqual('#Error-imageDescription'); + + /* + Due to Enzyme issue #1213, we must wrap React Fragments in a div in order + to succesfully shallow them. Once Enzyme introduces support for React Fragments, + we can remove the extraneous div. + */ + const imageDescriptionInputDescriptionMessages = shallowWithIntl(
{imageDescriptionInput.prop('description')}
).find(WrappedMessage); + expect(imageDescriptionInputDescriptionMessages.at(0).prop('message')) + .toEqual(messages.editImageModalImageDescriptionDescription); + expect(imageDescriptionInputDescriptionMessages.at(1).prop('message')) + .toEqual(messages.editImageModalLearnMore); + + expect(imageDescriptionInput.prop('id')).toEqual('imageDescription'); + expect(imageDescriptionInput.prop('type')).toEqual('text'); + expect(imageDescriptionInput.prop('value')).toEqual(''); + expect(imageDescriptionInput.prop('disabled')).toEqual(false); + }); + + it('a Learn More link in description', () => { + /* + Due to Enzyme issue #1213, we must wrap React Fragments in a div in order + to succesfully shallow them. Once Enzyme introduces support for React Fragments, + we can remove the extraneous div. + */ + const imageDescriptionInputDescriptionMessages = shallowWithIntl(
{getImageDescriptionInput(editImageModal).prop('description')}
).find(WrappedMessage); + + expect(imageDescriptionInputDescriptionMessages.at(1).prop('message')) + .toEqual(messages.editImageModalLearnMore); + expect(imageDescriptionInputDescriptionMessages.at(1).prop('children')().type).toEqual('a'); + }); + }); + + describe('a image description CheckBox with', () => { + it('a CheckBox', () => { + expect(getImageDescriptionInputCheckBox(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDescriptionInputCheckbox = + getImageDescriptionInputCheckBox(editImageModal); + + expect(imageDescriptionInputCheckbox.prop('id')).toEqual('isDecorative'); + expect(imageDescriptionInputCheckbox.prop('id')).toEqual('isDecorative'); + + expect(shallowWithIntl(imageDescriptionInputCheckbox.prop('label')).prop('message')) + .toEqual(messages.editImageModalImageIsDecorativeCheckboxLabel); + + expect(imageDescriptionInputCheckbox.prop('checked')).toEqual(false); + }); + + it('a Learn More link in description', () => { + /* + Due to Enzyme issue #1213, we must wrap React Fragments in a div in order + to succesfully shallow them. Once Enzyme introduces support for React Fragments, + we can remove the extraneous div. + */ + const imageDescriptionInputCheckBoxDescriptionMessages = shallowWithIntl(
{getImageDescriptionInputCheckBox(editImageModal).prop('description')}
).find(WrappedMessage); + expect(imageDescriptionInputCheckBoxDescriptionMessages.at(1).prop('children')().type).toEqual('a'); + expect(imageDescriptionInputCheckBoxDescriptionMessages.at(1).prop('message')) + .toEqual(messages.editImageModalLearnMore); + }); + }); + }); + + describe('an imageDimensions Fieldset with', () => { + describe('a Fieldset with', () => { + it('a Fieldset', () => { + expect(getImageDimensionsFieldset(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDimensionsFieldset = getImageDimensionsFieldset(editImageModal); + + expect(shallowWithIntl(imageDimensionsFieldset.prop('legend')).prop('message')) + .toEqual(messages.editImageModalDimensionsLegend); + expect(imageDimensionsFieldset.prop('id')).toEqual('imageDimensionsFieldset'); + expect(shallowWithIntl(imageDimensionsFieldset.prop('invalidMessage')).prop('message')).toEqual(messages.editImageModalFormValidImageDimensions); + expect(imageDimensionsFieldset.prop('isValid')).toEqual(true); + expect(imageDimensionsFieldset.prop('variant')).toEqual({ status: Variant.status.DANGER }); + expect(shallowWithIntl(imageDimensionsFieldset.prop('variantIconDescription')).prop('message')).toEqual(messages.editImageModalFormError); + }); + }); + + it('a form-row', () => { + expect(getImageDimensionsFieldset(editImageModal).find('div.form-row')).toHaveLength(1); + }); + + describe('an imageDimensions width InputText with', () => { + it('an InputText', () => { + expect(getImageDimensionsWidthInput(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDimensionsWidthInput = getImageDimensionsWidthInput(editImageModal); + + expect(imageDimensionsWidthInput.prop('name')).toEqual('imageWidth'); + expect(shallowWithIntl(imageDimensionsWidthInput.prop('label')).prop('message')) + .toEqual(messages.editImageModalImageWidthLabel); + expect(imageDimensionsWidthInput.prop('id')).toEqual('imageWidth'); + expect(imageDimensionsWidthInput.prop('type')).toEqual('number'); + expect(imageDimensionsWidthInput.prop('value')).toEqual(''); + }); + }); + + describe('an imageDimensionsHeight InputText with', () => { + it('an InputText', () => { + expect(getImageDimensionsHeightInput(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDimensionsHeightInput = getImageDimensionsHeightInput(editImageModal); + + expect(imageDimensionsHeightInput.prop('name')).toEqual('imageHeight'); + expect(shallowWithIntl(imageDimensionsHeightInput.prop('label')).prop('message')) + .toEqual(messages.editImageModalImageHeightLabel); + expect(imageDimensionsHeightInput.prop('id')).toEqual('imageHeight'); + expect(imageDimensionsHeightInput.prop('type')).toEqual('number'); + expect(imageDimensionsHeightInput.prop('value')).toEqual(''); + }); + }); + + describe('an imageDimensions lockProportions CheckBox with', () => { + it('a CheckBox', () => { + expect(getImageDimensionsCheckBox(editImageModal)).toHaveLength(1); + }); + + it('correct initial props', () => { + const imageDimensionsCheckBox = getImageDimensionsCheckBox(editImageModal); + + expect(imageDimensionsCheckBox.prop('id')).toEqual('lockProportions'); + expect(imageDimensionsCheckBox.prop('name')).toEqual('lockProportions'); + expect(shallowWithIntl(imageDimensionsCheckBox.prop('label')).prop('message')) + .toEqual(messages.editImageModalLockImageProportionsCheckboxLabel); + expect(imageDimensionsCheckBox.prop('checked')).toEqual(true); + }); + }); + }); }); }); }); @@ -332,81 +604,220 @@ describe('EditImageModal', () => { expect(editImageModal.state('isModalOpen')).toEqual(false); }); - it('modal is not open by default', () => { - /* - In order to access the props of the modal, we need a reference - to the modal before we have dove on it. - */ - const modal = editImageModal.find(Modal); - expect(modal.prop('open')).toEqual(false); - }); + describe('behaves', () => { + it('has correct initial state for a course with assets', () => { + editImageModal.setProps({ + assetsList: testAssetsList, + }); - it('this.state.baseAssetURL is empty string by default', () => { - expect(editImageModal.state('baseAssetURL')).toEqual(''); - }); + expect(editImageModal.state('areImageDimensionsValid')).toEqual(true); + expect(editImageModal.state('areProportionsLocked')).toEqual(true); + expect(editImageModal.state('assetsPageType')).toEqual(pageTypes.NORMAL); + expect(editImageModal.state('baseAssetURL')).toEqual(''); + expect(editImageModal.state('currentValidationMessages')).toEqual({}); + expect(editImageModal.state('displayLoadingSpinner')).toEqual(false); + expect(editImageModal.state('imageDescription')).toEqual(''); + expect(editImageModal.state('imageDimensions')).toEqual({}); + expect(editImageModal.state('imageSource')).toEqual(''); + expect(editImageModal.state('imageStyle')).toEqual(''); + expect(editImageModal.state('isImageDecorative')).toEqual(false); + expect(editImageModal.state('isImageDescriptionValid')).toEqual(true); + expect(editImageModal.state('isImageLoaded')).toEqual(false); + expect(editImageModal.state('isImageLoading')).toEqual(false); + expect(editImageModal.state('isStatusAlertOpen')).toEqual(false); + expect(editImageModal.state('isModalOpen')).toEqual(false); + expect(editImageModal.state('pageNumber')).toEqual(1); + expect(editImageModal.state('shouldShowPreviousButton')).toEqual(false); + }); - it('handleOpenModal sets correct state for empty event (inserting an image)', () => { - editImageModal.instance().handleOpenModal(new CustomEvent('openModal', { detail: {} })); - - expect(editImageModal.state('baseAssetURL')).toEqual(''); - expect(editImageModal.state('imageDescription')).toEqual(''); - expect(editImageModal.state('imageDimensions')).toEqual({}); - expect(editImageModal.state('imageStyle')).toEqual(''); - expect(editImageModal.state('imageSource')).toEqual(''); - expect(editImageModal.state('isImageDecorative')).toEqual(false); - expect(editImageModal.state('isImageLoaded')).toEqual(false); - expect(editImageModal.state('isModalOpen')).toEqual(true); - }); + it('handleOpenModal sets correct state for empty event (inserting an image) with assets', () => { + editImageModal.setProps({ + assetsList: testAssetsList, + }); - it('handleOpenModal sets correct state for event with data (editing an image)', () => { - editImageModal.instance().handleOpenModal(new CustomEvent('openModal', { - detail: { - alt: sampleText, - baseAssetUrl: sampleText, - height: sampleImgData.naturalHeight, - src: sampleText, - style: sampleText, + editImageModal.instance().handleOpenModal(new CustomEvent('openModal', { detail: {} })); + + expect(editImageModal.state('areImageDimensionsValid')).toEqual(true); + expect(editImageModal.state('areProportionsLocked')).toEqual(true); + expect(editImageModal.state('assetsPageType')).toEqual(pageTypes.NORMAL); + expect(editImageModal.state('baseAssetURL')).toEqual(''); + expect(editImageModal.state('currentUploadErrorMessage')).toBe(null); + expect(editImageModal.state('currentValidationMessages')).toEqual({}); + expect(editImageModal.state('displayLoadingSpinner')).toEqual(false); + expect(editImageModal.state('imageDescription')).toEqual(''); + expect(editImageModal.state('imageDimensions')).toEqual({}); + expect(editImageModal.state('imageSource')).toEqual(''); + expect(editImageModal.state('imageStyle')).toEqual(''); + expect(editImageModal.state('isImageDecorative')).toEqual(false); + expect(editImageModal.state('isImageDescriptionValid')).toEqual(true); + expect(editImageModal.state('isImageLoaded')).toEqual(false); + expect(editImageModal.state('isImageLoading')).toEqual(false); + expect(editImageModal.state('isStatusAlertOpen')).toEqual(false); + expect(editImageModal.state('isModalOpen')).toEqual(true); + expect(editImageModal.state('pageNumber')).toEqual(1); + expect(editImageModal.state('shouldShowPreviousButton')).toEqual(true); + }); + + it('handleOpenModal sets correct state for empty event (inserting an image) without assets', () => { + editImageModal.instance().handleOpenModal(new CustomEvent('openModal', { detail: {} })); + + expect(editImageModal.state('areImageDimensionsValid')).toEqual(true); + expect(editImageModal.state('areProportionsLocked')).toEqual(true); + expect(editImageModal.state('assetsPageType')).toEqual(pageTypes.NO_ASSETS); + expect(editImageModal.state('baseAssetURL')).toEqual(''); + expect(editImageModal.state('currentUploadErrorMessage')).toBe(null); + expect(editImageModal.state('currentValidationMessages')).toEqual({}); + expect(editImageModal.state('displayLoadingSpinner')).toEqual(false); + expect(editImageModal.state('imageDescription')).toEqual(''); + expect(editImageModal.state('imageDimensions')).toEqual({}); + expect(editImageModal.state('imageSource')).toEqual(''); + expect(editImageModal.state('imageStyle')).toEqual(''); + expect(editImageModal.state('isImageDecorative')).toEqual(false); + expect(editImageModal.state('isImageDescriptionValid')).toEqual(true); + expect(editImageModal.state('isImageLoaded')).toEqual(false); + expect(editImageModal.state('isImageLoading')).toEqual(false); + expect(editImageModal.state('isStatusAlertOpen')).toEqual(false); + expect(editImageModal.state('isModalOpen')).toEqual(true); + expect(editImageModal.state('pageNumber')).toEqual(1); + expect(editImageModal.state('shouldShowPreviousButton')).toEqual(true); + }); + + it('handleOpenModal sets correct state for event with data (editing an image)', () => { + editImageModal.setProps({ + assetsList: testAssetsList, + }); + + editImageModal.instance().handleOpenModal(new CustomEvent('openModal', { + detail: { + alt: sampleText, + baseAssetUrl: sampleText, + height: sampleImgData.naturalHeight, + src: sampleText, + style: sampleText, + width: sampleImgData.naturalWidth, + }, + })); + + expect(editImageModal.state('areImageDimensionsValid')).toEqual(true); + expect(editImageModal.state('assetsPageType')).toEqual(pageTypes.NORMAL); + expect(editImageModal.state('baseAssetURL')).toEqual(sampleText); + expect(editImageModal.state('currentUploadErrorMessage')).toBe(null); + expect(editImageModal.state('currentValidationMessages')).toEqual({}); + expect(editImageModal.state('displayLoadingSpinner')).toEqual(false); + expect(editImageModal.state('imageDescription')).toEqual(sampleText); + expect(editImageModal.state('imageDimensions')).toEqual({ width: sampleImgData.naturalWidth, - }, - })); - - expect(editImageModal.state('baseAssetURL')).toEqual(sampleText); - expect(editImageModal.state('imageDescription')).toEqual(sampleText); - expect(editImageModal.state('imageDimensions')).toEqual({ - width: sampleImgData.naturalWidth, - height: sampleImgData.naturalHeight, - aspectRatio: sampleImgData.aspectRatio, - }); - expect(editImageModal.state('isImageDecorative')).toEqual(false); - expect(editImageModal.state('imageStyle')).toEqual(sampleText); - expect(editImageModal.state('imageSource')).toEqual(sampleText); - expect(editImageModal.state('isImageDecorative')).toEqual(false); - expect(editImageModal.state('isImageLoaded')).toEqual(true); - expect(editImageModal.state('isModalOpen')).toEqual(true); - }); + height: sampleImgData.naturalHeight, + aspectRatio: sampleImgData.aspectRatio, + }); + expect(editImageModal.state('imageStyle')).toEqual(sampleText); + expect(editImageModal.state('imageSource')).toEqual(sampleText); + expect(editImageModal.state('isImageDecorative')).toEqual(false); + expect(editImageModal.state('isImageDescriptionValid')).toEqual(true); + expect(editImageModal.state('isImageLoaded')).toEqual(true); + expect(editImageModal.state('isImageLoading')).toEqual(false); + expect(editImageModal.state('isStatusAlertOpen')).toEqual(false); + expect(editImageModal.state('isModalOpen')).toEqual(true); + expect(editImageModal.state('pageNumber')).toEqual(2); + expect(editImageModal.state('shouldShowPreviousButton')).toEqual(false); + }); - it('onEditImageModalClose sets this.state.isModalOpen to false', () => { - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + it('onEditImageModalClose sets this.state.open to false', () => { + const closeModalButton = getModalFooter(editImageModal).find(Button).at(1); + + editImageModal.setState({ + open: true, + }); + + editImageModal.instance().setModalWrapperRef({ + dispatchEvent: jest.fn(), + }); + + closeModalButton.simulate('click'); + + expect(editImageModal.state('isModalOpen')).toEqual(false); }); - const focusSpy = jest.fn(); - editImageModal.instance().setModalWrapperRef({ - dispatchEvent: jest.fn(), + it('onEditImageModalClose sets this.state.isModalOpen to false', () => { + editImageModal.setState({ + pageNumber: 2, + shouldShowPreviousButton: true, + }); + + const focusSpy = jest.fn(); + editImageModal.instance().setModalWrapperRef({ + dispatchEvent: jest.fn(), + }); + editImageModal.instance().setStatusAlertRef({ + focus: focusSpy, + }); + + const closeModalButton = getModalFooter(editImageModal).find(Button).at(1); + closeModalButton.simulate('click'); + + expect(editImageModal.state('isModalOpen')).toEqual(false); + }); + + it('onEditImageModalClose sets calls clearSearch prop', () => { + const clearSearchSpy = jest.fn(); + + editImageModal.setProps({ + clearSearch: clearSearchSpy, + + }); + + editImageModal.instance().setModalWrapperRef({ + dispatchEvent: jest.fn(), + }); + + const closeModalButton = getModalFooter(editImageModal).find(Button).at(1); + closeModalButton.simulate('click'); + + expect(clearSearchSpy).toHaveBeenCalledTimes(1); }); - editImageModal.instance().setStatusAlertRef({ - focus: focusSpy, + + it('onEditImageModalClose sets calls resetImageSelection', () => { + const resetImageSelectionSpy = jest.fn(); + + editImageModal.instance().resetImageSelection = resetImageSelectionSpy; + + editImageModal.instance().setModalWrapperRef({ + dispatchEvent: jest.fn(), + }); + + const closeModalButton = getModalFooter(editImageModal).find(Button).at(1); + closeModalButton.simulate('click'); + + expect(resetImageSelectionSpy).toHaveBeenCalledTimes(1); }); - const closeModalButton = getModal(editImageModal).find('.modal-footer').find(Button).first(); - closeModalButton.simulate('click'); + it('resetImageSelection calls updatePage prop', () => { + const updatePageSpy = jest.fn(); - expect(editImageModal.state('isModalOpen')).toEqual(false); - expect(focusSpy).toHaveBeenCalledTimes(1); + editImageModal.setProps({ + updatePage: updatePageSpy, + }); + + editImageModal.instance().resetImageSelection(); + + expect(updatePageSpy).toHaveBeenCalledTimes(1); + expect(updatePageSpy).toHaveBeenCalledWith(0, courseDetails); + }); + + it('resetImageSelection calls clearSelectedAsset prop', () => { + const clearSelectedAssetSpy = jest.fn(); + + editImageModal.setProps({ + clearSelectedAsset: clearSelectedAssetSpy, + }); + + editImageModal.instance().resetImageSelection(); + + expect(clearSelectedAssetSpy).toHaveBeenCalledTimes(1); + }); }); - describe('Status Alert: Page 1', () => { + describe('Status Alert: page 1', () => { beforeEach(() => { const refMock = { focus: jest.fn(), @@ -450,6 +861,7 @@ describe('EditImageModal', () => { type: assetActions.upload.UPLOAD_EXCEED_MAX_COUNT_ERROR, }, }); + const statusAlert = getStatusAlert(editImageModal); expect(statusAlert.prop('open')).toEqual(true); /* @@ -468,6 +880,7 @@ describe('EditImageModal', () => { type: assetActions.upload.UPLOAD_INVALID_FILE_TYPE_ERROR, }, }); + const statusAlert = getStatusAlert(editImageModal); expect(statusAlert.prop('open')).toEqual(true); /* @@ -486,6 +899,7 @@ describe('EditImageModal', () => { type: assetActions.upload.UPLOAD_INVALID_FILE_TYPE_ERROR, }, }); + const focusSpy = jest.fn(); editImageModal.instance().setDropZoneButtonRef({ focus: focusSpy, @@ -496,7 +910,7 @@ describe('EditImageModal', () => { }); }); - describe('Status Alert: Page 2', () => { + describe('Status Alert: page 2', () => { beforeEach(() => { const refMock = { focus: jest.fn(), @@ -522,24 +936,20 @@ describe('EditImageModal', () => { expect(editImageModal.state('isStatusAlertOpen')).toEqual(true); }); - it('StatusAlert open prop is false when status alert is closed', () => { + it('status alert is displayed if invalid form submitted', () => { getInsertImageButton(editImageModal).simulate('click'); - getCloseStatusAlertButton(editImageModal).simulate('click'); - - expect(getStatusAlert(editImageModal).prop('open')).toEqual(false); - }); + editImageModal.update(); - it('status alert is not displayed by default', () => { - expect(getStatusAlert(editImageModal).prop('open')).toEqual(false); + expect(getStatusAlert(editImageModal).prop('open')).toEqual(true); }); - it('status alert is displayed if invalid form submitted', () => { + it('StatusAlert open prop is false when status alert is closed', () => { getInsertImageButton(editImageModal).simulate('click'); - editImageModal.update(); + getCloseStatusAlertButton(editImageModal).simulate('click'); - expect(getStatusAlert(editImageModal).prop('open')).toEqual(true); + expect(getStatusAlert(editImageModal).prop('open')).toEqual(false); }); it('this.state.currentValidationMessages is empty object by default', () => { @@ -550,7 +960,6 @@ describe('EditImageModal', () => { getInsertImageButton(editImageModal).simulate('click'); expect(editImageModal.state('currentValidationMessages').imageDescription.props.message).toEqual(messages.editImageModalFormValidImageDescription); - // TODO: add image dimensions }); it('this.state.currentValidationMessages has correct validation message when invalid image description submitted', () => { @@ -560,34 +969,31 @@ describe('EditImageModal', () => { getInsertImageButton(editImageModal).simulate('click'); - expect(editImageModal.state('currentValidationMessages')).not.toHaveProperty('imageSource'); + expect(editImageModal.state('currentValidationMessages')).not.toHaveProperty('imageDimensions'); expect(editImageModal.state('currentValidationMessages').imageDescription.props.message).toEqual(messages.editImageModalFormValidImageDescription); }); - // TODO: invalid image dimensions - it('this.state.currentValidationMessages has correct validation message when invalid image dimensions submitted', () => { editImageModal.setState({ imageSource: sampleText, imageDescription: sampleText, imageDimensions: { - height: -100, - width: -100, + height: -1 * sampleImgData.height, + width: -1 * sampleImgData.width, }, }); getInsertImageButton(editImageModal).simulate('click'); expect(editImageModal.state('currentValidationMessages').imageWidth.props.message).toEqual(messages.editImageModalFormValidImageDimensions); - expect(editImageModal.state('currentValidationMessages')).not.toHaveProperty('imageSource'); expect(editImageModal.state('currentValidationMessages')).not.toHaveProperty('imageDescription'); }); it('this.state.currentValidationMessages is empty when valid form submitted', () => { editImageModal.setState({ imageDimensions: { - width: 100, - height: 100, + width: sampleImgData.naturalWidth, + height: sampleImgData.naturalHeight, }, imageDescription: sampleText, }); @@ -602,13 +1008,11 @@ describe('EditImageModal', () => { expect(editImageModal.state('currentValidationMessages')).not.toHaveProperty('imageDescription'); }); - // TODO: check image description? - it('status alert has correct validation messages when invalid form submitted', () => { editImageModal.setState({ imageDimensions: { - height: -100, - width: -100, + height: (-1 * sampleImgData.naturalHeight), + width: (-1 * sampleImgData.naturalWidth), }, }); @@ -616,7 +1020,7 @@ describe('EditImageModal', () => { editImageModal.update(); - const statusAlertListItems = getStatusAlert(editImageModal).dive({ context: { store, intl } }).find('div ul.bullet-list li a'); + const statusAlertListItems = shallowWithIntl(getStatusAlert(editImageModal).prop('dialog')).find('div ul.bullet-list li a'); expect(statusAlertListItems).toHaveLength(2); expect(statusAlertListItems.at(0).find(WrappedMessage).prop('message')).toEqual(messages.editImageModalFormValidImageDescription); expect(statusAlertListItems.at(1).find(WrappedMessage).prop('message')).toEqual(messages.editImageModalFormValidImageDimensions); @@ -625,8 +1029,8 @@ describe('EditImageModal', () => { it('validation messages are hyperlinks that navigate to appropriate form elements', () => { editImageModal.setState({ imageDimensions: { - height: -100, - width: -100, + height: (-1 * sampleImgData.naturalHeight), + width: (-1 * sampleImgData.naturalWidth), }, }); @@ -635,7 +1039,7 @@ describe('EditImageModal', () => { // force re-render to make sure validation messages are rendered editImageModal.update(); - const statusAlertListItems = getStatusAlert(editImageModal).dive({ context: { store, intl } }).find('div ul.bullet-list li a'); + const statusAlertListItems = shallowWithIntl(getStatusAlert(editImageModal).prop('dialog')).find('div ul.bullet-list li a'); expect(statusAlertListItems).toHaveLength(2); expect(statusAlertListItems.at(0).prop('href')).toEqual('#imageDescription'); expect(statusAlertListItems.at(1).prop('href')).toEqual('#imageWidth'); @@ -654,13 +1058,12 @@ describe('EditImageModal', () => { const statusAlert = getStatusAlert(editImageModal); - const validationMessages = statusAlert - .dive({ context: { store, intl } }).find(WrappedMessage); + const validationMessages = shallowWithIntl(statusAlert.prop('dialog')).find(WrappedMessage); expect(validationMessages).toHaveLength(2); expect(validationMessages.at(0).prop('message')).toEqual(messages.editImageModalFormErrorMissingFields); expect(validationMessages.at(1).prop('message')).toEqual(messages.editImageModalFormValidImageDescription); - const statusAlertListItems = statusAlert.dive({ context: { store, intl } }).find('div ul.bullet-list li a'); + const statusAlertListItems = shallowWithIntl(statusAlert.prop('dialog')).find('div ul.bullet-list li a'); expect(statusAlertListItems).toHaveLength(1); expect(statusAlertListItems.at(0).find(WrappedMessage).prop('message')).toEqual(messages.editImageModalFormValidImageDescription); }); @@ -678,7 +1081,7 @@ describe('EditImageModal', () => { editImageModal.update(); - const statusAlertListItems = getStatusAlert(editImageModal).dive({ context: { store, intl } }).find('div ul.bullet-list li a'); + const statusAlertListItems = shallowWithIntl(getStatusAlert(editImageModal).prop('dialog')).find('div ul.bullet-list li a'); expect(statusAlertListItems).toHaveLength(1); expect(statusAlertListItems.at(0).find(WrappedMessage).prop('message')).toEqual(messages.editImageModalFormValidImageDimensions); }); @@ -696,6 +1099,24 @@ describe('EditImageModal', () => { expect(focusSpy).toHaveBeenCalledTimes(1); }); + + it('focus on page 2 is moved to image description input when status alert is closed and previous button is not shown', () => { + editImageModal.setState({ + shouldShowPreviousButton: false, + }); + + const focusSpy = jest.fn(); + + editImageModal.instance().setImageDescriptionInputRef({ + focus: focusSpy, + }); + + getInsertImageButton(editImageModal).simulate('click'); + + getCloseStatusAlertButton(editImageModal).simulate('click'); + + expect(focusSpy).toHaveBeenCalledTimes(1); + }); }); describe('Validation Messages', () => { @@ -705,6 +1126,7 @@ describe('EditImageModal', () => { }); editImageModal.setState({ + open: true, pageNumber: 2, shouldShowPreviousButton: true, }); @@ -713,22 +1135,22 @@ describe('EditImageModal', () => { it('isValid states for each field is false if invalid form data submitted', () => { editImageModal.setState({ imageDimensions: { - height: -100, - width: -100, + height: (-1 * sampleImgData.naturalHeight), + width: (-1 * sampleImgData.naturalWidth), }, }); getInsertImageButton(editImageModal).simulate('click'); expect(editImageModal.state('isImageDescriptionValid')).toEqual(false); - expect(editImageModal.state('isImageDimensionsValid')).toEqual(false); + expect(editImageModal.state('areImageDimensionsValid')).toEqual(false); }); it('fieldsets show validation messages if invalid form data submitted', () => { editImageModal.setState({ imageDimensions: { - height: -100, - width: -100, + height: (-1 * sampleImgData.naturalHeight), + width: (-1 * sampleImgData.naturalWidth), }, pageNumber: 2, shouldShowPreviousButton: true, @@ -740,11 +1162,11 @@ describe('EditImageModal', () => { const imageDescriptionFieldset = getImageDescriptionFieldset(editImageModal); expect(imageDescriptionFieldset.prop('isValid')).toEqual(false); - expect(imageDescriptionFieldset.prop('invalidMessage').props.message).toEqual(messages.editImageModalFormValidImageDescription); + expect(shallowWithIntl(imageDescriptionFieldset.prop('invalidMessage')).prop('message')).toEqual(messages.editImageModalFormValidImageDescription); const imageDimensionsFieldset = getImageDimensionsFieldset(editImageModal); expect(imageDimensionsFieldset.prop('isValid')).toEqual(false); - expect(imageDimensionsFieldset.prop('invalidMessage').props.message).toEqual(messages.editImageModalFormValidImageDimensions); + expect(shallowWithIntl(imageDimensionsFieldset.prop('invalidMessage')).prop('message')).toEqual(messages.editImageModalFormValidImageDimensions); }); }); }); @@ -788,650 +1210,638 @@ describe('EditImageModal', () => { expect(clearAssetsStatusSpy).toHaveBeenCalledTimes(1); expect(editImageModal.state('pageNumber')).toEqual(2); }); - }); - describe('Image Preview', () => { - beforeEach(() => { - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + describe('AssetsDropZone', () => { + it('has correct props', () => { + const dropZone = getModalBody(editImageModal).find('Connect(AssetsDropZone)'); + expect(dropZone.prop('maxFileCount')).toEqual(1); + expect(dropZone.prop('maxFileSizeMB')).toEqual(10); + expect(dropZone.prop('acceptedFileTypes')).toEqual('image/*'); + expect(dropZone.prop('compactStyle')).toEqual(true); }); }); - it('this.state.imageDimensions are set on image load', () => { - editImageModal.setState({ - imageSource: sampleText, + describe('Image Preview', () => { + beforeEach(() => { + editImageModal.setState({ + pageNumber: 2, + shouldShowPreviousButton: true, + }); }); - getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); - - expect(editImageModal.state('imageDimensions')).toEqual({ - width: sampleImgData.naturalWidth, - height: sampleImgData.naturalHeight, - aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, - }); - }); + it('correct state is set on image load', () => { + editImageModal.setState({ + imageSource: sampleText, + }); - it('this.state.isImageLoading is false by default', () => { - expect(editImageModal.state('isImageLoading')).toEqual(false); - }); + getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); - it('this.state.isImageLoading is set on image load', () => { - editImageModal.setState({ - imageSource: sampleText, + expect(editImageModal.state('displayLoadingSpinner')).toEqual(false); + expect(editImageModal.state('imageDimensions')).toEqual({ + width: sampleImgData.naturalWidth, + height: sampleImgData.naturalHeight, + aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + }); + expect(editImageModal.state('isImageLoaded')).toEqual(true); + expect(editImageModal.state('isImageLoading')).toEqual(false); }); - getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); + it('correct state is set on image error', () => { + editImageModal.setState({ + imageSource: sampleText, + }); - expect(editImageModal.state('isImageLoading')).toEqual(false); - }); + getModalBody(editImageModal).find('img').simulate('error'); - it('this.state.isImageLoading is set on image error', () => { - editImageModal.setState({ - imageSource: sampleText, + expect(editImageModal.state('displayLoadingSpinner')).toEqual(false); + expect(editImageModal.state('imageDimensions')).toEqual({}); + expect(editImageModal.state('isImageLoaded')).toEqual(false); + expect(editImageModal.state('isImageLoading')).toEqual(false); }); - getModalBody(editImageModal).find('img').simulate('error'); - - expect(editImageModal.state('isImageLoading')).toEqual(false); - }); + it('with visible image preview image when this.state.isImageLoaded is false (default)', () => { + editImageModal.setState({ + imageSource: sampleText, + }); - it('this.state.isImageLoaded is false by default', () => { - expect(editImageModal.state('isImageLoaded')).toEqual(false); - }); + const img = getModalBody(editImageModal).find('img'); - it('with visible image preview image when this.state.isImageLoaded is false (default)', () => { - editImageModal.setState({ - imageSource: sampleText, + expect(img.prop('className')).toEqual(expect.stringContaining('invisible')); }); - const img = getModalBody(editImageModal).find('img'); + it('with visible image preview image when this.state.isImageLoaded is true ', () => { + editImageModal.setState({ + imageSource: sampleText, + isImageLoaded: true, + }); - expect(img.prop('className')).toEqual(expect.stringContaining('invisible')); - }); + const img = getModalBody(editImageModal).find('img'); - it('with visible image preview image when this.state.isImageLoaded is true ', () => { - editImageModal.setState({ - imageSource: sampleText, - isImageLoaded: true, + // TODO: replace this with asymmetric matcher expect.not.stringContaining when released + expect(img.prop('className').includes('invisible')).toEqual(false); }); - const img = getModalBody(editImageModal).find('img'); - - // TODO: replace this with asymmetric matcher expect.not.stringContaining when released - expect(img.prop('className').includes('invisible')).toEqual(false); - }); - - it('with visible image preview placeholder text when this.state.isImageLoaded is false (default)', () => { - const imagePreviewPlaceholderText = getModalBody(editImageModal).find('.image-preview-placeholder').find(WrappedMessage); + it('with visible image preview placeholder text when this.state.isImageLoaded is false (default)', () => { + const imagePreviewPlaceholderText = getModalBody(editImageModal).find('.image-preview-placeholder').find(WrappedMessage); - const imagePreviewPlaceholderTextMessage = imagePreviewPlaceholderText - .dive({ context: { store, intl } }) - .dive({ context: { store, intl } }).find(FormattedMessage) - .dive({ context: { store, intl } }); - - // TODO: replace this with asymmetric matcher expect.not.stringContaining when released - expect(imagePreviewPlaceholderTextMessage.prop('className').includes('invisible')).toEqual(false); - }); + const imagePreviewPlaceholderTextMessage = imagePreviewPlaceholderText + .dive({ context: { store, intl } }) + .dive({ context: { store, intl } }).find(FormattedMessage) + .dive({ context: { store, intl } }); - it('with invisible image preview placeholder text when this.state.isImageLoaded is true', () => { - editImageModal.setState({ - isImageLoaded: true, - pageNumber: 2, - shouldShowPreviousButton: true, + // TODO: replace this with asymmetric matcher expect.not.stringContaining when released + expect(imagePreviewPlaceholderTextMessage.prop('className').includes('invisible')).toEqual(false); }); - const imagePreviewPlaceholderText = getModalBody(editImageModal).find('.image-preview-placeholder').find(WrappedMessage); + it('with invisible image preview placeholder text when this.state.isImageLoaded is true', () => { + editImageModal.setState({ + isImageLoaded: true, + pageNumber: 2, + shouldShowPreviousButton: true, + }); - const imagePreviewPlaceholderTextMessage = imagePreviewPlaceholderText - .dive({ context: { store, intl } }) - .dive({ context: { store, intl } }).find(FormattedMessage) - .dive({ context: { store, intl } }); + const imagePreviewPlaceholderText = getModalBody(editImageModal).find('.image-preview-placeholder').find(WrappedMessage); - expect(imagePreviewPlaceholderTextMessage.prop('className')).toEqual(expect.stringContaining('invisible')); - }); - }); + const imagePreviewPlaceholderTextMessage = imagePreviewPlaceholderText + .dive({ context: { store, intl } }) + .dive({ context: { store, intl } }).find(FormattedMessage) + .dive({ context: { store, intl } }); - // Commenting this out for now as we're going to create a new way to insert images - // and workflow changes to test here - describe('Image Source Input', () => { - beforeEach(() => { - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + expect(imagePreviewPlaceholderTextMessage.prop('className')).toEqual(expect.stringContaining('invisible')); }); }); - it('this.state.imageSource is empty string by default', () => { - expect(editImageModal.state('imageSource')).toEqual(''); - }); + describe('Image Description Fieldset', () => { + beforeEach(() => { + const refMock = { + focus: jest.fn(), + }; - // TODO: duplicate of above - it('sets isImageLoading to false and isImageLoaded to true when image preview loads successfully', () => { - editImageModal.setState({ - imageSource: sampleText, + editImageModal.instance().setImageDescriptionInputRef(refMock); + editImageModal.instance().setPreviousButtonRef(refMock); + editImageModal.instance().setStatusAlertRef(refMock); + + editImageModal.setState({ + pageNumber: 2, + shouldShowPreviousButton: true, + }); }); - getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); + it('sends this.state.imageDescription as value prop to image description input', () => { + editImageModal.setState({ + imageDescription: sampleText, + }); - expect(editImageModal.state('isImageLoading')).toEqual(false); - expect(editImageModal.state('isImageLoaded')).toEqual(true); - }); + expect(getImageDescriptionInput(editImageModal).prop('value')).toEqual(sampleText); + }); - it('sets isImageLoading to false and isImageLoaded to false when image preview load errors', () => { - editImageModal.setState({ - imageSource: sampleText, + it('sets this.state.imageDescription with value on input onBlur', () => { + getImageDescriptionInput(editImageModal).simulate('blur', sampleText); + expect(editImageModal.state('imageDescription')).toEqual(sampleText); }); - getModalBody(editImageModal).find('img').simulate('error'); + it('sets this.state.isImageDecorative with value on checkbox onChange', () => { + const isImageDecoractiveCheckBox = getImageDescriptionInputCheckBox(editImageModal); - expect(editImageModal.state('isImageLoading')).toEqual(false); - expect(editImageModal.state('isImageLoaded')).toEqual(false); - }); - }); + isImageDecoractiveCheckBox.simulate('change', true); - describe('Image Description Input', () => { - beforeEach(() => { - const refMock = { - focus: jest.fn(), - }; + expect(editImageModal.state('isImageDecorative')).toEqual(true); - editImageModal.instance().setImageDescriptionInputRef(refMock); - editImageModal.instance().setPreviousButtonRef(refMock); - editImageModal.instance().setStatusAlertRef(refMock); + isImageDecoractiveCheckBox.simulate('change', false); - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + expect(editImageModal.state('isImageDecorative')).toEqual(false); }); - }); - - it('this.state.imageDescription is empty string by default', () => { - expect(editImageModal.state('imageDescription')).toEqual(''); - }); - it('this.state.isImageDecorative is false by default', () => { - expect(editImageModal.state('isImageDecorative')).toEqual(false); - }); + it('sends this.state.isImageDecorative as checkbox checked prop to image description checkbox', () => { + editImageModal.setState({ + isImageDecorative: true, + }); - it('value is empty string by default', () => { - expect(getImageDescriptionInput(editImageModal).prop('value')).toEqual(''); - }); + expect(getImageDescriptionInputCheckBox(editImageModal).prop('checked')).toEqual(true); - it('checkbox is unchecked by default', () => { - expect(getImageDescriptionInputCheckBox(editImageModal).prop('checked')).toEqual(false); - }); + editImageModal.setState({ + isImageDecorative: false, + }); - it('displays this.state.imageSource as value', () => { - editImageModal.setState({ - imageDescription: sampleText, + expect(getImageDescriptionInputCheckBox(editImageModal).prop('checked')).toEqual(false); }); - expect(getImageDescriptionInput(editImageModal).prop('value')).toEqual(sampleText); - }); + it('toggles image description input disabled prop via checkbox', () => { + getImageDescriptionInputCheckBox(editImageModal).simulate('change', true); - it('sets this.state.isImageDecorative with value on checkbox onChange', () => { - getImageDescriptionInputCheckBox(editImageModal).simulate('change', true); + editImageModal.update(); - expect(editImageModal.state('isImageDecorative')).toEqual(true); - }); + expect(getImageDescriptionInput(editImageModal).prop('disabled')).toEqual(true); - it('displays this.state.isImageDecorative as checkbox checked', () => { - editImageModal.setState({ - isImageDecorative: true, + getImageDescriptionInputCheckBox(editImageModal).simulate('change', false); + + editImageModal.update(); + + expect(getImageDescriptionInput(editImageModal).prop('disabled')).toEqual(false); }); - expect(getImageDescriptionInputCheckBox(editImageModal).prop('checked')).toEqual(true); - }); + it('returns correct feedback for invalid description (uses initial state)', () => { + const feedback = editImageModal.instance().validateImageDescription(); - it('toggles image description disabled prop via checkbox', () => { - editImageModal.setState({ - isImageDecorative: true, + expect(feedback.isValid).toEqual(false); + expect(shallowWithIntl(feedback.validationMessage).prop('message')) + .toEqual(messages.editImageModalFormValidImageDescription); + expect(shallowWithIntl(feedback.dangerIconDescription).prop('message')) + .toEqual(messages.editImageModalFormError); }); - let imageDescriptionInput = getImageDescriptionInput(editImageModal); + it('returns correct feedback for valid description (with non-empty description)', () => { + editImageModal.setState({ + imageDescription: sampleText, + }); - expect(imageDescriptionInput.prop('disabled')).toEqual(true); + const feedback = editImageModal.instance().validateImageDescription(); - editImageModal.setState({ - isImageDecorative: false, + expect(feedback.isValid).toEqual(true); + expect(feedback.validationMessage).toBeUndefined(); + expect(feedback.dangerIconDescription).toBeUndefined(); }); - imageDescriptionInput = getImageDescriptionInput(editImageModal); - - expect(imageDescriptionInput.prop('disabled')).toEqual(false); - }); + it('returns correct feedback for valid description (with checked checkbox)', () => { + editImageModal.setState({ + isImageDecorative: true, + }); - it('returns correct feedback for invalid description (uses initial state)', () => { - const feedback = editImageModal.instance().validateImageDescription(); + const feedback = editImageModal.instance().validateImageDescription(); - expect(feedback.isValid).toEqual(false); - expect(feedback.validationMessage.props.message) - .toEqual(messages.editImageModalFormValidImageDescription); - expect(feedback.dangerIconDescription.props.message) - .toEqual(messages.editImageModalFormError); + expect(feedback.isValid).toEqual(true); + expect(feedback.validationMessage).toBeUndefined(); + expect(feedback.dangerIconDescription).toBeUndefined(); + }); }); - it('returns correct feedback for valid description (with non-empty description)', () => { - editImageModal.setState({ - imageDescription: sampleText, + describe('Image Dimensions Fieldset', () => { + beforeEach(() => { + editImageModal.setState({ + pageNumber: 2, + shouldShowPreviousButton: true, + }); }); - const feedback = editImageModal.instance().validateImageDescription(); + it('sets this.state.areProportionsLocked with value on checkbox onChange', () => { + getImageDimensionsCheckBox(editImageModal).simulate('change', false); - expect(feedback.isValid).toEqual(true); - expect(feedback.validationMessage).toBeUndefined(); - expect(feedback.dangerIconDescription).toBeUndefined(); - }); + expect(editImageModal.state('areProportionsLocked')).toEqual(false); - it('returns correct feedback for valid description (with checked checkbox)', () => { - editImageModal.setState({ - isImageDecorative: true, + getImageDimensionsCheckBox(editImageModal).simulate('change', true); + + expect(editImageModal.state('areProportionsLocked')).toEqual(true); }); - const feedback = editImageModal.instance().validateImageDescription(); + it('displays this.state.areProportionsLocked as checkbox checked', () => { + editImageModal.setState({ + areProportionsLocked: true, + }); - expect(feedback.isValid).toEqual(true); - expect(feedback.validationMessage).toBeUndefined(); - expect(feedback.dangerIconDescription).toBeUndefined(); - }); - }); + expect(getImageDimensionsCheckBox(editImageModal).prop('checked')).toEqual(true); - describe('Image Dimensions Input', () => { - beforeEach(() => { - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + editImageModal.setState({ + areProportionsLocked: false, + }); + + expect(getImageDimensionsCheckBox(editImageModal).prop('checked')).toEqual(false); }); - }); - it('this.state.imageDimensions is empty object by default', () => { - expect(editImageModal.state('imageDimensions')).toEqual({}); - }); + it('onImageDimensionBlur throws an Error for an unknown dimension type', () => { + expect(() => editImageModal.instance().onImageDimensionBlur(sampleText)).toThrow(Error); + expect(() => editImageModal.instance().onImageDimensionBlur(sampleText)).toThrow(`Unknown dimension type ${sampleText}.`); + }); - it('this.state.areProportionsLocked is true by default', () => { - expect(editImageModal.state('areProportionsLocked')).toEqual(true); - }); - it('width input value is empty string by default', () => { - expect(getImageDimensionsWidthInput(editImageModal).prop('value')).toEqual(''); - }); + it('returns correct feedback for invalid dimensions (negative numbers)', () => { + editImageModal.setState({ + imageDimensions: { + height: -1 * sampleImgData.height, + width: -1 * sampleImgData.width, + }, + }); - it('height input value is empty string by default', () => { - expect(getImageDimensionsHeightInput(editImageModal).prop('value')).toEqual(''); - }); + const feedback = editImageModal.instance().validateImageDimensions(); - it('checkbox is unchecked by default', () => { - expect(getImageDescriptionInputCheckBox(editImageModal).prop('checked')).toEqual(false); - }); + expect(feedback.isValid).toEqual(false); + expect(shallowWithIntl(feedback.validationMessage).prop('message')) + .toEqual(messages.editImageModalFormValidImageDimensions); + expect(shallowWithIntl(feedback.dangerIconDescription).prop('message')) + .toEqual(messages.editImageModalFormError); + }); - it('sets this.state.isImageDecorative with value on checkbox onChange', () => { - getImageDescriptionInputCheckBox(editImageModal).simulate('change', true); + it('returns correct feedback for valid dimension (positive numbers)', () => { + editImageModal.setState({ + imageDescription: sampleText, + imageDimensions: { + height: sampleImgData.height, + width: sampleImgData.width, + }, + }); - expect(editImageModal.state('areProportionsLocked')).toEqual(true); - }); + const feedback = editImageModal.instance().validateImageDimensions(); - it('displays this.state.areProportionsLocked as checkbox checked', () => { - editImageModal.setState({ - areProportionsLocked: true, + expect(feedback.isValid).toEqual(true); + expect(feedback.validationMessage).toBeUndefined(); + expect(feedback.dangerIconDescription).toBeUndefined(); }); - editImageModal.update(); + it('returns correct feedback for valid dimensions (uses empty object/initial state', () => { + const feedback = editImageModal.instance().validateImageDimensions(); - expect(getImageDimensionsCheckBox(editImageModal).prop('checked')).toEqual(true); - }); + expect(feedback.isValid).toEqual(true); + expect(feedback.validationMessage).toBeUndefined(); + expect(feedback.dangerIconDescription).toBeUndefined(); + }); - describe('this.state.imageDimensions responds correctly to locked proportions', () => { - beforeEach(() => { - editImageModal.setState({ - imageSource: sampleText, - pageNumber: 2, - shouldShowPreviousButton: true, + describe('this.state.imageDimensions responds correctly to locked proportions', () => { + beforeEach(() => { + editImageModal.setState({ + imageSource: sampleText, + pageNumber: 2, + shouldShowPreviousButton: true, + }); + + getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); + editImageModal.update(); }); - getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); - editImageModal.update(); - }); + it('height responds to width change', () => { + getImageDimensionsWidthInput(editImageModal).simulate('blur', 50); + + expect(editImageModal.state('imageDimensions')).toEqual({ + width: 50, + height: 100, + aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + }); + }); - it('height responds to width change', () => { - getImageDimensionsWidthInput(editImageModal).simulate('blur', 50); + it('width responds to height change', () => { + getImageDimensionsHeightInput(editImageModal).simulate('blur', 400); - expect(editImageModal.state('imageDimensions')).toEqual({ - width: 50, - height: 100, - aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + expect(editImageModal.state('imageDimensions')).toEqual({ + width: 200, + height: 400, + aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + }); }); }); - it('width responds to height change', () => { - getImageDimensionsHeightInput(editImageModal).simulate('blur', 400); + describe('this.state.imageDimensions responds correctly to unlocked proportions', () => { + beforeEach(() => { + editImageModal.setState({ + imageSource: sampleText, + pageNumber: 2, + shouldShowPreviousButton: true, + }); - expect(editImageModal.state('imageDimensions')).toEqual({ - width: 200, - height: 400, - aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + getImageDimensionsCheckBox(editImageModal).simulate('change', false); + + getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); + + editImageModal.update(); + }); + + it('height does not respond to width change', () => { + getImageDimensionsWidthInput(editImageModal).simulate('blur', 50); + + expect(editImageModal.state('imageDimensions')).toEqual({ + width: 50, + height: sampleImgData.naturalHeight, + aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + }); + }); + + it('width does not respond to height change', () => { + getImageDimensionsHeightInput(editImageModal).simulate('blur', 400); + + expect(editImageModal.state('imageDimensions')).toEqual({ + width: sampleImgData.naturalWidth, + height: 400, + aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + }); }); }); }); - describe('this.state.imageDimensions responds correctly to unlocked proportions', () => { + describe('Next button', () => { beforeEach(() => { editImageModal.setState({ - imageSource: sampleText, - pageNumber: 2, + pageNumber: 1, shouldShowPreviousButton: true, }); - getImageDimensionsCheckBox(editImageModal).simulate('change', false); - - getModalBody(editImageModal).find('img').simulate('load', { target: { ...sampleImgData } }); + editImageModal.setProps({ + selectedAsset: { + portable_url: 'foo', + }, + }); + const refMock = { + focus: jest.fn(), + }; - editImageModal.update(); + editImageModal.instance().setPreviousButtonRef(refMock); }); - it('height does not respond to width change', () => { - getImageDimensionsWidthInput(editImageModal).simulate('blur', 50); - - expect(editImageModal.state('imageDimensions')).toEqual({ - width: 50, - height: sampleImgData.naturalHeight, - aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, + it('goes to page 2', () => { + const clearAssetsStatusSpy = jest.fn(); + editImageModal.setProps({ + clearAssetsStatus: clearAssetsStatusSpy, }); - }); - it('width does not respond to height change', () => { - getImageDimensionsHeightInput(editImageModal).simulate('blur', 400); + getNextButton(editImageModal).simulate('click'); + editImageModal.update(); - expect(editImageModal.state('imageDimensions')).toEqual({ - width: sampleImgData.naturalWidth, - height: 400, - aspectRatio: sampleImgData.naturalWidth / sampleImgData.naturalHeight, - }); + expect(editImageModal.state('isStatusAlertOpen')).toEqual(false); + expect(editImageModal.state('pageNumber')).toEqual(2); + expect(editImageModal.state('uploadErrorMessageBody')).toBeUndefined(); + expect(clearAssetsStatusSpy).toHaveBeenCalledTimes(1); }); - it('throws an Error for an unknown dimension type', () => { - expect(() => editImageModal.instance().onImageDimensionBlur(sampleText)).toThrow(Error); - expect(() => editImageModal.instance().onImageDimensionBlur(sampleText)).toThrow(`Unknown dimension type ${sampleText}.`); - }); - }); - }); + it('focuses on Previous/Back button', () => { + const focusSpy = jest.fn(); + editImageModal.instance().setPreviousButtonRef({ + focus: focusSpy, + }); - describe('Next button', () => { - beforeEach(() => { - editImageModal.setState({ - pageNumber: 1, - shouldShowPreviousButton: true, - }); + getNextButton(editImageModal).simulate('click'); + editImageModal.update(); - editImageModal.setProps({ - selectedAsset: { - portable_url: 'foo', - }, + editImageModal.instance().componentDidUpdate({}, { pageNumber: 1 }); + expect(focusSpy).toHaveBeenCalledTimes(1); }); - const refMock = { - focus: jest.fn(), - }; - - editImageModal.instance().setPreviousButtonRef(refMock); - }); - it('goes to page 2', () => { - const clearAssetsStatusSpy = jest.fn(); - editImageModal.setProps({ - clearAssetsStatus: clearAssetsStatusSpy, - }); + it('closes statusAlert', () => { + editImageModal.setProps({ + assetsStatus: { + type: assetActions.upload.UPLOAD_EXCEED_MAX_COUNT_ERROR, + }, + }); + let statusAlert = getStatusAlert(editImageModal); + expect(statusAlert.prop('open')).toEqual(true); - getNextButton(editImageModal).simulate('click'); - editImageModal.update(); + getNextButton(editImageModal).simulate('click'); + editImageModal.update(); - expect(editImageModal.state('isStatusAlertOpen')).toEqual(false); - expect(editImageModal.state('pageNumber')).toEqual(2); - expect(editImageModal.state('uploadErrorMessageBody')).toBeUndefined(); - expect(clearAssetsStatusSpy).toHaveBeenCalledTimes(1); + statusAlert = getStatusAlert(editImageModal); + expect(statusAlert.prop('open')).toEqual(false); + }); }); - it('focuses on Previous/Back button', () => { - const focusSpy = jest.fn(); - editImageModal.instance().setPreviousButtonRef({ - focus: focusSpy, - }); + describe('Previous/Back button', () => { + beforeEach(() => { + editImageModal.setState({ + pageNumber: 2, + shouldShowPreviousButton: true, + }); + const refMock = { + focus: jest.fn(), + }; - getNextButton(editImageModal).simulate('click'); - editImageModal.update(); + editImageModal.instance().setDropZoneButtonRef(refMock); + }); - editImageModal.instance().componentDidUpdate({}, { pageNumber: 1 }); - expect(focusSpy).toHaveBeenCalledTimes(1); - }); + it('goes to page 1', () => { + getPreviousButton(editImageModal).simulate('click'); + editImageModal.update(); - it('closes statusAlert', () => { - editImageModal.setProps({ - assetsStatus: { - type: assetActions.upload.UPLOAD_EXCEED_MAX_COUNT_ERROR, - }, + expect(editImageModal.state('pageNumber')).toEqual(1); }); - let statusAlert = getStatusAlert(editImageModal); - expect(statusAlert.prop('open')).toEqual(true); - getNextButton(editImageModal).simulate('click'); - editImageModal.update(); + it('focuses on Upload button', () => { + const focusSpy = jest.fn(); + editImageModal.instance().setDropZoneButtonRef({ + focus: focusSpy, + }); - statusAlert = getStatusAlert(editImageModal); - expect(statusAlert.prop('open')).toEqual(false); - }); - }); + getPreviousButton(editImageModal).simulate('click'); + editImageModal.update(); - describe('Previous/Back button', () => { - beforeEach(() => { - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + editImageModal.instance().componentDidUpdate({}, { isModalOpen: true, pageNumber: 2 }); + expect(focusSpy).toHaveBeenCalledTimes(1); }); - const refMock = { - focus: jest.fn(), - }; - - editImageModal.instance().setDropZoneButtonRef(refMock); }); - it('goes to page 1', () => { - getPreviousButton(editImageModal).simulate('click'); - editImageModal.update(); - - expect(editImageModal.state('pageNumber')).toEqual(1); - }); + describe('Insert Image button', () => { + let validationMock; + let dispatchEventSpy; - it('focuses on Upload button', () => { - const focusSpy = jest.fn(); - editImageModal.instance().setDropZoneButtonRef({ - focus: focusSpy, - }); + beforeEach(() => { + editImageModal.setState({ + pageNumber: 2, + shouldShowPreviousButton: true, + }); - getPreviousButton(editImageModal).simulate('click'); - editImageModal.update(); + dispatchEventSpy = jest.fn(); - editImageModal.instance().componentDidUpdate({}, { isModalOpen: true, pageNumber: 2 }); - expect(focusSpy).toHaveBeenCalledTimes(1); - }); - }); + editImageModal.instance().setImageFormRef({ + dispatchEvent: dispatchEventSpy, + }); - describe('Insert Image button', () => { - let validationMock; - let dispatchEventSpy; + /* + Let's make form valid by default. The reason we mock the validation + functions instead of setting valid input for the appropriate fields + is to avoid the creation of imgRef when imageSource is not falsy, + which messes with some of the tests. + */ + validationMock = jest.fn(); + validationMock.mockReturnValue({ isValid: true }); - beforeEach(() => { - editImageModal.setState({ - pageNumber: 2, - shouldShowPreviousButton: true, + editImageModal.instance().validateImageDescription = validationMock; }); - dispatchEventSpy = jest.fn(); - editImageModal.instance().setImageFormRef({ - dispatchEvent: dispatchEventSpy, + it('sends bubbles as true', () => { + getInsertImageButton(editImageModal).simulate('click'); + expect(dispatchEventSpy.mock.calls[0][0].bubbles).toEqual(true); }); - /* - Let's make form valid by default. The reason we mock the validation - functions instead of setting valid input for the appropriate fields - is to avoid the creation of imgRef when imageSource is not falsy, - which messes with some of the tests. - */ - validationMock = jest.fn(); - validationMock.mockReturnValue({ isValid: true }); - - editImageModal.instance().validateImageSource = validationMock; - editImageModal.instance().validateImageDescription = validationMock; - }); - + it('sends width in submitForm event', () => { + getImageDimensionsWidthInput(editImageModal).simulate('blur', sampleImgData.naturalWidth); - it('sends bubbles as true', () => { - getInsertImageButton(editImageModal).simulate('click'); - expect(dispatchEventSpy.mock.calls[0][0].bubbles).toEqual(true); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends width in submitForm event', () => { - getImageDimensionsWidthInput(editImageModal).simulate('blur', sampleImgData.naturalWidth); + expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(sampleImgData.naturalWidth); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends height in submitForm event', () => { + getImageDimensionsHeightInput(editImageModal).simulate('blur', sampleImgData.naturalHeight); - expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(sampleImgData.naturalWidth); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends height in submitForm event', () => { - getImageDimensionsHeightInput(editImageModal).simulate('blur', sampleImgData.naturalHeight); + expect(dispatchEventSpy.mock.calls[0][0].detail.height) + .toEqual(sampleImgData.naturalHeight); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends width as null in submitForm event if width is set to empty string/NaN (input cleared) and imgRef is falsy', () => { + getImageDimensionsWidthInput(editImageModal).simulate('blur', ''); - expect(dispatchEventSpy.mock.calls[0][0].detail.height).toEqual(sampleImgData.naturalHeight); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends width as null in submitForm event if width is set to empty string/NaN (input cleared) and imgRef is falsy', () => { - getImageDimensionsWidthInput(editImageModal).simulate('blur', ''); + expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(null); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends height as null in submitForm event if height is set to empty string/NaN (input cleared) and imgRef is falsy', () => { + getImageDimensionsHeightInput(editImageModal).simulate('blur', ''); - expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(null); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends height as null in submitForm event if height is set to empty string/NaN (input cleared) and imgRef is falsy', () => { - getImageDimensionsHeightInput(editImageModal).simulate('blur', ''); + expect(dispatchEventSpy.mock.calls[0][0].detail.height).toEqual(null); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends natural width in submitForm event if width is set to empty string/NaN (input cleared) ', () => { + // set mocked imageRef data + editImageModal.instance().setImageRef({ ...sampleImgData }); - expect(dispatchEventSpy.mock.calls[0][0].detail.height).toEqual(null); - }); + getImageDimensionsWidthInput(editImageModal).simulate('blur', ''); - it('sends natural width in submitForm event if width is set to empty string/NaN (input cleared) ', () => { - // set mocked imageRef data - editImageModal.instance().setImageRef({ ...sampleImgData }); + getInsertImageButton(editImageModal).simulate('click'); - getImageDimensionsWidthInput(editImageModal).simulate('blur', ''); + expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(sampleImgData.naturalWidth); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends natural height in submitForm event if height is set to empty string/NaN (input cleared) ', () => { + // set mocked imageRef data + editImageModal.instance().setImageRef({ ...sampleImgData }); - expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(sampleImgData.naturalWidth); - }); + getImageDimensionsHeightInput(editImageModal).simulate('blur', ''); - it('sends natural height in submitForm event if height is set to empty string/NaN (input cleared) ', () => { - // set mocked imageRef data - editImageModal.instance().setImageRef({ ...sampleImgData }); + getInsertImageButton(editImageModal).simulate('click'); - getImageDimensionsHeightInput(editImageModal).simulate('blur', ''); + expect(dispatchEventSpy.mock.calls[0][0].detail.height) + .toEqual(sampleImgData.naturalHeight); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends null in submitForm event if width is set to empty string/NaN (input cleared) but no imgRef ', () => { + getImageDimensionsWidthInput(editImageModal).simulate('blur', ''); - expect(dispatchEventSpy.mock.calls[0][0].detail.height).toEqual(sampleImgData.naturalHeight); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends null in submitForm event if width is set to empty string/NaN (input cleared) but no imgRef ', () => { - getImageDimensionsWidthInput(editImageModal).simulate('blur', ''); + expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(null); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends natural height in submitForm event if height is set to empty string/NaN (input cleared) but no imgRef', () => { + getImageDimensionsHeightInput(editImageModal).simulate('blur', ''); - expect(dispatchEventSpy.mock.calls[0][0].detail.width).toEqual(null); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends natural height in submitForm event if height is set to empty string/NaN (input cleared) but no imgRef', () => { - getImageDimensionsHeightInput(editImageModal).simulate('blur', ''); + expect(dispatchEventSpy.mock.calls[0][0].detail.height).toEqual(null); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends this.state.imageSource in submitForm event', () => { + editImageModal.setState({ + baseAssetURL: 'edx.org', + imageSource: sampleText, + }); - expect(dispatchEventSpy.mock.calls[0][0].detail.height).toEqual(null); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends this.state.imageSource in submitForm event', () => { - editImageModal.setState({ - baseAssetURL: 'edx.org', - imageSource: sampleText, + expect(dispatchEventSpy.mock.calls[0][0].detail.src).toEqual(rewriteStaticLinks(sampleText, '/static/', 'edx.org')); }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends this.state.imageDescription in submitForm event if not this.state.imageIsDecorative', () => { + getImageDescriptionInput(editImageModal).simulate('blur', sampleText); - expect(dispatchEventSpy.mock.calls[0][0].detail.src).toEqual(rewriteStaticLinks(sampleText, '/static/', 'edx.org')); - }); + editImageModal.update(); - it('sends this.state.imageDescription in submitForm event if not this.state.imageIsDecorative', () => { - getImageDescriptionInput(editImageModal).simulate('blur', sampleText); + getInsertImageButton(editImageModal).simulate('click'); - editImageModal.update(); + expect(dispatchEventSpy.mock.calls[0][0].detail.alt).toEqual(sampleText); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends empty string in submitForm event if this.state.imageIsDecorative', () => { + getImageDescriptionInput(editImageModal).simulate('blur', sampleText); - expect(dispatchEventSpy.mock.calls[0][0].detail.alt).toEqual(sampleText); - }); + getImageDescriptionInputCheckBox(editImageModal).simulate('change', true); - it('sends empty string in submitForm event if this.state.imageIsDecorative', () => { - getImageDescriptionInput(editImageModal).simulate('blur', sampleText); + getInsertImageButton(editImageModal).simulate('click'); - getImageDescriptionInputCheckBox(editImageModal).simulate('change', true); + expect(dispatchEventSpy.mock.calls[0][0].detail.alt).toEqual(''); + }); - getInsertImageButton(editImageModal).simulate('click'); + it('sends this.state.imageStyle in submitForm event', () => { + editImageModal.setState({ + imageStyle: sampleText, + }); - expect(dispatchEventSpy.mock.calls[0][0].detail.alt).toEqual(''); - }); + getInsertImageButton(editImageModal).simulate('click'); - it('sends this.state.imageStyle in submitForm event', () => { - editImageModal.setState({ - imageStyle: sampleText, + expect(dispatchEventSpy.mock.calls[0][0].detail.style).toEqual(sampleText); }); - getInsertImageButton(editImageModal).simulate('click'); + it('does not dispatch event if form is invalid', () => { + validationMock.mockReturnValue({ isValid: false }); - expect(dispatchEventSpy.mock.calls[0][0].detail.style).toEqual(sampleText); - }); - - it('does not dispatch event if form is invalid', () => { - validationMock.mockReturnValue({ isValid: false }); + editImageModal.instance().setStatusAlertRef({ + focus: jest.fn(), + }); - editImageModal.instance().setStatusAlertRef({ - focus: jest.fn(), - }); + editImageModal.setState({ + imageDescription: '', + imageSource: sampleText, + }); - editImageModal.setState({ - imageDescription: '', - imageSource: sampleText, - }); + const insertImageButton = getInsertImageButton(editImageModal); - const insertImageButton = getInsertImageButton(editImageModal); + insertImageButton.simulate('click'); + expect(dispatchEventSpy).toHaveBeenCalledTimes(0); - insertImageButton.simulate('click'); - expect(dispatchEventSpy).toHaveBeenCalledTimes(0); + editImageModal.setState({ + imageDescription: sampleText, + imageSource: '', + }); - editImageModal.setState({ - imageDescription: sampleText, - imageSource: '', - }); + insertImageButton.simulate('click'); + expect(dispatchEventSpy).toHaveBeenCalledTimes(0); - insertImageButton.simulate('click'); - expect(dispatchEventSpy).toHaveBeenCalledTimes(0); + editImageModal.setState({ + imageDescription: '', + imageSource: '', + }); - editImageModal.setState({ - imageDescription: '', - imageSource: '', + insertImageButton.simulate('click'); + expect(dispatchEventSpy).toHaveBeenCalledTimes(0); }); - - insertImageButton.simulate('click'); - expect(dispatchEventSpy).toHaveBeenCalledTimes(0); }); }); }); diff --git a/src/components/EditImageModal/displayMessages.jsx b/src/components/EditImageModal/displayMessages.jsx index 6ffd1761..d8834a52 100644 --- a/src/components/EditImageModal/displayMessages.jsx +++ b/src/components/EditImageModal/displayMessages.jsx @@ -16,6 +16,11 @@ const messages = defineMessages({ defaultMessage: '0 images found', description: 'Message displayed in table when no image results are found.', }, + editImageModalCancelButton: { + id: 'editImageModalCancelButton', + defaultMessage: 'Cancel', + description: 'Button text to close the modal', + }, editImageModalFormError: { id: 'editImageModalFormError', defaultMessage: 'Error', @@ -36,11 +41,6 @@ const messages = defineMessages({ defaultMessage: 'Image dimensions must be positive numbers.', description: 'Error message displayed when invalid image dimension values are entered into a form', }, - editImageModalFormValidImageSource: { - id: 'editImageModalFormValidImageSource', - defaultMessage: 'Make sure the image source is correct.', - description: 'Error message for when an invalid image source URL is entered into the form', - }, editImageModalImageDescriptionDescription: { id: 'editImageModalImageDescriptionDescription', defaultMessage: 'Alternative text for users who cannot view the image, such as "The sky with clouds".', @@ -81,16 +81,6 @@ const messages = defineMessages({ defaultMessage: 'Image Preview', description: 'Label for the image preview area', }, - editImageModalImageSourceDescription: { - id: 'editImageModalImageSourceDescription', - defaultMessage: 'The Studio URL from the Files & Uploads page or an external URL, such as {link}.', - description: 'Description for the image source URL input, which asks for a URL from Studio or an external URL and gives an example of an external URL', - }, - editImageModalImageSourceLabel: { - id: 'editImageModalImageSourceLabel', - defaultMessage: 'Image Source URL', - description: 'Label for the text input box for an image\'s source URL', - }, editImageModalInsertImageButton: { id: 'editImageModalInsertImageButton', defaultMessage: 'Insert Image', @@ -116,6 +106,11 @@ const messages = defineMessages({ defaultMessage: 'Add an Image', description: 'Title of the modal used for adding an image', }, + editImageModalInsertHeader: { + id: 'editImageModalInsertHeader', + defaultMessage: 'Select a previously uploaded image', + description: 'Header of the modal used for adding an image', + }, editImageModalEditTitle: { id: 'editImageModalEditTitle', defaultMessage: 'Edit Image Settings', @@ -126,21 +121,6 @@ const messages = defineMessages({ defaultMessage: 'or', description: 'Describes two choices,', }, - editImageModalImageNotFoundError: { - id: 'editImageModalImageNotFoundError', - defaultMessage: 'Make sure the image source is correct.', - description: 'Error message displayed below URL field input when user-entered URL did not load an image', - }, - editImageModalImageLoadingIcon: { - id: 'editImageModalImageLoadingIcon', - defaultMessage: 'Loading...', - description: 'Text displayed with a loading spinner icon indicating that an image is loading', - }, - editImageModalCancelButton: { - id: 'editImageModalCancelButton', - defaultMessage: 'Cancel', - description: 'Button text to close the modal', - }, editImageModalNextPageButton: { id: 'editImageModalNextPageButton', defaultMessage: 'Next', diff --git a/src/components/EditImageModal/index.jsx b/src/components/EditImageModal/index.jsx index c0352f63..662f88a3 100644 --- a/src/components/EditImageModal/index.jsx +++ b/src/components/EditImageModal/index.jsx @@ -40,6 +40,7 @@ const imageWidthID = 'imageWidth'; const modalWrapperID = 'modalWrapper'; const initialEditImageModalState = { + areImageDimensionsValid: true, areProportionsLocked: true, assetsPageType: pageTypes.SKELETON, baseAssetURL: '', @@ -48,15 +49,15 @@ const initialEditImageModalState = { displayLoadingSpinner: false, imageDescription: '', imageDimensions: {}, + imageSource: '', + imageStyle: '', isImageDecorative: false, + isImageDescriptionValid: true, isImageLoaded: false, isImageLoading: false, - isImageDescriptionValid: true, isImageDimensionsValid: true, isModalOpen: false, isStatusAlertOpen: false, - imageSource: '', - imageStyle: '', pageNumber: 1, shouldShowPreviousButton: false, }; @@ -268,7 +269,7 @@ export default class EditImageModal extends React.Component { this.setState({ isStatusAlertOpen: !isValidFormContent, isImageDescriptionValid: isValidImageDescription.isValid, - isImageDimensionsValid: isValidImageDimensions.isValid, + areImageDimensionsValid: isValidImageDimensions.isValid, currentValidationMessages, }); @@ -444,7 +445,7 @@ export default class EditImageModal extends React.Component { legend={} id={imageDimensionsFieldsetID} invalidMessage={} - isValid={this.state.isImageDimensionsValid} + isValid={this.state.areImageDimensionsValid} variant={{ status: Variant.status.DANGER, }} @@ -674,7 +675,7 @@ export default class EditImageModal extends React.Component {
-

Select a previously uploaded image

+
diff --git a/src/components/Pagination/Pagination.test.jsx b/src/components/Pagination/Pagination.test.jsx index c3e3466c..c5d4400e 100644 --- a/src/components/Pagination/Pagination.test.jsx +++ b/src/components/Pagination/Pagination.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import courseDetails from '../../utils/testConstants'; +import { courseDetails } from '../../utils/testConstants'; import { mountWithIntl } from '../../utils/i18n/enzymeHelper'; import Pagination from './index'; diff --git a/src/data/i18n/default/transifex_input.json b/src/data/i18n/default/transifex_input.json index da5ed03c..dde917c3 100644 --- a/src/data/i18n/default/transifex_input.json +++ b/src/data/i18n/default/transifex_input.json @@ -94,11 +94,11 @@ "editImageModalAssetsListLoadingSpinner": "Loading spinner", "editImageModalAssetsListNoAssetsMessage": "0 images uploaded", "editImageModalAssetsListNoResultsMessage": "0 images found", + "editImageModalCancelButton": "Cancel", "editImageModalFormError": "Error", "editImageModalFormErrorMissingFields": "Make sure to fill in all fields.", "editImageModalFormValidImageDescription": "Add an image description or specify that the image is decorative only.", "editImageModalFormValidImageDimensions": "Image dimensions must be positive numbers.", - "editImageModalFormValidImageSource": "Make sure the image source is correct.", "editImageModalImageDescriptionDescription": "Alternative text for users who cannot view the image, such as \"The sky with clouds\".", "editImageModalImageDescriptionLabel": "Image Description (Alt Text)", "editImageModalImageDescriptionLegend": "Image Description", @@ -107,18 +107,14 @@ "editImageModalImageIsDecorativeCheckboxDescription": "This image is a background or other image that does not require alternative text.", "editImageModalImageIsDecorativeCheckboxLabel": "This image is decorative only", "editImageModalImagePreviewText": "Image Preview", - "editImageModalImageSourceDescription": "The Studio URL from the Files & Uploads page or an external URL, such as {link}.", - "editImageModalImageSourceLabel": "Image Source URL", "editImageModalInsertImageButton": "Insert Image", "editImageModalLearnMore": "Learn more.", "editImageModalLockImageProportionsCheckboxLabel": "Lock proportions", "editImageModalImageWidth": "Width", "editImageModalInsertTitle": "Add an Image", + "editImageModalInsertHeader": "Select a previously uploaded image", "editImageModalEditTitle": "Edit Image Settings", "editImageModalImageOrFields": "or", - "editImageModalImageNotFoundError": "Make sure the image source is correct.", - "editImageModalImageLoadingIcon": "Loading...", - "editImageModalCancelButton": "Cancel", "editImageModalNextPageButton": "Next", "editImageModalPreviousPageButton": "Back", "editImageModalInvalidFileType": "Files must be images, such as .jpg, .png, and .tiff files. No files were uploaded.", diff --git a/src/utils/testConstants.jsx b/src/utils/testConstants.jsx index 5ced2559..d32f5bd3 100644 --- a/src/utils/testConstants.jsx +++ b/src/utils/testConstants.jsx @@ -5,7 +5,7 @@ import thunkMiddleware from 'redux-thunk'; import accessibility from '../data/reducers/accessibility'; import { assets, metadata } from '../data/reducers/assets'; -const courseDetails = { +export const courseDetails = { lang: 'en', url_name: 'course', name: 'edX Demonstration Course', @@ -17,8 +17,6 @@ const courseDetails = { base_url: 'sfe', }; -export default courseDetails; - const thumbnail = '/animal'; const copyUrl = 'animal';