@pie-element/ebsr 6.5.0 → 6.5.1-beta.587

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