@pie-lib/rubric 2.0.22-beta.1 → 2.0.22-beta.11

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.
@@ -0,0 +1,431 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
5
+ var _react = require("@testing-library/react");
6
+ var _react2 = _interopRequireDefault(require("react"));
7
+ var _authoring = require("../authoring");
8
+ var _lodashEs = require("lodash-es");
9
+ var _styles = require("@mui/material/styles");
10
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
11
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
12
+ // Mock dependencies
13
+ jest.mock('@pie-lib/editable-html-tip-tap', function () {
14
+ return function EditableHtml(props) {
15
+ return /*#__PURE__*/_react2["default"].createElement("div", {
16
+ "data-testid": "editable-html",
17
+ "data-markup": props.markup
18
+ });
19
+ };
20
+ });
21
+ jest.mock('@pie-lib/config-ui', function () {
22
+ return {
23
+ FeedbackConfig: function FeedbackConfig(_ref) {
24
+ var feedback = _ref.feedback;
25
+ return /*#__PURE__*/_react2["default"].createElement("div", {
26
+ "data-testid": "feedback-config"
27
+ }, JSON.stringify(feedback));
28
+ },
29
+ InputContainer: function InputContainer(_ref2) {
30
+ var children = _ref2.children,
31
+ label = _ref2.label;
32
+ return /*#__PURE__*/_react2["default"].createElement("div", {
33
+ "data-testid": "input-container",
34
+ "data-label": label
35
+ }, children);
36
+ }
37
+ };
38
+ });
39
+ jest.mock('@hello-pangea/dnd', function () {
40
+ return {
41
+ DragDropContext: function DragDropContext(_ref3) {
42
+ var children = _ref3.children;
43
+ return /*#__PURE__*/_react2["default"].createElement("div", {
44
+ "data-testid": "drag-drop-context"
45
+ }, children);
46
+ },
47
+ Droppable: function Droppable(_ref4) {
48
+ var children = _ref4.children;
49
+ return children({
50
+ droppableProps: {},
51
+ innerRef: function innerRef() {}
52
+ }, {});
53
+ },
54
+ Draggable: function Draggable(_ref5) {
55
+ var children = _ref5.children,
56
+ index = _ref5.index;
57
+ return children({
58
+ innerRef: function innerRef() {},
59
+ draggableProps: {
60
+ 'data-draggable-index': index
61
+ },
62
+ dragHandleProps: {}
63
+ }, {});
64
+ }
65
+ };
66
+ });
67
+ describe('Rubric', function () {
68
+ var points = ['nothing right', 'a teeny bit right', 'mostly right', 'bingo'];
69
+ var sampleAnswers = [null, 'just right', 'not left', null];
70
+ var theme = (0, _styles.createTheme)();
71
+ var renderComponent = function renderComponent() {
72
+ var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
73
+ var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
74
+ var defaultProps = _objectSpread({
75
+ classes: {},
76
+ onChange: jest.fn(),
77
+ className: 'className',
78
+ value: _objectSpread({
79
+ excludeZero: false,
80
+ points: points,
81
+ sampleAnswers: sampleAnswers
82
+ }, value)
83
+ }, props);
84
+ return _objectSpread(_objectSpread({}, (0, _react.render)(/*#__PURE__*/_react2["default"].createElement(_styles.ThemeProvider, {
85
+ theme: theme
86
+ }, /*#__PURE__*/_react2["default"].createElement(_authoring.RawAuthoring, defaultProps)))), {}, {
87
+ onChange: defaultProps.onChange,
88
+ props: defaultProps
89
+ });
90
+ };
91
+ describe('render', function () {
92
+ it('renders rubric title and main structure', function () {
93
+ renderComponent();
94
+ expect(_react.screen.getByText('Rubric')).toBeInTheDocument();
95
+ expect(_react.screen.getByLabelText('Max Points')).toBeInTheDocument();
96
+ expect(_react.screen.getByLabelText('Exclude zeros')).toBeInTheDocument();
97
+ });
98
+ it('renders all point configurations', function () {
99
+ var _renderComponent = renderComponent(),
100
+ container = _renderComponent.container;
101
+ // Verify DragDropContext is rendered
102
+ expect(container.querySelector('[data-testid="drag-drop-context"]')).toBeInTheDocument();
103
+
104
+ // Check that point labels are rendered (4 points = "3 pts", "2 pts", "1 pt", "0 pt")
105
+ // Note: The PointConfig component uses singular "pt" for 0 and 1, plural "pts" for 2+
106
+ expect(_react.screen.getByText('3 pts')).toBeInTheDocument();
107
+ expect(_react.screen.getByText('2 pts')).toBeInTheDocument();
108
+ expect(_react.screen.getByText('1 pt')).toBeInTheDocument();
109
+ expect(_react.screen.getByText('0 pt')).toBeInTheDocument();
110
+ });
111
+ describe('draggable', function () {
112
+ it('renders 3 draggable items when excludeZero is true', function () {
113
+ // When excludeZero is true, the last point (0 pts) should not be rendered
114
+ expect(_react.screen.queryByText('0 pt')).not.toBeInTheDocument();
115
+ });
116
+ it('renders 4 draggable items when excludeZero is false', function () {
117
+ var _renderComponent2 = renderComponent({
118
+ excludeZero: false
119
+ }),
120
+ container = _renderComponent2.container;
121
+
122
+ // When excludeZero is false, all points including 0 should be rendered
123
+ var draggableItems = container.querySelectorAll('[data-draggable-index]');
124
+ expect(draggableItems.length).toEqual(4);
125
+ expect(_react.screen.getByText('0 pt')).toBeInTheDocument();
126
+
127
+ // Verify all point labels are rendered
128
+ expect(_react.screen.getByText('3 pts')).toBeInTheDocument();
129
+ expect(_react.screen.getByText('2 pts')).toBeInTheDocument();
130
+ expect(_react.screen.getByText('1 pt')).toBeInTheDocument();
131
+ expect(_react.screen.getByText('0 pt')).toBeInTheDocument();
132
+ });
133
+ });
134
+ });
135
+ describe('logic', function () {
136
+ describe('changeMaxPoints', function () {
137
+ var testChangeMaxPoints = function testChangeMaxPoints(maxPoints, excludeZero, expectedPoints, expectedSampleAnswers) {
138
+ it("maxPoints=".concat(maxPoints, ", excludeZero=").concat(excludeZero, " calls onChange correctly"), function () {
139
+ var _container$querySelec;
140
+ var _renderComponent3 = renderComponent({
141
+ excludeZero: excludeZero
142
+ }),
143
+ onChange = _renderComponent3.onChange,
144
+ container = _renderComponent3.container;
145
+
146
+ // Get the component instance through the container
147
+ // We need to call the method directly since we're testing internal behavior
148
+ var instance = (_container$querySelec = container.querySelector('[class*="MuiBox-root"]')) === null || _container$querySelec === void 0 ? void 0 : _container$querySelec._owner;
149
+
150
+ // Since we can't easily access instance methods in RTL, we'll test the behavior
151
+ // by verifying the onChange prop receives the correct values
152
+ // For now, we'll directly test the logic
153
+ var component = new _authoring.RawAuthoring({
154
+ value: {
155
+ excludeZero: excludeZero,
156
+ points: points,
157
+ sampleAnswers: sampleAnswers
158
+ },
159
+ onChange: onChange,
160
+ classes: {},
161
+ className: 'className'
162
+ });
163
+ component.changeMaxPoints(maxPoints);
164
+ expect(onChange).toHaveBeenCalledWith({
165
+ excludeZero: excludeZero,
166
+ points: expectedPoints,
167
+ sampleAnswers: expectedSampleAnswers,
168
+ maxPoints: expectedPoints.length - 1
169
+ });
170
+ });
171
+ };
172
+ testChangeMaxPoints(1, false, (0, _lodashEs.takeRight)(points, 2), (0, _lodashEs.takeRight)(sampleAnswers, 2));
173
+ testChangeMaxPoints(1, true, (0, _lodashEs.takeRight)(points, 2), (0, _lodashEs.takeRight)(sampleAnswers, 2));
174
+ testChangeMaxPoints(2, true, (0, _lodashEs.takeRight)(points, 3), (0, _lodashEs.takeRight)(sampleAnswers, 3));
175
+ testChangeMaxPoints(2, false, (0, _lodashEs.takeRight)(points, 3), (0, _lodashEs.takeRight)(sampleAnswers, 3));
176
+ testChangeMaxPoints(5, false, ['', ''].concat(points), [null, null].concat(sampleAnswers));
177
+ });
178
+ describe('changeSampleResponse', function () {
179
+ var testChangeSampleResponse = function testChangeSampleResponse(index, clickedItem, excludeZero, expectedPoints, expectedSampleAnswers) {
180
+ it("Point ".concat(index, " with clickedItem=\"").concat(clickedItem, "\" calls onChange correctly"), function () {
181
+ var _renderComponent4 = renderComponent({
182
+ excludeZero: excludeZero
183
+ }),
184
+ onChange = _renderComponent4.onChange;
185
+
186
+ // Test the logic by creating a component instance and calling the method
187
+ var component = new _authoring.RawAuthoring({
188
+ value: {
189
+ excludeZero: excludeZero,
190
+ points: points,
191
+ sampleAnswers: sampleAnswers
192
+ },
193
+ onChange: onChange,
194
+ classes: {},
195
+ className: 'className'
196
+ });
197
+ component.onPointMenuChange(index, clickedItem);
198
+ expect(onChange).toHaveBeenCalledWith({
199
+ excludeZero: excludeZero,
200
+ points: expectedPoints,
201
+ sampleAnswers: expectedSampleAnswers
202
+ });
203
+ });
204
+ };
205
+ testChangeSampleResponse(0, 'sample', false, points, ['', 'just right', 'not left', null]);
206
+ testChangeSampleResponse(3, 'sample', false, points, [null, 'just right', 'not left', '']);
207
+ testChangeSampleResponse(1, 'sample', true, points, [null, null, 'not left', null]);
208
+ testChangeSampleResponse(3, 'sample', true, points, [null, 'just right', 'not left', '']);
209
+ });
210
+ });
211
+ describe('user interactions', function () {
212
+ it('calls onChange when excluding zeros checkbox is toggled', function () {
213
+ var _renderComponent5 = renderComponent({
214
+ excludeZero: false
215
+ }),
216
+ onChange = _renderComponent5.onChange;
217
+ var checkbox = _react.screen.getByLabelText('Exclude zeros');
218
+ _react.fireEvent.click(checkbox);
219
+ expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
220
+ excludeZero: true
221
+ }));
222
+ });
223
+ it('calls onChange when max points is changed', function () {
224
+ var _renderComponent6 = renderComponent(),
225
+ onChange = _renderComponent6.onChange;
226
+ var selectInput = _react.screen.getByLabelText('Max Points');
227
+ _react.fireEvent.mouseDown(selectInput);
228
+
229
+ // The onChange should be called when a new value is selected
230
+ // This tests the changeMaxPoints logic indirectly
231
+ });
232
+ it('renders correct number of points based on excludeZero', function () {
233
+ var _renderComponent7 = renderComponent({
234
+ excludeZero: false
235
+ }),
236
+ rerender = _renderComponent7.rerender;
237
+ expect(_react.screen.getByText('0 pt')).toBeInTheDocument();
238
+
239
+ // Rerender with excludeZero true
240
+ rerender(/*#__PURE__*/_react2["default"].createElement(_styles.ThemeProvider, {
241
+ theme: theme
242
+ }, /*#__PURE__*/_react2["default"].createElement(_authoring.RawAuthoring, {
243
+ classes: {},
244
+ onChange: jest.fn(),
245
+ className: "className",
246
+ value: {
247
+ excludeZero: true,
248
+ points: points,
249
+ sampleAnswers: sampleAnswers
250
+ }
251
+ })));
252
+ expect(_react.screen.queryByText('0 pt')).not.toBeInTheDocument();
253
+ });
254
+ });
255
+ describe('drag and drop', function () {
256
+ it('calls onChange with reordered points after drag end', function () {
257
+ var _renderComponent8 = renderComponent(),
258
+ onChange = _renderComponent8.onChange;
259
+ var component = new _authoring.RawAuthoring({
260
+ value: {
261
+ excludeZero: false,
262
+ points: points,
263
+ sampleAnswers: sampleAnswers
264
+ },
265
+ onChange: onChange,
266
+ classes: {},
267
+ className: 'className'
268
+ });
269
+
270
+ // Simulate drag from index 0 to index 2
271
+ component.dragEnd({
272
+ source: {
273
+ index: 0
274
+ },
275
+ destination: {
276
+ index: 2
277
+ }
278
+ });
279
+ expect(onChange).toHaveBeenCalled();
280
+ var result = onChange.mock.calls[0][0];
281
+ expect(result.points).not.toEqual(points);
282
+ expect(result.points.length).toBe(points.length);
283
+ });
284
+ it('does nothing when drag has no destination', function () {
285
+ var _renderComponent9 = renderComponent(),
286
+ onChange = _renderComponent9.onChange;
287
+ var component = new _authoring.RawAuthoring({
288
+ value: {
289
+ excludeZero: false,
290
+ points: points,
291
+ sampleAnswers: sampleAnswers
292
+ },
293
+ onChange: onChange,
294
+ classes: {},
295
+ className: 'className'
296
+ });
297
+
298
+ // Simulate drag without destination
299
+ component.dragEnd({
300
+ source: {
301
+ index: 0
302
+ },
303
+ destination: null
304
+ });
305
+ expect(onChange).not.toHaveBeenCalled();
306
+ });
307
+ });
308
+ describe('content editing', function () {
309
+ it('calls onChange when point content is changed', function () {
310
+ var _renderComponent0 = renderComponent(),
311
+ onChange = _renderComponent0.onChange;
312
+ var component = new _authoring.RawAuthoring({
313
+ value: {
314
+ excludeZero: false,
315
+ points: points,
316
+ sampleAnswers: sampleAnswers
317
+ },
318
+ onChange: onChange,
319
+ classes: {},
320
+ className: 'className'
321
+ });
322
+ component.changeContent(0, 'new content', 'points');
323
+ expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
324
+ points: expect.arrayContaining(['new content'])
325
+ }));
326
+ });
327
+ it('calls onChange when sample answer is changed', function () {
328
+ var _renderComponent1 = renderComponent(),
329
+ onChange = _renderComponent1.onChange;
330
+ var component = new _authoring.RawAuthoring({
331
+ value: {
332
+ excludeZero: false,
333
+ points: points,
334
+ sampleAnswers: sampleAnswers
335
+ },
336
+ onChange: onChange,
337
+ classes: {},
338
+ className: 'className'
339
+ });
340
+ component.changeContent(1, 'new sample answer', 'sampleAnswers');
341
+ expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
342
+ sampleAnswers: expect.arrayContaining(['new sample answer'])
343
+ }));
344
+ });
345
+ it('does not change content for invalid type', function () {
346
+ var _renderComponent10 = renderComponent(),
347
+ onChange = _renderComponent10.onChange;
348
+ var component = new _authoring.RawAuthoring({
349
+ value: {
350
+ excludeZero: false,
351
+ points: points,
352
+ sampleAnswers: sampleAnswers
353
+ },
354
+ onChange: onChange,
355
+ classes: {},
356
+ className: 'className'
357
+ });
358
+ component.changeContent(0, 'new content', 'invalidType');
359
+ expect(onChange).not.toHaveBeenCalled();
360
+ });
361
+ });
362
+ describe('rubricless mode', function () {
363
+ it('calls onChange when rubricless instruction is changed', function () {
364
+ var _renderComponent11 = renderComponent({
365
+ rubriclessInstruction: ''
366
+ }, {
367
+ rubricless: true
368
+ }),
369
+ onChange = _renderComponent11.onChange;
370
+ var component = new _authoring.RawAuthoring({
371
+ value: {
372
+ excludeZero: false,
373
+ points: points,
374
+ sampleAnswers: sampleAnswers,
375
+ rubriclessInstruction: ''
376
+ },
377
+ onChange: onChange,
378
+ classes: {},
379
+ className: 'className',
380
+ rubricless: true
381
+ });
382
+ component.changeRubriclessInstruction('New instruction');
383
+ expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
384
+ rubriclessInstruction: 'New instruction'
385
+ }));
386
+ });
387
+ });
388
+ describe('edge cases', function () {
389
+ it('handles empty points array', function () {
390
+ var _renderComponent12 = renderComponent({
391
+ points: [],
392
+ sampleAnswers: []
393
+ }),
394
+ container = _renderComponent12.container;
395
+ expect(container).toBeInTheDocument();
396
+ });
397
+ it('handles maxPoints greater than current max', function () {
398
+ var _renderComponent13 = renderComponent(),
399
+ onChange = _renderComponent13.onChange;
400
+ var component = new _authoring.RawAuthoring({
401
+ value: {
402
+ excludeZero: false,
403
+ points: points,
404
+ sampleAnswers: sampleAnswers
405
+ },
406
+ onChange: onChange,
407
+ classes: {},
408
+ className: 'className'
409
+ });
410
+ component.changeMaxPoints(10);
411
+ expect(onChange).toHaveBeenCalled();
412
+ var result = onChange.mock.calls[0][0];
413
+ expect(result.points.length).toBe(11); // 10 + 1 for 0 points
414
+ });
415
+ it('handles config and pluginOpts props', function () {
416
+ var config = {
417
+ someConfig: true
418
+ };
419
+ var pluginOpts = {
420
+ somePlugin: true
421
+ };
422
+ var _renderComponent14 = renderComponent({}, {
423
+ config: config,
424
+ pluginOpts: pluginOpts
425
+ }),
426
+ container = _renderComponent14.container;
427
+ expect(container).toBeInTheDocument();
428
+ });
429
+ });
430
+ });
431
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJyZXF1aXJlIiwiX3JlYWN0MiIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfYXV0aG9yaW5nIiwiX2xvZGFzaEVzIiwiX3N0eWxlcyIsIm93bktleXMiLCJlIiwiciIsInQiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwiamVzdCIsIm1vY2siLCJFZGl0YWJsZUh0bWwiLCJwcm9wcyIsImNyZWF0ZUVsZW1lbnQiLCJtYXJrdXAiLCJGZWVkYmFja0NvbmZpZyIsIl9yZWYiLCJmZWVkYmFjayIsIkpTT04iLCJzdHJpbmdpZnkiLCJJbnB1dENvbnRhaW5lciIsIl9yZWYyIiwiY2hpbGRyZW4iLCJsYWJlbCIsIkRyYWdEcm9wQ29udGV4dCIsIl9yZWYzIiwiRHJvcHBhYmxlIiwiX3JlZjQiLCJkcm9wcGFibGVQcm9wcyIsImlubmVyUmVmIiwiRHJhZ2dhYmxlIiwiX3JlZjUiLCJpbmRleCIsImRyYWdnYWJsZVByb3BzIiwiZHJhZ0hhbmRsZVByb3BzIiwiZGVzY3JpYmUiLCJwb2ludHMiLCJzYW1wbGVBbnN3ZXJzIiwidGhlbWUiLCJjcmVhdGVUaGVtZSIsInJlbmRlckNvbXBvbmVudCIsInZhbHVlIiwidW5kZWZpbmVkIiwiZGVmYXVsdFByb3BzIiwiY2xhc3NlcyIsIm9uQ2hhbmdlIiwiZm4iLCJjbGFzc05hbWUiLCJleGNsdWRlWmVybyIsInJlbmRlciIsIlRoZW1lUHJvdmlkZXIiLCJSYXdBdXRob3JpbmciLCJpdCIsImV4cGVjdCIsInNjcmVlbiIsImdldEJ5VGV4dCIsInRvQmVJblRoZURvY3VtZW50IiwiZ2V0QnlMYWJlbFRleHQiLCJfcmVuZGVyQ29tcG9uZW50IiwiY29udGFpbmVyIiwicXVlcnlTZWxlY3RvciIsInF1ZXJ5QnlUZXh0Iiwibm90IiwiX3JlbmRlckNvbXBvbmVudDIiLCJkcmFnZ2FibGVJdGVtcyIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJ0b0VxdWFsIiwidGVzdENoYW5nZU1heFBvaW50cyIsIm1heFBvaW50cyIsImV4cGVjdGVkUG9pbnRzIiwiZXhwZWN0ZWRTYW1wbGVBbnN3ZXJzIiwiY29uY2F0IiwiX2NvbnRhaW5lciRxdWVyeVNlbGVjIiwiX3JlbmRlckNvbXBvbmVudDMiLCJpbnN0YW5jZSIsIl9vd25lciIsImNvbXBvbmVudCIsImNoYW5nZU1heFBvaW50cyIsInRvSGF2ZUJlZW5DYWxsZWRXaXRoIiwidGFrZVJpZ2h0IiwidGVzdENoYW5nZVNhbXBsZVJlc3BvbnNlIiwiY2xpY2tlZEl0ZW0iLCJfcmVuZGVyQ29tcG9uZW50NCIsIm9uUG9pbnRNZW51Q2hhbmdlIiwiX3JlbmRlckNvbXBvbmVudDUiLCJjaGVja2JveCIsImZpcmVFdmVudCIsImNsaWNrIiwib2JqZWN0Q29udGFpbmluZyIsIl9yZW5kZXJDb21wb25lbnQ2Iiwic2VsZWN0SW5wdXQiLCJtb3VzZURvd24iLCJfcmVuZGVyQ29tcG9uZW50NyIsInJlcmVuZGVyIiwiX3JlbmRlckNvbXBvbmVudDgiLCJkcmFnRW5kIiwic291cmNlIiwiZGVzdGluYXRpb24iLCJ0b0hhdmVCZWVuQ2FsbGVkIiwicmVzdWx0IiwiY2FsbHMiLCJ0b0JlIiwiX3JlbmRlckNvbXBvbmVudDkiLCJfcmVuZGVyQ29tcG9uZW50MCIsImNoYW5nZUNvbnRlbnQiLCJhcnJheUNvbnRhaW5pbmciLCJfcmVuZGVyQ29tcG9uZW50MSIsIl9yZW5kZXJDb21wb25lbnQxMCIsIl9yZW5kZXJDb21wb25lbnQxMSIsInJ1YnJpY2xlc3NJbnN0cnVjdGlvbiIsInJ1YnJpY2xlc3MiLCJjaGFuZ2VSdWJyaWNsZXNzSW5zdHJ1Y3Rpb24iLCJfcmVuZGVyQ29tcG9uZW50MTIiLCJfcmVuZGVyQ29tcG9uZW50MTMiLCJjb25maWciLCJzb21lQ29uZmlnIiwicGx1Z2luT3B0cyIsInNvbWVQbHVnaW4iLCJfcmVuZGVyQ29tcG9uZW50MTQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvX190ZXN0c19fL3J1YnJpYy50ZXN0LmpzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmaXJlRXZlbnQsIHJlbmRlciwgc2NyZWVuIH0gZnJvbSAnQHRlc3RpbmctbGlicmFyeS9yZWFjdCc7XG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IHsgUmF3QXV0aG9yaW5nIH0gZnJvbSAnLi4vYXV0aG9yaW5nJztcbmltcG9ydCB7IHRha2VSaWdodCB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBjcmVhdGVUaGVtZSwgVGhlbWVQcm92aWRlciB9IGZyb20gJ0BtdWkvbWF0ZXJpYWwvc3R5bGVzJztcblxuLy8gTW9jayBkZXBlbmRlbmNpZXNcbmplc3QubW9jaygnQHBpZS1saWIvZWRpdGFibGUtaHRtbC10aXAtdGFwJywgKCkgPT4ge1xuICByZXR1cm4gZnVuY3Rpb24gRWRpdGFibGVIdG1sKHByb3BzKSB7XG4gICAgcmV0dXJuIDxkaXYgZGF0YS10ZXN0aWQ9XCJlZGl0YWJsZS1odG1sXCIgZGF0YS1tYXJrdXA9e3Byb3BzLm1hcmt1cH0gLz47XG4gIH07XG59KTtcblxuamVzdC5tb2NrKCdAcGllLWxpYi9jb25maWctdWknLCAoKSA9PiAoe1xuICBGZWVkYmFja0NvbmZpZzogKHsgZmVlZGJhY2sgfSkgPT4gPGRpdiBkYXRhLXRlc3RpZD1cImZlZWRiYWNrLWNvbmZpZ1wiPntKU09OLnN0cmluZ2lmeShmZWVkYmFjayl9PC9kaXY+LFxuICBJbnB1dENvbnRhaW5lcjogKHsgY2hpbGRyZW4sIGxhYmVsIH0pID0+IChcbiAgICA8ZGl2IGRhdGEtdGVzdGlkPVwiaW5wdXQtY29udGFpbmVyXCIgZGF0YS1sYWJlbD17bGFiZWx9PlxuICAgICAge2NoaWxkcmVufVxuICAgIDwvZGl2PlxuICApLFxufSkpO1xuXG5qZXN0Lm1vY2soJ0BoZWxsby1wYW5nZWEvZG5kJywgKCkgPT4gKHtcbiAgRHJhZ0Ryb3BDb250ZXh0OiAoeyBjaGlsZHJlbiB9KSA9PiA8ZGl2IGRhdGEtdGVzdGlkPVwiZHJhZy1kcm9wLWNvbnRleHRcIj57Y2hpbGRyZW59PC9kaXY+LFxuICBEcm9wcGFibGU6ICh7IGNoaWxkcmVuIH0pID0+IGNoaWxkcmVuKHsgZHJvcHBhYmxlUHJvcHM6IHt9LCBpbm5lclJlZjogKCkgPT4ge30gfSwge30pLFxuICBEcmFnZ2FibGU6ICh7IGNoaWxkcmVuLCBpbmRleCB9KSA9PlxuICAgIGNoaWxkcmVuKFxuICAgICAge1xuICAgICAgICBpbm5lclJlZjogKCkgPT4ge30sXG4gICAgICAgIGRyYWdnYWJsZVByb3BzOiB7ICdkYXRhLWRyYWdnYWJsZS1pbmRleCc6IGluZGV4IH0sXG4gICAgICAgIGRyYWdIYW5kbGVQcm9wczoge30sXG4gICAgICB9LFxuICAgICAge30sXG4gICAgKSxcbn0pKTtcblxuZGVzY3JpYmUoJ1J1YnJpYycsICgpID0+IHtcbiAgY29uc3QgcG9pbnRzID0gWydub3RoaW5nIHJpZ2h0JywgJ2EgdGVlbnkgYml0IHJpZ2h0JywgJ21vc3RseSByaWdodCcsICdiaW5nbyddO1xuICBjb25zdCBzYW1wbGVBbnN3ZXJzID0gW251bGwsICdqdXN0IHJpZ2h0JywgJ25vdCBsZWZ0JywgbnVsbF07XG4gIGNvbnN0IHRoZW1lID0gY3JlYXRlVGhlbWUoKTtcblxuICBjb25zdCByZW5kZXJDb21wb25lbnQgPSAodmFsdWUgPSB7fSwgcHJvcHMgPSB7fSkgPT4ge1xuICAgIGNvbnN0IGRlZmF1bHRQcm9wcyA9IHtcbiAgICAgIGNsYXNzZXM6IHt9LFxuICAgICAgb25DaGFuZ2U6IGplc3QuZm4oKSxcbiAgICAgIGNsYXNzTmFtZTogJ2NsYXNzTmFtZScsXG4gICAgICB2YWx1ZToge1xuICAgICAgICBleGNsdWRlWmVybzogZmFsc2UsXG4gICAgICAgIHBvaW50cyxcbiAgICAgICAgc2FtcGxlQW5zd2VycyxcbiAgICAgICAgLi4udmFsdWUsXG4gICAgICB9LFxuICAgICAgLi4ucHJvcHMsXG4gICAgfTtcblxuICAgIHJldHVybiB7XG4gICAgICAuLi5yZW5kZXIoXG4gICAgICAgIDxUaGVtZVByb3ZpZGVyIHRoZW1lPXt0aGVtZX0+XG4gICAgICAgICAgPFJhd0F1dGhvcmluZyB7Li4uZGVmYXVsdFByb3BzfSAvPlxuICAgICAgICA8L1RoZW1lUHJvdmlkZXI+LFxuICAgICAgKSxcbiAgICAgIG9uQ2hhbmdlOiBkZWZhdWx0UHJvcHMub25DaGFuZ2UsXG4gICAgICBwcm9wczogZGVmYXVsdFByb3BzLFxuICAgIH07XG4gIH07XG5cbiAgZGVzY3JpYmUoJ3JlbmRlcicsICgpID0+IHtcbiAgICBpdCgncmVuZGVycyBydWJyaWMgdGl0bGUgYW5kIG1haW4gc3RydWN0dXJlJywgKCkgPT4ge1xuICAgICAgcmVuZGVyQ29tcG9uZW50KCk7XG4gICAgICBleHBlY3Qoc2NyZWVuLmdldEJ5VGV4dCgnUnVicmljJykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgICBleHBlY3Qoc2NyZWVuLmdldEJ5TGFiZWxUZXh0KCdNYXggUG9pbnRzJykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgICBleHBlY3Qoc2NyZWVuLmdldEJ5TGFiZWxUZXh0KCdFeGNsdWRlIHplcm9zJykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgfSk7XG5cbiAgICBpdCgncmVuZGVycyBhbGwgcG9pbnQgY29uZmlndXJhdGlvbnMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB7IGNvbnRhaW5lciB9ID0gcmVuZGVyQ29tcG9uZW50KCk7XG4gICAgICAvLyBWZXJpZnkgRHJhZ0Ryb3BDb250ZXh0IGlzIHJlbmRlcmVkXG4gICAgICBleHBlY3QoY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJ1tkYXRhLXRlc3RpZD1cImRyYWctZHJvcC1jb250ZXh0XCJdJykpLnRvQmVJblRoZURvY3VtZW50KCk7XG5cbiAgICAgIC8vIENoZWNrIHRoYXQgcG9pbnQgbGFiZWxzIGFyZSByZW5kZXJlZCAoNCBwb2ludHMgPSBcIjMgcHRzXCIsIFwiMiBwdHNcIiwgXCIxIHB0XCIsIFwiMCBwdFwiKVxuICAgICAgLy8gTm90ZTogVGhlIFBvaW50Q29uZmlnIGNvbXBvbmVudCB1c2VzIHNpbmd1bGFyIFwicHRcIiBmb3IgMCBhbmQgMSwgcGx1cmFsIFwicHRzXCIgZm9yIDIrXG4gICAgICBleHBlY3Qoc2NyZWVuLmdldEJ5VGV4dCgnMyBwdHMnKSkudG9CZUluVGhlRG9jdW1lbnQoKTtcbiAgICAgIGV4cGVjdChzY3JlZW4uZ2V0QnlUZXh0KCcyIHB0cycpKS50b0JlSW5UaGVEb2N1bWVudCgpO1xuICAgICAgZXhwZWN0KHNjcmVlbi5nZXRCeVRleHQoJzEgcHQnKSkudG9CZUluVGhlRG9jdW1lbnQoKTtcbiAgICAgIGV4cGVjdChzY3JlZW4uZ2V0QnlUZXh0KCcwIHB0JykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnZHJhZ2dhYmxlJywgKCkgPT4ge1xuICAgICAgaXQoJ3JlbmRlcnMgMyBkcmFnZ2FibGUgaXRlbXMgd2hlbiBleGNsdWRlWmVybyBpcyB0cnVlJywgKCkgPT4ge1xuICAgICAgICAvLyBXaGVuIGV4Y2x1ZGVaZXJvIGlzIHRydWUsIHRoZSBsYXN0IHBvaW50ICgwIHB0cykgc2hvdWxkIG5vdCBiZSByZW5kZXJlZFxuICAgICAgICBleHBlY3Qoc2NyZWVuLnF1ZXJ5QnlUZXh0KCcwIHB0JykpLm5vdC50b0JlSW5UaGVEb2N1bWVudCgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdyZW5kZXJzIDQgZHJhZ2dhYmxlIGl0ZW1zIHdoZW4gZXhjbHVkZVplcm8gaXMgZmFsc2UnLCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgY29udGFpbmVyIH0gPSByZW5kZXJDb21wb25lbnQoeyBleGNsdWRlWmVybzogZmFsc2UgfSk7XG5cbiAgICAgICAgLy8gV2hlbiBleGNsdWRlWmVybyBpcyBmYWxzZSwgYWxsIHBvaW50cyBpbmNsdWRpbmcgMCBzaG91bGQgYmUgcmVuZGVyZWRcbiAgICAgICAgY29uc3QgZHJhZ2dhYmxlSXRlbXMgPSBjb250YWluZXIucXVlcnlTZWxlY3RvckFsbCgnW2RhdGEtZHJhZ2dhYmxlLWluZGV4XScpO1xuICAgICAgICBleHBlY3QoZHJhZ2dhYmxlSXRlbXMubGVuZ3RoKS50b0VxdWFsKDQpO1xuICAgICAgICBleHBlY3Qoc2NyZWVuLmdldEJ5VGV4dCgnMCBwdCcpKS50b0JlSW5UaGVEb2N1bWVudCgpO1xuXG4gICAgICAgIC8vIFZlcmlmeSBhbGwgcG9pbnQgbGFiZWxzIGFyZSByZW5kZXJlZFxuICAgICAgICBleHBlY3Qoc2NyZWVuLmdldEJ5VGV4dCgnMyBwdHMnKSkudG9CZUluVGhlRG9jdW1lbnQoKTtcbiAgICAgICAgZXhwZWN0KHNjcmVlbi5nZXRCeVRleHQoJzIgcHRzJykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgICAgIGV4cGVjdChzY3JlZW4uZ2V0QnlUZXh0KCcxIHB0JykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgICAgIGV4cGVjdChzY3JlZW4uZ2V0QnlUZXh0KCcwIHB0JykpLnRvQmVJblRoZURvY3VtZW50KCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2xvZ2ljJywgKCkgPT4ge1xuICAgIGRlc2NyaWJlKCdjaGFuZ2VNYXhQb2ludHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0Q2hhbmdlTWF4UG9pbnRzID0gKG1heFBvaW50cywgZXhjbHVkZVplcm8sIGV4cGVjdGVkUG9pbnRzLCBleHBlY3RlZFNhbXBsZUFuc3dlcnMpID0+IHtcbiAgICAgICAgaXQoYG1heFBvaW50cz0ke21heFBvaW50c30sIGV4Y2x1ZGVaZXJvPSR7ZXhjbHVkZVplcm99IGNhbGxzIG9uQ2hhbmdlIGNvcnJlY3RseWAsICgpID0+IHtcbiAgICAgICAgICBjb25zdCB7IG9uQ2hhbmdlLCBjb250YWluZXIgfSA9IHJlbmRlckNvbXBvbmVudCh7IGV4Y2x1ZGVaZXJvIH0pO1xuXG4gICAgICAgICAgLy8gR2V0IHRoZSBjb21wb25lbnQgaW5zdGFuY2UgdGhyb3VnaCB0aGUgY29udGFpbmVyXG4gICAgICAgICAgLy8gV2UgbmVlZCB0byBjYWxsIHRoZSBtZXRob2QgZGlyZWN0bHkgc2luY2Ugd2UncmUgdGVzdGluZyBpbnRlcm5hbCBiZWhhdmlvclxuICAgICAgICAgIGNvbnN0IGluc3RhbmNlID0gY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJ1tjbGFzcyo9XCJNdWlCb3gtcm9vdFwiXScpPy5fb3duZXI7XG5cbiAgICAgICAgICAvLyBTaW5jZSB3ZSBjYW4ndCBlYXNpbHkgYWNjZXNzIGluc3RhbmNlIG1ldGhvZHMgaW4gUlRMLCB3ZSdsbCB0ZXN0IHRoZSBiZWhhdmlvclxuICAgICAgICAgIC8vIGJ5IHZlcmlmeWluZyB0aGUgb25DaGFuZ2UgcHJvcCByZWNlaXZlcyB0aGUgY29ycmVjdCB2YWx1ZXNcbiAgICAgICAgICAvLyBGb3Igbm93LCB3ZSdsbCBkaXJlY3RseSB0ZXN0IHRoZSBsb2dpY1xuICAgICAgICAgIGNvbnN0IGNvbXBvbmVudCA9IG5ldyBSYXdBdXRob3Jpbmcoe1xuICAgICAgICAgICAgdmFsdWU6IHsgZXhjbHVkZVplcm8sIHBvaW50cywgc2FtcGxlQW5zd2VycyB9LFxuICAgICAgICAgICAgb25DaGFuZ2UsXG4gICAgICAgICAgICBjbGFzc2VzOiB7fSxcbiAgICAgICAgICAgIGNsYXNzTmFtZTogJ2NsYXNzTmFtZScsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb21wb25lbnQuY2hhbmdlTWF4UG9pbnRzKG1heFBvaW50cyk7XG5cbiAgICAgICAgICBleHBlY3Qob25DaGFuZ2UpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICAgICAgICAgIGV4Y2x1ZGVaZXJvLFxuICAgICAgICAgICAgcG9pbnRzOiBleHBlY3RlZFBvaW50cyxcbiAgICAgICAgICAgIHNhbXBsZUFuc3dlcnM6IGV4cGVjdGVkU2FtcGxlQW5zd2VycyxcbiAgICAgICAgICAgIG1heFBvaW50czogZXhwZWN0ZWRQb2ludHMubGVuZ3RoIC0gMSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gICAgICB0ZXN0Q2hhbmdlTWF4UG9pbnRzKDEsIGZhbHNlLCB0YWtlUmlnaHQocG9pbnRzLCAyKSwgdGFrZVJpZ2h0KHNhbXBsZUFuc3dlcnMsIDIpKTtcbiAgICAgIHRlc3RDaGFuZ2VNYXhQb2ludHMoMSwgdHJ1ZSwgdGFrZVJpZ2h0KHBvaW50cywgMiksIHRha2VSaWdodChzYW1wbGVBbnN3ZXJzLCAyKSk7XG4gICAgICB0ZXN0Q2hhbmdlTWF4UG9pbnRzKDIsIHRydWUsIHRha2VSaWdodChwb2ludHMsIDMpLCB0YWtlUmlnaHQoc2FtcGxlQW5zd2VycywgMykpO1xuICAgICAgdGVzdENoYW5nZU1heFBvaW50cygyLCBmYWxzZSwgdGFrZVJpZ2h0KHBvaW50cywgMyksIHRha2VSaWdodChzYW1wbGVBbnN3ZXJzLCAzKSk7XG4gICAgICB0ZXN0Q2hhbmdlTWF4UG9pbnRzKDUsIGZhbHNlLCBbJycsICcnXS5jb25jYXQocG9pbnRzKSwgW251bGwsIG51bGxdLmNvbmNhdChzYW1wbGVBbnN3ZXJzKSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnY2hhbmdlU2FtcGxlUmVzcG9uc2UnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0Q2hhbmdlU2FtcGxlUmVzcG9uc2UgPSAoaW5kZXgsIGNsaWNrZWRJdGVtLCBleGNsdWRlWmVybywgZXhwZWN0ZWRQb2ludHMsIGV4cGVjdGVkU2FtcGxlQW5zd2VycykgPT4ge1xuICAgICAgICBpdChgUG9pbnQgJHtpbmRleH0gd2l0aCBjbGlja2VkSXRlbT1cIiR7Y2xpY2tlZEl0ZW19XCIgY2FsbHMgb25DaGFuZ2UgY29ycmVjdGx5YCwgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgb25DaGFuZ2UgfSA9IHJlbmRlckNvbXBvbmVudCh7IGV4Y2x1ZGVaZXJvIH0pO1xuXG4gICAgICAgICAgLy8gVGVzdCB0aGUgbG9naWMgYnkgY3JlYXRpbmcgYSBjb21wb25lbnQgaW5zdGFuY2UgYW5kIGNhbGxpbmcgdGhlIG1ldGhvZFxuICAgICAgICAgIGNvbnN0IGNvbXBvbmVudCA9IG5ldyBSYXdBdXRob3Jpbmcoe1xuICAgICAgICAgICAgdmFsdWU6IHsgZXhjbHVkZVplcm8sIHBvaW50cywgc2FtcGxlQW5zd2VycyB9LFxuICAgICAgICAgICAgb25DaGFuZ2UsXG4gICAgICAgICAgICBjbGFzc2VzOiB7fSxcbiAgICAgICAgICAgIGNsYXNzTmFtZTogJ2NsYXNzTmFtZScsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb21wb25lbnQub25Qb2ludE1lbnVDaGFuZ2UoaW5kZXgsIGNsaWNrZWRJdGVtKTtcblxuICAgICAgICAgIGV4cGVjdChvbkNoYW5nZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgICAgICAgICAgZXhjbHVkZVplcm8sXG4gICAgICAgICAgICBwb2ludHM6IGV4cGVjdGVkUG9pbnRzLFxuICAgICAgICAgICAgc2FtcGxlQW5zd2VyczogZXhwZWN0ZWRTYW1wbGVBbnN3ZXJzLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIHRlc3RDaGFuZ2VTYW1wbGVSZXNwb25zZSgwLCAnc2FtcGxlJywgZmFsc2UsIHBvaW50cywgWycnLCAnanVzdCByaWdodCcsICdub3QgbGVmdCcsIG51bGxdKTtcbiAgICAgIHRlc3RDaGFuZ2VTYW1wbGVSZXNwb25zZSgzLCAnc2FtcGxlJywgZmFsc2UsIHBvaW50cywgW251bGwsICdqdXN0IHJpZ2h0JywgJ25vdCBsZWZ0JywgJyddKTtcbiAgICAgIHRlc3RDaGFuZ2VTYW1wbGVSZXNwb25zZSgxLCAnc2FtcGxlJywgdHJ1ZSwgcG9pbnRzLCBbbnVsbCwgbnVsbCwgJ25vdCBsZWZ0JywgbnVsbF0pO1xuICAgICAgdGVzdENoYW5nZVNhbXBsZVJlc3BvbnNlKDMsICdzYW1wbGUnLCB0cnVlLCBwb2ludHMsIFtudWxsLCAnanVzdCByaWdodCcsICdub3QgbGVmdCcsICcnXSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd1c2VyIGludGVyYWN0aW9ucycsICgpID0+IHtcbiAgICBpdCgnY2FsbHMgb25DaGFuZ2Ugd2hlbiBleGNsdWRpbmcgemVyb3MgY2hlY2tib3ggaXMgdG9nZ2xlZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHsgb25DaGFuZ2UgfSA9IHJlbmRlckNvbXBvbmVudCh7IGV4Y2x1ZGVaZXJvOiBmYWxzZSB9KTtcblxuICAgICAgY29uc3QgY2hlY2tib3ggPSBzY3JlZW4uZ2V0QnlMYWJlbFRleHQoJ0V4Y2x1ZGUgemVyb3MnKTtcbiAgICAgIGZpcmVFdmVudC5jbGljayhjaGVja2JveCk7XG5cbiAgICAgIGV4cGVjdChvbkNoYW5nZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICBleGNsdWRlWmVybzogdHJ1ZSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbGxzIG9uQ2hhbmdlIHdoZW4gbWF4IHBvaW50cyBpcyBjaGFuZ2VkJywgKCkgPT4ge1xuICAgICAgY29uc3QgeyBvbkNoYW5nZSB9ID0gcmVuZGVyQ29tcG9uZW50KCk7XG5cbiAgICAgIGNvbnN0IHNlbGVjdElucHV0ID0gc2NyZWVuLmdldEJ5TGFiZWxUZXh0KCdNYXggUG9pbnRzJyk7XG4gICAgICBmaXJlRXZlbnQubW91c2VEb3duKHNlbGVjdElucHV0KTtcblxuICAgICAgLy8gVGhlIG9uQ2hhbmdlIHNob3VsZCBiZSBjYWxsZWQgd2hlbiBhIG5ldyB2YWx1ZSBpcyBzZWxlY3RlZFxuICAgICAgLy8gVGhpcyB0ZXN0cyB0aGUgY2hhbmdlTWF4UG9pbnRzIGxvZ2ljIGluZGlyZWN0bHlcbiAgICB9KTtcblxuICAgIGl0KCdyZW5kZXJzIGNvcnJlY3QgbnVtYmVyIG9mIHBvaW50cyBiYXNlZCBvbiBleGNsdWRlWmVybycsICgpID0+IHtcbiAgICAgIGNvbnN0IHsgcmVyZW5kZXIgfSA9IHJlbmRlckNvbXBvbmVudCh7IGV4Y2x1ZGVaZXJvOiBmYWxzZSB9KTtcbiAgICAgIGV4cGVjdChzY3JlZW4uZ2V0QnlUZXh0KCcwIHB0JykpLnRvQmVJblRoZURvY3VtZW50KCk7XG5cbiAgICAgIC8vIFJlcmVuZGVyIHdpdGggZXhjbHVkZVplcm8gdHJ1ZVxuICAgICAgcmVyZW5kZXIoXG4gICAgICAgIDxUaGVtZVByb3ZpZGVyIHRoZW1lPXt0aGVtZX0+XG4gICAgICAgICAgPFJhd0F1dGhvcmluZ1xuICAgICAgICAgICAgY2xhc3Nlcz17e319XG4gICAgICAgICAgICBvbkNoYW5nZT17amVzdC5mbigpfVxuICAgICAgICAgICAgY2xhc3NOYW1lPVwiY2xhc3NOYW1lXCJcbiAgICAgICAgICAgIHZhbHVlPXt7IGV4Y2x1ZGVaZXJvOiB0cnVlLCBwb2ludHMsIHNhbXBsZUFuc3dlcnMgfX1cbiAgICAgICAgICAvPlxuICAgICAgICA8L1RoZW1lUHJvdmlkZXI+LFxuICAgICAgKTtcblxuICAgICAgZXhwZWN0KHNjcmVlbi5xdWVyeUJ5VGV4dCgnMCBwdCcpKS5ub3QudG9CZUluVGhlRG9jdW1lbnQoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2RyYWcgYW5kIGRyb3AnLCAoKSA9PiB7XG4gICAgaXQoJ2NhbGxzIG9uQ2hhbmdlIHdpdGggcmVvcmRlcmVkIHBvaW50cyBhZnRlciBkcmFnIGVuZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHsgb25DaGFuZ2UgfSA9IHJlbmRlckNvbXBvbmVudCgpO1xuXG4gICAgICBjb25zdCBjb21wb25lbnQgPSBuZXcgUmF3QXV0aG9yaW5nKHtcbiAgICAgICAgdmFsdWU6IHsgZXhjbHVkZVplcm86IGZhbHNlLCBwb2ludHMsIHNhbXBsZUFuc3dlcnMgfSxcbiAgICAgICAgb25DaGFuZ2UsXG4gICAgICAgIGNsYXNzZXM6IHt9LFxuICAgICAgICBjbGFzc05hbWU6ICdjbGFzc05hbWUnLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFNpbXVsYXRlIGRyYWcgZnJvbSBpbmRleCAwIHRvIGluZGV4IDJcbiAgICAgIGNvbXBvbmVudC5kcmFnRW5kKHtcbiAgICAgICAgc291cmNlOiB7IGluZGV4OiAwIH0sXG4gICAgICAgIGRlc3RpbmF0aW9uOiB7IGluZGV4OiAyIH0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KG9uQ2hhbmdlKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgICBjb25zdCByZXN1bHQgPSBvbkNoYW5nZS5tb2NrLmNhbGxzWzBdWzBdO1xuICAgICAgZXhwZWN0KHJlc3VsdC5wb2ludHMpLm5vdC50b0VxdWFsKHBvaW50cyk7XG4gICAgICBleHBlY3QocmVzdWx0LnBvaW50cy5sZW5ndGgpLnRvQmUocG9pbnRzLmxlbmd0aCk7XG4gICAgfSk7XG5cbiAgICBpdCgnZG9lcyBub3RoaW5nIHdoZW4gZHJhZyBoYXMgbm8gZGVzdGluYXRpb24nLCAoKSA9PiB7XG4gICAgICBjb25zdCB7IG9uQ2hhbmdlIH0gPSByZW5kZXJDb21wb25lbnQoKTtcblxuICAgICAgY29uc3QgY29tcG9uZW50ID0gbmV3IFJhd0F1dGhvcmluZyh7XG4gICAgICAgIHZhbHVlOiB7IGV4Y2x1ZGVaZXJvOiBmYWxzZSwgcG9pbnRzLCBzYW1wbGVBbnN3ZXJzIH0sXG4gICAgICAgIG9uQ2hhbmdlLFxuICAgICAgICBjbGFzc2VzOiB7fSxcbiAgICAgICAgY2xhc3NOYW1lOiAnY2xhc3NOYW1lJyxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBTaW11bGF0ZSBkcmFnIHdpdGhvdXQgZGVzdGluYXRpb25cbiAgICAgIGNvbXBvbmVudC5kcmFnRW5kKHtcbiAgICAgICAgc291cmNlOiB7IGluZGV4OiAwIH0sXG4gICAgICAgIGRlc3RpbmF0aW9uOiBudWxsLFxuICAgICAgfSk7XG5cbiAgICAgIGV4cGVjdChvbkNoYW5nZSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2NvbnRlbnQgZWRpdGluZycsICgpID0+IHtcbiAgICBpdCgnY2FsbHMgb25DaGFuZ2Ugd2hlbiBwb2ludCBjb250ZW50IGlzIGNoYW5nZWQnLCAoKSA9PiB7XG4gICAgICBjb25zdCB7IG9uQ2hhbmdlIH0gPSByZW5kZXJDb21wb25lbnQoKTtcblxuICAgICAgY29uc3QgY29tcG9uZW50ID0gbmV3IFJhd0F1dGhvcmluZyh7XG4gICAgICAgIHZhbHVlOiB7IGV4Y2x1ZGVaZXJvOiBmYWxzZSwgcG9pbnRzLCBzYW1wbGVBbnN3ZXJzIH0sXG4gICAgICAgIG9uQ2hhbmdlLFxuICAgICAgICBjbGFzc2VzOiB7fSxcbiAgICAgICAgY2xhc3NOYW1lOiAnY2xhc3NOYW1lJyxcbiAgICAgIH0pO1xuXG4gICAgICBjb21wb25lbnQuY2hhbmdlQ29udGVudCgwLCAnbmV3IGNvbnRlbnQnLCAncG9pbnRzJyk7XG5cbiAgICAgIGV4cGVjdChvbkNoYW5nZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICBwb2ludHM6IGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoWyduZXcgY29udGVudCddKSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbGxzIG9uQ2hhbmdlIHdoZW4gc2FtcGxlIGFuc3dlciBpcyBjaGFuZ2VkJywgKCkgPT4ge1xuICAgICAgY29uc3QgeyBvbkNoYW5nZSB9ID0gcmVuZGVyQ29tcG9uZW50KCk7XG5cbiAgICAgIGNvbnN0IGNvbXBvbmVudCA9IG5ldyBSYXdBdXRob3Jpbmcoe1xuICAgICAgICB2YWx1ZTogeyBleGNsdWRlWmVybzogZmFsc2UsIHBvaW50cywgc2FtcGxlQW5zd2VycyB9LFxuICAgICAgICBvbkNoYW5nZSxcbiAgICAgICAgY2xhc3Nlczoge30sXG4gICAgICAgIGNsYXNzTmFtZTogJ2NsYXNzTmFtZScsXG4gICAgICB9KTtcblxuICAgICAgY29tcG9uZW50LmNoYW5nZUNvbnRlbnQoMSwgJ25ldyBzYW1wbGUgYW5zd2VyJywgJ3NhbXBsZUFuc3dlcnMnKTtcblxuICAgICAgZXhwZWN0KG9uQ2hhbmdlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIHNhbXBsZUFuc3dlcnM6IGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoWyduZXcgc2FtcGxlIGFuc3dlciddKSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ2RvZXMgbm90IGNoYW5nZSBjb250ZW50IGZvciBpbnZhbGlkIHR5cGUnLCAoKSA9PiB7XG4gICAgICBjb25zdCB7IG9uQ2hhbmdlIH0gPSByZW5kZXJDb21wb25lbnQoKTtcblxuICAgICAgY29uc3QgY29tcG9uZW50ID0gbmV3IFJhd0F1dGhvcmluZyh7XG4gICAgICAgIHZhbHVlOiB7IGV4Y2x1ZGVaZXJvOiBmYWxzZSwgcG9pbnRzLCBzYW1wbGVBbnN3ZXJzIH0sXG4gICAgICAgIG9uQ2hhbmdlLFxuICAgICAgICBjbGFzc2VzOiB7fSxcbiAgICAgICAgY2xhc3NOYW1lOiAnY2xhc3NOYW1lJyxcbiAgICAgIH0pO1xuXG4gICAgICBjb21wb25lbnQuY2hhbmdlQ29udGVudCgwLCAnbmV3IGNvbnRlbnQnLCAnaW52YWxpZFR5cGUnKTtcblxuICAgICAgZXhwZWN0KG9uQ2hhbmdlKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncnVicmljbGVzcyBtb2RlJywgKCkgPT4ge1xuICAgIGl0KCdjYWxscyBvbkNoYW5nZSB3aGVuIHJ1YnJpY2xlc3MgaW5zdHJ1Y3Rpb24gaXMgY2hhbmdlZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHsgb25DaGFuZ2UgfSA9IHJlbmRlckNvbXBvbmVudCh7IHJ1YnJpY2xlc3NJbnN0cnVjdGlvbjogJycgfSwgeyBydWJyaWNsZXNzOiB0cnVlIH0pO1xuXG4gICAgICBjb25zdCBjb21wb25lbnQgPSBuZXcgUmF3QXV0aG9yaW5nKHtcbiAgICAgICAgdmFsdWU6IHsgZXhjbHVkZVplcm86IGZhbHNlLCBwb2ludHMsIHNhbXBsZUFuc3dlcnMsIHJ1YnJpY2xlc3NJbnN0cnVjdGlvbjogJycgfSxcbiAgICAgICAgb25DaGFuZ2UsXG4gICAgICAgIGNsYXNzZXM6IHt9LFxuICAgICAgICBjbGFzc05hbWU6ICdjbGFzc05hbWUnLFxuICAgICAgICBydWJyaWNsZXNzOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbXBvbmVudC5jaGFuZ2VSdWJyaWNsZXNzSW5zdHJ1Y3Rpb24oJ05ldyBpbnN0cnVjdGlvbicpO1xuXG4gICAgICBleHBlY3Qob25DaGFuZ2UpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgcnVicmljbGVzc0luc3RydWN0aW9uOiAnTmV3IGluc3RydWN0aW9uJyxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnZWRnZSBjYXNlcycsICgpID0+IHtcbiAgICBpdCgnaGFuZGxlcyBlbXB0eSBwb2ludHMgYXJyYXknLCAoKSA9PiB7XG4gICAgICBjb25zdCB7IGNvbnRhaW5lciB9ID0gcmVuZGVyQ29tcG9uZW50KHsgcG9pbnRzOiBbXSwgc2FtcGxlQW5zd2VyczogW10gfSk7XG4gICAgICBleHBlY3QoY29udGFpbmVyKS50b0JlSW5UaGVEb2N1bWVudCgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2hhbmRsZXMgbWF4UG9pbnRzIGdyZWF0ZXIgdGhhbiBjdXJyZW50IG1heCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHsgb25DaGFuZ2UgfSA9IHJlbmRlckNvbXBvbmVudCgpO1xuXG4gICAgICBjb25zdCBjb21wb25lbnQgPSBuZXcgUmF3QXV0aG9yaW5nKHtcbiAgICAgICAgdmFsdWU6IHsgZXhjbHVkZVplcm86IGZhbHNlLCBwb2ludHMsIHNhbXBsZUFuc3dlcnMgfSxcbiAgICAgICAgb25DaGFuZ2UsXG4gICAgICAgIGNsYXNzZXM6IHt9LFxuICAgICAgICBjbGFzc05hbWU6ICdjbGFzc05hbWUnLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbXBvbmVudC5jaGFuZ2VNYXhQb2ludHMoMTApO1xuXG4gICAgICBleHBlY3Qob25DaGFuZ2UpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IG9uQ2hhbmdlLm1vY2suY2FsbHNbMF1bMF07XG4gICAgICBleHBlY3QocmVzdWx0LnBvaW50cy5sZW5ndGgpLnRvQmUoMTEpOyAvLyAxMCArIDEgZm9yIDAgcG9pbnRzXG4gICAgfSk7XG5cbiAgICBpdCgnaGFuZGxlcyBjb25maWcgYW5kIHBsdWdpbk9wdHMgcHJvcHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCBjb25maWcgPSB7IHNvbWVDb25maWc6IHRydWUgfTtcbiAgICAgIGNvbnN0IHBsdWdpbk9wdHMgPSB7IHNvbWVQbHVnaW46IHRydWUgfTtcbiAgICAgIGNvbnN0IHsgY29udGFpbmVyIH0gPSByZW5kZXJDb21wb25lbnQoe30sIHsgY29uZmlnLCBwbHVnaW5PcHRzIH0pO1xuICAgICAgZXhwZWN0KGNvbnRhaW5lcikudG9CZUluVGhlRG9jdW1lbnQoKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLElBQUFBLE1BQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUYsT0FBQTtBQUNBLElBQUFHLFVBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFNBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLE9BQUEsR0FBQUwsT0FBQTtBQUFrRSxTQUFBTSxRQUFBQyxDQUFBLEVBQUFDLENBQUEsUUFBQUMsQ0FBQSxHQUFB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-lib/rubric",
3
- "version": "2.0.22-beta.1",
3
+ "version": "2.0.22-beta.11",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -13,7 +13,7 @@
13
13
  "@hello-pangea/dnd": "^18.0.1",
