@pie-element/ebsr 14.2.2-next.1 → 14.2.2

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 (97) hide show
  1. package/CHANGELOG.json +1547 -0
  2. package/CHANGELOG.md +2291 -0
  3. package/LICENSE.md +5 -0
  4. package/README.md +62 -0
  5. package/configure/CHANGELOG.json +992 -0
  6. package/configure/CHANGELOG.md +2154 -0
  7. package/configure/lib/defaults.js +229 -0
  8. package/configure/lib/defaults.js.map +1 -0
  9. package/configure/lib/index.js +154 -0
  10. package/configure/lib/index.js.map +1 -0
  11. package/configure/lib/main.js +222 -0
  12. package/configure/lib/main.js.map +1 -0
  13. package/configure/package.json +23 -0
  14. package/configure/src/__tests__/index.test.js +492 -0
  15. package/configure/src/defaults.js +173 -0
  16. package/configure/src/index.js +174 -0
  17. package/configure/src/main.jsx +235 -0
  18. package/controller/CHANGELOG.json +552 -0
  19. package/controller/CHANGELOG.md +1286 -0
  20. package/controller/lib/defaults.js +31 -0
  21. package/controller/lib/defaults.js.map +1 -0
  22. package/controller/lib/index.js +448 -0
  23. package/controller/lib/index.js.map +1 -0
  24. package/controller/lib/utils.js +18 -0
  25. package/controller/lib/utils.js.map +1 -0
  26. package/controller/package.json +18 -0
  27. package/controller/src/__tests__/index.test.js +591 -0
  28. package/controller/src/__tests__/utils.test.js +48 -0
  29. package/controller/src/defaults.js +25 -0
  30. package/controller/src/index.js +442 -0
  31. package/controller/src/utils.js +18 -0
  32. package/docs/config-schema.json +5787 -0
  33. package/docs/config-schema.json.md +4278 -0
  34. package/docs/demo/config.js +8 -0
  35. package/docs/demo/generate.js +52 -0
  36. package/docs/demo/index.html +2 -0
  37. package/docs/demo/session.js +14 -0
  38. package/docs/pie-schema.json +2911 -0
  39. package/docs/pie-schema.json.md +2142 -0
  40. package/ebsr.png +0 -0
  41. package/lib/index.js +207 -0
  42. package/lib/index.js.map +1 -0
  43. package/lib/print.js +186 -0
  44. package/lib/print.js.map +1 -0
  45. package/module/configure.js +1 -0
  46. package/module/controller.js +5664 -0
  47. package/module/demo.js +77 -0
  48. package/module/element.js +1 -0
  49. package/module/index.html +21 -0
  50. package/module/manifest.json +14 -0
  51. package/module/print-demo.js +115 -0
  52. package/module/print.html +18 -0
  53. package/module/print.js +1 -0
  54. package/package.json +19 -88
  55. package/src/__tests__/index.test.js +129 -0
  56. package/src/index.js +222 -0
  57. package/src/print.js +207 -0
  58. package/configure.js +0 -2
  59. package/controller.js +0 -1
  60. package/dist/author/defaults.d.ts +0 -348
  61. package/dist/author/defaults.js +0 -161
  62. package/dist/author/index.d.ts +0 -34
  63. package/dist/author/index.js +0 -78
  64. package/dist/author/main.d.ts +0 -22
  65. package/dist/author/main.js +0 -121
  66. package/dist/browser/author/index.js +0 -13940
  67. package/dist/browser/author/index.js.map +0 -1
  68. package/dist/browser/browser-CdX8WGiZ.js +0 -207
  69. package/dist/browser/browser-CdX8WGiZ.js.map +0 -1
  70. package/dist/browser/controller/index.js +0 -257
  71. package/dist/browser/controller/index.js.map +0 -1
  72. package/dist/browser/delivery/index.js +0 -133
  73. package/dist/browser/delivery/index.js.map +0 -1
  74. package/dist/browser/dist-CaWRqnXk.js +0 -62
  75. package/dist/browser/dist-CaWRqnXk.js.map +0 -1
  76. package/dist/browser/dist-D9ARZhQk.js +0 -1426
  77. package/dist/browser/dist-D9ARZhQk.js.map +0 -1
  78. package/dist/browser/dist-DQkngCcw.js +0 -36
  79. package/dist/browser/dist-DQkngCcw.js.map +0 -1
  80. package/dist/browser/print/index.js +0 -107
  81. package/dist/browser/print/index.js.map +0 -1
  82. package/dist/controller/defaults.d.ts +0 -15
  83. package/dist/controller/defaults.js +0 -26
  84. package/dist/controller/index.d.ts +0 -42
  85. package/dist/controller/index.js +0 -185
  86. package/dist/controller/utils.d.ts +0 -10
  87. package/dist/controller/utils.js +0 -8
  88. package/dist/delivery/index.d.ts +0 -26
  89. package/dist/delivery/index.js +0 -132
  90. package/dist/index.d.ts +0 -1
  91. package/dist/index.iife.d.ts +0 -8
  92. package/dist/index.iife.js +0 -165
  93. package/dist/index.js +0 -2
  94. package/dist/print/index.d.ts +0 -25
  95. package/dist/print/index.js +0 -106
  96. package/dist/runtime-support.d.ts +0 -12
  97. package/dist/runtime-support.js +0 -12
