@khanacademy/perseus 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/.babelrc.js +1 -1
  2. package/CHANGELOG.md +7 -0
  3. package/dist/es/index.js +15 -1
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.css +11934 -0
  6. package/dist/index.js +15 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/strings.js +148 -1
  9. package/package.json +40 -4
  10. package/src/README.md +7 -0
  11. package/src/__stories__/item-renderer.stories.jsx +27 -0
  12. package/src/__stories__/server-item-renderer.stories.jsx +27 -0
  13. package/src/__testdata__/item-renderer_testdata.js +161 -0
  14. package/src/__testdata__/renderer_testdata.js +123 -0
  15. package/src/__tests__/__snapshots__/item-renderer_test.jsx.snap +233 -0
  16. package/src/__tests__/__snapshots__/perseus-markdown_test.jsx.snap +516 -0
  17. package/src/__tests__/__snapshots__/pure-markdown_test.js.snap +113 -0
  18. package/src/__tests__/__snapshots__/renderer_test.jsx.snap +576 -0
  19. package/src/__tests__/__snapshots__/server-item-renderer_test.jsx.snap +306 -0
  20. package/src/__tests__/a11y_test.jsx +304 -0
  21. package/src/__tests__/item-renderer_test.jsx +892 -0
  22. package/src/__tests__/mock-asset-loading-widget.jsx +57 -0
  23. package/src/__tests__/mock-widget.jsx +35 -0
  24. package/src/__tests__/perseus-markdown_test.jsx +747 -0
  25. package/src/__tests__/pure-markdown_test.js +552 -0
  26. package/src/__tests__/renderability_test.jsx +481 -0
  27. package/src/__tests__/renderer-api_test.jsx +333 -0
  28. package/src/__tests__/renderer_test.jsx +1792 -0
  29. package/src/__tests__/server-item-renderer_test.jsx +516 -0
  30. package/src/__tests__/test-items/image-item.js +25 -0
  31. package/src/__tests__/test-items/input-number-1-item.js +27 -0
  32. package/src/__tests__/test-items/input-number-2-item.js +39 -0
  33. package/src/__tests__/test-items/table-item.js +30 -0
  34. package/src/__tests__/tex-wrangler_test.js +83 -0
  35. package/src/__tests__/util_test.js +41 -0
  36. package/src/a11y.js +46 -0
  37. package/src/all-widgets.js +9 -0
  38. package/src/article-renderer.jsx +215 -0
  39. package/src/asset-context.js +30 -0
  40. package/src/basic-widgets.js +13 -0
  41. package/src/components/__stories__/button-group.stories.jsx +61 -0
  42. package/src/components/__stories__/fixed-to-responsive.stories.jsx +132 -0
  43. package/src/components/__stories__/graph.stories.jsx +27 -0
  44. package/src/components/__stories__/graphie.stories.jsx +28 -0
  45. package/src/components/__stories__/hud.stories.jsx +36 -0
  46. package/src/components/__stories__/icon.stories.jsx +56 -0
  47. package/src/components/__stories__/image-loader.stories.jsx +60 -0
  48. package/src/components/__stories__/info-tip.stories.jsx +33 -0
  49. package/src/components/__stories__/inline-icon.stories.jsx +39 -0
  50. package/src/components/__stories__/input-with-examples.stories.jsx +51 -0
  51. package/src/components/__stories__/lint.stories.jsx +40 -0
  52. package/src/components/__stories__/math-input.stories.jsx +29 -0
  53. package/src/components/__stories__/math-output.stories.jsx +24 -0
  54. package/src/components/__stories__/multi-button-group.stories.jsx +69 -0
  55. package/src/components/__stories__/number-input.stories.jsx +42 -0
  56. package/src/components/__stories__/possible-answers.stories.jsx +22 -0
  57. package/src/components/__stories__/prop-check-box.stories.jsx +62 -0
  58. package/src/components/__stories__/range-input.stories.jsx +28 -0
  59. package/src/components/__stories__/simple-keypad-input.stories.jsx +28 -0
  60. package/src/components/__stories__/sortable.stories.jsx +73 -0
  61. package/src/components/__stories__/stub-tag-editor.stories.jsx +44 -0
  62. package/src/components/__stories__/svg-image.stories.jsx +60 -0
  63. package/src/components/__stories__/tex.stories.jsx +18 -0
  64. package/src/components/__stories__/text-buttons.stories.jsx +51 -0
  65. package/src/components/__stories__/text-input.stories.jsx +34 -0
  66. package/src/components/__stories__/text-list-editor.stories.jsx +33 -0
  67. package/src/components/__stories__/zoomable-tex.stories.jsx +39 -0
  68. package/src/components/__stories__/zoomable.stories.jsx +40 -0
  69. package/src/components/__testdata__/sorter_testdata.js +20 -0
  70. package/src/components/__tests__/__snapshots__/sortable_test.jsx.snap +79 -0
  71. package/src/components/__tests__/__snapshots__/sorter_test.jsx.snap +297 -0
  72. package/src/components/__tests__/number-input_test.jsx +112 -0
  73. package/src/components/__tests__/sortable_test.jsx +234 -0
  74. package/src/components/__tests__/sorter_test.jsx +111 -0
  75. package/src/components/__tests__/zoomable_test.jsx +388 -0
  76. package/src/components/button-group.jsx +131 -0
  77. package/src/components/constants.js +15 -0
  78. package/src/components/fixed-to-responsive.jsx +163 -0
  79. package/src/components/graph.jsx +414 -0
  80. package/src/components/graphie-classes.jsx +148 -0
  81. package/src/components/graphie-movables.jsx +342 -0
  82. package/src/components/graphie.jsx +353 -0
  83. package/src/components/highlighting/highlightable-content.jsx +245 -0
  84. package/src/components/highlighting/highlights.js +208 -0
  85. package/src/components/highlighting/ranges.js +299 -0
  86. package/src/components/highlighting/types.js +73 -0
  87. package/src/components/highlighting/ui/highlight-renderer.jsx +179 -0
  88. package/src/components/highlighting/ui/highlight-set-renderer.jsx +190 -0
  89. package/src/components/highlighting/ui/highlight-tooltip.jsx +153 -0
  90. package/src/components/highlighting/ui/highlighting-ui.jsx +163 -0
  91. package/src/components/highlighting/ui/selection-tracker.jsx +195 -0
  92. package/src/components/highlighting/ui/types.js +21 -0
  93. package/src/components/highlighting/ui/util.js +166 -0
  94. package/src/components/highlighting/word-indexer.jsx +155 -0
  95. package/src/components/hud.jsx +179 -0
  96. package/src/components/icon.jsx +149 -0
  97. package/src/components/image-loader.jsx +175 -0
  98. package/src/components/info-tip/info-tip.jsx +149 -0
  99. package/src/components/info-tip.jsx +38 -0
  100. package/src/components/inline-icon.jsx +81 -0
  101. package/src/components/input-with-examples.jsx +231 -0
  102. package/src/components/lint.jsx +456 -0
  103. package/src/components/math-input.jsx +282 -0
  104. package/src/components/math-output.jsx +128 -0
  105. package/src/components/multi-button-group.jsx +137 -0
  106. package/src/components/new-tooltip/README.md +110 -0
  107. package/src/components/new-tooltip/__stories__/flexible-position.stories.jsx +437 -0
  108. package/src/components/new-tooltip/__stories__/new-tooltip.stories.jsx +665 -0
  109. package/src/components/new-tooltip/__stories__/tooltip-arrow.stories.jsx +70 -0
  110. package/src/components/new-tooltip/__stories__/tooltip-bubble.stories.jsx +98 -0
  111. package/src/components/new-tooltip/__tests__/style-constants_test.js +8 -0
  112. package/src/components/new-tooltip/__tests__/util_test.js +47 -0
  113. package/src/components/new-tooltip/flexible-position.jsx +182 -0
  114. package/src/components/new-tooltip/new-tooltip.jsx +399 -0
  115. package/src/components/new-tooltip/style-constants.js +13 -0
  116. package/src/components/new-tooltip/tooltip-arrow.jsx +184 -0
  117. package/src/components/new-tooltip/tooltip-bubble.jsx +223 -0
  118. package/src/components/new-tooltip/tooltip-portal.jsx +101 -0
  119. package/src/components/new-tooltip/tooltip-positioner.jsx +529 -0
  120. package/src/components/new-tooltip/types.js +183 -0
  121. package/src/components/new-tooltip/util.js +27 -0
  122. package/src/components/number-input.jsx +253 -0
  123. package/src/components/possible-answers.jsx +36 -0
  124. package/src/components/prop-check-box.jsx +78 -0
  125. package/src/components/range-input.jsx +61 -0
  126. package/src/components/simple-keypad-input.jsx +91 -0
  127. package/src/components/sortable.jsx +872 -0
  128. package/src/components/stub-tag-editor.jsx +53 -0
  129. package/src/components/svg-image.jsx +762 -0
  130. package/src/components/tex-buttons.jsx +322 -0
  131. package/src/components/tex.jsx +70 -0
  132. package/src/components/text-input.jsx +82 -0
  133. package/src/components/text-list-editor.jsx +157 -0
  134. package/src/components/tooltip.jsx +395 -0
  135. package/src/components/visibility-observer/__stories__/visibility-observer.stories.jsx +140 -0
  136. package/src/components/visibility-observer/get-scroll-parent.js +45 -0
  137. package/src/components/visibility-observer/visibility-observer.js +109 -0
  138. package/src/components/visibility-observer/visibility-observer.jsx +123 -0
  139. package/src/components/zoomable-tex.jsx +70 -0
  140. package/src/components/zoomable.jsx +304 -0
  141. package/src/components.js +17 -0
  142. package/src/dependencies.js +22 -0
  143. package/src/error-boundary.jsx +48 -0
  144. package/src/extra-widgets.js +75 -0
  145. package/src/gorgon/README +40 -0
  146. package/src/gorgon/__tests__/matcher_test.js +497 -0
  147. package/src/gorgon/__tests__/rule_test.js +101 -0
  148. package/src/gorgon/__tests__/rules_test.js +487 -0
  149. package/src/gorgon/__tests__/selector-parser_test.js +52 -0
  150. package/src/gorgon/__tests__/tree-transformer_test.js +446 -0
  151. package/src/gorgon/gorgon.js +290 -0
  152. package/src/gorgon/proptypes.js +29 -0
  153. package/src/gorgon/rule.js +413 -0
  154. package/src/gorgon/rules/absolute-url.js +24 -0
  155. package/src/gorgon/rules/all-rules.js +72 -0
  156. package/src/gorgon/rules/blockquoted-math.js +10 -0
  157. package/src/gorgon/rules/blockquoted-widget.js +10 -0
  158. package/src/gorgon/rules/double-spacing-after-terminal.js +12 -0
  159. package/src/gorgon/rules/extra-content-spacing.js +12 -0
  160. package/src/gorgon/rules/heading-level-1.js +14 -0
  161. package/src/gorgon/rules/heading-level-skip.js +20 -0
  162. package/src/gorgon/rules/heading-sentence-case.js +11 -0
  163. package/src/gorgon/rules/heading-title-case.js +63 -0
  164. package/src/gorgon/rules/image-alt-text.js +21 -0
  165. package/src/gorgon/rules/image-in-table.js +10 -0
  166. package/src/gorgon/rules/image-spaces-around-urls.js +35 -0
  167. package/src/gorgon/rules/image-widget.js +50 -0
  168. package/src/gorgon/rules/link-click-here.js +11 -0
  169. package/src/gorgon/rules/lint-utils.js +48 -0
  170. package/src/gorgon/rules/long-paragraph.js +14 -0
  171. package/src/gorgon/rules/math-adjacent.js +10 -0
  172. package/src/gorgon/rules/math-align-extra-break.js +11 -0
  173. package/src/gorgon/rules/math-align-linebreaks.js +43 -0
  174. package/src/gorgon/rules/math-empty.js +10 -0
  175. package/src/gorgon/rules/math-font-size.js +12 -0
  176. package/src/gorgon/rules/math-frac.js +10 -0
  177. package/src/gorgon/rules/math-nested.js +11 -0
  178. package/src/gorgon/rules/math-starts-with-space.js +12 -0
  179. package/src/gorgon/rules/math-text-empty.js +10 -0
  180. package/src/gorgon/rules/math-without-dollars.js +14 -0
  181. package/src/gorgon/rules/nested-lists.js +11 -0
  182. package/src/gorgon/rules/profanity.js +10 -0
  183. package/src/gorgon/rules/table-missing-cells.js +20 -0
  184. package/src/gorgon/rules/unbalanced-code-delimiters.js +14 -0
  185. package/src/gorgon/rules/unescaped-dollar.js +10 -0
  186. package/src/gorgon/rules/widget-in-table.js +10 -0
  187. package/src/gorgon/selector.js +506 -0
  188. package/src/gorgon/tree-transformer.js +588 -0
  189. package/src/hint-renderer.jsx +159 -0
  190. package/src/hints-renderer.jsx +359 -0
  191. package/src/icon-paths.js +120 -0
  192. package/src/index.js +149 -2
  193. package/src/init.js +49 -0
  194. package/src/interaction-tracker.js +60 -0
  195. package/src/interactive2/__tests__/movable-mock.js +48 -0
  196. package/src/interactive2/__tests__/movable-point_test.js +146 -0
  197. package/src/interactive2/interactive-util.js +152 -0
  198. package/src/interactive2/movable-helper-methods.js +160 -0
  199. package/src/interactive2/movable-line-options.js +392 -0
  200. package/src/interactive2/movable-line.js +322 -0
  201. package/src/interactive2/movable-point-options.js +190 -0
  202. package/src/interactive2/movable-point.jsx +604 -0
  203. package/src/interactive2/movable-polygon-options.js +351 -0
  204. package/src/interactive2/movable-polygon.js +367 -0
  205. package/src/interactive2/movable.js +273 -0
  206. package/src/interactive2/objective_.js +79 -0
  207. package/src/interactive2/types.js +3 -0
  208. package/src/interactive2/wrapped-defaults.js +86 -0
  209. package/src/interactive2/wrapped-ellipse.js +87 -0
  210. package/src/interactive2/wrapped-line.js +109 -0
  211. package/src/interactive2/wrapped-path.js +47 -0
  212. package/src/interactive2.js +91 -0
  213. package/src/item-renderer.jsx +518 -0
  214. package/src/item-version.js +12 -0
  215. package/src/jipt-paragraphs.js +44 -0
  216. package/src/jquery.mobile.vmouse.js +545 -0
  217. package/src/keypad-context.js +33 -0
  218. package/src/loading-context.js +20 -0
  219. package/src/logging/log.js +107 -0
  220. package/src/logging/log_test.js +41 -0
  221. package/src/mixins/changeable.jsx +115 -0
  222. package/src/mixins/editor-jsonify.jsx +13 -0
  223. package/src/mixins/provide-keypad.jsx +131 -0
  224. package/src/mixins/widget-jsonify-deprecated.jsx +23 -0
  225. package/src/mixins/widget-prop-blacklist.js +36 -0
  226. package/src/multi-items/__stories__/multi-renderer.stories.js +88 -0
  227. package/src/multi-items/__testdata__/multi-renderer_testdata.js +174 -0
  228. package/src/multi-items/__tests__/__snapshots__/multi-renderer_test.js.snap +994 -0
  229. package/src/multi-items/__tests__/items_test.js +245 -0
  230. package/src/multi-items/__tests__/multi-renderer_test.js +903 -0
  231. package/src/multi-items/__tests__/prop-type-builders_test.js +134 -0
  232. package/src/multi-items/__tests__/shapes_test.js +44 -0
  233. package/src/multi-items/__tests__/trees_test.js +316 -0
  234. package/src/multi-items/item-types.js +55 -0
  235. package/src/multi-items/items.js +176 -0
  236. package/src/multi-items/multi-renderer.jsx +542 -0
  237. package/src/multi-items/prop-type-builders.js +105 -0
  238. package/src/multi-items/shape-types.js +47 -0
  239. package/src/multi-items/shapes.js +53 -0
  240. package/src/multi-items/tree-types.js +42 -0
  241. package/src/multi-items/trees.js +345 -0
  242. package/src/multi-items.js +76 -0
  243. package/src/not-gorgon.js +129 -0
  244. package/src/perseus-api.jsx +270 -0
  245. package/src/perseus-env.js +26 -0
  246. package/src/perseus-error.js +19 -0
  247. package/src/perseus-markdown.jsx +434 -0
  248. package/src/perseus-types.js +1597 -0
  249. package/src/pure-markdown.js +346 -0
  250. package/src/question-paragraph.jsx +30 -0
  251. package/src/renderability.jsx +108 -0
  252. package/src/renderer.jsx +1931 -0
  253. package/src/server-item-renderer.jsx +467 -0
  254. package/src/sigfigs.jsx +492 -0
  255. package/src/styles/articles.less +748 -0
  256. package/src/styles/constants.js +119 -0
  257. package/src/styles/global-constants.js +350 -0
  258. package/src/styles/global-styles.js +307 -0
  259. package/src/styles/khan-exercise.css +1304 -0
  260. package/src/styles/media-queries.js +48 -0
  261. package/src/styles/perseus-renderer.less +1008 -0
  262. package/src/styles/shared.js +132 -0
  263. package/src/styles/util.less +47 -0
  264. package/src/styles/variables.boostrap.less +301 -0
  265. package/src/styles/variables.less +68 -0
  266. package/src/styles/variables.shared.less +356 -0
  267. package/src/styles/widgets/categorizer.less +39 -0
  268. package/src/styles/widgets/definition.less +86 -0
  269. package/src/styles/widgets/dropdown.less +3 -0
  270. package/src/styles/widgets/expression.less +147 -0
  271. package/src/styles/widgets/graded-group.less +36 -0
  272. package/src/styles/widgets/grapher.less +11 -0
  273. package/src/styles/widgets/group.less +19 -0
  274. package/src/styles/widgets/image.less +29 -0
  275. package/src/styles/widgets/interactive-graph.less +61 -0
  276. package/src/styles/widgets/label-image.less +41 -0
  277. package/src/styles/widgets/matcher.less +8 -0
  278. package/src/styles/widgets/matrix.less +120 -0
  279. package/src/styles/widgets/measurer.less +20 -0
  280. package/src/styles/widgets/orderer.less +97 -0
  281. package/src/styles/widgets/passage.less +151 -0
  282. package/src/styles/widgets/plotter.less +33 -0
  283. package/src/styles/widgets/radio.less +52 -0
  284. package/src/styles/widgets/reaction-diagram.less +35 -0
  285. package/src/styles/widgets/sequence.less +5 -0
  286. package/src/styles/widgets/sortable.less +127 -0
  287. package/src/styles/widgets/table.less +56 -0
  288. package/src/styles/widgets/transformer.less +28 -0
  289. package/src/styles/widgets/unit.less +14 -0
  290. package/src/tex-wrangler.js +176 -0
  291. package/src/traversal.jsx +141 -0
  292. package/src/types.js +538 -0
  293. package/src/util/a11y.js +24 -0
  294. package/src/util/answer-types.js +862 -0
  295. package/src/util/answer-types_test.js +115 -0
  296. package/src/util/colors.js +94 -0
  297. package/src/util/fix-passage-refs.jsx +122 -0
  298. package/src/util/graph-utils.js +16 -0
  299. package/src/util/graphie.js +1585 -0
  300. package/src/util/interactive.js +4071 -0
  301. package/src/util/katex-preprocess.js +16 -0
  302. package/src/util/math.js +296 -0
  303. package/src/util/mobile-native-utils.js +14 -0
  304. package/src/util/mobile-native-utils_test.js +24 -0
  305. package/src/util/register-all-widgets-for-testing.js +12 -0
  306. package/src/util/scroll-utils.js +162 -0
  307. package/src/util/sizing-utils.js +46 -0
  308. package/src/util/tex.js +203 -0
  309. package/src/util/url-utils.js +36 -0
  310. package/src/util.js +990 -0
  311. package/src/version.js +11 -0
  312. package/src/widget-container.jsx +174 -0
  313. package/src/widgets/__stories__/categorizer.stories.jsx +15 -0
  314. package/src/widgets/__stories__/cs-program.stories.jsx +15 -0
  315. package/src/widgets/__stories__/definition.stories.jsx +38 -0
  316. package/src/widgets/__stories__/dropdown.stories.jsx +15 -0
  317. package/src/widgets/__stories__/explanation.stories.jsx +19 -0
  318. package/src/widgets/__stories__/expression.stories.jsx +26 -0
  319. package/src/widgets/__stories__/graded-group-set.stories.jsx +32 -0
  320. package/src/widgets/__stories__/graded-group.stories.jsx +32 -0
  321. package/src/widgets/__stories__/grapher.stories.jsx +47 -0
  322. package/src/widgets/__stories__/group.stories.jsx +15 -0
  323. package/src/widgets/__stories__/iframe.stories.jsx +15 -0
  324. package/src/widgets/__stories__/image.stories.jsx +62 -0
  325. package/src/widgets/__stories__/input-number.stories.jsx +90 -0
  326. package/src/widgets/__stories__/interaction.stories.jsx +15 -0
  327. package/src/widgets/__stories__/interactive-graph.stories.jsx +61 -0
  328. package/src/widgets/__stories__/matcher.stories.jsx +15 -0
  329. package/src/widgets/__stories__/matrix.stories.jsx +15 -0
  330. package/src/widgets/__stories__/number-line.stories.jsx +15 -0
  331. package/src/widgets/__stories__/numeric-input.stories.jsx +19 -0
  332. package/src/widgets/__stories__/orderer.stories.jsx +15 -0
  333. package/src/widgets/__stories__/passage-ref.stories.jsx +19 -0
  334. package/src/widgets/__stories__/passage.stories.jsx +19 -0
  335. package/src/widgets/__stories__/radio.stories.jsx +82 -0
  336. package/src/widgets/__stories__/sorter.stories.jsx +15 -0
  337. package/src/widgets/__stories__/transformer.stories.jsx +15 -0
  338. package/src/widgets/__stories__/video.stories.jsx +15 -0
  339. package/src/widgets/__testdata__/categorizer_testdata.js +50 -0
  340. package/src/widgets/__testdata__/cs-program_testdata.js +28 -0
  341. package/src/widgets/__testdata__/dropdown_testdata.js +34 -0
  342. package/src/widgets/__testdata__/explanation_testdata.js +56 -0
  343. package/src/widgets/__testdata__/expression_testdata.js +95 -0
  344. package/src/widgets/__testdata__/graded-group-set_testdata.js +358 -0
  345. package/src/widgets/__testdata__/graded-group_testdata.js +79 -0
  346. package/src/widgets/__testdata__/grapher_testdata.js +376 -0
  347. package/src/widgets/__testdata__/group_testdata.js +156 -0
  348. package/src/widgets/__testdata__/iframe_testdata.js +36 -0
  349. package/src/widgets/__testdata__/image_testdata.js +38 -0
  350. package/src/widgets/__testdata__/input-number_testdata.js +73 -0
  351. package/src/widgets/__testdata__/interaction_testdata.js +264 -0
  352. package/src/widgets/__testdata__/interactive-graph_testdata.js +646 -0
  353. package/src/widgets/__testdata__/matcher_testdata.js +34 -0
  354. package/src/widgets/__testdata__/matrix_testdata.js +29 -0
  355. package/src/widgets/__testdata__/number-line_testdata.js +31 -0
  356. package/src/widgets/__testdata__/numeric-input_testdata.js +266 -0
  357. package/src/widgets/__testdata__/orderer_testdata.js +58 -0
  358. package/src/widgets/__testdata__/passage-ref_testdata.js +41 -0
  359. package/src/widgets/__testdata__/passage_testdata.js +71 -0
  360. package/src/widgets/__testdata__/radio_testdata.js +210 -0
  361. package/src/widgets/__testdata__/sorter_testdata.js +20 -0
  362. package/src/widgets/__testdata__/transformer_testdata.js +109 -0
  363. package/src/widgets/__testdata__/video_testdata.js +22 -0
  364. package/src/widgets/__tests__/__snapshots__/categorizer_test.jsx.snap +928 -0
  365. package/src/widgets/__tests__/__snapshots__/cs-program_test.jsx.snap +75 -0
  366. package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +99 -0
  367. package/src/widgets/__tests__/__snapshots__/dropdown_test.jsx.snap +143 -0
  368. package/src/widgets/__tests__/__snapshots__/explanation_test.js.snap +473 -0
  369. package/src/widgets/__tests__/__snapshots__/expression_test.jsx.snap +38 -0
  370. package/src/widgets/__tests__/__snapshots__/graded-group-set-jipt_test.jsx.snap +754 -0
  371. package/src/widgets/__tests__/__snapshots__/graded-group-set_test.jsx.snap +310 -0
  372. package/src/widgets/__tests__/__snapshots__/graded-group_test.jsx.snap +863 -0
  373. package/src/widgets/__tests__/__snapshots__/grapher_test.jsx.snap +2880 -0
  374. package/src/widgets/__tests__/__snapshots__/group_test.jsx.snap +1154 -0
  375. package/src/widgets/__tests__/__snapshots__/iframe_test.jsx.snap +69 -0
  376. package/src/widgets/__tests__/__snapshots__/image_test.jsx.snap +388 -0
  377. package/src/widgets/__tests__/__snapshots__/input-number_test.jsx.snap +978 -0
  378. package/src/widgets/__tests__/__snapshots__/interaction_test.jsx.snap +311 -0
  379. package/src/widgets/__tests__/__snapshots__/interactive-graph_test.jsx.snap +2915 -0
  380. package/src/widgets/__tests__/__snapshots__/matcher_test.jsx.snap +1039 -0
  381. package/src/widgets/__tests__/__snapshots__/matrix_test.jsx.snap +450 -0
  382. package/src/widgets/__tests__/__snapshots__/number-line_test.jsx.snap +888 -0
  383. package/src/widgets/__tests__/__snapshots__/numeric-input_test.jsx.snap +930 -0
  384. package/src/widgets/__tests__/__snapshots__/orderer_test.jsx.snap +275 -0
  385. package/src/widgets/__tests__/__snapshots__/passage-ref_test.jsx.snap +446 -0
  386. package/src/widgets/__tests__/__snapshots__/passage_test.jsx.snap +1988 -0
  387. package/src/widgets/__tests__/__snapshots__/radio_test.jsx.snap +7107 -0
  388. package/src/widgets/__tests__/__snapshots__/video_test.jsx.snap +163 -0
  389. package/src/widgets/__tests__/categorizer_test.jsx +205 -0
  390. package/src/widgets/__tests__/cs-program_test.jsx +45 -0
  391. package/src/widgets/__tests__/definition_test.js +152 -0
  392. package/src/widgets/__tests__/dropdown_test.jsx +106 -0
  393. package/src/widgets/__tests__/explanation_test.js +199 -0
  394. package/src/widgets/__tests__/expression_test.jsx +439 -0
  395. package/src/widgets/__tests__/graded-group-set-jipt_test.jsx +33 -0
  396. package/src/widgets/__tests__/graded-group-set_test.jsx +270 -0
  397. package/src/widgets/__tests__/graded-group_test.jsx +233 -0
  398. package/src/widgets/__tests__/grapher.cypress.jsx +486 -0
  399. package/src/widgets/__tests__/grapher_test.jsx +35 -0
  400. package/src/widgets/__tests__/group_test.jsx +512 -0
  401. package/src/widgets/__tests__/iframe_test.jsx +47 -0
  402. package/src/widgets/__tests__/image_test.jsx +65 -0
  403. package/src/widgets/__tests__/input-number_test.jsx +360 -0
  404. package/src/widgets/__tests__/interaction_test.jsx +33 -0
  405. package/src/widgets/__tests__/interactive-graph.cypress.jsx +697 -0
  406. package/src/widgets/__tests__/interactive-graph_test.jsx +105 -0
  407. package/src/widgets/__tests__/matcher_test.jsx +157 -0
  408. package/src/widgets/__tests__/matrix_test.jsx +84 -0
  409. package/src/widgets/__tests__/number-line_test.jsx +81 -0
  410. package/src/widgets/__tests__/numeric-input_test.jsx +574 -0
  411. package/src/widgets/__tests__/orderer_test.jsx +75 -0
  412. package/src/widgets/__tests__/passage-ref_test.jsx +166 -0
  413. package/src/widgets/__tests__/passage_test.jsx +133 -0
  414. package/src/widgets/__tests__/radio/base-radio_test.jsx +82 -0
  415. package/src/widgets/__tests__/radio_test.jsx +651 -0
  416. package/src/widgets/__tests__/renderQuestion.jsx +65 -0
  417. package/src/widgets/__tests__/unit_test.jsx +144 -0
  418. package/src/widgets/__tests__/video_test.jsx +55 -0
  419. package/src/widgets/categorizer.jsx +338 -0
  420. package/src/widgets/cs-program.jsx +228 -0
  421. package/src/widgets/definition.jsx +141 -0
  422. package/src/widgets/dropdown.jsx +143 -0
  423. package/src/widgets/explanation.jsx +315 -0
  424. package/src/widgets/expression.jsx +654 -0
  425. package/src/widgets/graded-group-answer-bar.jsx +152 -0
  426. package/src/widgets/graded-group-set.jsx +285 -0
  427. package/src/widgets/graded-group.jsx +448 -0
  428. package/src/widgets/grapher/util.jsx +819 -0
  429. package/src/widgets/grapher.jsx +658 -0
  430. package/src/widgets/group.jsx +213 -0
  431. package/src/widgets/iframe.jsx +199 -0
  432. package/src/widgets/image.jsx +309 -0
  433. package/src/widgets/input-number.jsx +410 -0
  434. package/src/widgets/interaction/arrow-picker.jsx +39 -0
  435. package/src/widgets/interaction/color-picker.jsx +69 -0
  436. package/src/widgets/interaction/dash-picker.jsx +46 -0
  437. package/src/widgets/interaction/element-container.jsx +97 -0
  438. package/src/widgets/interaction.jsx +742 -0
  439. package/src/widgets/interactive-graph.jsx +2821 -0
  440. package/src/widgets/label-image/__stories__/answer-choices.stories.jsx +93 -0
  441. package/src/widgets/label-image/__stories__/marker.stories.jsx +172 -0
  442. package/src/widgets/label-image/answer-choices.jsx +311 -0
  443. package/src/widgets/label-image/marker.jsx +365 -0
  444. package/src/widgets/label-image/types.js +33 -0
  445. package/src/widgets/label-image.jsx +841 -0
  446. package/src/widgets/label-image_test.js +840 -0
  447. package/src/widgets/lights-puzzle.jsx +356 -0
  448. package/src/widgets/matcher.jsx +271 -0
  449. package/src/widgets/matrix.jsx +615 -0
  450. package/src/widgets/measurer.jsx +215 -0
  451. package/src/widgets/molecule/__tests__/layout_test.jsx +159 -0
  452. package/src/widgets/molecule/__tests__/parser_test.jsx +142 -0
  453. package/src/widgets/molecule/molecule-drawing.jsx +175 -0
  454. package/src/widgets/molecule/molecule-layout.jsx +367 -0
  455. package/src/widgets/molecule/smiles-parser.jsx +300 -0
  456. package/src/widgets/molecule.jsx +172 -0
  457. package/src/widgets/number-line.jsx +858 -0
  458. package/src/widgets/numeric-input.jsx +622 -0
  459. package/src/widgets/orderer.jsx +753 -0
  460. package/src/widgets/passage/__tests__/passage-markdown_test.jsx +382 -0
  461. package/src/widgets/passage/get-line-height-for-node.js +10 -0
  462. package/src/widgets/passage/passage-markdown.jsx +416 -0
  463. package/src/widgets/passage-ref-target.jsx +70 -0
  464. package/src/widgets/passage-ref.jsx +198 -0
  465. package/src/widgets/passage.jsx +601 -0
  466. package/src/widgets/plotter.jsx +1198 -0
  467. package/src/widgets/radio/__stories__/base-radio.stories.jsx +40 -0
  468. package/src/widgets/radio/__stories__/choice-icon.stories.jsx +157 -0
  469. package/src/widgets/radio/__stories__/choice-none-above.stories.jsx +26 -0
  470. package/src/widgets/radio/__stories__/cross-out-button.stories.jsx +64 -0
  471. package/src/widgets/radio/__stories__/cross-out-menu.stories.jsx +59 -0
  472. package/src/widgets/radio/__stories__/cross-out-tooltip.stories.jsx +59 -0
  473. package/src/widgets/radio/__stories__/focus-ring.stories.jsx +38 -0
  474. package/src/widgets/radio/__stories__/option-status.stories.jsx +118 -0
  475. package/src/widgets/radio/__stories__/toggleable-radio-button.stories.jsx +28 -0
  476. package/src/widgets/radio/base-radio.jsx +642 -0
  477. package/src/widgets/radio/choice-icon.jsx +468 -0
  478. package/src/widgets/radio/choice-none-above.jsx +54 -0
  479. package/src/widgets/radio/choice.jsx +692 -0
  480. package/src/widgets/radio/choice.jsx.fixture.js +64 -0
  481. package/src/widgets/radio/cross-out-button.jsx +136 -0
  482. package/src/widgets/radio/cross-out-menu-wrapper.jsx +492 -0
  483. package/src/widgets/radio/cross-out-tooltip.jsx +129 -0
  484. package/src/widgets/radio/focus-ring.jsx +51 -0
  485. package/src/widgets/radio/option-status.jsx +89 -0
  486. package/src/widgets/radio/toggleable-radio-button.jsx +133 -0
  487. package/src/widgets/radio/util.js +32 -0
  488. package/src/widgets/radio/util_test.js +19 -0
  489. package/src/widgets/radio/widget.jsx +470 -0
  490. package/src/widgets/radio.jsx +156 -0
  491. package/src/widgets/reaction-diagram.jsx +136 -0
  492. package/src/widgets/sequence.jsx +140 -0
  493. package/src/widgets/simulator.jsx +808 -0
  494. package/src/widgets/sorter.jsx +146 -0
  495. package/src/widgets/table.jsx +395 -0
  496. package/src/widgets/transformer.jsx +2870 -0
  497. package/src/widgets/unit.jsx +371 -0
  498. package/src/widgets/video-transcript-link.jsx +84 -0
  499. package/src/widgets/video-transcript-link_test.js +211 -0
  500. package/src/widgets/video.jsx +131 -0
  501. package/src/widgets.js +431 -0
  502. package/src/zoom.js +539 -0
  503. package/src/__tests__/index.test.js +0 -14