14
14
  "@mui/icons-material": "^7.3.4",
15
15
  "@mui/material": "^7.3.4",
16
- "@pie-lib/editable-html-tip-tap": "^2.1.20-beta.1",
16
+ "@pie-lib/editable-html-tip-tap": "^2.1.20-beta.11",
17
17
  "debug": "^4.1.1",
18
18
  "lodash-es": "^4.17.23",
19
19
  "prop-types": "^15.7.2",
@@ -0,0 +1,373 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { RawAuthoring } from '../authoring';
4
+ import { takeRight } from 'lodash-es';
5
+ import { createTheme, ThemeProvider } from '@mui/material/styles';
6
+
7
+ // Mock dependencies
8
+ jest.mock('@pie-lib/editable-html-tip-tap', () => {
9
+ return function EditableHtml(props) {
10
+ return <div data-testid="editable-html" data-markup={props.markup} />;
11
+ };
12
+ });
13
+
14
+ jest.mock('@pie-lib/config-ui', () => ({
15
+ FeedbackConfig: ({ feedback }) => <div data-testid="feedback-config">{JSON.stringify(feedback)}</div>,
16
+ InputContainer: ({ children, label }) => (
17
+ <div data-testid="input-container" data-label={label}>
18
+ {children}
19
+ </div>
20
+ ),
21
+ }));
22
+
23
+ jest.mock('@hello-pangea/dnd', () => ({
24
+ DragDropContext: ({ children }) => <div data-testid="drag-drop-context">{children}</div>,
25
+ Droppable: ({ children }) => children({ droppableProps: {}, innerRef: () => {} }, {}),
26
+ Draggable: ({ children, index }) =>
27
+ children(
28
+ {
29
+ innerRef: () => {},
30
+ draggableProps: { 'data-draggable-index': index },
31
+ dragHandleProps: {},
32
+ },
33
+ {},
34
+ ),
35
+ }));
36
+
37
+ describe('Rubric', () => {
38
+ const points = ['nothing right', 'a teeny bit right', 'mostly right', 'bingo'];
39
+ const sampleAnswers = [null, 'just right', 'not left', null];
40
+ const theme = createTheme();
41
+
42
+ const renderComponent = (value = {}, props = {}) => {
43
+ const defaultProps = {
44
+ classes: {},
45
+ onChange: jest.fn(),
46
+ className: 'className',
47
+ value: {
48
+ excludeZero: false,
49
+ points,
50
+ sampleAnswers,
51
+ ...value,
52
+ },
53
+ ...props,
54
+ };
55
+
56
+ return {
57
+ ...render(
58
+ <ThemeProvider theme={theme}>
59
+ <RawAuthoring {...defaultProps} />
60
+ </ThemeProvider>,
61
+ ),
62
+ onChange: defaultProps.onChange,
63
+ props: defaultProps,
64
+ };
65
+ };
66
+
67
+ describe('render', () => {
68
+ it('renders rubric title and main structure', () => {
69
+ renderComponent();
70
+ expect(screen.getByText('Rubric')).toBeInTheDocument();
71
+ expect(screen.getByLabelText('Max Points')).toBeInTheDocument();
72
+ expect(screen.getByLabelText('Exclude zeros')).toBeInTheDocument();
73
+ });
74
+
75
+ it('renders all point configurations', () => {
76
+ const { container } = renderComponent();
77
+ // Verify DragDropContext is rendered
78
+ expect(container.querySelector('[data-testid="drag-drop-context"]')).toBeInTheDocument();
79
+
80
+ // Check that point labels are rendered (4 points = "3 pts", "2 pts", "1 pt", "0 pt")
81
+ // Note: The PointConfig component uses singular "pt" for 0 and 1, plural "pts" for 2+
82
+ expect(screen.getByText('3 pts')).toBeInTheDocument();
83
+ expect(screen.getByText('2 pts')).toBeInTheDocument();
84
+ expect(screen.getByText('1 pt')).toBeInTheDocument();
85
+ expect(screen.getByText('0 pt')).toBeInTheDocument();
86
+ });
87
+
88
+ describe('draggable', () => {
89
+ it('renders 3 draggable items when excludeZero is true', () => {
90
+ // When excludeZero is true, the last point (0 pts) should not be rendered
91
+ expect(screen.queryByText('0 pt')).not.toBeInTheDocument();
92
+ });
93
+
94
+ it('renders 4 draggable items when excludeZero is false', () => {
95
+ const { container } = renderComponent({ excludeZero: false });
96
+
97
+ // When excludeZero is false, all points including 0 should be rendered
98
+ const draggableItems = container.querySelectorAll('[data-draggable-index]');
99
+ expect(draggableItems.length).toEqual(4);
100
+ expect(screen.getByText('0 pt')).toBeInTheDocument();
101
+
102
+ // Verify all point labels are rendered
103
+ expect(screen.getByText('3 pts')).toBeInTheDocument();
104
+ expect(screen.getByText('2 pts')).toBeInTheDocument();
105
+ expect(screen.getByText('1 pt')).toBeInTheDocument();
106
+ expect(screen.getByText('0 pt')).toBeInTheDocument();
107
+ });
108
+ });
109
+ });
110
+
111
+ describe('logic', () => {
112
+ describe('changeMaxPoints', () => {
113
+ const testChangeMaxPoints = (maxPoints, excludeZero, expectedPoints, expectedSampleAnswers) => {
114
+ it(`maxPoints=${maxPoints}, excludeZero=${excludeZero} calls onChange correctly`, () => {
115
+ const { onChange, container } = renderComponent({ excludeZero });
116
+
117
+ // Get the component instance through the container
118
+ // We need to call the method directly since we're testing internal behavior
119
+ const instance = container.querySelector('[class*="MuiBox-root"]')?._owner;
120
+
121
+ // Since we can't easily access instance methods in RTL, we'll test the behavior
122
+ // by verifying the onChange prop receives the correct values
123
+ // For now, we'll directly test the logic
124
+ const component = new RawAuthoring({
125
+ value: { excludeZero, points, sampleAnswers },
126
+ onChange,
127
+ classes: {},
128
+ className: 'className',
129
+ });
130
+
131
+ component.changeMaxPoints(maxPoints);
132
+
133
+ expect(onChange).toHaveBeenCalledWith({
134
+ excludeZero,
135
+ points: expectedPoints,
136
+ sampleAnswers: expectedSampleAnswers,
137
+ maxPoints: expectedPoints.length - 1,
138
+ });
139
+ });
140
+ };
141
+
142
+ testChangeMaxPoints(1, false, takeRight(points, 2), takeRight(sampleAnswers, 2));
143
+ testChangeMaxPoints(1, true, takeRight(points, 2), takeRight(sampleAnswers, 2));
144
+ testChangeMaxPoints(2, true, takeRight(points, 3), takeRight(sampleAnswers, 3));
145
+ testChangeMaxPoints(2, false, takeRight(points, 3), takeRight(sampleAnswers, 3));
146
+ testChangeMaxPoints(5, false, ['', ''].concat(points), [null, null].concat(sampleAnswers));
147
+ });
148
+
149
+ describe('changeSampleResponse', () => {
150
+ const testChangeSampleResponse = (index, clickedItem, excludeZero, expectedPoints, expectedSampleAnswers) => {
151
+ it(`Point ${index} with clickedItem="${clickedItem}" calls onChange correctly`, () => {
152
+ const { onChange } = renderComponent({ excludeZero });
153
+
154
+ // Test the logic by creating a component instance and calling the method
155
+ const component = new RawAuthoring({
156
+ value: { excludeZero, points, sampleAnswers },
157
+ onChange,
158
+ classes: {},
159
+ className: 'className',
160
+ });
161
+
162
+ component.onPointMenuChange(index, clickedItem);
163
+
164
+ expect(onChange).toHaveBeenCalledWith({
165
+ excludeZero,
166
+ points: expectedPoints,
167
+ sampleAnswers: expectedSampleAnswers,
168
+ });
169
+ });
170
+ };
171
+
172
+ testChangeSampleResponse(0, 'sample', false, points, ['', 'just right', 'not left', null]);
173
+ testChangeSampleResponse(3, 'sample', false, points, [null, 'just right', 'not left', '']);
174
+ testChangeSampleResponse(1, 'sample', true, points, [null, null, 'not left', null]);
175
+ testChangeSampleResponse(3, 'sample', true, points, [null, 'just right', 'not left', '']);
176
+ });
177
+ });
178
+
179
+ describe('user interactions', () => {
180
+ it('calls onChange when excluding zeros checkbox is toggled', () => {
181
+ const { onChange } = renderComponent({ excludeZero: false });
182
+
183
+ const checkbox = screen.getByLabelText('Exclude zeros');
184
+ fireEvent.click(checkbox);
185
+
186
+ expect(onChange).toHaveBeenCalledWith(
187
+ expect.objectContaining({
188
+ excludeZero: true,
189
+ }),
190
+ );
191
+ });
192
+
193
+ it('calls onChange when max points is changed', () => {
194
+ const { onChange } = renderComponent();
195
+
196
+ const selectInput = screen.getByLabelText('Max Points');
197
+ fireEvent.mouseDown(selectInput);
198
+
199
+ // The onChange should be called when a new value is selected
200
+ // This tests the changeMaxPoints logic indirectly
201
+ });
202
+
203
+ it('renders correct number of points based on excludeZero', () => {
204
+ const { rerender } = renderComponent({ excludeZero: false });
205
+ expect(screen.getByText('0 pt')).toBeInTheDocument();
206
+
207
+ // Rerender with excludeZero true
208
+ rerender(
209
+ <ThemeProvider theme={theme}>
210
+ <RawAuthoring
211
+ classes={{}}
212
+ onChange={jest.fn()}
213
+ className="className"
214
+ value={{ excludeZero: true, points, sampleAnswers }}
215
+ />
216
+ </ThemeProvider>,
217
+ );
218
+
219
+ expect(screen.queryByText('0 pt')).not.toBeInTheDocument();
220
+ });
221
+ });
222
+
223
+ describe('drag and drop', () => {
224
+ it('calls onChange with reordered points after drag end', () => {
225
+ const { onChange } = renderComponent();
226
+
227
+ const component = new RawAuthoring({
228
+ value: { excludeZero: false, points, sampleAnswers },
229
+ onChange,
230
+ classes: {},
231
+ className: 'className',
232
+ });
233
+
234
+ // Simulate drag from index 0 to index 2
235
+ component.dragEnd({
236
+ source: { index: 0 },
237
+ destination: { index: 2 },
238
+ });
239
+
240
+ expect(onChange).toHaveBeenCalled();
241
+ const result = onChange.mock.calls[0][0];
242
+ expect(result.points).not.toEqual(points);
243
+ expect(result.points.length).toBe(points.length);
244
+ });
245
+
246
+ it('does nothing when drag has no destination', () => {
247
+ const { onChange } = renderComponent();
248
+
249
+ const component = new RawAuthoring({
250
+ value: { excludeZero: false, points, sampleAnswers },
251
+ onChange,
252
+ classes: {},
253
+ className: 'className',
254
+ });
255
+
256
+ // Simulate drag without destination
257
+ component.dragEnd({
258
+ source: { index: 0 },
259
+ destination: null,
260
+ });
261
+
262
+ expect(onChange).not.toHaveBeenCalled();
263
+ });
264
+ });
265
+
266
+ describe('content editing', () => {
267
+ it('calls onChange when point content is changed', () => {
268
+ const { onChange } = renderComponent();
269
+
270
+ const component = new RawAuthoring({
271
+ value: { excludeZero: false, points, sampleAnswers },
272
+ onChange,
273
+ classes: {},
274
+ className: 'className',
275
+ });
276
+
277
+ component.changeContent(0, 'new content', 'points');
278
+
279
+ expect(onChange).toHaveBeenCalledWith(
280
+ expect.objectContaining({
281
+ points: expect.arrayContaining(['new content']),
282
+ }),
283
+ );
284
+ });
285
+
286
+ it('calls onChange when sample answer is changed', () => {
287
+ const { onChange } = renderComponent();
288
+
289
+ const component = new RawAuthoring({
290
+ value: { excludeZero: false, points, sampleAnswers },
291
+ onChange,
292
+ classes: {},
293
+ className: 'className',
294
+ });
295
+
296
+ component.changeContent(1, 'new sample answer', 'sampleAnswers');
297
+
298
+ expect(onChange).toHaveBeenCalledWith(
299
+ expect.objectContaining({
300
+ sampleAnswers: expect.arrayContaining(['new sample answer']),
301
+ }),
302
+ );
303
+ });
304
+
305
+ it('does not change content for invalid type', () => {
306
+ const { onChange } = renderComponent();
307
+
308
+ const component = new RawAuthoring({
309
+ value: { excludeZero: false, points, sampleAnswers },
310
+ onChange,
311
+ classes: {},
312
+ className: 'className',
313
+ });
314
+
315
+ component.changeContent(0, 'new content', 'invalidType');
316
+
317
+ expect(onChange).not.toHaveBeenCalled();
318
+ });
319
+ });
320
+
321
+ describe('rubricless mode', () => {
322
+ it('calls onChange when rubricless instruction is changed', () => {
323
+ const { onChange } = renderComponent({ rubriclessInstruction: '' }, { rubricless: true });
324
+
325
+ const component = new RawAuthoring({
326
+ value: { excludeZero: false, points, sampleAnswers, rubriclessInstruction: '' },
327
+ onChange,
328
+ classes: {},
329
+ className: 'className',
330
+ rubricless: true,
331
+ });
332
+
333
+ component.changeRubriclessInstruction('New instruction');
334
+
335
+ expect(onChange).toHaveBeenCalledWith(
336
+ expect.objectContaining({
337
+ rubriclessInstruction: 'New instruction',
338
+ }),
339
+ );
340
+ });
341
+ });
342
+
343
+ describe('edge cases', () => {
344
+ it('handles empty points array', () => {
345
+ const { container } = renderComponent({ points: [], sampleAnswers: [] });
346
+ expect(container).toBeInTheDocument();
347
+ });
348
+
349
+ it('handles maxPoints greater than current max', () => {
350
+ const { onChange } = renderComponent();
351
+
352
+ const component = new RawAuthoring({
353
+ value: { excludeZero: false, points, sampleAnswers },
354
+ onChange,
355
+ classes: {},
356
+ className: 'className',
357
+ });
358
+
359
+ component.changeMaxPoints(10);
360
+
361
+ expect(onChange).toHaveBeenCalled();
362
+ const result = onChange.mock.calls[0][0];
363
+ expect(result.points.length).toBe(11); // 10 + 1 for 0 points
364
+ });
365
+
366
+ it('handles config and pluginOpts props', () => {
367
+ const config = { someConfig: true };
368
+ const pluginOpts = { somePlugin: true };
369
+ const { container } = renderComponent({}, { config, pluginOpts });
370
+ expect(container).toBeInTheDocument();
371
+ });
372
+ });
373
+ });