@khanacademy/perseus-editor 4.1.5 → 4.1.6

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 (175) hide show
  1. package/dist/es/index.js +1 -1
  2. package/dist/index.js +1 -1
  3. package/package.json +9 -6
  4. package/.babelrc.js +0 -8
  5. package/.eslintrc.js +0 -12
  6. package/CHANGELOG.md +0 -1155
  7. package/src/README.md +0 -7
  8. package/src/__stories__/editor-page.stories.tsx +0 -65
  9. package/src/__stories__/editor.stories.tsx +0 -134
  10. package/src/__stories__/item-editor.stories.tsx +0 -41
  11. package/src/__stories__/tex-error-view.stories.tsx +0 -26
  12. package/src/__testdata__/input-number.testdata.ts +0 -27
  13. package/src/__tests__/editor.test.tsx +0 -142
  14. package/src/__tests__/hint-editor.test.tsx +0 -83
  15. package/src/__tests__/i18n.test.ts +0 -501
  16. package/src/__tests__/integration.test.ts +0 -5
  17. package/src/__tests__/item-extras-editor.test.tsx +0 -85
  18. package/src/__tests__/traversal.test.ts +0 -377
  19. package/src/all-editors.test.ts +0 -16
  20. package/src/all-editors.ts +0 -83
  21. package/src/all-widgets.ts +0 -7
  22. package/src/article-editor.tsx +0 -438
  23. package/src/components/__stories__/blur-input.stories.tsx +0 -22
  24. package/src/components/__stories__/section-control-button.stories.tsx +0 -26
  25. package/src/components/__tests__/blur-input.test.tsx +0 -67
  26. package/src/components/blur-input.tsx +0 -69
  27. package/src/components/checkbox.tsx +0 -194
  28. package/src/components/device-framer.tsx +0 -90
  29. package/src/components/drag-target.tsx +0 -87
  30. package/src/components/dropdown-option.tsx +0 -311
  31. package/src/components/form-wrapped-text-field.tsx +0 -245
  32. package/src/components/graph-points-count-selector.tsx +0 -31
  33. package/src/components/graph-settings.tsx +0 -627
  34. package/src/components/graph-type-selector.tsx +0 -31
  35. package/src/components/hover-behavior.ts +0 -177
  36. package/src/components/json-editor.tsx +0 -121
  37. package/src/components/link.ts +0 -173
  38. package/src/components/section-control-button.tsx +0 -53
  39. package/src/components/segment-count-selector.tsx +0 -27
  40. package/src/components/simple-button.tsx +0 -85
  41. package/src/components/sortable.tsx +0 -187
  42. package/src/components/util.ts +0 -38
  43. package/src/components/viewport-resizer.tsx +0 -72
  44. package/src/components/widget-editor.tsx +0 -222
  45. package/src/components/widget-select.tsx +0 -48
  46. package/src/diffs/__stories__/perseus-diff-wrapper.tsx +0 -11
  47. package/src/diffs/__stories__/structured-item-diff.stories.tsx +0 -855
  48. package/src/diffs/__stories__/tags-diff.stories.tsx +0 -36
  49. package/src/diffs/__stories__/text-diff.stories.tsx +0 -35
  50. package/src/diffs/__tests__/split-diff.test.ts +0 -33
  51. package/src/diffs/__tests__/string-array-diff.test.ts +0 -73
  52. package/src/diffs/__tests__/structured-item-diff.test.ts +0 -433
  53. package/src/diffs/__tests__/widget-diff-performer.test.ts +0 -43
  54. package/src/diffs/article-diff.tsx +0 -69
  55. package/src/diffs/item-diff.tsx +0 -76
  56. package/src/diffs/renderer-diff.tsx +0 -137
  57. package/src/diffs/split-diff.ts +0 -31
  58. package/src/diffs/string-array-diff.ts +0 -74
  59. package/src/diffs/structured-item-diff.tsx +0 -275
  60. package/src/diffs/tags-diff.tsx +0 -49
  61. package/src/diffs/text-diff.tsx +0 -193
  62. package/src/diffs/widget-diff-performer.ts +0 -69
  63. package/src/diffs/widget-diff.tsx +0 -290
  64. package/src/editor-page.tsx +0 -325
  65. package/src/editor.tsx +0 -1099
  66. package/src/hint-editor.tsx +0 -469
  67. package/src/i18n.ts +0 -140
  68. package/src/iframe-content-renderer.tsx +0 -188
  69. package/src/index.ts +0 -30
  70. package/src/item-editor.tsx +0 -158
  71. package/src/item-extras-editor.tsx +0 -230
  72. package/src/katex-mhchem/index.js +0 -73
  73. package/src/katex-mhchem/parser.js +0 -2659
  74. package/src/multirenderer-editor.tsx +0 -1061
  75. package/src/stateful-article-editor.tsx +0 -173
  76. package/src/stateful-editor-page.tsx +0 -88
  77. package/src/styles/perseus-editor.less +0 -1321
  78. package/src/testing-widgets.ts +0 -11
  79. package/src/tex-error-view.tsx +0 -90
  80. package/src/util/points.test.ts +0 -24
  81. package/src/util/points.ts +0 -13
  82. package/src/util/register-all-widgets-and-editors-for-testing.test.ts +0 -17
  83. package/src/util/register-all-widgets-and-editors-for-testing.ts +0 -17
  84. package/src/version.ts +0 -10
  85. package/src/widgets/__stories__/categorizer-editor.stories.tsx +0 -24
  86. package/src/widgets/__stories__/definition-editor.stories.tsx +0 -18
  87. package/src/widgets/__stories__/dropdown-editor.stories.tsx +0 -18
  88. package/src/widgets/__stories__/explanation-editor.stories.tsx +0 -18
  89. package/src/widgets/__stories__/expression-editor.stories.tsx +0 -122
  90. package/src/widgets/__stories__/image-editor.stories.tsx +0 -72
  91. package/src/widgets/__stories__/input-number-editor.stories.tsx +0 -18
  92. package/src/widgets/__stories__/interaction-editor.stories.tsx +0 -37
  93. package/src/widgets/__stories__/label-image-editor.stories.tsx +0 -99
  94. package/src/widgets/__stories__/matcher-editor.stories.tsx +0 -18
  95. package/src/widgets/__stories__/number-line-editor.stories.tsx +0 -18
  96. package/src/widgets/__stories__/numeric-input-editor.stories.tsx +0 -18
  97. package/src/widgets/__stories__/radio-editor.stories.tsx +0 -116
  98. package/src/widgets/__stories__/sorter-editor.stories.tsx +0 -18
  99. package/src/widgets/__tests__/categorizer-editor.test.tsx +0 -51
  100. package/src/widgets/__tests__/definition-editor.test.tsx +0 -41
  101. package/src/widgets/__tests__/dropdown-editor.test.tsx +0 -57
  102. package/src/widgets/__tests__/explanation-editor.test.tsx +0 -59
  103. package/src/widgets/__tests__/expression-editor.test.tsx +0 -403
  104. package/src/widgets/__tests__/input-number-editor.test.tsx +0 -128
  105. package/src/widgets/__tests__/matcher-editor.test.tsx +0 -47
  106. package/src/widgets/__tests__/number-line-editor.test.tsx +0 -144
  107. package/src/widgets/__tests__/numeric-input-editor.test.tsx +0 -177
  108. package/src/widgets/__tests__/radio-editor.test.tsx +0 -118
  109. package/src/widgets/__tests__/sorter-editor.test.tsx +0 -55
  110. package/src/widgets/categorizer-editor.tsx +0 -104
  111. package/src/widgets/cs-program-editor.tsx +0 -256
  112. package/src/widgets/definition-editor.tsx +0 -77
  113. package/src/widgets/deprecated-standin-editor.tsx +0 -29
  114. package/src/widgets/dropdown-editor.tsx +0 -211
  115. package/src/widgets/example-graphie-widget-editor.tsx +0 -70
  116. package/src/widgets/example-graphie-widget.tsx +0 -172
  117. package/src/widgets/example-widget-editor.tsx +0 -62
  118. package/src/widgets/example-widget.tsx +0 -154
  119. package/src/widgets/explanation-editor.tsx +0 -92
  120. package/src/widgets/expression-editor.tsx +0 -557
  121. package/src/widgets/graded-group-editor.tsx +0 -161
  122. package/src/widgets/graded-group-set-editor.tsx +0 -104
  123. package/src/widgets/grapher-editor.tsx +0 -155
  124. package/src/widgets/group-editor.tsx +0 -83
  125. package/src/widgets/iframe-editor.tsx +0 -202
  126. package/src/widgets/image-editor.tsx +0 -367
  127. package/src/widgets/input-number-editor.tsx +0 -288
  128. package/src/widgets/interaction-editor/constraint-editor.tsx +0 -134
  129. package/src/widgets/interaction-editor/function-editor.tsx +0 -108
  130. package/src/widgets/interaction-editor/index.ts +0 -3
  131. package/src/widgets/interaction-editor/interaction-editor.tsx +0 -749
  132. package/src/widgets/interaction-editor/label-editor.tsx +0 -87
  133. package/src/widgets/interaction-editor/line-editor.tsx +0 -125
  134. package/src/widgets/interaction-editor/mathquill-input.tsx +0 -81
  135. package/src/widgets/interaction-editor/movable-line-editor.tsx +0 -121
  136. package/src/widgets/interaction-editor/movable-point-editor.tsx +0 -89
  137. package/src/widgets/interaction-editor/parametric-editor.tsx +0 -117
  138. package/src/widgets/interaction-editor/point-editor.tsx +0 -72
  139. package/src/widgets/interaction-editor/rectangle-editor.tsx +0 -96
  140. package/src/widgets/interactive-graph-editor.tsx +0 -571
  141. package/src/widgets/label-image/__stories__/answer-choices.stories.tsx +0 -82
  142. package/src/widgets/label-image/__stories__/behavior.stories.tsx +0 -31
  143. package/src/widgets/label-image/__stories__/marker.stories.tsx +0 -75
  144. package/src/widgets/label-image/__stories__/question-markers.stories.tsx +0 -107
  145. package/src/widgets/label-image/__stories__/select-image.stories.tsx +0 -59
  146. package/src/widgets/label-image/answer-choices.tsx +0 -231
  147. package/src/widgets/label-image/behavior.tsx +0 -122
  148. package/src/widgets/label-image/marker.tsx +0 -290
  149. package/src/widgets/label-image/question-markers.tsx +0 -176
  150. package/src/widgets/label-image/select-image.tsx +0 -81
  151. package/src/widgets/label-image-editor.tsx +0 -252
  152. package/src/widgets/lights-puzzle-editor.tsx +0 -278
  153. package/src/widgets/matcher-editor.tsx +0 -149
  154. package/src/widgets/matrix-editor.tsx +0 -156
  155. package/src/widgets/measurer-editor.tsx +0 -253
  156. package/src/widgets/molecule-editor.tsx +0 -64
  157. package/src/widgets/number-line-editor.tsx +0 -512
  158. package/src/widgets/numeric-input-editor.tsx +0 -536
  159. package/src/widgets/orderer-editor.tsx +0 -172
  160. package/src/widgets/passage-editor.tsx +0 -117
  161. package/src/widgets/passage-ref-editor.tsx +0 -80
  162. package/src/widgets/passage-ref-target-editor.tsx +0 -49
  163. package/src/widgets/plotter-editor.tsx +0 -542
  164. package/src/widgets/radio/editor.tsx +0 -398
  165. package/src/widgets/reaction-diagram-editor.tsx +0 -131
  166. package/src/widgets/sequence-editor.tsx +0 -205
  167. package/src/widgets/simple-markdown-tester-editor.tsx +0 -86
  168. package/src/widgets/simple-markdown-tester.tsx +0 -92
  169. package/src/widgets/simulator-editor.tsx +0 -146
  170. package/src/widgets/sorter-editor.tsx +0 -103
  171. package/src/widgets/table-editor.tsx +0 -164
  172. package/src/widgets/unit-editor.tsx +0 -299
  173. package/src/widgets/video-editor.tsx +0 -73
  174. package/tsconfig-build.json +0 -22
  175. package/tsconfig-build.tsbuildinfo +0 -1