@@ -0,0 +1,163 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`video widget should snapshot on mobile: first mobile render 1`] = `
4
+ <div>
5
+ <span
6
+ class="mock-KatexProvider"
7
+ >
8
+ <div
9
+ class="perseus-renderer perseus-renderer-responsive"
10
+ >
11
+ <div
12
+ class="paragraph"
13
+ data-perseus-paragraph-index="0"
14
+ >
15
+ <div
16
+ class="paragraph"
17
+ >
18
+ Watch the Biogeography: Where Life Lives video to find the answer.
19
+ </div>
20
+ </div>
21
+ <div
22
+ class="paragraph"
23
+ data-perseus-paragraph-index="1"
24
+ >
25
+ <div
26
+ class="paragraph"
27
+ >
28
+ <div
29
+ class="perseus-widget-container widget-nohighlight widget-block"
30
+ >
31
+ <div
32
+ class="default_xu2jcg"
33
+ >
34
+ <div
35
+ class="fixed-to-responsive"
36
+ style="max-width: 1280px; max-height: 720px;"
37
+ >
38
+ <div
39
+ style="padding-bottom: 56.25%;"
40
+ />
41
+ <div
42
+ class="default_xu2jcg-o_O-srOnly_19bpjuy"
43
+ >
44
+ Khan Academy video wrapper
45
+ </div>
46
+ <iframe
47
+ allowfullscreen=""
48
+ class="perseus-video-widget"
49
+ height="720"
50
+ sandbox="allow-same-origin allow-scripts"
51
+ src="https://www.khanacademy.org/embed_video?slug=biogeography-where-life-lives&internal_video_only=1"
52
+ width="1280"
53
+ />
54
+ </div>
55
+ <div
56
+ class="default_xu2jcg-o_O-transcriptLink_18xwqfz"
57
+ >
58
+ <span
59
+ class="text_f1191h"
60
+ />
61
+ <div
62
+ aria-hidden="true"
63
+ class="default_xu2jcg-o_O-inlineStyles_sc01dy"
64
+ />
65
+ <a
66
+ class="shared_1ff70zb-o_O-default_nelfll visited-no-recolor"
67
+ href="/transcript/videoNotFound"
68
+ rel="noopener noreferrer"
69
+ tabindex="0"
70
+ target="_blank"
71
+ >
72
+ See video transcript
73
+ </a>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </span>
81
+ </div>
82
+ `;
83
+
84
+ exports[`video widget should snapshot: first render 1`] = `
85
+ <div>
86
+ <span
87
+ class="mock-KatexProvider"
88
+ >
89
+ <div
90
+ class="perseus-renderer perseus-renderer-responsive"
91
+ >
92
+ <div
93
+ class="paragraph"
94
+ data-perseus-paragraph-index="0"
95
+ >
96
+ <div
97
+ class="paragraph"
98
+ >
99
+ Watch the Biogeography: Where Life Lives video to find the answer.
100
+ </div>
101
+ </div>
102
+ <div
103
+ class="paragraph"
104
+ data-perseus-paragraph-index="1"
105
+ >
106
+ <div
107
+ class="paragraph"
108
+ >
109
+ <div
110
+ class="perseus-widget-container widget-nohighlight widget-block"
111
+ >
112
+ <div
113
+ class="default_xu2jcg"
114
+ >
115
+ <div
116
+ class="fixed-to-responsive"
117
+ style="max-width: 1280px; max-height: 720px;"
118
+ >
119
+ <div
120
+ style="padding-bottom: 56.25%;"
121
+ />
122
+ <div
123
+ class="default_xu2jcg-o_O-srOnly_19bpjuy"
124
+ >
125
+ Khan Academy video wrapper
126
+ </div>
127
+ <iframe
128
+ allowfullscreen=""
129
+ class="perseus-video-widget"
130
+ height="720"
131
+ sandbox="allow-same-origin allow-scripts"
132
+ src="https://www.khanacademy.org/embed_video?slug=biogeography-where-life-lives&internal_video_only=1"
133
+ width="1280"
134
+ />
135
+ </div>
136
+ <div
137
+ class="default_xu2jcg-o_O-transcriptLink_18xwqfz"
138
+ >
139
+ <span
140
+ class="text_f1191h"
141
+ />
142
+ <div
143
+ aria-hidden="true"
144
+ class="default_xu2jcg-o_O-inlineStyles_sc01dy"
145
+ />
146
+ <a
147
+ class="shared_1ff70zb-o_O-default_nelfll visited-no-recolor"
148
+ href="/transcript/videoNotFound"
149
+ rel="noopener noreferrer"
150
+ tabindex="0"
151
+ target="_blank"
152
+ >
153
+ See video transcript
154
+ </a>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ </span>
162
+ </div>
163
+ `;
@@ -0,0 +1,205 @@
1
+ // @flow
2
+
3
+ import {screen} from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import "@testing-library/jest-dom";
6
+
7
+ import {testDependencies} from "../../../../../testing/test-dependencies.js";
8
+ import * as Dependencies from "../../dependencies.js";
9
+ import {question1} from "../__testdata__/categorizer_testdata.js";
10
+ import {Categorizer} from "../categorizer.jsx";
11
+
12
+ import {renderQuestion} from "./renderQuestion.jsx";
13
+
14
+ import type {APIOptions} from "../../types.js";
15
+ import type {Rubric} from "../categorizer.jsx";
16
+
17
+ describe("categorizer widget", () => {
18
+ beforeEach(() => {
19
+ jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
20
+ testDependencies,
21
+ );
22
+ });
23
+
24
+ it("should snapshot", () => {
25
+ // Arrange
26
+ const apiOptions: APIOptions = {
27
+ isMobile: false,
28
+ };
29
+
30
+ // Act
31
+ const {container} = renderQuestion(question1, apiOptions);
32
+
33
+ // Assert
34
+ expect(container).toMatchSnapshot("first render");
35
+ });
36
+
37
+ it("should snapshot on mobile", () => {
38
+ // Arrange
39
+ const apiOptions: APIOptions = {
40
+ isMobile: true,
41
+ };
42
+
43
+ // Act
44
+ const {container} = renderQuestion(question1, apiOptions);
45
+
46
+ // Assert
47
+ expect(container).toMatchSnapshot("first mobile render");
48
+ });
49
+
50
+ it("is incorrect when blank", () => {
51
+ // Arrange
52
+ const apiOptions: APIOptions = {
53
+ isMobile: false,
54
+ };
55
+ const {renderer} = renderQuestion(question1, apiOptions);
56
+
57
+ // Act
58
+ const [_, score] = renderer.guessAndScore();
59
+
60
+ // Assert
61
+ expect(score).toMatchInlineSnapshot(`
62
+ Object {
63
+ "message": "Make sure you select something for every row.",
64
+ "type": "invalid",
65
+ }
66
+ `);
67
+ });
68
+
69
+ it("can be answered incorrectly", () => {
70
+ // arrange
71
+ const {renderer} = renderQuestion(question1);
72
+
73
+ const firstItem = screen.getAllByRole("row")[0];
74
+ userEvent.click(firstItem);
75
+
76
+ // act
77
+ const [_, score] = renderer.guessAndScore();
78
+
79
+ // assert
80
+ expect(score).toMatchInlineSnapshot(`
81
+ Object {
82
+ "message": "Make sure you select something for every row.",
83
+ "type": "invalid",
84
+ }
85
+ `);
86
+ });
87
+
88
+ it("can be answered correctly", () => {
89
+ // arrange
90
+ const {renderer} = renderQuestion(question1);
91
+
92
+ // act
93
+ userEvent.click(
94
+ screen.getAllByRole("button", {name: "No relationship"})[0],
95
+ );
96
+ userEvent.click(
97
+ screen.getAllByRole("button", {
98
+ name: "Positive linear relationship",
99
+ })[0],
100
+ );
101
+ userEvent.click(
102
+ screen.getAllByRole("button", {
103
+ name: "Negative linear relationship",
104
+ })[1],
105
+ );
106
+ userEvent.click(
107
+ screen.getAllByRole("button", {name: "Nonlinear relationship"})[1],
108
+ );
109
+
110
+ jest.runOnlyPendingTimers();
111
+ renderer.guessAndScore();
112
+
113
+ // assert
114
+ expect(renderer).toHaveBeenAnsweredCorrectly();
115
+ });
116
+ });
117
+
118
+ describe("validating answers", () => {
119
+ it("gives points when the answer is correct", () => {
120
+ const rubric: Rubric = {
121
+ items: ["Graph $1$", "Graph $2$"],
122
+ values: [1, 3],
123
+ randomizeItems: false,
124
+ categories: [
125
+ "No relationship",
126
+ "Positive linear relationship",
127
+ "Negative linear relationship",
128
+ "Nonlinear relationship",
129
+ ],
130
+ highlightLint: false,
131
+ static: false,
132
+ };
133
+
134
+ const useInput = {
135
+ values: [1, 3],
136
+ };
137
+ const score = Categorizer.validate(useInput, rubric);
138
+
139
+ expect(score).toMatchInlineSnapshot(`
140
+ Object {
141
+ "earned": 1,
142
+ "message": null,
143
+ "total": 1,
144
+ "type": "points",
145
+ }
146
+ `);
147
+ });
148
+
149
+ it("does not give points when incorrectly answered", () => {
150
+ const rubric: Rubric = {
151
+ items: ["Graph $1$", "Graph $2$"],
152
+ values: [1, 3],
153
+ randomizeItems: false,
154
+ categories: [
155
+ "No relationship",
156
+ "Positive linear relationship",
157
+ "Negative linear relationship",
158
+ "Nonlinear relationship",
159
+ ],
160
+ highlightLint: false,
161
+ static: false,
162
+ };
163
+
164
+ const useInput = {
165
+ values: [2, 3],
166
+ };
167
+ const score = Categorizer.validate(useInput, rubric);
168
+
169
+ expect(score).toMatchInlineSnapshot(`
170
+ Object {
171
+ "earned": 0,
172
+ "message": null,
173
+ "total": 1,
174
+ "type": "points",
175
+ }
176
+ `);
177
+ });
178
+ it("tells the learner its not complete if not selected", () => {
179
+ const rubric: Rubric = {
180
+ items: ["Graph $1$", "Graph $2$"],
181
+ values: [1, 3],
182
+ randomizeItems: false,
183
+ categories: [
184
+ "No relationship",
185
+ "Positive linear relationship",
186
+ "Negative linear relationship",
187
+ "Nonlinear relationship",
188
+ ],
189
+ highlightLint: false,
190
+ static: false,
191
+ };
192
+
193
+ const useInput = {
194
+ values: [2],
195
+ };
196
+ const score = Categorizer.validate(useInput, rubric);
197
+
198
+ expect(score).toMatchInlineSnapshot(`
199
+ Object {
200
+ "message": "Make sure you select something for every row.",
201
+ "type": "invalid",
202
+ }
203
+ `);
204
+ });
205
+ });
@@ -0,0 +1,45 @@
1
+ // @flow
2
+
3
+ import "@testing-library/jest-dom";
4
+
5
+ import {testDependencies} from "../../../../../testing/test-dependencies.js";
6
+ import * as Dependencies from "../../dependencies.js";
7
+ import {question1} from "../__testdata__/cs-program_testdata.js";
8
+
9
+ import {renderQuestion} from "./renderQuestion.jsx";
10
+
11
+ describe("cs-program widget", () => {
12
+ beforeEach(() => {
13
+ jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
14
+ testDependencies,
15
+ );
16
+ });
17
+
18
+ it("should snapshot", () => {
19
+ // Arrange
20
+ const apiOptions = {
21
+ isMobile: false,
22
+ };
23
+
24
+ // Act
25
+ const {container} = renderQuestion(question1, apiOptions);
26
+
27
+ // Assert
28
+ expect(container).toMatchSnapshot("first render");
29
+ });
30
+
31
+ it("should snapshot on mobile", () => {
32
+ // Arrange
33
+ const apiOptions = {
34
+ isMobile: true,
35
+ };
36
+
37
+ // Act
38
+ const {container} = renderQuestion(question1, apiOptions);
39
+
40
+ // Assert
41
+ expect(container).toMatchSnapshot("first mobile render");
42
+ });
43
+
44
+ // This widget doesn't have any direct behavior, it just renders an iframe
45
+ });
@@ -0,0 +1,152 @@
1
+ // @flow
2
+ import {screen, waitForElementToBeRemoved} from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+
5
+ import "@testing-library/jest-dom"; // Imports custom matchers
6
+
7
+ import {testDependencies} from "../../../../../testing/test-dependencies.js";
8
+ import * as Dependencies from "../../dependencies.js";
9
+
10
+ import {renderQuestion} from "./renderQuestion.jsx";
11
+
12
+ const question = {
13
+ content:
14
+ "Read the excerpt and answer the question below. \n\nThe Governor and Council of the Massachusetts had much conference many days; and at last . . . . concluded a peace and friendship with [[\u2603 definition 1]], upon these conditions.",
15
+ images: {},
16
+ widgets: {
17
+ "definition 1": {
18
+ graded: true,
19
+ version: {
20
+ major: 0,
21
+ minor: 0,
22
+ },
23
+ static: false,
24
+ type: "definition",
25
+ options: {
26
+ definition: "Definition text",
27
+ togglePrompt: "the Pequots",
28
+ static: false,
29
+ },
30
+ alignment: "default",
31
+ },
32
+ },
33
+ };
34
+
35
+ describe("Definition widget", () => {
36
+ beforeEach(() => {
37
+ jest.useRealTimers();
38
+
39
+ jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
40
+ testDependencies,
41
+ );
42
+ });
43
+
44
+ it("should have a default snapshot", () => {
45
+ // Arrange & Act
46
+ const {container} = renderQuestion(question);
47
+
48
+ // Assert
49
+ expect(container).toMatchSnapshot("first render");
50
+ });
51
+
52
+ it("should have an open state snapshot", () => {
53
+ // Arrange
54
+ const {container} = renderQuestion(question);
55
+
56
+ // Act
57
+ const definitionAnchor = screen.getByText("the Pequots");
58
+ userEvent.hover(definitionAnchor);
59
+
60
+ // Assert
61
+ expect(container).toMatchSnapshot("open state");
62
+ });
63
+
64
+ it("should display the definition on hover", async () => {
65
+ // Arrange
66
+ renderQuestion(question);
67
+
68
+ // Act
69
+ const definitionAnchor = screen.getByText("the Pequots");
70
+ userEvent.hover(definitionAnchor);
71
+
72
+ // Assert
73
+ const tooltip = await screen.findByRole("tooltip");
74
+ expect(tooltip).toBeVisible();
75
+ expect(tooltip).toHaveTextContent("Definition text");
76
+ });
77
+
78
+ it("should display the definition on click", async () => {
79
+ // Arrange
80
+ renderQuestion(question);
81
+
82
+ // Act
83
+ const definitionAnchor = screen.getByText("the Pequots");
84
+ userEvent.click(definitionAnchor);
85
+ const tooltip = await screen.findByRole("tooltip");
86
+
87
+ // Assert
88
+ expect(tooltip).toBeVisible();
89
+ expect(tooltip).toHaveTextContent("Definition text");
90
+ });
91
+
92
+ it("should show via focus by the tab key", async () => {
93
+ // Arrange
94
+ renderQuestion(question);
95
+
96
+ // Act - Tab in to set focus
97
+ userEvent.tab();
98
+
99
+ // Assert
100
+ const tooltip = await screen.findByRole("tooltip");
101
+ expect(tooltip).toBeVisible();
102
+ expect(tooltip).toHaveTextContent("Definition text");
103
+ });
104
+
105
+ it("should hide and blur by the tab key", async () => {
106
+ // Arrange
107
+ renderQuestion(question);
108
+
109
+ // Act - Tab in to set focus, tab out to blur
110
+ userEvent.tab();
111
+ await screen.findByRole("tooltip");
112
+ userEvent.tab();
113
+ await waitForElementToBeRemoved(() => screen.queryByRole("tooltip"));
114
+
115
+ // Assert
116
+ expect(screen.queryByRole("tooltip")).toBeNull();
117
+ });
118
+
119
+ it("should dimiss by a click when showing", async () => {
120
+ renderQuestion(question);
121
+
122
+ // Act
123
+ // Click on the anchor
124
+ const definitionAnchor = screen.getByText("the Pequots");
125
+ userEvent.click(definitionAnchor);
126
+
127
+ // Move the mouse away and make sure text is still visible
128
+ userEvent.unhover(definitionAnchor);
129
+ await screen.findByRole("tooltip");
130
+
131
+ // Click to elsewhere, tooltip is hidden
132
+ userEvent.click((document.body: any));
133
+ await waitForElementToBeRemoved(() => screen.queryByRole("tooltip"));
134
+
135
+ // Assert
136
+ expect(screen.queryByRole("tooltip")).toBeNull();
137
+ });
138
+
139
+ it("should not affect answerable", () => {
140
+ // Arrange and act
141
+ const {renderer} = renderQuestion(question);
142
+ const result = renderer.scoreWidgets();
143
+
144
+ // Assert
145
+ expect(result["definition 1"]).toMatchObject({
146
+ type: "points",
147
+ earned: 0,
148
+ total: 0,
149
+ message: null,
150
+ });
151
+ });
152
+ });
@@ -0,0 +1,106 @@
1
+ // @flow
2
+ import {screen} from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+
5
+ // TODO(FEI-3857): Include in jest setup so that we don't need to import it everywhere
6
+ import "@testing-library/jest-dom/extend-expect";
7
+
8
+ import {testDependencies} from "../../../../../testing/test-dependencies.js";
9
+ import * as Dependencies from "../../dependencies.js";
10
+ import {question1} from "../__testdata__/dropdown_testdata.js";
11
+
12
+ import {renderQuestion} from "./renderQuestion.jsx";
13
+
14
+ describe("Dropdown widget", () => {
15
+ beforeEach(() => {
16
+ jest.useRealTimers();
17
+
18
+ jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
19
+ testDependencies,
20
+ );
21
+ });
22
+
23
+ it("should snapshot", () => {
24
+ // Arrange and Act
25
+ const {container} = renderQuestion(question1);
26
+
27
+ // Assert
28
+ expect(container).toMatchSnapshot("initial render");
29
+ });
30
+
31
+ it("should snapshot when opened", async () => {
32
+ // Arrange
33
+ const {container} = renderQuestion(question1);
34
+
35
+ // Act
36
+ const dropdown = screen.getByRole("button");
37
+ userEvent.click(dropdown);
38
+ await screen.findByText("less than or equal to");
39
+
40
+ // Assert
41
+ expect(container).toMatchSnapshot("dropdown open");
42
+ });
43
+
44
+ it("should show placeholder text", () => {
45
+ // Arrange
46
+ renderQuestion(question1);
47
+
48
+ // Act
49
+ const dropdown = screen.getByRole("button");
50
+
51
+ // Assert
52
+ // get asserts if it doesn't find a single matching element
53
+ expect(dropdown).toHaveTextContent("greater/less than or equal to");
54
+ });
55
+
56
+ it("should be answerable correctly", () => {
57
+ // Arrange
58
+ const {renderer} = renderQuestion(question1);
59
+
60
+ // Act
61
+ const dropdown = screen.getByRole("button");
62
+ userEvent.click(dropdown);
63
+ userEvent.click(screen.getByText("less than or equal to"));
64
+
65
+ // Assert
66
+ expect(dropdown).toHaveTextContent("less than or equal to");
67
+ expect(renderer).toHaveBeenAnsweredCorrectly();
68
+ });
69
+
70
+ it("should be answerable incorrectly", () => {
71
+ // Arrange
72
+ const {renderer} = renderQuestion(question1);
73
+
74
+ // Act
75
+ const dropdown = screen.getByRole("button");
76
+ userEvent.click(dropdown);
77
+ userEvent.click(screen.getByText("greater than or equal to"));
78
+
79
+ // Assert
80
+ expect(dropdown).toHaveTextContent("greater than or equal to");
81
+ expect(renderer).toHaveBeenAnsweredIncorrectly();
82
+ });
83
+
84
+ it("should be invalid on first render", () => {
85
+ // Arrange and Act
86
+ const {renderer} = renderQuestion(question1);
87
+
88
+ // Assert
89
+ expect(renderer).toHaveInvalidInput();
90
+ });
91
+
92
+ it("should be return true when focus() called", () => {
93
+ // Arrange
94
+ const {renderer} = renderQuestion(question1);
95
+
96
+ // Act
97
+ const focused = renderer.focus();
98
+
99
+ // Assert
100
+ expect(focused).toBeTrue();
101
+ // TODO(LP-10797): we don't check that the document.activeElement is
102
+ // actually set because the dropdown widget focuses a <div> (it's root
103
+ // element), which is not actually focusable because it doesn't have a
104
+ // tabindex.
105
+ });
106
+ });