@@ -0,0 +1,591 @@
1
+ import { model, outcome, createCorrectResponseSession } from '../index';
2
+ import { isResponseCorrect } from '../utils';
3
+
4
+ const PART_A = 'partA';
5
+ const PART_B = 'partB';
6
+
7
+ jest.mock('../utils', () => ({
8
+ isResponseCorrect: jest.fn(),
9
+ }));
10
+
11
+ describe('controller', () => {
12
+ let result, question, session, env;
13
+
14
+ beforeEach(() => {
15
+ question = {
16
+ partA: {
17
+ choiceMode: 'checkbox',
18
+ feedbackEnabled: true,
19
+ choices: [
20
+ {
21
+ value: 'yellow',
22
+ label: 'Yellow',
23
+ correct: true,
24
+ feedback: {
25
+ type: 'custom',
26
+ value: 'foo',
27
+ },
28
+ },
29
+ {
30
+ value: 'green',
31
+ label: 'Green',
32
+ feedback: {
33
+ type: 'default',
34
+ },
35
+ },
36
+ ],
37
+ choicePrefix: 'numbers',
38
+ prompt: `prompt ${PART_A}`,
39
+ promptEnabled: true,
40
+ lockChoiceOrder: true,
41
+ partialScoring: false,
42
+ },
43
+ partB: {
44
+ choiceMode: 'checkbox',
45
+ feedbackEnabled: true,
46
+ choices: [
47
+ {
48
+ value: 'orange',
49
+ label: 'Orange',
50
+ correct: true,
51
+ feedback: {
52
+ type: 'custom',
53
+ value: 'foo',
54
+ },
55
+ },
56
+ {
57
+ value: 'purple',
58
+ label: 'Purple',
59
+ feedback: {
60
+ type: 'default',
61
+ },
62
+ },
63
+ {
64
+ value: 'c',
65
+ correct: true,
66
+ },
67
+ ],
68
+ choicePrefix: 'numbers',
69
+ prompt: `prompt ${PART_B}`,
70
+ promptEnabled: true,
71
+ lockChoiceOrder: true,
72
+ partialScoring: false,
73
+ },
74
+ };
75
+ });
76
+
77
+ describe('outcome partialScoring test', () => {
78
+ const mkQuestion = (extra) => ({
79
+ partA: {
80
+ choiceMode: 'radio',
81
+ feedbackEnabled: true,
82
+ choices: [
83
+ {
84
+ value: 'yellow',
85
+ label: 'Yellow',
86
+ correct: true,
87
+ feedback: {
88
+ type: 'custom',
89
+ value: 'foo',
90
+ },
91
+ },
92
+ {
93
+ value: 'blue',
94
+ label: 'Blue',
95
+ correct: true,
96
+ feedback: {
97
+ type: 'custom',
98
+ value: 'foo',
99
+ },
100
+ },
101
+ {
102
+ value: 'green',
103
+ label: 'Green',
104
+ feedback: {
105
+ type: 'default',
106
+ },
107
+ },
108
+ ],
109
+ choicePrefix: 'numbers',
110
+ prompt: `prompt ${PART_A}`,
111
+ promptEnabled: true,
112
+ lockChoiceOrder: true,
113
+ },
114
+ partB: {
115
+ choiceMode: 'radio',
116
+ feedbackEnabled: true,
117
+ choices: [
118
+ {
119
+ value: 'orange',
120
+ label: 'Orange',
121
+ correct: true,
122
+ feedback: {
123
+ type: 'custom',
124
+ value: 'foo',
125
+ },
126
+ },
127
+ {
128
+ value: 'red',
129
+ label: 'Red',
130
+ correct: true,
131
+ feedback: {
132
+ type: 'custom',
133
+ value: 'foo',
134
+ },
135
+ },
136
+ {
137
+ value: 'purple',
138
+ label: 'Purple',
139
+ feedback: {
140
+ type: 'default',
141
+ },
142
+ },
143
+ ],
144
+ choicePrefix: 'numbers',
145
+ prompt: `prompt ${PART_B}`,
146
+ promptEnabled: true,
147
+ lockChoiceOrder: true,
148
+ },
149
+ partialScoring: false,
150
+ ...extra,
151
+ });
152
+
153
+ const assertOutcome = (message, extra, value1, value2, env, expected, expectedMax) => {
154
+ it(message, async () => {
155
+ const question = mkQuestion(extra);
156
+ const result = await outcome(question, { value: { partA: { value: value1 }, partB: { value: value2 } } }, env);
157
+ expect(result.score).toEqual(expected);
158
+ expect(result.max).toEqual(expectedMax);
159
+ });
160
+ };
161
+
162
+ assertOutcome(
163
+ 'element.partialScoring = true, partA correct, partB correct',
164
+ { partialScoring: true },
165
+ ['yellow', 'blue'],
166
+ ['orange', 'red'],
167
+ { mode: 'evaluate' },
168
+ 2,
169
+ 2,
170
+ );
171
+
172
+ assertOutcome(
173
+ 'element.partialScoring = true, partA correct, partB partially correct',
174
+ { partialScoring: true },
175
+ ['yellow', 'blue'],
176
+ ['orange'],
177
+ { mode: 'evaluate' },
178
+ 1,
179
+ 2,
180
+ );
181
+
182
+ assertOutcome(
183
+ 'element.partialScoring = true, partA correct, partB incorrect',
184
+ { partialScoring: true },
185
+ ['yellow', 'blue'],
186
+ [],
187
+ { mode: 'evaluate' },
188
+ 1,
189
+ 2,
190
+ );
191
+
192
+ assertOutcome(
193
+ 'element.partialScoring = true, partA incorrect, partB correct',
194
+ { partialScoring: true },
195
+ [],
196
+ ['orange', 'red'],
197
+ { mode: 'evaluate' },
198
+ 0,
199
+ 2,
200
+ );
201
+
202
+ assertOutcome(
203
+ 'element.partialScoring = true, partA partially correct, partB partially correct',
204
+ { partialScoring: true },
205
+ ['yellow'],
206
+ ['orange'],
207
+ { mode: 'evaluate' },
208
+ 0,
209
+ 2,
210
+ );
211
+
212
+ assertOutcome(
213
+ 'element.partialScoring = true, partA incorrect, partB partially correct',
214
+ { partialScoring: true },
215
+ ['yellow'],
216
+ ['orange'],
217
+ { mode: 'evaluate' },
218
+ 0,
219
+ 2,
220
+ );
221
+
222
+ assertOutcome(
223
+ 'element.partialScoring = true, partA incorrect, partB incorrect',
224
+ { partialScoring: true },
225
+ ['yellow'],
226
+ ['orange'],
227
+ { mode: 'evaluate' },
228
+ 0,
229
+ 2,
230
+ );
231
+
232
+ assertOutcome(
233
+ 'element.partialScoring = false, partA correct, partB correct',
234
+ { partialScoring: false },
235
+ ['yellow', 'blue'],
236
+ ['orange', 'red'],
237
+ { mode: 'evaluate' },
238
+ 1,
239
+ 1,
240
+ );
241
+
242
+ assertOutcome(
243
+ 'element.partialScoring = false, partA incorrect, partB correct',
244
+ { partialScoring: false },
245
+ ['yellow'],
246
+ ['orange', 'red'],
247
+ { mode: 'evaluate' },
248
+ 0,
249
+ 1,
250
+ );
251
+
252
+ assertOutcome(
253
+ 'element.partialScoring = false, partA correct, partB incorrect',
254
+ { partialScoring: false },
255
+ ['yellow', 'blue'],
256
+ ['orange'],
257
+ { mode: 'evaluate' },
258
+ 0,
259
+ 1,
260
+ );
261
+
262
+ assertOutcome(
263
+ 'element.partialScoring = false, partA incorrect, partB incorrect',
264
+ { partialScoring: false },
265
+ [],
266
+ [],
267
+ { mode: 'evaluate' },
268
+ 0,
269
+ 1,
270
+ );
271
+ });
272
+
273
+ describe('outcome', () => {
274
+ describe('dichotomous', () => {
275
+ const returnsScoreOf = (message, values1, values2, score) => {
276
+ it(`${message} => ${score}`, async () => {
277
+ const result = await outcome(
278
+ { ...question, partialScoring: false },
279
+ { value: { partA: { value: values1 }, partB: { value: values2 } } },
280
+ );
281
+ expect(result.score).toEqual(score);
282
+ expect(result.max).toEqual(1);
283
+ });
284
+ };
285
+
286
+ returnsScoreOf('both correct', ['yellow'], ['orange', 'c'], 1); // both correct
287
+ returnsScoreOf('both incorrect', ['green'], ['purple'], 0); // both wrong
288
+ returnsScoreOf('partA incorrect, partB correct', ['green'], ['orange', 'c'], 0); // first wrong, second correct
289
+ returnsScoreOf('partA correct, partB incorrect', ['yellow'], ['purple'], 0); // first correct, second wrong
290
+ });
291
+
292
+ describe('partial scoring', () => {
293
+ const returnsScoreOf = (message, values1, values2, score) => {
294
+ it(`${message} => ${score}`, async () => {
295
+ const result = await outcome(
296
+ { ...question, partialScoring: true },
297
+ { value: { partA: { value: values1 }, partB: { value: values2 } } },
298
+ );
299
+ expect(result.score).toBeCloseTo(score);
300
+ expect(result.max).toEqual(2);
301
+ });
302
+ };
303
+
304
+ returnsScoreOf('both correct', ['yellow'], ['orange', 'c'], 2);
305
+ returnsScoreOf('both incorrect', [], [], 0);
306
+ returnsScoreOf('partA correct, partB incorrect', ['yellow'], [], 1);
307
+ returnsScoreOf('partA correct, partB partially correct', ['yellow'], ['c'], 1);
308
+ returnsScoreOf('partA incorrect, partB correct', ['green'], ['orange', 'c'], 0);
309
+ returnsScoreOf('partA partially correct, partB correct', ['green', 'yellow'], ['orange', 'c'], 0);
310
+ });
311
+
312
+ const returnsScoreWhen = (session) => {
313
+ it(`returns empty: true if session is ${JSON.stringify(session)}`, async () => {
314
+ const result = await outcome(question, session);
315
+ expect(result).toEqual({ score: 0, scoreA: 0, scoreB: 0, empty: true, logTrace: ['Student did not answer the question.'] });
316
+ });
317
+ };
318
+
319
+ returnsScoreWhen(undefined);
320
+ returnsScoreWhen(null);
321
+ returnsScoreWhen({});
322
+ });
323
+
324
+ describe('model', () => {
325
+ const capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1);
326
+
327
+ describe('mode: gather', () => {
328
+ beforeEach(async () => {
329
+ session = {};
330
+ env = { mode: 'gather' };
331
+ result = await model(question, session, env);
332
+ });
333
+
334
+ it('returns disabled', () => {
335
+ expect(result.disabled).toEqual(false);
336
+ });
337
+
338
+ it('returns mode', () => {
339
+ expect(result.mode).toEqual('gather');
340
+ });
341
+
342
+ const returnsPrompt = (part) => {
343
+ it(`returns ${part} prompt`, () => {
344
+ expect(result[part].prompt).toEqual(`prompt ${part}`);
345
+ });
346
+ };
347
+
348
+ const returnsChoiceMode = (part) => {
349
+ it(`returns ${part} choiceMode`, () => {
350
+ expect(result[part].choiceMode).toEqual('checkbox');
351
+ });
352
+ };
353
+
354
+ const returnsKeyMode = (part) => {
355
+ it(`returns ${part} choicePrefix`, () => {
356
+ expect(result[part].choicePrefix).toEqual('numbers');
357
+ });
358
+ };
359
+
360
+ const returnsComplete = (part, min) => {
361
+ it(`returns ${part} complete`, () => {
362
+ expect(result[part].complete).toEqual({ min });
363
+ });
364
+ };
365
+
366
+ const doesNotReturnCorrect = (part) => {
367
+ it(`does not return ${part} responseCorrect`, () => {
368
+ expect(result[part].responseCorrect).toBe(undefined);
369
+ });
370
+ };
371
+
372
+ const returnsChoices = (part, value1, value2) => {
373
+ it(`returns ${part} choices`, () => {
374
+ expect(result[part].choices).toEqual(
375
+ expect.arrayContaining([
376
+ { value: value1, label: capitalize(value1), rationale: null },
377
+ { value: value2, label: capitalize(value2), rationale: null },
378
+ ]),
379
+ );
380
+ });
381
+ };
382
+
383
+ returnsPrompt(PART_A);
384
+ returnsPrompt(PART_B);
385
+
386
+ returnsChoiceMode(PART_A);
387
+ returnsChoiceMode(PART_B);
388
+
389
+ returnsKeyMode(PART_A);
390
+ returnsKeyMode(PART_B);
391
+
392
+ returnsComplete(PART_A, 1);
393
+ returnsComplete(PART_B, 2);
394
+
395
+ returnsChoices(PART_A, 'yellow', 'green');
396
+ returnsChoices(PART_B, 'orange', 'purple');
397
+
398
+ doesNotReturnCorrect(PART_A);
399
+ doesNotReturnCorrect(PART_B);
400
+ });
401
+
402
+ describe('model - with updateSession', () => {
403
+ it('calls updateSession', async () => {
404
+ session = { id: '1', element: 'ebsr-element' };
405
+ env = { mode: 'gather' };
406
+ const updateSession = jest.fn().mockResolvedValue();
407
+ await model(
408
+ {
409
+ ...question,
410
+ partA: {
411
+ ...question.partA,
412
+ lockChoiceOrder: false,
413
+ },
414
+ partB: {
415
+ ...question.partB,
416
+ lockChoiceOrder: false,
417
+ },
418
+ },
419
+ session,
420
+ env,
421
+ updateSession,
422
+ );
423
+ expect(updateSession).toHaveBeenCalledWith('1', 'ebsr-element', {
424
+ shuffledValues: {
425
+ partA: expect.arrayContaining(['yellow', 'green']),
426
+ partB: expect.arrayContaining(['orange', 'purple']),
427
+ },
428
+ });
429
+ });
430
+ });
431
+
432
+ describe('model - without valid updateSession', () => {
433
+ const assertModel = (updateSession) => {
434
+ it(`does not throw error if updateSession is ${updateSession}`, async () => {
435
+ session = {
436
+ id: '1',
437
+ element: 'ebsr-element',
438
+ shuffledValues: { partA: [], partB: [] },
439
+ };
440
+ env = { mode: 'gather' };
441
+
442
+ await model(
443
+ {
444
+ ...question,
445
+ partA: {
446
+ ...question.partA,
447
+ lockChoiceOrder: false,
448
+ },
449
+ partB: {
450
+ ...question.partB,
451
+ lockChoiceOrder: false,
452
+ },
453
+ },
454
+ session,
455
+ env,
456
+ );
457
+ });
458
+ };
459
+
460
+ assertModel(undefined);
461
+ assertModel(null);
462
+ assertModel('text');
463
+ });
464
+
465
+ describe('mode: view', () => {
466
+ beforeEach(async () => {
467
+ session = {};
468
+ env = { mode: 'view' };
469
+ result = await model(question, session, env);
470
+ });
471
+
472
+ it('returns disabled', () => {
473
+ expect(result.disabled).toEqual(true);
474
+ });
475
+ });
476
+
477
+ describe('mode: evaluate', () => {
478
+ beforeEach(async () => {
479
+ session = {};
480
+ env = { mode: 'evaluate' };
481
+ isResponseCorrect.mockReturnValue(false);
482
+ result = await model(question, session, env);
483
+ return result;
484
+ });
485
+
486
+ const returnsChoicesWCorrect = (part, value1, value2) => {
487
+ it(`returns ${part} choices w/ correct`, () => {
488
+ expect(result[part].choices).toEqual(
489
+ expect.arrayContaining([
490
+ {
491
+ value: value1,
492
+ label: capitalize(value1),
493
+ correct: true,
494
+ feedback: 'foo',
495
+ rationale: null,
496
+ },
497
+ {
498
+ value: value2,
499
+ label: capitalize(value2),
500
+ correct: false,
501
+ feedback: 'Incorrect',
502
+ rationale: null,
503
+ },
504
+ ]),
505
+ );
506
+ });
507
+ };
508
+
509
+ const returnsChoicesWCorrectFeedbackDisabled = (part, value1, value2) => {
510
+ // feedback enabled for partB and disabled for partA
511
+ it(`returns ${part} choices w/ correct even if feedbackEnabled is false`, async () => {
512
+ let res = await model(
513
+ {
514
+ ...question,
515
+ partA: {
516
+ ...question.partA,
517
+ feedbackEnabled: false,
518
+ },
519
+ partB: {
520
+ ...question.partB,
521
+ feedbackEnabled: false,
522
+ },
523
+ },
524
+ session,
525
+ env,
526
+ );
527
+
528
+ expect(result[part].choices).toEqual(
529
+ expect.arrayContaining([
530
+ {
531
+ value: value1,
532
+ label: capitalize(value1),
533
+ correct: true,
534
+ feedback: 'foo',
535
+ rationale: null,
536
+ },
537
+ {
538
+ value: value2,
539
+ label: capitalize(value2),
540
+ correct: false,
541
+ feedback: 'Incorrect',
542
+ rationale: null,
543
+ },
544
+ ]),
545
+ );
546
+ });
547
+ };
548
+
549
+ const returnsIsResponseCorrect = (part) => {
550
+ it(`returns ${part} is response correct`, () => {
551
+ expect(result[part].responseCorrect).toEqual(false);
552
+ });
553
+ };
554
+
555
+ // Second param will be correct (yellow for A; orange for B)
556
+ returnsChoicesWCorrect(PART_A, 'yellow', 'green');
557
+ returnsChoicesWCorrect(PART_B, 'orange', 'purple');
558
+
559
+ // Second param will be correct (yellow for A; orange for B)
560
+ returnsChoicesWCorrectFeedbackDisabled(PART_A, 'yellow', 'green');
561
+ returnsChoicesWCorrectFeedbackDisabled(PART_B, 'orange', 'purple');
562
+
563
+ returnsIsResponseCorrect(PART_A);
564
+ returnsIsResponseCorrect(PART_B);
565
+ });
566
+
567
+ describe('correct response', () => {
568
+ it('returns correct response if env is correct', async () => {
569
+ const sess = await createCorrectResponseSession(question, {
570
+ mode: 'gather',
571
+ role: 'instructor',
572
+ });
573
+ expect(sess).toEqual({
574
+ id: '1',
575
+ value: {
576
+ partA: { id: 'partA', value: ['yellow'] },
577
+ partB: { id: 'partB', value: ['orange', 'c'] },
578
+ },
579
+ });
580
+ });
581
+
582
+ it('returns null env is student', async () => {
583
+ const noResult = await createCorrectResponseSession(question, {
584
+ mode: 'gather',
585
+ role: 'student',
586
+ });
587
+ expect(noResult).toBeNull();
588
+ });
589
+ });
590
+ });
591
+ });
@@ -0,0 +1,48 @@
1
+ import { isResponseCorrect } from '../utils';
2
+
3
+ describe('isResponseCorrect', () => {
4
+ let question;
5
+
6
+ beforeEach(() => {
7
+ question = {
8
+ partA: {
9
+ choiceMode: 'radio',
10
+ feedbackEnabled: true,
11
+ choices: [
12
+ {
13
+ value: 'yellow',
14
+ label: 'Yellow',
15
+ correct: true,
16
+ feedback: {
17
+ type: 'custom',
18
+ value: 'foo',
19
+ },
20
+ },
21
+ {
22
+ value: 'green',
23
+ label: 'Green',
24
+ feedback: {
25
+ type: 'default',
26
+ },
27
+ },
28
+ ],
29
+ choicePrefix: 'numbers',
30
+ prompt: `prompt partA`,
31
+ },
32
+ };
33
+ });
34
+
35
+ const returnsIsResponseCorrect = (session) => {
36
+ it(`response is not correct if session is ${JSON.stringify(session)}`, () => {
37
+ expect(isResponseCorrect(question.partA, 'partA', session)).toEqual(false);
38
+ });
39
+ };
40
+
41
+ returnsIsResponseCorrect(undefined);
42
+ returnsIsResponseCorrect(null);
43
+ returnsIsResponseCorrect({});
44
+
45
+ it('response is correct if session is defined', () => {
46
+ expect(isResponseCorrect(question.partA, 'partA', { value: { partA: { value: ['yellow'] } } })).toEqual(true);
47
+ });
48
+ });
@@ -0,0 +1,25 @@
1
+ const partModel = (base) => ({
2
+ choiceMode: 'radio',
3
+ choicePrefix: 'letters',
4
+ choices: [],
5
+ choicesLayout: 'vertical',
6
+ feedbackEnabled: false,
7
+ gridColumns: 2,
8
+ prompt: '',
9
+ promptEnabled: true,
10
+ rationale: '',
11
+ rationaleEnabled: true,
12
+ spellCheckEnabled: true,
13
+ studentInstructionsEnabled: true,
14
+ teacherInstructions: '',
15
+ teacherInstructionsEnabled: true,
16
+ toolbarEditorPosition: 'bottom',
17
+ ...base,
18
+ });
19
+
20
+ export default {
21
+ partLabels: true,
22
+ partLabelType: 'Letters',
23
+ partA: partModel(),
24
+ partB: partModel(),
25
+ };