package/src/README.md DELETED
@@ -1,7 +0,0 @@
1
- The Perseus editor, with all the widgets.
2
-
3
- TODO(benkraft): Figure out and document how this relates to the other perseus
4
- packages.
5
-
6
- Code-Owner: Learning Platform
7
- Crowdin-Category: content.chrome
@@ -1,65 +0,0 @@
1
- import {action} from "@storybook/addon-actions";
2
- import * as React from "react";
3
-
4
- import {EditorPage} from "..";
5
- import {registerAllWidgetsAndEditorsForTesting} from "../util/register-all-widgets-and-editors-for-testing";
6
-
7
- import type {
8
- DeviceType,
9
- Hint,
10
- PerseusAnswerArea,
11
- PerseusRenderer,
12
- } from "@khanacademy/perseus";
13
-
14
- registerAllWidgetsAndEditorsForTesting(); // SIDE_EFFECTY!!!! :cry:
15
-
16
- export default {
17
- title: "Perseus/Editor/EditorPage",
18
- };
19
-
20
- const onChangeAction = action("onChange");
21
-
22
- export const Demo = (): React.ReactElement => {
23
- const [previewDevice, setPreviewDevice] =
24
- React.useState<DeviceType>("phone");
25
- const [jsonMode, setJsonMode] = React.useState<boolean | undefined>(false);
26
- const [answerArea, setAnswerArea] = React.useState<
27
- PerseusAnswerArea | undefined | null
28
- >();
29
- const [question, setQuestion] = React.useState<
30
- PerseusRenderer | undefined
31
- >();
32
- const [hints, setHints] = React.useState<ReadonlyArray<Hint> | undefined>();
33
-
34
- return (
35
- <EditorPage
36
- apiOptions={{isMobile: false}}
37
- previewDevice={previewDevice}
38
- onPreviewDeviceChange={(newDevice) => setPreviewDevice(newDevice)}
39
- developerMode={true}
40
- jsonMode={jsonMode}
41
- answerArea={answerArea}
42
- question={question}
43
- hints={hints}
44
- frameSource="about:blank"
45
- previewURL="about:blank"
46
- itemId="1"
47
- onChange={(props) => {
48
- onChangeAction(props);
49
-
50
- if ("jsonMode" in props) {
51
- setJsonMode(props.jsonMode);
52
- }
53
- if ("answerArea" in props) {
54
- setAnswerArea(props.answerArea);
55
- }
56
- if ("question" in props) {
57
- setQuestion(props.question);
58
- }
59
- if ("hints" in props) {
60
- setHints(props.hints);
61
- }
62
- }}
63
- />
64
- );
65
- };
@@ -1,134 +0,0 @@
1
- /* eslint-disable react/prop-types */
2
- import {ApiOptions} from "@khanacademy/perseus";
3
- import {View} from "@khanacademy/wonder-blocks-core";
4
- import {action} from "@storybook/addon-actions";
5
- import * as React from "react";
6
-
7
- import {Editor} from "..";
8
- import SideBySide from "../../../../testing/side-by-side";
9
- import {question1} from "../__testdata__/input-number.testdata";
10
- import {registerAllWidgetsAndEditorsForTesting} from "../util/register-all-widgets-and-editors-for-testing";
11
-
12
- import type {PerseusRenderer} from "@khanacademy/perseus";
13
-
14
- registerAllWidgetsAndEditorsForTesting(); // SIDE_EFFECTY!!!! :cry:
15
-
16
- export default {
17
- title: "Perseus/Editor/Editor",
18
- };
19
-
20
- export const Demo = (): React.ReactElement => {
21
- return (
22
- <Editor
23
- apiOptions={ApiOptions.defaults}
24
- content={question1.content}
25
- placeholder=""
26
- widgets={question1.widgets}
27
- images={question1.images}
28
- disabled={false}
29
- widgetEnabled={true}
30
- immutableWidgets={false}
31
- showWordCount={true}
32
- warnNoPrompt={true}
33
- warnNoWidgets={true}
34
- onChange={(props) => {}}
35
- />
36
- );
37
- };
38
-
39
- export const DemoInteractiveGraph = (): React.ReactElement => {
40
- const editorRef = React.useRef<Editor>(null);
41
- const [options, setOptions] = React.useState({});
42
- const [content, setContent] = React.useState(
43
- "[[\u2603 interactive-graph 1]]",
44
- );
45
- const [images, setImages] = React.useState<PerseusRenderer["images"]>({});
46
- const [widgets, setWidgets] = React.useState<PerseusRenderer["widgets"]>({
47
- "interactive-graph 1": {
48
- options: {
49
- labels: ["x", "y"],
50
- range: [
51
- [-10, 10],
52
- [-10, 10],
53
- ],
54
- gridStep: [1, 1],
55
- snapStep: [1, 1],
56
- step: [1, 1],
57
- backgroundImage: {
58
- url: null,
59
- },
60
- markings: "graph",
61
- showProtractor: false,
62
- showRuler: false,
63
- showTooltips: false,
64
- rulerLabel: "",
65
- rulerTicks: 10,
66
- graph: {
67
- type: "linear",
68
- coords: [
69
- [1, 1],
70
- [5, 5],
71
- ],
72
- },
73
- correct: {
74
- type: "linear",
75
- },
76
- },
77
- type: "interactive-graph",
78
- version: {
79
- major: 0,
80
- minor: 0,
81
- },
82
- },
83
- });
84
-
85
- return (
86
- // Many of the editor components use scoped CSS that requires this
87
- // class to be above it.
88
- // TODO: Refactor to aphrodite styles instead of scoped CSS in Less.
89
- <div className="framework-perseus">
90
- <SideBySide
91
- leftTitle="Editor"
92
- left={
93
- <View style={{width: "360px", margin: "20px"}}>
94
- <Editor
95
- ref={editorRef}
96
- apiOptions={ApiOptions.defaults}
97
- content={content}
98
- placeholder=""
99
- widgets={widgets}
100
- images={images}
101
- disabled={false}
102
- widgetEnabled={true}
103
- immutableWidgets={false}
104
- showWordCount={true}
105
- warnNoPrompt={false}
106
- warnNoWidgets={true}
107
- onChange={(props: Partial<PerseusRenderer>) => {
108
- action("onChange")(props);
109
- if (props.content) {
110
- setContent(props.content);
111
- } else if (props.widgets) {
112
- setWidgets(props.widgets);
113
- } else if (props.images) {
114
- setImages(props.images);
115
- }
116
- // We need to wait for one tick so that the editor
117
- // has been re-rendered with the changed props. If
118
- // we don't wait, we get the values from the n-1
119
- // render and miss the latest change.
120
- setTimeout(() => {
121
- setOptions(
122
- editorRef.current?.serialize() || {},
123
- );
124
- }, 0);
125
- }}
126
- />
127
- </View>
128
- }
129
- rightTitle="Serialized Widget Options"
130
- jsonObject={options}
131
- />
132
- </div>
133
- );
134
- };
@@ -1,41 +0,0 @@
1
- /* eslint-disable react/prop-types */
2
- import * as React from "react";
3
-
4
- import ItemExtrasEditor from "../item-extras-editor";
5
-
6
- import type {Meta, StoryObj} from "@storybook/react";
7
-
8
- import "../styles/perseus-editor.less";
9
-
10
- type Props = React.ComponentProps<typeof ItemExtrasEditor>;
11
-
12
- const Wrapper = (props: Props) => {
13
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
14
- const {onChange, ...rest} = props;
15
- const [extras, setExtras] =
16
- React.useState<Partial<typeof ItemExtrasEditor.defaultProps>>(rest);
17
-
18
- return (
19
- <ItemExtrasEditor
20
- {...extras}
21
- onChange={(e) => {
22
- props.onChange?.(e); // to register action in storybook
23
- setExtras((prevExtras) => ({...prevExtras, ...e}));
24
- }}
25
- />
26
- );
27
- };
28
-
29
- const story: Meta<Props> = {
30
- title: "Perseus/Editor/Item Extras Editor",
31
- component: ItemExtrasEditor,
32
- render: (args) => <Wrapper {...args} />,
33
- argTypes: {onChange: {action: "changed"}},
34
- };
35
- export default story;
36
-
37
- type Story = StoryObj<typeof ItemExtrasEditor>;
38
-
39
- export const Default: Story = {
40
- args: {...ItemExtrasEditor.defaultProps},
41
- };
@@ -1,26 +0,0 @@
1
- import TexErrorView from "../tex-error-view";
2
-
3
- import type {Meta, StoryObj} from "@storybook/react";
4
-
5
- const meta: Meta<typeof TexErrorView> = {
6
- component: TexErrorView,
7
- title: "Perseus/Editor/TexErrorView",
8
- };
9
-
10
- export default meta;
11
- type Story = StoryObj<typeof TexErrorView>;
12
-
13
- export const Primary: Story = {
14
- args: {
15
- errorList: [
16
- {
17
- math: "\\x^2",
18
- message: "TeX parse error: Undefined control sequence: \\x",
19
- },
20
- {
21
- math: "\\y^2",
22
- message: "TeX parse error: Undefined control sequence: \\y",
23
- },
24
- ],
25
- },
26
- };
@@ -1,27 +0,0 @@
1
- import type {PerseusRenderer, InputNumberWidget} from "@khanacademy/perseus";
2
-
3
- export const question1: PerseusRenderer = {
4
- content:
5
- "A sequence is defined recursively as follows:\n\n\n$\\qquad\\displaystyle{{a}_{n}}=-\\frac{1}{a_{n-1}-1} \n~~~~~~\\text{ with}\\qquad\\displaystyle{{a}_{0}}=\\frac{1}{2}\\,$\n\n\nFind the term $a_3$ in the sequence.\n\n[[\u2603 input-number 1]]",
6
- images: {},
7
- widgets: {
8
- "input-number 1": {
9
- graded: true,
10
- version: {
11
- major: 0,
12
- minor: 0,
13
- },
14
- static: false,
15
- type: "input-number",
16
- options: {
17
- maxError: 0.1,
18
- inexact: false,
19
- value: 0.5,
20
- simplify: "required",
21
- answerType: "number",
22
- size: "normal",
23
- },
24
- alignment: "default",
25
- } as InputNumberWidget,
26
- },
27
- };
@@ -1,142 +0,0 @@
1
- import {
2
- ApiOptions,
3
- Dependencies,
4
- Widgets,
5
- widgets,
6
- Util,
7
- } from "@khanacademy/perseus";
8
- import {render, screen} from "@testing-library/react";
9
- import userEvent from "@testing-library/user-event";
10
- import * as React from "react";
11
- import "@testing-library/jest-dom"; // Imports custom mathers
12
-
13
- import {testDependencies} from "../../../../testing/test-dependencies";
14
- import Editor from "../editor";
15
- import ImageEditor from "../widgets/image-editor";
16
-
17
- import type {PropsFor} from "@khanacademy/wonder-blocks-core";
18
-
19
- const Harnessed = (props: Partial<PropsFor<typeof Editor>>) => {
20
- return (
21
- <Editor
22
- apiOptions={ApiOptions.defaults}
23
- onChange={() => {}}
24
- content="[[☃ image 1]]"
25
- widgets={{
26
- "image 1": {
27
- type: "image",
28
- options: {
29
- backgroundImage: {
30
- url: "http://placekitten.com/200/300",
31
- },
32
- },
33
- },
34
- }}
35
- {...props}
36
- />
37
- );
38
- };
39
-
40
- describe("Editor", () => {
41
- beforeAll(() => {
42
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
43
- const ImageWidget = widgets.find((w) => w.name === "image")!;
44
- expect(ImageWidget).toBeDefined();
45
- Widgets.registerWidget("image", ImageWidget);
46
- Widgets.registerEditors([ImageEditor]);
47
- });
48
-
49
- beforeEach(() => {
50
- jest.spyOn(Dependencies, "getDependencies").mockReturnValue(
51
- testDependencies,
52
- );
53
- });
54
-
55
- it("should delete widget if confirmed", async () => {
56
- const onChangeMock = jest.fn();
57
- jest.spyOn(window, "confirm").mockReturnValue(true);
58
-
59
- // Arrange
60
- render(<Harnessed onChange={onChangeMock} />);
61
-
62
- // Act
63
- userEvent.click(
64
- screen.getByRole("button", {name: "Remove image widget"}),
65
- );
66
-
67
- // Assert
68
- expect(onChangeMock).toHaveBeenCalledWith({content: ""});
69
- });
70
-
71
- it("should NOT delete widget if not confirmed", async () => {
72
- const onChangeMock = jest.fn();
73
- jest.spyOn(window, "confirm").mockReturnValue(false);
74
-
75
- // Arrange
76
- render(<Harnessed onChange={onChangeMock} />);
77
-
78
- // Act
79
- userEvent.click(
80
- screen.getByRole("button", {name: "Remove image widget"}),
81
- );
82
-
83
- // Assert
84
- expect(onChangeMock).not.toHaveBeenCalled();
85
- });
86
-
87
- test("clicking on the widget editor should open it", async () => {
88
- // Arrange
89
- render(<Harnessed />);
90
-
91
- // Act
92
- const widgetDisclosure = screen.getByRole("link", {
93
- name: "image 1",
94
- });
95
- userEvent.click(widgetDisclosure);
96
-
97
- // Assert
98
- const previewImage = screen.getByAltText("Editor preview of image");
99
- expect(previewImage).toHaveAttribute(
100
- "src",
101
- "http://placekitten.com/200/300",
102
- );
103
- });
104
-
105
- it("should update values", async () => {
106
- // Arrange
107
- jest.spyOn(Util, "getImageSizeModern").mockResolvedValue([200, 200]);
108
-
109
- const changeFn = jest.fn();
110
- render(<Harnessed onChange={changeFn} />);
111
-
112
- // Act
113
- const widgetDisclosure = screen.getByRole("link", {
114
- name: "image 1",
115
- });
116
- userEvent.click(widgetDisclosure);
117
-
118
- const captionInput = screen.getByLabelText(/Caption:/);
119
-
120
- userEvent.clear(captionInput);
121
- userEvent.type(captionInput, "A picture of kittens");
122
- userEvent.tab(); // blurring the input triggers onChange to be called
123
- jest.runOnlyPendingTimers();
124
-
125
- // Assert
126
- expect(changeFn).toHaveBeenCalledWith(
127
- {
128
- widgets: {
129
- "image 1": expect.objectContaining({
130
- type: "image",
131
- graded: true,
132
- options: expect.objectContaining({
133
- caption: "A picture of kittens",
134
- }),
135
- }),
136
- },
137
- },
138
- undefined,
139
- undefined,
140
- );
141
- });
142
- });
@@ -1,83 +0,0 @@
1
- import "@testing-library/jest-dom";
2
- import {render, screen} from "@testing-library/react";
3
- import userEvent from "@testing-library/user-event";
4
- import * as React from "react";
5
-
6
- import CombinedHintsEditor from "../hint-editor";
7
-
8
- describe("CombinedHintsEditor", () => {
9
- it("should render", () => {
10
- render(
11
- <CombinedHintsEditor deviceType="phone" previewURL="about:blank" />,
12
- );
13
- });
14
-
15
- it("should confirm before removing a hint", () => {
16
- // Arrange
17
- const comfirmSpy = jest.spyOn(window, "confirm").mockReturnValue(false);
18
- render(
19
- <CombinedHintsEditor
20
- deviceType="phone"
21
- previewURL="about:blank"
22
- hints={[
23
- {content: "You know this one!", widgets: {}, images: {}},
24
- {content: "Ok, the answer is 3", widgets: {}, images: {}},
25
- ]}
26
- />,
27
- );
28
-
29
- // Act
30
- userEvent.click(screen.getAllByText("Remove this hint")[0]);
31
-
32
- // Assert
33
- expect(comfirmSpy).toHaveBeenCalled();
34
- });
35
-
36
- it("should not remove the hint if not confirmed", () => {
37
- // Arrange
38
- jest.spyOn(window, "confirm").mockReturnValue(false);
39
- const onChangeMock = jest.fn();
40
- render(
41
- <CombinedHintsEditor
42
- deviceType="phone"
43
- previewURL="about:blank"
44
- hints={[
45
- {content: "You know this one!", widgets: {}, images: {}},
46
- {content: "Ok, the answer is 3", widgets: {}, images: {}},
47
- ]}
48
- onChange={onChangeMock}
49
- />,
50
- );
51
-
52
- // Act
53
- userEvent.click(screen.getAllByText("Remove this hint")[0]);
54
-
55
- // Assert
56
- expect(onChangeMock).not.toHaveBeenCalled();
57
- });
58
-
59
- it("should remove the hint if confirmed", () => {
60
- // Arrange
61
- jest.spyOn(window, "confirm").mockReturnValue(true);
62
- const onChangeMock = jest.fn();
63
- render(
64
- <CombinedHintsEditor
65
- deviceType="phone"
66
- previewURL="about:blank"
67
- hints={[
68
- {content: "You know this one!", widgets: {}, images: {}},
69
- {content: "Ok, the answer is 3", widgets: {}, images: {}},
70
- ]}
71
- onChange={onChangeMock}
72
- />,
73
- );
74
-
75
- // Act
76
- userEvent.click(screen.getAllByText("Remove this hint")[0]);
77
-
78
- // Assert
79
- expect(onChangeMock).toHaveBeenCalledWith({
80
- hints: [{content: "Ok, the answer is 3", widgets: {}, images: {}}],
81
- });
82
- });
83
- });