@vived/app 6.6.0 → 6.7.1

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 (176) hide show
  1. package/dist/cjs/BaseApp/UC/RenderCanvasUC.js +17 -36
  2. package/dist/cjs/BaseApp/UC/RenderCanvasUC.js.map +1 -1
  3. package/dist/cjs/BaseApp/UC/RenderCanvasUC.test.js +18 -18
  4. package/dist/cjs/BaseApp/UC/RenderCanvasUC.test.js.map +1 -1
  5. package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.js +9 -28
  6. package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.js.map +1 -1
  7. package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.test.js +51 -0
  8. package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.test.js.map +1 -0
  9. package/dist/cjs/EventSystem/Entities/EventEntity.js +12 -2
  10. package/dist/cjs/EventSystem/Entities/EventEntity.js.map +1 -1
  11. package/dist/cjs/EventSystem/Entities/EventEntity.test.js +45 -0
  12. package/dist/cjs/EventSystem/Entities/EventEntity.test.js.map +1 -1
  13. package/dist/cjs/EventSystem/Mocks/MockEventEntity.js +7 -2
  14. package/dist/cjs/EventSystem/Mocks/MockEventEntity.js.map +1 -1
  15. package/dist/cjs/EventSystem/types.js.map +1 -1
  16. package/dist/cjs/ObjectPick/Factories/setupObjectPick.js +18 -1
  17. package/dist/cjs/ObjectPick/Factories/setupObjectPick.js.map +1 -1
  18. package/dist/cjs/ObjectPick/Factories/setupObjectPick.test.js +55 -0
  19. package/dist/cjs/ObjectPick/Factories/setupObjectPick.test.js.map +1 -0
  20. package/dist/cjs/Procedure/Adapters/procedureAdapter.js +1 -0
  21. package/dist/cjs/Procedure/Adapters/procedureAdapter.js.map +1 -1
  22. package/dist/cjs/Procedure/Adapters/procedureAdapter.test.js +1 -0
  23. package/dist/cjs/Procedure/Adapters/procedureAdapter.test.js.map +1 -1
  24. package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.js +2 -0
  25. package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.js.map +1 -1
  26. package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.test.js +3 -0
  27. package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.test.js.map +1 -1
  28. package/dist/cjs/Procedure/Adapters/procedureHintAdapter.test.js +1 -0
  29. package/dist/cjs/Procedure/Adapters/procedureHintAdapter.test.js.map +1 -1
  30. package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.js +2 -0
  31. package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.js.map +1 -1
  32. package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.test.js +3 -0
  33. package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.test.js.map +1 -1
  34. package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.js +2 -0
  35. package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.js.map +1 -1
  36. package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.test.js +3 -0
  37. package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.test.js.map +1 -1
  38. package/dist/cjs/Procedure/Entities/ProcedureEntity.js +163 -24
  39. package/dist/cjs/Procedure/Entities/ProcedureEntity.js.map +1 -1
  40. package/dist/cjs/Procedure/Entities/ProcedureEntity.test.js +240 -0
  41. package/dist/cjs/Procedure/Entities/ProcedureEntity.test.js.map +1 -1
  42. package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.js +20 -0
  43. package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.js.map +1 -1
  44. package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.test.js +25 -0
  45. package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.test.js.map +1 -1
  46. package/dist/cjs/Procedure/Mocks/MockProcedureEntity.js +2 -0
  47. package/dist/cjs/Procedure/Mocks/MockProcedureEntity.js.map +1 -1
  48. package/dist/cjs/Procedure/PM/ProcedurePM.js +13 -1
  49. package/dist/cjs/Procedure/PM/ProcedurePM.js.map +1 -1
  50. package/dist/cjs/Procedure/PM/ProcedurePM.test.js +34 -0
  51. package/dist/cjs/Procedure/PM/ProcedurePM.test.js.map +1 -1
  52. package/dist/cjs/Procedure/UCs/UpdateProcedureEventsUCHook.test.js +3 -0
  53. package/dist/cjs/Procedure/UCs/UpdateProcedureEventsUCHook.test.js.map +1 -1
  54. package/dist/cjs/Procedure/types.js.map +1 -1
  55. package/dist/cjs/TouchController/UC/UpdateTouchInoutBound.test.js +37 -0
  56. package/dist/cjs/TouchController/UC/UpdateTouchInoutBound.test.js.map +1 -1
  57. package/dist/cjs/TouchController/UC/UpdateTouchInputBound.js +17 -4
  58. package/dist/cjs/TouchController/UC/UpdateTouchInputBound.js.map +1 -1
  59. package/dist/esm/BaseApp/UC/RenderCanvasUC.js +17 -36
  60. package/dist/esm/BaseApp/UC/RenderCanvasUC.js.map +1 -1
  61. package/dist/esm/BaseApp/UC/RenderCanvasUC.test.js +18 -18
  62. package/dist/esm/BaseApp/UC/RenderCanvasUC.test.js.map +1 -1
  63. package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.js +9 -28
  64. package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.js.map +1 -1
  65. package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.test.js +49 -0
  66. package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.test.js.map +1 -0
  67. package/dist/esm/EventSystem/Entities/EventEntity.js +12 -2
  68. package/dist/esm/EventSystem/Entities/EventEntity.js.map +1 -1
  69. package/dist/esm/EventSystem/Entities/EventEntity.test.js +45 -0
  70. package/dist/esm/EventSystem/Entities/EventEntity.test.js.map +1 -1
  71. package/dist/esm/EventSystem/Mocks/MockEventEntity.js +7 -2
  72. package/dist/esm/EventSystem/Mocks/MockEventEntity.js.map +1 -1
  73. package/dist/esm/EventSystem/types.js.map +1 -1
  74. package/dist/esm/ObjectPick/Factories/setupObjectPick.js +18 -1
  75. package/dist/esm/ObjectPick/Factories/setupObjectPick.js.map +1 -1
  76. package/dist/esm/ObjectPick/Factories/setupObjectPick.test.js +53 -0
  77. package/dist/esm/ObjectPick/Factories/setupObjectPick.test.js.map +1 -0
  78. package/dist/esm/Procedure/Adapters/procedureAdapter.js +1 -0
  79. package/dist/esm/Procedure/Adapters/procedureAdapter.js.map +1 -1
  80. package/dist/esm/Procedure/Adapters/procedureAdapter.test.js +1 -0
  81. package/dist/esm/Procedure/Adapters/procedureAdapter.test.js.map +1 -1
  82. package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.js +2 -0
  83. package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.js.map +1 -1
  84. package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.test.js +3 -0
  85. package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.test.js.map +1 -1
  86. package/dist/esm/Procedure/Adapters/procedureHintAdapter.test.js +1 -0
  87. package/dist/esm/Procedure/Adapters/procedureHintAdapter.test.js.map +1 -1
  88. package/dist/esm/Procedure/Adapters/procedureProgressAdapter.js +2 -0
  89. package/dist/esm/Procedure/Adapters/procedureProgressAdapter.js.map +1 -1
  90. package/dist/esm/Procedure/Adapters/procedureProgressAdapter.test.js +3 -0
  91. package/dist/esm/Procedure/Adapters/procedureProgressAdapter.test.js.map +1 -1
  92. package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.js +2 -0
  93. package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.js.map +1 -1
  94. package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.test.js +3 -0
  95. package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.test.js.map +1 -1
  96. package/dist/esm/Procedure/Entities/ProcedureEntity.js +163 -24
  97. package/dist/esm/Procedure/Entities/ProcedureEntity.js.map +1 -1
  98. package/dist/esm/Procedure/Entities/ProcedureEntity.test.js +240 -0
  99. package/dist/esm/Procedure/Entities/ProcedureEntity.test.js.map +1 -1
  100. package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.js +20 -0
  101. package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.js.map +1 -1
  102. package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.test.js +26 -1
  103. package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.test.js.map +1 -1
  104. package/dist/esm/Procedure/Mocks/MockProcedureEntity.js +2 -0
  105. package/dist/esm/Procedure/Mocks/MockProcedureEntity.js.map +1 -1
  106. package/dist/esm/Procedure/PM/ProcedurePM.js +13 -1
  107. package/dist/esm/Procedure/PM/ProcedurePM.js.map +1 -1
  108. package/dist/esm/Procedure/PM/ProcedurePM.test.js +34 -0
  109. package/dist/esm/Procedure/PM/ProcedurePM.test.js.map +1 -1
  110. package/dist/esm/Procedure/UCs/UpdateProcedureEventsUCHook.test.js +3 -0
  111. package/dist/esm/Procedure/UCs/UpdateProcedureEventsUCHook.test.js.map +1 -1
  112. package/dist/esm/Procedure/types.js.map +1 -1
  113. package/dist/esm/TouchController/UC/UpdateTouchInoutBound.test.js +37 -0
  114. package/dist/esm/TouchController/UC/UpdateTouchInoutBound.test.js.map +1 -1
  115. package/dist/esm/TouchController/UC/UpdateTouchInputBound.js +17 -4
  116. package/dist/esm/TouchController/UC/UpdateTouchInputBound.js.map +1 -1
  117. package/dist/types/Challenge/Factories/ChallengeFeatureFactory.d.ts +7 -16
  118. package/dist/types/Challenge/Factories/ChallengeFeatureFactory.d.ts.map +1 -1
  119. package/dist/types/Challenge/Factories/ChallengeFeatureFactory.test.d.ts +2 -0
  120. package/dist/types/Challenge/Factories/ChallengeFeatureFactory.test.d.ts.map +1 -0
  121. package/dist/types/EventSystem/Entities/EventEntity.d.ts +13 -2
  122. package/dist/types/EventSystem/Entities/EventEntity.d.ts.map +1 -1
  123. package/dist/types/EventSystem/Mocks/MockEventEntity.d.ts +3 -2
  124. package/dist/types/EventSystem/Mocks/MockEventEntity.d.ts.map +1 -1
  125. package/dist/types/EventSystem/types.d.ts +23 -0
  126. package/dist/types/EventSystem/types.d.ts.map +1 -1
  127. package/dist/types/ObjectPick/Factories/setupObjectPick.d.ts +10 -0
  128. package/dist/types/ObjectPick/Factories/setupObjectPick.d.ts.map +1 -1
  129. package/dist/types/ObjectPick/Factories/setupObjectPick.test.d.ts +2 -0
  130. package/dist/types/ObjectPick/Factories/setupObjectPick.test.d.ts.map +1 -0
  131. package/dist/types/Procedure/Adapters/procedureAdapter.d.ts.map +1 -1
  132. package/dist/types/Procedure/Adapters/procedureAuthoringAdapter.d.ts.map +1 -1
  133. package/dist/types/Procedure/Adapters/procedureProgressAdapter.d.ts.map +1 -1
  134. package/dist/types/Procedure/Adapters/procedureQuizResultAdapter.d.ts.map +1 -1
  135. package/dist/types/Procedure/Entities/ProcedureEntity.d.ts +10 -0
  136. package/dist/types/Procedure/Entities/ProcedureEntity.d.ts.map +1 -1
  137. package/dist/types/Procedure/Factories/ProcedureFeatureFactory.d.ts +6 -0
  138. package/dist/types/Procedure/Factories/ProcedureFeatureFactory.d.ts.map +1 -1
  139. package/dist/types/Procedure/Mocks/MockProcedureEntity.d.ts +3 -0
  140. package/dist/types/Procedure/Mocks/MockProcedureEntity.d.ts.map +1 -1
  141. package/dist/types/Procedure/types.d.ts +17 -1
  142. package/dist/types/Procedure/types.d.ts.map +1 -1
  143. package/dist/types/TouchController/UC/UpdateTouchInputBound.d.ts +11 -0
  144. package/dist/types/TouchController/UC/UpdateTouchInputBound.d.ts.map +1 -1
  145. package/package.json +6 -3
  146. package/src/EventSystem/CONTEXT.md +29 -17
  147. package/dist/cjs/FramedScreen/Factories/setupStandardFramedScreen.test.js +0 -31
  148. package/dist/cjs/FramedScreen/Factories/setupStandardFramedScreen.test.js.map +0 -1
  149. package/dist/cjs/StateMachine/Controller/clickRestoreScene.js +0 -14
  150. package/dist/cjs/StateMachine/Controller/clickRestoreScene.js.map +0 -1
  151. package/dist/cjs/StateMachine/Controller/clickRestoreScene.test.js +0 -26
  152. package/dist/cjs/StateMachine/Controller/clickRestoreScene.test.js.map +0 -1
  153. package/dist/cjs/TestUtils/index.js +0 -18
  154. package/dist/cjs/TestUtils/index.js.map +0 -1
  155. package/dist/cjs/TestUtils/setupFeatureForTesting.js +0 -60
  156. package/dist/cjs/TestUtils/setupFeatureForTesting.js.map +0 -1
  157. package/dist/esm/FramedScreen/Factories/setupStandardFramedScreen.test.js +0 -29
  158. package/dist/esm/FramedScreen/Factories/setupStandardFramedScreen.test.js.map +0 -1
  159. package/dist/esm/StateMachine/Controller/clickRestoreScene.js +0 -11
  160. package/dist/esm/StateMachine/Controller/clickRestoreScene.js.map +0 -1
  161. package/dist/esm/StateMachine/Controller/clickRestoreScene.test.js +0 -24
  162. package/dist/esm/StateMachine/Controller/clickRestoreScene.test.js.map +0 -1
  163. package/dist/esm/TestUtils/index.js +0 -2
  164. package/dist/esm/TestUtils/index.js.map +0 -1
  165. package/dist/esm/TestUtils/setupFeatureForTesting.js +0 -57
  166. package/dist/esm/TestUtils/setupFeatureForTesting.js.map +0 -1
  167. package/dist/types/FramedScreen/Factories/setupStandardFramedScreen.test.d.ts +0 -2
  168. package/dist/types/FramedScreen/Factories/setupStandardFramedScreen.test.d.ts.map +0 -1
  169. package/dist/types/StateMachine/Controller/clickRestoreScene.d.ts +0 -3
  170. package/dist/types/StateMachine/Controller/clickRestoreScene.d.ts.map +0 -1
  171. package/dist/types/StateMachine/Controller/clickRestoreScene.test.d.ts +0 -2
  172. package/dist/types/StateMachine/Controller/clickRestoreScene.test.d.ts.map +0 -1
  173. package/dist/types/TestUtils/index.d.ts +0 -2
  174. package/dist/types/TestUtils/index.d.ts.map +0 -1
  175. package/dist/types/TestUtils/setupFeatureForTesting.d.ts +0 -48
  176. package/dist/types/TestUtils/setupFeatureForTesting.d.ts.map +0 -1
@@ -217,5 +217,245 @@ describe("ProcedureEntity", () => {
217
217
  expect(procedureEntity.showHints).toBe(false);
218
218
  expect(procedureEntity.isQuiz).toBe(true);
219
219
  });
220
+ describe("recordUserEvent revisits (order matters)", () => {
221
+ beforeEach(() => {
222
+ procedureEntity.addEventId("s1");
223
+ procedureEntity.addEventId("s2");
224
+ procedureEntity.addEventId("s3");
225
+ procedureEntity.setOrderMatters(true);
226
+ });
227
+ it("does not log a re-emission of an already-completed step", () => {
228
+ procedureEntity.recordUserEvent("s1");
229
+ procedureEntity.recordUserEvent("s2");
230
+ procedureEntity.recordUserEvent("s1");
231
+ expect(procedureEntity.userEventLog).toEqual(["s1", "s2"]);
232
+ expect(procedureEntity.currentStepIndex).toBe(2);
233
+ });
234
+ it("does not set a validation message for a benign revisit", () => {
235
+ procedureEntity.recordUserEvent("s1");
236
+ procedureEntity.recordUserEvent("s1");
237
+ expect(procedureEntity.validationMessage).toBeNull();
238
+ });
239
+ it("still logs and flags an early emission of a later step", () => {
240
+ procedureEntity.recordUserEvent("s1");
241
+ procedureEntity.recordUserEvent("s3");
242
+ expect(procedureEntity.userEventLog).toEqual(["s1", "s3"]);
243
+ expect(procedureEntity.validationMessage).toBe("Expected 's2', but got 's3'");
244
+ expect(procedureEntity.currentStepIndex).toBe(1);
245
+ });
246
+ });
247
+ describe("calculateScore (order matters, 10 steps)", () => {
248
+ const steps = [
249
+ "s1",
250
+ "s2",
251
+ "s3",
252
+ "s4",
253
+ "s5",
254
+ "s6",
255
+ "s7",
256
+ "s8",
257
+ "s9",
258
+ "s10",
259
+ ];
260
+ const record = (...ids) => ids.forEach((id) => procedureEntity.recordUserEvent(id));
261
+ const correctFlags = () => procedureEntity.calculateScore().comparison.map((c) => c.correct);
262
+ beforeEach(() => {
263
+ steps.forEach((s) => procedureEntity.addEventId(s));
264
+ procedureEntity.setOrderMatters(true);
265
+ });
266
+ it("scores a perfect run 100% with every step correct", () => {
267
+ record(...steps);
268
+ const score = procedureEntity.calculateScore();
269
+ expect(score.percentage).toBe(100);
270
+ expect(score.comparison.map((c) => c.eventId)).toEqual(steps);
271
+ expect(correctFlags()).toEqual(new Array(10).fill(true));
272
+ });
273
+ it("does not penalize one extra authored event emitted early", () => {
274
+ record("s1", "s7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10");
275
+ expect(procedureEntity.calculateScore().percentage).toBe(100);
276
+ expect(correctFlags()).toEqual(new Array(10).fill(true));
277
+ });
278
+ it("scores a skipped step 90% and marks only that step incorrect", () => {
279
+ record("s1", "s2", "s3", "s4", "s6", "s7", "s8", "s9", "s10");
280
+ expect(procedureEntity.calculateScore().percentage).toBe(90);
281
+ expect(correctFlags()).toEqual([
282
+ true,
283
+ true,
284
+ true,
285
+ true,
286
+ false,
287
+ true,
288
+ true,
289
+ true,
290
+ true,
291
+ true,
292
+ ]);
293
+ });
294
+ it("scores swapped steps 90%, keeping the earlier expected step (deterministic tie-break)", () => {
295
+ record("s1", "s2", "s3", "s5", "s4", "s6", "s7", "s8", "s9", "s10");
296
+ for (let run = 0; run < 3; run++) {
297
+ const score = procedureEntity.calculateScore();
298
+ expect(score.percentage).toBe(90);
299
+ expect(score.comparison[3].correct).toBe(true);
300
+ expect(score.comparison[4].correct).toBe(false);
301
+ expect(score.comparison.filter((c) => c.correct).length).toBe(9);
302
+ }
303
+ });
304
+ it("scores a repeated first step 100% with no duplicate in the log", () => {
305
+ record("s1", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10");
306
+ expect(procedureEntity.userEventLog).toEqual(steps);
307
+ expect(procedureEntity.validationMessage).toBeNull();
308
+ expect(procedureEntity.calculateScore().percentage).toBe(100);
309
+ expect(correctFlags()).toEqual(new Array(10).fill(true));
310
+ });
311
+ it("scores a fully reversed run 10%", () => {
312
+ record(...[...steps].reverse());
313
+ const score = procedureEntity.calculateScore();
314
+ expect(score.percentage).toBe(10);
315
+ expect(score.comparison[0].correct).toBe(true);
316
+ expect(score.comparison.filter((c) => c.correct).length).toBe(1);
317
+ });
318
+ it("scores an empty log 0% with every step incorrect", () => {
319
+ const score = procedureEntity.calculateScore();
320
+ expect(score.percentage).toBe(0);
321
+ expect(correctFlags()).toEqual(new Array(10).fill(false));
322
+ score.comparison.forEach((c) => {
323
+ expect(c.expected).toBe(true);
324
+ expect(c.actual).toBe(false);
325
+ });
326
+ });
327
+ it("keeps the comparison shape { eventId, expected, actual, correct }", () => {
328
+ record("s1", "s2", "s3", "s4", "s6", "s7", "s8", "s9", "s10");
329
+ const skipped = procedureEntity.calculateScore().comparison[4];
330
+ expect(skipped).toEqual({
331
+ eventId: "s5",
332
+ expected: true,
333
+ actual: false,
334
+ correct: false,
335
+ });
336
+ });
337
+ });
338
+ describe("calculateScore edge cases", () => {
339
+ it("returns { percentage: 0, comparison: [] } for an empty procedure", () => {
340
+ procedureEntity.setOrderMatters(true);
341
+ expect(procedureEntity.calculateScore()).toEqual({
342
+ percentage: 0,
343
+ comparison: [],
344
+ });
345
+ });
346
+ it("keeps set-based scoring when order does not matter", () => {
347
+ procedureEntity.addEventId("a");
348
+ procedureEntity.addEventId("b");
349
+ procedureEntity.addEventId("c");
350
+ procedureEntity.setOrderMatters(false);
351
+ procedureEntity.recordUserEvent("c");
352
+ procedureEntity.recordUserEvent("a");
353
+ const score = procedureEntity.calculateScore();
354
+ expect(score.percentage).toBe(67);
355
+ expect(score.comparison.map((c) => c.correct)).toEqual([
356
+ true,
357
+ false,
358
+ true,
359
+ ]);
360
+ });
361
+ });
362
+ describe("event category lookup (#53)", () => {
363
+ it("treats every step as assessed when no lookup is injected", () => {
364
+ expect(procedureEntity.getEventCategory("navigate-to-overhead")).toBe("assessed");
365
+ });
366
+ it("resolves a step's category through the injected lookup at call time", () => {
367
+ procedureEntity.setEventCategoryLookup((eventId) => eventId === "navigate-to-overhead" ? "instructional" : "assessed");
368
+ expect(procedureEntity.getEventCategory("navigate-to-overhead")).toBe("instructional");
369
+ expect(procedureEntity.getEventCategory("lever")).toBe("assessed");
370
+ });
371
+ it("notifies observers when the lookup is injected so presenters rebuild", () => {
372
+ const observer = jest.fn();
373
+ procedureEntity.addChangeObserver(observer);
374
+ procedureEntity.setEventCategoryLookup(() => "assessed");
375
+ expect(observer).toHaveBeenCalledTimes(1);
376
+ });
377
+ });
378
+ describe("quiz mode with instructional steps (#53)", () => {
379
+ const NAV = "navigate-to-overhead";
380
+ beforeEach(() => {
381
+ procedureEntity.setEventCategoryLookup((eventId) => eventId === NAV ? "instructional" : "assessed");
382
+ procedureEntity.addEventId(NAV);
383
+ procedureEntity.addEventId("lever");
384
+ procedureEntity.addEventId("valve");
385
+ procedureEntity.setIsQuiz(true);
386
+ });
387
+ it("scores only the assessed subsequence", () => {
388
+ procedureEntity.recordUserEvent("lever");
389
+ procedureEntity.recordUserEvent("valve");
390
+ expect(procedureEntity.calculateScore()).toEqual({
391
+ percentage: 100,
392
+ comparison: [
393
+ { eventId: "lever", expected: true, actual: true, correct: true },
394
+ { eventId: "valve", expected: true, actual: true, correct: true },
395
+ ],
396
+ });
397
+ });
398
+ it("logs an instructional emission without advancing or flagging the attempt", () => {
399
+ procedureEntity.recordUserEvent(NAV);
400
+ expect(procedureEntity.userEventLog).toEqual([NAV]);
401
+ expect(procedureEntity.currentStepIndex).toBe(0);
402
+ expect(procedureEntity.validationMessage).toBeNull();
403
+ expect(procedureEntity.getNextExpectedEvent()).toBe("lever");
404
+ });
405
+ it("does not misalign later assessed steps around an instructional emission", () => {
406
+ procedureEntity.recordUserEvent("lever");
407
+ procedureEntity.recordUserEvent(NAV);
408
+ procedureEntity.recordUserEvent("valve");
409
+ expect(procedureEntity.isComplete).toBe(true);
410
+ expect(procedureEntity.getProgressPercentage()).toBe(100);
411
+ expect(procedureEntity.calculateScore().percentage).toBe(100);
412
+ });
413
+ it("treats a quiz made only of instructional steps like an empty procedure", () => {
414
+ procedureEntity.removeEventId("lever");
415
+ procedureEntity.removeEventId("valve");
416
+ procedureEntity.recordUserEvent(NAV);
417
+ expect(procedureEntity.isComplete).toBe(false);
418
+ expect(procedureEntity.getProgressPercentage()).toBe(0);
419
+ expect(procedureEntity.getNextExpectedEvent()).toBeNull();
420
+ expect(procedureEntity.calculateScore()).toEqual({
421
+ percentage: 0,
422
+ comparison: [],
423
+ });
424
+ });
425
+ it("ignores categories entirely in training mode", () => {
426
+ procedureEntity.setIsQuiz(false);
427
+ procedureEntity.recordUserEvent(NAV);
428
+ expect(procedureEntity.currentStepIndex).toBe(1);
429
+ expect(procedureEntity.getProgressPercentage()).toBe(33);
430
+ procedureEntity.recordUserEvent("lever");
431
+ procedureEntity.recordUserEvent("valve");
432
+ expect(procedureEntity.isComplete).toBe(true);
433
+ expect(procedureEntity.calculateScore().comparison).toHaveLength(3);
434
+ });
435
+ it("logs a repeated instructional emission only once, however often the student revisits", () => {
436
+ procedureEntity.recordUserEvent(NAV);
437
+ procedureEntity.recordUserEvent("lever");
438
+ procedureEntity.recordUserEvent(NAV);
439
+ procedureEntity.recordUserEvent(NAV);
440
+ expect(procedureEntity.userEventLog).toEqual([NAV, "lever"]);
441
+ // The bounded log never changes the assessed score.
442
+ expect(procedureEntity.calculateScore().percentage).toBe(50);
443
+ });
444
+ it("flags a quiz whose steps are all instructional as needing an assessed step", () => {
445
+ procedureEntity.removeEventId("lever");
446
+ procedureEntity.removeEventId("valve");
447
+ expect(procedureEntity.getAuthoringValidationMessage()).toBe("A quiz needs at least one assessed step");
448
+ expect(procedureEntity.validateProgress()).toBe("A quiz needs at least one assessed step");
449
+ });
450
+ it("does not flag a quiz that has assessed steps, nor an all-instructional training procedure", () => {
451
+ // The mixed quiz has assessed steps → no authoring message.
452
+ expect(procedureEntity.getAuthoringValidationMessage()).toBeNull();
453
+ // All-instructional, but training mode is never a quiz problem.
454
+ procedureEntity.removeEventId("lever");
455
+ procedureEntity.removeEventId("valve");
456
+ procedureEntity.setIsQuiz(false);
457
+ expect(procedureEntity.getAuthoringValidationMessage()).toBeNull();
458
+ });
459
+ });
220
460
  });
221
461
  //# sourceMappingURL=ProcedureEntity.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProcedureEntity.test.js","sourceRoot":"","sources":["../../../../src/Procedure/Entities/ProcedureEntity.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObjectRepo, makeAppObjectRepo } from \"@vived/core\";\r\nimport { ProcedureEntity, makeProcedureEntity } from \"./ProcedureEntity\";\r\n\r\ndescribe(\"ProcedureEntity\", () => {\r\n\tlet appObjects: AppObjectRepo;\r\n\tlet procedureEntity: ProcedureEntity;\r\n\r\n\tbeforeEach(() => {\r\n\t\tappObjects = makeAppObjectRepo();\r\n\t\tconst appObject = appObjects.getOrCreate(\"TestProcedure\");\r\n\t\tprocedureEntity = makeProcedureEntity(appObject);\r\n\t});\r\n\r\n\tit(\"implements Challenge interface correctly\", () => {\r\n\t\texpect(procedureEntity.challengeID).toBe(\"PROCEDURE\");\r\n\t\texpect(procedureEntity.name).toBe(\"Procedure\");\r\n\t\texpect(typeof procedureEntity.consumerHelpText).toBe(\"string\");\r\n\t\texpect(typeof procedureEntity.authorHelpText).toBe(\"string\");\r\n\t\texpect(typeof procedureEntity.reset).toBe(\"function\");\r\n\t});\r\n\r\n\tit(\"has dynamic helpHeading based on quiz mode\", () => {\r\n\t\texpect(procedureEntity.helpHeading).toBe(\"Procedure Training\");\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\texpect(procedureEntity.helpHeading).toBe(\"Procedure Challenge\");\r\n\t\tprocedureEntity.setIsQuiz(false);\r\n\t\texpect(procedureEntity.helpHeading).toBe(\"Procedure Training\");\r\n\t});\r\n\r\n\tit(\"has dynamic consumerHelpText based on quiz mode\", () => {\r\n\t\texpect(procedureEntity.consumerHelpText).toBe(\r\n\t\t\t\"Follow the steps in order to complete the training procedure.\",\r\n\t\t);\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\texpect(procedureEntity.consumerHelpText).toBe(\r\n\t\t\t\"Complete the procedure challenge on your own and get scored after submitting.\",\r\n\t\t);\r\n\t\tprocedureEntity.setIsQuiz(false);\r\n\t\texpect(procedureEntity.consumerHelpText).toBe(\r\n\t\t\t\"Follow the steps in order to complete the training procedure.\",\r\n\t\t);\r\n\t});\r\n\r\n\tit(\"has correct singleton registration\", () => {\r\n\t\tconst retrieved = ProcedureEntity.get(appObjects);\r\n\t\texpect(retrieved).toBe(procedureEntity);\r\n\t});\r\n\r\n\tit(\"starts with empty event list\", () => {\r\n\t\texpect(procedureEntity.eventIds).toEqual([]);\r\n\t});\r\n\r\n\tit(\"can add events to procedure\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event_1\");\r\n\t\tprocedureEntity.addEventId(\"test_event_2\");\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"test_event_1\", \"test_event_2\"]);\r\n\t});\r\n\r\n\tit(\"prevents duplicate events\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event\");\r\n\t\tprocedureEntity.addEventId(\"test_event\");\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"test_event\"]);\r\n\t\texpect(procedureEntity.validationMessage).toContain(\"already in the procedure\");\r\n\t});\r\n\r\n\tit(\"can remove events from procedure\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event_1\");\r\n\t\tprocedureEntity.addEventId(\"test_event_2\");\r\n\t\tprocedureEntity.removeEventId(\"test_event_1\");\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"test_event_2\"]);\r\n\t});\r\n\r\n\tit(\"handles removing non-existent events\", () => {\r\n\t\tprocedureEntity.removeEventId(\"non_existent\");\r\n\t\texpect(procedureEntity.validationMessage).toContain(\"not in the procedure\");\r\n\t});\r\n\r\n\tit(\"can clear all events\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event_1\");\r\n\t\tprocedureEntity.addEventId(\"test_event_2\");\r\n\t\tprocedureEntity.clearEventIds();\r\n\t\texpect(procedureEntity.eventIds).toEqual([]);\r\n\t});\r\n\r\n\tit(\"starts with empty user event log\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([]);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t});\r\n\r\n\tit(\"records user events for ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([\"event_1\"]);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(1);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(2);\r\n\t});\r\n\r\n\tit(\"validates order in ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.validationMessage).toContain(\r\n\t\t\t\"Expected 'event_1', but got 'event_2'\",\r\n\t\t);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t});\r\n\r\n\tit(\"ignores order in unordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([\"event_3\", \"event_1\"]);\r\n\t});\r\n\r\n\tit(\"ignores events not in procedure\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.recordUserEvent(\"unknown_event\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([]);\r\n\t});\r\n\r\n\tit(\"detects completion in ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.isComplete).toBe(true);\r\n\t});\r\n\r\n\tit(\"detects completion in unordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.isComplete).toBe(true);\r\n\t});\r\n\r\n\tit(\"returns false for empty procedures\", () => {\r\n\t\tprocedureEntity.clearEventIds();\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t});\r\n\r\n\tit(\"calculates progress for ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.addEventId(\"event_4\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(0);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(25);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(50);\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_4\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(100);\r\n\t});\r\n\r\n\tit(\"calculates progress for unordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.addEventId(\"event_4\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(0);\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(25);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(50);\r\n\t});\r\n\r\n\tit(\"provides next expected event for ordered procedures with hints enabled\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\tprocedureEntity.setShowHints(true);\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_1\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_2\");\r\n\t});\r\n\r\n\tit(\"provides next unemitted event for unordered procedures with hints enabled\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\tprocedureEntity.setShowHints(true);\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_1\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_1\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_2\");\r\n\t});\r\n\r\n\tit(\"returns null when hints are disabled\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.setShowHints(false);\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(null);\r\n\t});\r\n\r\n\tit(\"can toggle order matters setting\", () => {\r\n\t\texpect(procedureEntity.orderMatters).toBe(true);\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\texpect(procedureEntity.orderMatters).toBe(false);\r\n\t});\r\n\r\n\tit(\"can toggle hints setting\", () => {\r\n\t\texpect(procedureEntity.showHints).toBe(true);\r\n\t\tprocedureEntity.setShowHints(false);\r\n\t\texpect(procedureEntity.showHints).toBe(false);\r\n\t});\r\n\r\n\tit(\"can toggle quiz mode\", () => {\r\n\t\texpect(procedureEntity.isQuiz).toBe(false);\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\texpect(procedureEntity.isQuiz).toBe(true);\r\n\t});\r\n\r\n\tit(\"resets user progress while preserving configuration\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\tprocedureEntity.setShowHints(false);\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.userEventLog.length).toBe(1);\r\n\t\tprocedureEntity.reset();\r\n\t\texpect(procedureEntity.userEventLog).toEqual([]);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t\texpect(procedureEntity.validationMessage).toBe(null);\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"event_1\", \"event_2\"]);\r\n\t\texpect(procedureEntity.orderMatters).toBe(false);\r\n\t\texpect(procedureEntity.showHints).toBe(false);\r\n\t\texpect(procedureEntity.isQuiz).toBe(true);\r\n\t});\r\n});\r\n"]}
1
+ {"version":3,"file":"ProcedureEntity.test.js","sourceRoot":"","sources":["../../../../src/Procedure/Entities/ProcedureEntity.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObjectRepo, makeAppObjectRepo } from \"@vived/core\";\r\nimport { ProcedureEntity, makeProcedureEntity } from \"./ProcedureEntity\";\r\n\r\ndescribe(\"ProcedureEntity\", () => {\r\n\tlet appObjects: AppObjectRepo;\r\n\tlet procedureEntity: ProcedureEntity;\r\n\r\n\tbeforeEach(() => {\r\n\t\tappObjects = makeAppObjectRepo();\r\n\t\tconst appObject = appObjects.getOrCreate(\"TestProcedure\");\r\n\t\tprocedureEntity = makeProcedureEntity(appObject);\r\n\t});\r\n\r\n\tit(\"implements Challenge interface correctly\", () => {\r\n\t\texpect(procedureEntity.challengeID).toBe(\"PROCEDURE\");\r\n\t\texpect(procedureEntity.name).toBe(\"Procedure\");\r\n\t\texpect(typeof procedureEntity.consumerHelpText).toBe(\"string\");\r\n\t\texpect(typeof procedureEntity.authorHelpText).toBe(\"string\");\r\n\t\texpect(typeof procedureEntity.reset).toBe(\"function\");\r\n\t});\r\n\r\n\tit(\"has dynamic helpHeading based on quiz mode\", () => {\r\n\t\texpect(procedureEntity.helpHeading).toBe(\"Procedure Training\");\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\texpect(procedureEntity.helpHeading).toBe(\"Procedure Challenge\");\r\n\t\tprocedureEntity.setIsQuiz(false);\r\n\t\texpect(procedureEntity.helpHeading).toBe(\"Procedure Training\");\r\n\t});\r\n\r\n\tit(\"has dynamic consumerHelpText based on quiz mode\", () => {\r\n\t\texpect(procedureEntity.consumerHelpText).toBe(\r\n\t\t\t\"Follow the steps in order to complete the training procedure.\",\r\n\t\t);\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\texpect(procedureEntity.consumerHelpText).toBe(\r\n\t\t\t\"Complete the procedure challenge on your own and get scored after submitting.\",\r\n\t\t);\r\n\t\tprocedureEntity.setIsQuiz(false);\r\n\t\texpect(procedureEntity.consumerHelpText).toBe(\r\n\t\t\t\"Follow the steps in order to complete the training procedure.\",\r\n\t\t);\r\n\t});\r\n\r\n\tit(\"has correct singleton registration\", () => {\r\n\t\tconst retrieved = ProcedureEntity.get(appObjects);\r\n\t\texpect(retrieved).toBe(procedureEntity);\r\n\t});\r\n\r\n\tit(\"starts with empty event list\", () => {\r\n\t\texpect(procedureEntity.eventIds).toEqual([]);\r\n\t});\r\n\r\n\tit(\"can add events to procedure\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event_1\");\r\n\t\tprocedureEntity.addEventId(\"test_event_2\");\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"test_event_1\", \"test_event_2\"]);\r\n\t});\r\n\r\n\tit(\"prevents duplicate events\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event\");\r\n\t\tprocedureEntity.addEventId(\"test_event\");\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"test_event\"]);\r\n\t\texpect(procedureEntity.validationMessage).toContain(\"already in the procedure\");\r\n\t});\r\n\r\n\tit(\"can remove events from procedure\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event_1\");\r\n\t\tprocedureEntity.addEventId(\"test_event_2\");\r\n\t\tprocedureEntity.removeEventId(\"test_event_1\");\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"test_event_2\"]);\r\n\t});\r\n\r\n\tit(\"handles removing non-existent events\", () => {\r\n\t\tprocedureEntity.removeEventId(\"non_existent\");\r\n\t\texpect(procedureEntity.validationMessage).toContain(\"not in the procedure\");\r\n\t});\r\n\r\n\tit(\"can clear all events\", () => {\r\n\t\tprocedureEntity.addEventId(\"test_event_1\");\r\n\t\tprocedureEntity.addEventId(\"test_event_2\");\r\n\t\tprocedureEntity.clearEventIds();\r\n\t\texpect(procedureEntity.eventIds).toEqual([]);\r\n\t});\r\n\r\n\tit(\"starts with empty user event log\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([]);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t});\r\n\r\n\tit(\"records user events for ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([\"event_1\"]);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(1);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(2);\r\n\t});\r\n\r\n\tit(\"validates order in ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.validationMessage).toContain(\r\n\t\t\t\"Expected 'event_1', but got 'event_2'\",\r\n\t\t);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t});\r\n\r\n\tit(\"ignores order in unordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([\"event_3\", \"event_1\"]);\r\n\t});\r\n\r\n\tit(\"ignores events not in procedure\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.recordUserEvent(\"unknown_event\");\r\n\t\texpect(procedureEntity.userEventLog).toEqual([]);\r\n\t});\r\n\r\n\tit(\"detects completion in ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.isComplete).toBe(true);\r\n\t});\r\n\r\n\tit(\"detects completion in unordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.isComplete).toBe(true);\r\n\t});\r\n\r\n\tit(\"returns false for empty procedures\", () => {\r\n\t\tprocedureEntity.clearEventIds();\r\n\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t});\r\n\r\n\tit(\"calculates progress for ordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.addEventId(\"event_4\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(0);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(25);\r\n\t\tprocedureEntity.recordUserEvent(\"event_2\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(50);\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_4\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(100);\r\n\t});\r\n\r\n\tit(\"calculates progress for unordered procedures\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.addEventId(\"event_4\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(0);\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(25);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getProgressPercentage()).toBe(50);\r\n\t});\r\n\r\n\tit(\"provides next expected event for ordered procedures with hints enabled\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(true);\r\n\t\tprocedureEntity.setShowHints(true);\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_1\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_2\");\r\n\t});\r\n\r\n\tit(\"provides next unemitted event for unordered procedures with hints enabled\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.addEventId(\"event_3\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\tprocedureEntity.setShowHints(true);\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_1\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_3\");\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_1\");\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"event_2\");\r\n\t});\r\n\r\n\tit(\"returns null when hints are disabled\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.setShowHints(false);\r\n\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(null);\r\n\t});\r\n\r\n\tit(\"can toggle order matters setting\", () => {\r\n\t\texpect(procedureEntity.orderMatters).toBe(true);\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\texpect(procedureEntity.orderMatters).toBe(false);\r\n\t});\r\n\r\n\tit(\"can toggle hints setting\", () => {\r\n\t\texpect(procedureEntity.showHints).toBe(true);\r\n\t\tprocedureEntity.setShowHints(false);\r\n\t\texpect(procedureEntity.showHints).toBe(false);\r\n\t});\r\n\r\n\tit(\"can toggle quiz mode\", () => {\r\n\t\texpect(procedureEntity.isQuiz).toBe(false);\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\texpect(procedureEntity.isQuiz).toBe(true);\r\n\t});\r\n\r\n\tit(\"resets user progress while preserving configuration\", () => {\r\n\t\tprocedureEntity.addEventId(\"event_1\");\r\n\t\tprocedureEntity.addEventId(\"event_2\");\r\n\t\tprocedureEntity.setOrderMatters(false);\r\n\t\tprocedureEntity.setShowHints(false);\r\n\t\tprocedureEntity.setIsQuiz(true);\r\n\t\tprocedureEntity.recordUserEvent(\"event_1\");\r\n\t\texpect(procedureEntity.userEventLog.length).toBe(1);\r\n\t\tprocedureEntity.reset();\r\n\t\texpect(procedureEntity.userEventLog).toEqual([]);\r\n\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t\texpect(procedureEntity.validationMessage).toBe(null);\r\n\t\texpect(procedureEntity.eventIds).toEqual([\"event_1\", \"event_2\"]);\r\n\t\texpect(procedureEntity.orderMatters).toBe(false);\r\n\t\texpect(procedureEntity.showHints).toBe(false);\r\n\t\texpect(procedureEntity.isQuiz).toBe(true);\r\n\t});\r\n\r\n\tdescribe(\"recordUserEvent revisits (order matters)\", () => {\r\n\t\tbeforeEach(() => {\r\n\t\t\tprocedureEntity.addEventId(\"s1\");\r\n\t\t\tprocedureEntity.addEventId(\"s2\");\r\n\t\t\tprocedureEntity.addEventId(\"s3\");\r\n\t\t\tprocedureEntity.setOrderMatters(true);\r\n\t\t});\r\n\r\n\t\tit(\"does not log a re-emission of an already-completed step\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(\"s1\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"s2\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"s1\");\r\n\t\t\texpect(procedureEntity.userEventLog).toEqual([\"s1\", \"s2\"]);\r\n\t\t\texpect(procedureEntity.currentStepIndex).toBe(2);\r\n\t\t});\r\n\r\n\t\tit(\"does not set a validation message for a benign revisit\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(\"s1\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"s1\");\r\n\t\t\texpect(procedureEntity.validationMessage).toBeNull();\r\n\t\t});\r\n\r\n\t\tit(\"still logs and flags an early emission of a later step\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(\"s1\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"s3\");\r\n\t\t\texpect(procedureEntity.userEventLog).toEqual([\"s1\", \"s3\"]);\r\n\t\t\texpect(procedureEntity.validationMessage).toBe(\r\n\t\t\t\t\"Expected 's2', but got 's3'\",\r\n\t\t\t);\r\n\t\t\texpect(procedureEntity.currentStepIndex).toBe(1);\r\n\t\t});\r\n\t});\r\n\r\n\tdescribe(\"calculateScore (order matters, 10 steps)\", () => {\r\n\t\tconst steps = [\r\n\t\t\t\"s1\",\r\n\t\t\t\"s2\",\r\n\t\t\t\"s3\",\r\n\t\t\t\"s4\",\r\n\t\t\t\"s5\",\r\n\t\t\t\"s6\",\r\n\t\t\t\"s7\",\r\n\t\t\t\"s8\",\r\n\t\t\t\"s9\",\r\n\t\t\t\"s10\",\r\n\t\t];\r\n\r\n\t\tconst record = (...ids: string[]) =>\r\n\t\t\tids.forEach((id) => procedureEntity.recordUserEvent(id));\r\n\r\n\t\tconst correctFlags = () =>\r\n\t\t\tprocedureEntity.calculateScore().comparison.map((c) => c.correct);\r\n\r\n\t\tbeforeEach(() => {\r\n\t\t\tsteps.forEach((s) => procedureEntity.addEventId(s));\r\n\t\t\tprocedureEntity.setOrderMatters(true);\r\n\t\t});\r\n\r\n\t\tit(\"scores a perfect run 100% with every step correct\", () => {\r\n\t\t\trecord(...steps);\r\n\t\t\tconst score = procedureEntity.calculateScore();\r\n\t\t\texpect(score.percentage).toBe(100);\r\n\t\t\texpect(score.comparison.map((c) => c.eventId)).toEqual(steps);\r\n\t\t\texpect(correctFlags()).toEqual(new Array(10).fill(true));\r\n\t\t});\r\n\r\n\t\tit(\"does not penalize one extra authored event emitted early\", () => {\r\n\t\t\trecord(\"s1\", \"s7\", \"s2\", \"s3\", \"s4\", \"s5\", \"s6\", \"s7\", \"s8\", \"s9\", \"s10\");\r\n\t\t\texpect(procedureEntity.calculateScore().percentage).toBe(100);\r\n\t\t\texpect(correctFlags()).toEqual(new Array(10).fill(true));\r\n\t\t});\r\n\r\n\t\tit(\"scores a skipped step 90% and marks only that step incorrect\", () => {\r\n\t\t\trecord(\"s1\", \"s2\", \"s3\", \"s4\", \"s6\", \"s7\", \"s8\", \"s9\", \"s10\");\r\n\t\t\texpect(procedureEntity.calculateScore().percentage).toBe(90);\r\n\t\t\texpect(correctFlags()).toEqual([\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t\tfalse,\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t\ttrue,\r\n\t\t\t]);\r\n\t\t});\r\n\r\n\t\tit(\"scores swapped steps 90%, keeping the earlier expected step (deterministic tie-break)\", () => {\r\n\t\t\trecord(\"s1\", \"s2\", \"s3\", \"s5\", \"s4\", \"s6\", \"s7\", \"s8\", \"s9\", \"s10\");\r\n\t\t\tfor (let run = 0; run < 3; run++) {\r\n\t\t\t\tconst score = procedureEntity.calculateScore();\r\n\t\t\t\texpect(score.percentage).toBe(90);\r\n\t\t\t\texpect(score.comparison[3].correct).toBe(true);\r\n\t\t\t\texpect(score.comparison[4].correct).toBe(false);\r\n\t\t\t\texpect(score.comparison.filter((c) => c.correct).length).toBe(9);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tit(\"scores a repeated first step 100% with no duplicate in the log\", () => {\r\n\t\t\trecord(\"s1\", \"s1\", \"s2\", \"s3\", \"s4\", \"s5\", \"s6\", \"s7\", \"s8\", \"s9\", \"s10\");\r\n\t\t\texpect(procedureEntity.userEventLog).toEqual(steps);\r\n\t\t\texpect(procedureEntity.validationMessage).toBeNull();\r\n\t\t\texpect(procedureEntity.calculateScore().percentage).toBe(100);\r\n\t\t\texpect(correctFlags()).toEqual(new Array(10).fill(true));\r\n\t\t});\r\n\r\n\t\tit(\"scores a fully reversed run 10%\", () => {\r\n\t\t\trecord(...[...steps].reverse());\r\n\t\t\tconst score = procedureEntity.calculateScore();\r\n\t\t\texpect(score.percentage).toBe(10);\r\n\t\t\texpect(score.comparison[0].correct).toBe(true);\r\n\t\t\texpect(score.comparison.filter((c) => c.correct).length).toBe(1);\r\n\t\t});\r\n\r\n\t\tit(\"scores an empty log 0% with every step incorrect\", () => {\r\n\t\t\tconst score = procedureEntity.calculateScore();\r\n\t\t\texpect(score.percentage).toBe(0);\r\n\t\t\texpect(correctFlags()).toEqual(new Array(10).fill(false));\r\n\t\t\tscore.comparison.forEach((c) => {\r\n\t\t\t\texpect(c.expected).toBe(true);\r\n\t\t\t\texpect(c.actual).toBe(false);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tit(\"keeps the comparison shape { eventId, expected, actual, correct }\", () => {\r\n\t\t\trecord(\"s1\", \"s2\", \"s3\", \"s4\", \"s6\", \"s7\", \"s8\", \"s9\", \"s10\");\r\n\t\t\tconst skipped = procedureEntity.calculateScore().comparison[4];\r\n\t\t\texpect(skipped).toEqual({\r\n\t\t\t\teventId: \"s5\",\r\n\t\t\t\texpected: true,\r\n\t\t\t\tactual: false,\r\n\t\t\t\tcorrect: false,\r\n\t\t\t});\r\n\t\t});\r\n\t});\r\n\r\n\tdescribe(\"calculateScore edge cases\", () => {\r\n\t\tit(\"returns { percentage: 0, comparison: [] } for an empty procedure\", () => {\r\n\t\t\tprocedureEntity.setOrderMatters(true);\r\n\t\t\texpect(procedureEntity.calculateScore()).toEqual({\r\n\t\t\t\tpercentage: 0,\r\n\t\t\t\tcomparison: [],\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tit(\"keeps set-based scoring when order does not matter\", () => {\r\n\t\t\tprocedureEntity.addEventId(\"a\");\r\n\t\t\tprocedureEntity.addEventId(\"b\");\r\n\t\t\tprocedureEntity.addEventId(\"c\");\r\n\t\t\tprocedureEntity.setOrderMatters(false);\r\n\t\t\tprocedureEntity.recordUserEvent(\"c\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"a\");\r\n\t\t\tconst score = procedureEntity.calculateScore();\r\n\t\t\texpect(score.percentage).toBe(67);\r\n\t\t\texpect(score.comparison.map((c) => c.correct)).toEqual([\r\n\t\t\t\ttrue,\r\n\t\t\t\tfalse,\r\n\t\t\t\ttrue,\r\n\t\t\t]);\r\n\t\t});\r\n\t});\r\n\r\n\tdescribe(\"event category lookup (#53)\", () => {\r\n\t\tit(\"treats every step as assessed when no lookup is injected\", () => {\r\n\t\t\texpect(procedureEntity.getEventCategory(\"navigate-to-overhead\")).toBe(\r\n\t\t\t\t\"assessed\",\r\n\t\t\t);\r\n\t\t});\r\n\r\n\t\tit(\"resolves a step's category through the injected lookup at call time\", () => {\r\n\t\t\tprocedureEntity.setEventCategoryLookup((eventId) =>\r\n\t\t\t\teventId === \"navigate-to-overhead\" ? \"instructional\" : \"assessed\",\r\n\t\t\t);\r\n\r\n\t\t\texpect(procedureEntity.getEventCategory(\"navigate-to-overhead\")).toBe(\r\n\t\t\t\t\"instructional\",\r\n\t\t\t);\r\n\t\t\texpect(procedureEntity.getEventCategory(\"lever\")).toBe(\"assessed\");\r\n\t\t});\r\n\r\n\t\tit(\"notifies observers when the lookup is injected so presenters rebuild\", () => {\r\n\t\t\tconst observer = jest.fn();\r\n\t\t\tprocedureEntity.addChangeObserver(observer);\r\n\r\n\t\t\tprocedureEntity.setEventCategoryLookup(() => \"assessed\");\r\n\r\n\t\t\texpect(observer).toHaveBeenCalledTimes(1);\r\n\t\t});\r\n\t});\r\n\r\n\tdescribe(\"quiz mode with instructional steps (#53)\", () => {\r\n\t\tconst NAV = \"navigate-to-overhead\";\r\n\r\n\t\tbeforeEach(() => {\r\n\t\t\tprocedureEntity.setEventCategoryLookup((eventId) =>\r\n\t\t\t\teventId === NAV ? \"instructional\" : \"assessed\",\r\n\t\t\t);\r\n\t\t\tprocedureEntity.addEventId(NAV);\r\n\t\t\tprocedureEntity.addEventId(\"lever\");\r\n\t\t\tprocedureEntity.addEventId(\"valve\");\r\n\t\t\tprocedureEntity.setIsQuiz(true);\r\n\t\t});\r\n\r\n\t\tit(\"scores only the assessed subsequence\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(\"lever\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"valve\");\r\n\r\n\t\t\texpect(procedureEntity.calculateScore()).toEqual({\r\n\t\t\t\tpercentage: 100,\r\n\t\t\t\tcomparison: [\r\n\t\t\t\t\t{ eventId: \"lever\", expected: true, actual: true, correct: true },\r\n\t\t\t\t\t{ eventId: \"valve\", expected: true, actual: true, correct: true },\r\n\t\t\t\t],\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tit(\"logs an instructional emission without advancing or flagging the attempt\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\r\n\t\t\texpect(procedureEntity.userEventLog).toEqual([NAV]);\r\n\t\t\texpect(procedureEntity.currentStepIndex).toBe(0);\r\n\t\t\texpect(procedureEntity.validationMessage).toBeNull();\r\n\t\t\texpect(procedureEntity.getNextExpectedEvent()).toBe(\"lever\");\r\n\t\t});\r\n\r\n\t\tit(\"does not misalign later assessed steps around an instructional emission\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(\"lever\");\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\t\t\tprocedureEntity.recordUserEvent(\"valve\");\r\n\r\n\t\t\texpect(procedureEntity.isComplete).toBe(true);\r\n\t\t\texpect(procedureEntity.getProgressPercentage()).toBe(100);\r\n\t\t\texpect(procedureEntity.calculateScore().percentage).toBe(100);\r\n\t\t});\r\n\r\n\t\tit(\"treats a quiz made only of instructional steps like an empty procedure\", () => {\r\n\t\t\tprocedureEntity.removeEventId(\"lever\");\r\n\t\t\tprocedureEntity.removeEventId(\"valve\");\r\n\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\r\n\t\t\texpect(procedureEntity.isComplete).toBe(false);\r\n\t\t\texpect(procedureEntity.getProgressPercentage()).toBe(0);\r\n\t\t\texpect(procedureEntity.getNextExpectedEvent()).toBeNull();\r\n\t\t\texpect(procedureEntity.calculateScore()).toEqual({\r\n\t\t\t\tpercentage: 0,\r\n\t\t\t\tcomparison: [],\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tit(\"ignores categories entirely in training mode\", () => {\r\n\t\t\tprocedureEntity.setIsQuiz(false);\r\n\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\t\t\texpect(procedureEntity.currentStepIndex).toBe(1);\r\n\t\t\texpect(procedureEntity.getProgressPercentage()).toBe(33);\r\n\r\n\t\t\tprocedureEntity.recordUserEvent(\"lever\");\r\n\t\t\tprocedureEntity.recordUserEvent(\"valve\");\r\n\t\t\texpect(procedureEntity.isComplete).toBe(true);\r\n\t\t\texpect(procedureEntity.calculateScore().comparison).toHaveLength(3);\r\n\t\t});\r\n\r\n\t\tit(\"logs a repeated instructional emission only once, however often the student revisits\", () => {\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\t\t\tprocedureEntity.recordUserEvent(\"lever\");\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\t\t\tprocedureEntity.recordUserEvent(NAV);\r\n\r\n\t\t\texpect(procedureEntity.userEventLog).toEqual([NAV, \"lever\"]);\r\n\t\t\t// The bounded log never changes the assessed score.\r\n\t\t\texpect(procedureEntity.calculateScore().percentage).toBe(50);\r\n\t\t});\r\n\r\n\t\tit(\"flags a quiz whose steps are all instructional as needing an assessed step\", () => {\r\n\t\t\tprocedureEntity.removeEventId(\"lever\");\r\n\t\t\tprocedureEntity.removeEventId(\"valve\");\r\n\r\n\t\t\texpect(procedureEntity.getAuthoringValidationMessage()).toBe(\r\n\t\t\t\t\"A quiz needs at least one assessed step\",\r\n\t\t\t);\r\n\t\t\texpect(procedureEntity.validateProgress()).toBe(\r\n\t\t\t\t\"A quiz needs at least one assessed step\",\r\n\t\t\t);\r\n\t\t});\r\n\r\n\t\tit(\"does not flag a quiz that has assessed steps, nor an all-instructional training procedure\", () => {\r\n\t\t\t// The mixed quiz has assessed steps → no authoring message.\r\n\t\t\texpect(procedureEntity.getAuthoringValidationMessage()).toBeNull();\r\n\r\n\t\t\t// All-instructional, but training mode is never a quiz problem.\r\n\t\t\tprocedureEntity.removeEventId(\"lever\");\r\n\t\t\tprocedureEntity.removeEventId(\"valve\");\r\n\t\t\tprocedureEntity.setIsQuiz(false);\r\n\t\t\texpect(procedureEntity.getAuthoringValidationMessage()).toBeNull();\r\n\t\t});\r\n\t});\r\n});\r\n"]}
@@ -1,5 +1,6 @@
1
1
  import { DomainFactory } from "@vived/core";
2
2
  import { ChallengeEntity } from "../../Challenge";
3
+ import { EventEntity } from "../../EventSystem/Entities/EventEntity";
3
4
  import { makeProcedureEntity, ProcedureEntity, } from "../Entities/ProcedureEntity";
4
5
  import { makeHintRegistry } from "../Entities/HintRegistry";
5
6
  import { makeAddProcedureEventUC } from "../UCs/AddProcedureEventUC";
@@ -44,8 +45,27 @@ export class ProcedureFeatureFactory extends DomainFactory {
44
45
  makeProcedurePM(this.appObject);
45
46
  }
46
47
  finalSetup() {
48
+ this.wireEventCategoryLookup();
47
49
  this.registerProcedureChallenge();
48
50
  }
51
+ /**
52
+ * Classification is derived at evaluation time from the EventSystem Registry
53
+ * (#53): hand the entity a lookup rather than copying categories into it, so
54
+ * events registered later (and slides authored earlier) are classified too.
55
+ */
56
+ wireEventCategoryLookup() {
57
+ const procedureEntity = this.getProcedureEntity();
58
+ if (!procedureEntity) {
59
+ this.warn("ProcedureEntity not found - cannot wire event categories");
60
+ return;
61
+ }
62
+ const eventEntity = EventEntity.get(this.appObjects);
63
+ if (!eventEntity) {
64
+ this.warn("EventEntity not found - every procedure step will be treated as assessed");
65
+ return;
66
+ }
67
+ procedureEntity.setEventCategoryLookup((eventId) => eventEntity.getEventCategory(eventId));
68
+ }
49
69
  registerProcedureChallenge() {
50
70
  const challengeEntity = ChallengeEntity.get(this.appObjects);
51
71
  const procedureEntity = this.getProcedureEntity();
@@ -1 +1 @@
1
- {"version":3,"file":"ProcedureFeatureFactory.js","sourceRoot":"","sources":["../../../../src/Procedure/Factories/ProcedureFeatureFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import { DomainFactory, AppObjectRepo } from \"@vived/core\";\r\nimport { ChallengeEntity } from \"../../Challenge\";\r\nimport {\r\n makeProcedureEntity,\r\n ProcedureEntity,\r\n} from \"../Entities/ProcedureEntity\";\r\nimport { makeHintRegistry } from \"../Entities/HintRegistry\";\r\nimport { makeAddProcedureEventUC } from \"../UCs/AddProcedureEventUC\";\r\nimport { makeRecordProcedureEventUC } from \"../UCs/RecordProcedureEventUC\";\r\nimport { makeResetProcedureProgressUC } from \"../UCs/ResetProcedureProgressUC\";\r\nimport { makeSerializeProcedure } from \"../UCs/SerializeProcedure\";\r\nimport { makeRemoveProcedureEventUC } from \"../UCs/RemoveProcedureEventUC\";\r\nimport { makeMoveProcedureEventUpUC } from \"../UCs/MoveProcedureEventUpUC\";\r\nimport { makeMoveProcedureEventDownUC } from \"../UCs/MoveProcedureEventDownUC\";\r\nimport { makeSetProcedureOrderMattersUC } from \"../UCs/SetProcedureOrderMattersUC\";\r\nimport { makeSetProcedureShowHintsUC } from \"../UCs/SetProcedureShowHintsUC\";\r\nimport { makeSetProcedureIsQuizUC } from \"../UCs/SetProcedureIsQuizUC\";\r\nimport { makeSubmitProcedureQuizUC } from \"../UCs/SubmitProcedureQuizUC\";\r\nimport { makeUpdateProcedureEventsUCHook } from \"../UCs/UpdateProcedureEventsUCHook\";\r\nimport { makeRecordProcedureSessionUC } from \"../UCs/RecordProcedureSessionUC\";\r\nimport { makeProcedurePM, ProcedurePM } from \"../PM/ProcedurePM\";\r\n\r\nexport class ProcedureFeatureFactory extends DomainFactory {\r\n factoryName = \"ProcedureFeatureFactory\";\r\n\r\n setupEntities(): void {\r\n makeProcedureEntity(this.appObject);\r\n makeHintRegistry(this.appObject);\r\n }\r\n\r\n setupUCs(): void {\r\n makeAddProcedureEventUC(this.appObject);\r\n makeRecordProcedureEventUC(this.appObject);\r\n makeResetProcedureProgressUC(this.appObject);\r\n makeSerializeProcedure(this.appObject);\r\n makeRemoveProcedureEventUC(this.appObject);\r\n makeMoveProcedureEventUpUC(this.appObject);\r\n makeMoveProcedureEventDownUC(this.appObject);\r\n makeSetProcedureOrderMattersUC(this.appObject);\r\n makeSetProcedureShowHintsUC(this.appObject);\r\n makeSetProcedureIsQuizUC(this.appObject);\r\n makeSubmitProcedureQuizUC(this.appObject);\r\n makeUpdateProcedureEventsUCHook(this.appObject);\r\n makeRecordProcedureSessionUC(this.appObject);\r\n }\r\n\r\n setupPMs(): void {\r\n makeProcedurePM(this.appObject);\r\n }\r\n\r\n finalSetup(): void {\r\n this.registerProcedureChallenge();\r\n }\r\n\r\n private registerProcedureChallenge(): void {\r\n const challengeEntity = ChallengeEntity.get(this.appObjects);\r\n const procedureEntity = this.getProcedureEntity();\r\n\r\n if (!challengeEntity) {\r\n this.warn(\r\n \"ChallengeEntity not found - Procedure challenge will not be available in selection\",\r\n );\r\n return;\r\n }\r\n\r\n if (!procedureEntity) {\r\n this.warn(\"ProcedureEntity not found - cannot register challenge\");\r\n return;\r\n }\r\n\r\n try {\r\n challengeEntity.registerChallenge(procedureEntity);\r\n } catch (error) {\r\n this.warn(`Failed to register Procedure challenge: ${error}`);\r\n }\r\n }\r\n\r\n getProcedureEntity(): ProcedureEntity | undefined {\r\n return ProcedureEntity.get(this.appObjects);\r\n }\r\n\r\n getProcedurePM(): ProcedurePM | undefined {\r\n return ProcedurePM.get(this.appObjects);\r\n }\r\n}\r\n\r\nexport const ProcedureFeatureComponents = {\r\n procedureEntityType: ProcedureEntity.type,\r\n procedurePMType: ProcedurePM.type,\r\n};\r\n\r\nexport function makeProcedureFeatureFactory(\r\n appObjects: AppObjectRepo,\r\n): ProcedureFeatureFactory {\r\n const appObject = appObjects.getOrCreate(\"Procedure\");\r\n return new ProcedureFeatureFactory(appObject);\r\n}\r\n"]}
1
+ {"version":3,"file":"ProcedureFeatureFactory.js","sourceRoot":"","sources":["../../../../src/Procedure/Factories/ProcedureFeatureFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import { DomainFactory, AppObjectRepo } from \"@vived/core\";\r\nimport { ChallengeEntity } from \"../../Challenge\";\r\nimport { EventEntity } from \"../../EventSystem/Entities/EventEntity\";\r\nimport {\r\n makeProcedureEntity,\r\n ProcedureEntity,\r\n} from \"../Entities/ProcedureEntity\";\r\nimport { makeHintRegistry } from \"../Entities/HintRegistry\";\r\nimport { makeAddProcedureEventUC } from \"../UCs/AddProcedureEventUC\";\r\nimport { makeRecordProcedureEventUC } from \"../UCs/RecordProcedureEventUC\";\r\nimport { makeResetProcedureProgressUC } from \"../UCs/ResetProcedureProgressUC\";\r\nimport { makeSerializeProcedure } from \"../UCs/SerializeProcedure\";\r\nimport { makeRemoveProcedureEventUC } from \"../UCs/RemoveProcedureEventUC\";\r\nimport { makeMoveProcedureEventUpUC } from \"../UCs/MoveProcedureEventUpUC\";\r\nimport { makeMoveProcedureEventDownUC } from \"../UCs/MoveProcedureEventDownUC\";\r\nimport { makeSetProcedureOrderMattersUC } from \"../UCs/SetProcedureOrderMattersUC\";\r\nimport { makeSetProcedureShowHintsUC } from \"../UCs/SetProcedureShowHintsUC\";\r\nimport { makeSetProcedureIsQuizUC } from \"../UCs/SetProcedureIsQuizUC\";\r\nimport { makeSubmitProcedureQuizUC } from \"../UCs/SubmitProcedureQuizUC\";\r\nimport { makeUpdateProcedureEventsUCHook } from \"../UCs/UpdateProcedureEventsUCHook\";\r\nimport { makeRecordProcedureSessionUC } from \"../UCs/RecordProcedureSessionUC\";\r\nimport { makeProcedurePM, ProcedurePM } from \"../PM/ProcedurePM\";\r\n\r\nexport class ProcedureFeatureFactory extends DomainFactory {\r\n factoryName = \"ProcedureFeatureFactory\";\r\n\r\n setupEntities(): void {\r\n makeProcedureEntity(this.appObject);\r\n makeHintRegistry(this.appObject);\r\n }\r\n\r\n setupUCs(): void {\r\n makeAddProcedureEventUC(this.appObject);\r\n makeRecordProcedureEventUC(this.appObject);\r\n makeResetProcedureProgressUC(this.appObject);\r\n makeSerializeProcedure(this.appObject);\r\n makeRemoveProcedureEventUC(this.appObject);\r\n makeMoveProcedureEventUpUC(this.appObject);\r\n makeMoveProcedureEventDownUC(this.appObject);\r\n makeSetProcedureOrderMattersUC(this.appObject);\r\n makeSetProcedureShowHintsUC(this.appObject);\r\n makeSetProcedureIsQuizUC(this.appObject);\r\n makeSubmitProcedureQuizUC(this.appObject);\r\n makeUpdateProcedureEventsUCHook(this.appObject);\r\n makeRecordProcedureSessionUC(this.appObject);\r\n }\r\n\r\n setupPMs(): void {\r\n makeProcedurePM(this.appObject);\r\n }\r\n\r\n finalSetup(): void {\r\n this.wireEventCategoryLookup();\r\n this.registerProcedureChallenge();\r\n }\r\n\r\n /**\r\n * Classification is derived at evaluation time from the EventSystem Registry\r\n * (#53): hand the entity a lookup rather than copying categories into it, so\r\n * events registered later (and slides authored earlier) are classified too.\r\n */\r\n private wireEventCategoryLookup(): void {\r\n const procedureEntity = this.getProcedureEntity();\r\n if (!procedureEntity) {\r\n this.warn(\"ProcedureEntity not found - cannot wire event categories\");\r\n return;\r\n }\r\n\r\n const eventEntity = EventEntity.get(this.appObjects);\r\n if (!eventEntity) {\r\n this.warn(\r\n \"EventEntity not found - every procedure step will be treated as assessed\",\r\n );\r\n return;\r\n }\r\n\r\n procedureEntity.setEventCategoryLookup((eventId) =>\r\n eventEntity.getEventCategory(eventId),\r\n );\r\n }\r\n\r\n private registerProcedureChallenge(): void {\r\n const challengeEntity = ChallengeEntity.get(this.appObjects);\r\n const procedureEntity = this.getProcedureEntity();\r\n\r\n if (!challengeEntity) {\r\n this.warn(\r\n \"ChallengeEntity not found - Procedure challenge will not be available in selection\",\r\n );\r\n return;\r\n }\r\n\r\n if (!procedureEntity) {\r\n this.warn(\"ProcedureEntity not found - cannot register challenge\");\r\n return;\r\n }\r\n\r\n try {\r\n challengeEntity.registerChallenge(procedureEntity);\r\n } catch (error) {\r\n this.warn(`Failed to register Procedure challenge: ${error}`);\r\n }\r\n }\r\n\r\n getProcedureEntity(): ProcedureEntity | undefined {\r\n return ProcedureEntity.get(this.appObjects);\r\n }\r\n\r\n getProcedurePM(): ProcedurePM | undefined {\r\n return ProcedurePM.get(this.appObjects);\r\n }\r\n}\r\n\r\nexport const ProcedureFeatureComponents = {\r\n procedureEntityType: ProcedureEntity.type,\r\n procedurePMType: ProcedurePM.type,\r\n};\r\n\r\nexport function makeProcedureFeatureFactory(\r\n appObjects: AppObjectRepo,\r\n): ProcedureFeatureFactory {\r\n const appObject = appObjects.getOrCreate(\"Procedure\");\r\n return new ProcedureFeatureFactory(appObject);\r\n}\r\n"]}
@@ -1,6 +1,6 @@
1
1
  import { makeAppObjectRepo, DomainFactoryRepo } from "@vived/core";
2
2
  import { ChallengeEntity } from "../../Challenge";
3
- import { makeEventEntity } from "../../EventSystem/Entities/EventEntity";
3
+ import { EventEntity, makeEventEntity } from "../../EventSystem/Entities/EventEntity";
4
4
  import { makeProcedureFeatureFactory, ProcedureFeatureFactory, } from "./ProcedureFeatureFactory";
5
5
  import { ProcedureEntity } from "../Entities/ProcedureEntity";
6
6
  import { AddProcedureEventUC } from "../UCs/AddProcedureEventUC";
@@ -98,6 +98,31 @@ describe("ProcedureFeatureFactory", () => {
98
98
  it("registers procedure challenge with ChallengeEntity", () => {
99
99
  expect(mockRegisterChallenge).toHaveBeenCalledWith(factory.getProcedureEntity());
100
100
  });
101
+ it("injects the EventEntity category lookup into the entity (#53)", () => {
102
+ const eventEntity = EventEntity.get(appObjects);
103
+ const entity = factory.getProcedureEntity();
104
+ // Registered after setup: the lookup is evaluated at call time, not cached.
105
+ eventEntity.register("navigate-to-overhead", "Go to overhead", {
106
+ category: "instructional",
107
+ });
108
+ eventEntity.register("lever", "Pull lever");
109
+ expect(entity.getEventCategory("navigate-to-overhead")).toBe("instructional");
110
+ expect(entity.getEventCategory("lever")).toBe("assessed");
111
+ expect(entity.getEventCategory("never-registered")).toBe("assessed");
112
+ });
113
+ it("warns and falls back to an assessed lookup when EventEntity is absent (#53)", () => {
114
+ const submitWarningSpy = jest.fn();
115
+ const newAppObjects = makeAppObjectRepo();
116
+ newAppObjects.submitWarning = submitWarningSpy;
117
+ // No EventEntity registered on this repo: the category lookup cannot wire.
118
+ const newDomainFactoryRepo = new DomainFactoryRepo(newAppObjects.getOrCreate("DomainFactory"));
119
+ const newFactory = makeProcedureFeatureFactory(newAppObjects);
120
+ newDomainFactoryRepo.setupDomain();
121
+ expect(submitWarningSpy).toHaveBeenCalledWith(expect.stringContaining("Procedure"), expect.stringContaining("EventEntity not found"));
122
+ // The entity keeps its default lookup, so every step is treated as assessed.
123
+ const entity = newFactory.getProcedureEntity();
124
+ expect(entity.getEventCategory("anything")).toBe("assessed");
125
+ });
101
126
  it("handles missing ChallengeEntity gracefully", () => {
102
127
  jest.mocked(ChallengeEntity.get).mockReturnValueOnce(undefined);
103
128
  const submitWarningSpy = jest.fn();
@@ -1 +1 @@
1
- {"version":3,"file":"ProcedureFeatureFactory.test.js","sourceRoot":"","sources":["../../../../src/Procedure/Factories/ProcedureFeatureFactory.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObjectRepo, makeAppObjectRepo, DomainFactoryRepo } from \"@vived/core\";\r\nimport { ChallengeEntity } from \"../../Challenge\";\r\nimport { makeEventEntity } from \"../../EventSystem/Entities/EventEntity\";\r\nimport {\r\n makeProcedureFeatureFactory,\r\n ProcedureFeatureFactory,\r\n} from \"./ProcedureFeatureFactory\";\r\nimport { ProcedureEntity } from \"../Entities/ProcedureEntity\";\r\nimport { AddProcedureEventUC } from \"../UCs/AddProcedureEventUC\";\r\nimport { SerializeProcedure } from \"../UCs/SerializeProcedure\";\r\nimport { SetProcedureOrderMattersUC } from \"../UCs/SetProcedureOrderMattersUC\";\r\nimport { SetProcedureShowHintsUC } from \"../UCs/SetProcedureShowHintsUC\";\r\nimport { SetProcedureIsQuizUC } from \"../UCs/SetProcedureIsQuizUC\";\r\n\r\njest.mock(\"../../Challenge\", () => ({\r\n ChallengeEntity: {\r\n get: jest.fn(),\r\n },\r\n}));\r\n\r\nconst mockRegisterChallenge = jest.fn();\r\nconst mockChallengeEntityInstance = {\r\n registerChallenge: mockRegisterChallenge,\r\n addChangeObserver: jest.fn(),\r\n removeChangeObserver: jest.fn(),\r\n selectedChallenge: null,\r\n};\r\n\r\ndescribe(\"ProcedureFeatureFactory\", () => {\r\n let appObjects: AppObjectRepo;\r\n let domainFactoryRepo: DomainFactoryRepo;\r\n let factory: ProcedureFeatureFactory;\r\n\r\n beforeEach(() => {\r\n jest.clearAllMocks();\r\n\r\n jest.mocked(ChallengeEntity.get).mockReturnValue(\r\n mockChallengeEntityInstance as any,\r\n );\r\n\r\n appObjects = makeAppObjectRepo();\r\n\r\n // Create a real EventEntity singleton so PM and UCs can find it\r\n const eventAppObject = appObjects.getOrCreate(\"EventSystem\");\r\n const eventEntity = makeEventEntity(eventAppObject);\r\n appObjects.registerSingleton(eventEntity);\r\n\r\n domainFactoryRepo = new DomainFactoryRepo(\r\n appObjects.getOrCreate(\"DomainFactory\"),\r\n );\r\n factory = makeProcedureFeatureFactory(appObjects);\r\n\r\n domainFactoryRepo.setupDomain();\r\n });\r\n\r\n it(\"creates factory with correct name\", () => {\r\n expect(factory.factoryName).toBe(\"ProcedureFeatureFactory\");\r\n });\r\n\r\n it(\"uses correct AppObject name\", () => {\r\n const procedureAppObject = appObjects.getOrCreate(\"Procedure\");\r\n expect(procedureAppObject).toBeDefined();\r\n });\r\n\r\n it(\"creates ProcedureEntity singleton\", () => {\r\n expect(factory.getProcedureEntity()).toBeDefined();\r\n expect(factory.getProcedureEntity()?.challengeID).toBe(\"PROCEDURE\");\r\n });\r\n\r\n it(\"registers ProcedureEntity as singleton\", () => {\r\n const entity = ProcedureEntity.get(appObjects);\r\n expect(entity).toBeDefined();\r\n expect(entity).toBe(factory.getProcedureEntity());\r\n });\r\n\r\n it(\"creates all required Use Cases\", () => {\r\n const addEventUC = AddProcedureEventUC.get(appObjects);\r\n expect(addEventUC).toBeDefined();\r\n\r\n const serializeUC = SerializeProcedure.get(appObjects);\r\n expect(serializeUC).toBeDefined();\r\n\r\n const setOrderMattersUC = SetProcedureOrderMattersUC.get(appObjects);\r\n expect(setOrderMattersUC).toBeDefined();\r\n\r\n const setShowHintsUC = SetProcedureShowHintsUC.get(appObjects);\r\n expect(setShowHintsUC).toBeDefined();\r\n\r\n const setIsQuizUC = SetProcedureIsQuizUC.get(appObjects);\r\n expect(setIsQuizUC).toBeDefined();\r\n });\r\n\r\n it(\"Use Cases can find their entity\", () => {\r\n const addEventUC = AddProcedureEventUC.get(appObjects);\r\n const entity = factory.getProcedureEntity();\r\n\r\n addEventUC!.addEvent(\"test_event\");\r\n expect(entity!.eventIds).toContain(\"test_event\");\r\n });\r\n\r\n it(\"configuration Use Cases can modify entity properties\", () => {\r\n const entity = factory.getProcedureEntity()!;\r\n const setOrderMattersUC = SetProcedureOrderMattersUC.get(appObjects)!;\r\n const setShowHintsUC = SetProcedureShowHintsUC.get(appObjects)!;\r\n const setIsQuizUC = SetProcedureIsQuizUC.get(appObjects)!;\r\n\r\n expect(entity.orderMatters).toBe(true);\r\n expect(entity.showHints).toBe(true);\r\n expect(entity.isQuiz).toBe(false);\r\n\r\n setOrderMattersUC.setOrderMatters(false);\r\n expect(entity.orderMatters).toBe(false);\r\n\r\n setShowHintsUC.setShowHints(false);\r\n expect(entity.showHints).toBe(false);\r\n\r\n setIsQuizUC.setIsQuiz(true);\r\n expect(entity.isQuiz).toBe(true);\r\n });\r\n\r\n it(\"creates ProcedurePM singleton\", () => {\r\n expect(factory.getProcedurePM()).toBeDefined();\r\n });\r\n\r\n it(\"PM can access entity state\", () => {\r\n const pm = factory.getProcedurePM();\r\n const entity = factory.getProcedureEntity();\r\n\r\n entity!.addEventId(\"test_event\");\r\n\r\n const vm = pm!.lastVM;\r\n expect(vm!.eventIds).toContain(\"test_event\");\r\n });\r\n\r\n it(\"registers procedure challenge with ChallengeEntity\", () => {\r\n expect(mockRegisterChallenge).toHaveBeenCalledWith(\r\n factory.getProcedureEntity(),\r\n );\r\n });\r\n\r\n it(\"handles missing ChallengeEntity gracefully\", () => {\r\n jest.mocked(ChallengeEntity.get).mockReturnValueOnce(undefined);\r\n\r\n const submitWarningSpy = jest.fn();\r\n const newAppObjects = makeAppObjectRepo();\r\n newAppObjects.submitWarning = submitWarningSpy;\r\n\r\n const newDomainFactoryRepo = new DomainFactoryRepo(\r\n newAppObjects.getOrCreate(\"DomainFactory\"),\r\n );\r\n makeProcedureFeatureFactory(newAppObjects);\r\n newDomainFactoryRepo.setupDomain();\r\n\r\n expect(submitWarningSpy).toHaveBeenCalledWith(\r\n expect.stringContaining(\"Procedure\"),\r\n expect.stringContaining(\"ChallengeEntity not found\"),\r\n );\r\n });\r\n\r\n it(\"all components can communicate\", () => {\r\n const entity = factory.getProcedureEntity()!;\r\n const pm = factory.getProcedurePM()!;\r\n const addEventUC = AddProcedureEventUC.get(appObjects)!;\r\n\r\n addEventUC.addEvent(\"integration_test_event\");\r\n\r\n expect(entity.eventIds).toContain(\"integration_test_event\");\r\n\r\n const vm = pm.lastVM!;\r\n expect(vm.eventIds).toContain(\"integration_test_event\");\r\n });\r\n\r\n it(\"provides access to created components\", () => {\r\n expect(factory.getProcedureEntity()).toBeInstanceOf(Object);\r\n expect(factory.getProcedurePM()).toBeInstanceOf(Object);\r\n });\r\n\r\n it(\"returns undefined for components when not properly initialized\", () => {\r\n const isolatedAppObjects = makeAppObjectRepo();\r\n const isolatedAppObject = isolatedAppObjects.getOrCreate(\"Isolated\");\r\n const isolatedFactory = new ProcedureFeatureFactory(isolatedAppObject);\r\n\r\n expect(isolatedFactory.getProcedureEntity()).toBeUndefined();\r\n });\r\n});\r\n"]}
1
+ {"version":3,"file":"ProcedureFeatureFactory.test.js","sourceRoot":"","sources":["../../../../src/Procedure/Factories/ProcedureFeatureFactory.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObjectRepo, makeAppObjectRepo, DomainFactoryRepo } from \"@vived/core\";\r\nimport { ChallengeEntity } from \"../../Challenge\";\r\nimport { EventEntity, makeEventEntity } from \"../../EventSystem/Entities/EventEntity\";\r\nimport {\r\n makeProcedureFeatureFactory,\r\n ProcedureFeatureFactory,\r\n} from \"./ProcedureFeatureFactory\";\r\nimport { ProcedureEntity } from \"../Entities/ProcedureEntity\";\r\nimport { AddProcedureEventUC } from \"../UCs/AddProcedureEventUC\";\r\nimport { SerializeProcedure } from \"../UCs/SerializeProcedure\";\r\nimport { SetProcedureOrderMattersUC } from \"../UCs/SetProcedureOrderMattersUC\";\r\nimport { SetProcedureShowHintsUC } from \"../UCs/SetProcedureShowHintsUC\";\r\nimport { SetProcedureIsQuizUC } from \"../UCs/SetProcedureIsQuizUC\";\r\n\r\njest.mock(\"../../Challenge\", () => ({\r\n ChallengeEntity: {\r\n get: jest.fn(),\r\n },\r\n}));\r\n\r\nconst mockRegisterChallenge = jest.fn();\r\nconst mockChallengeEntityInstance = {\r\n registerChallenge: mockRegisterChallenge,\r\n addChangeObserver: jest.fn(),\r\n removeChangeObserver: jest.fn(),\r\n selectedChallenge: null,\r\n};\r\n\r\ndescribe(\"ProcedureFeatureFactory\", () => {\r\n let appObjects: AppObjectRepo;\r\n let domainFactoryRepo: DomainFactoryRepo;\r\n let factory: ProcedureFeatureFactory;\r\n\r\n beforeEach(() => {\r\n jest.clearAllMocks();\r\n\r\n jest.mocked(ChallengeEntity.get).mockReturnValue(\r\n mockChallengeEntityInstance as any,\r\n );\r\n\r\n appObjects = makeAppObjectRepo();\r\n\r\n // Create a real EventEntity singleton so PM and UCs can find it\r\n const eventAppObject = appObjects.getOrCreate(\"EventSystem\");\r\n const eventEntity = makeEventEntity(eventAppObject);\r\n appObjects.registerSingleton(eventEntity);\r\n\r\n domainFactoryRepo = new DomainFactoryRepo(\r\n appObjects.getOrCreate(\"DomainFactory\"),\r\n );\r\n factory = makeProcedureFeatureFactory(appObjects);\r\n\r\n domainFactoryRepo.setupDomain();\r\n });\r\n\r\n it(\"creates factory with correct name\", () => {\r\n expect(factory.factoryName).toBe(\"ProcedureFeatureFactory\");\r\n });\r\n\r\n it(\"uses correct AppObject name\", () => {\r\n const procedureAppObject = appObjects.getOrCreate(\"Procedure\");\r\n expect(procedureAppObject).toBeDefined();\r\n });\r\n\r\n it(\"creates ProcedureEntity singleton\", () => {\r\n expect(factory.getProcedureEntity()).toBeDefined();\r\n expect(factory.getProcedureEntity()?.challengeID).toBe(\"PROCEDURE\");\r\n });\r\n\r\n it(\"registers ProcedureEntity as singleton\", () => {\r\n const entity = ProcedureEntity.get(appObjects);\r\n expect(entity).toBeDefined();\r\n expect(entity).toBe(factory.getProcedureEntity());\r\n });\r\n\r\n it(\"creates all required Use Cases\", () => {\r\n const addEventUC = AddProcedureEventUC.get(appObjects);\r\n expect(addEventUC).toBeDefined();\r\n\r\n const serializeUC = SerializeProcedure.get(appObjects);\r\n expect(serializeUC).toBeDefined();\r\n\r\n const setOrderMattersUC = SetProcedureOrderMattersUC.get(appObjects);\r\n expect(setOrderMattersUC).toBeDefined();\r\n\r\n const setShowHintsUC = SetProcedureShowHintsUC.get(appObjects);\r\n expect(setShowHintsUC).toBeDefined();\r\n\r\n const setIsQuizUC = SetProcedureIsQuizUC.get(appObjects);\r\n expect(setIsQuizUC).toBeDefined();\r\n });\r\n\r\n it(\"Use Cases can find their entity\", () => {\r\n const addEventUC = AddProcedureEventUC.get(appObjects);\r\n const entity = factory.getProcedureEntity();\r\n\r\n addEventUC!.addEvent(\"test_event\");\r\n expect(entity!.eventIds).toContain(\"test_event\");\r\n });\r\n\r\n it(\"configuration Use Cases can modify entity properties\", () => {\r\n const entity = factory.getProcedureEntity()!;\r\n const setOrderMattersUC = SetProcedureOrderMattersUC.get(appObjects)!;\r\n const setShowHintsUC = SetProcedureShowHintsUC.get(appObjects)!;\r\n const setIsQuizUC = SetProcedureIsQuizUC.get(appObjects)!;\r\n\r\n expect(entity.orderMatters).toBe(true);\r\n expect(entity.showHints).toBe(true);\r\n expect(entity.isQuiz).toBe(false);\r\n\r\n setOrderMattersUC.setOrderMatters(false);\r\n expect(entity.orderMatters).toBe(false);\r\n\r\n setShowHintsUC.setShowHints(false);\r\n expect(entity.showHints).toBe(false);\r\n\r\n setIsQuizUC.setIsQuiz(true);\r\n expect(entity.isQuiz).toBe(true);\r\n });\r\n\r\n it(\"creates ProcedurePM singleton\", () => {\r\n expect(factory.getProcedurePM()).toBeDefined();\r\n });\r\n\r\n it(\"PM can access entity state\", () => {\r\n const pm = factory.getProcedurePM();\r\n const entity = factory.getProcedureEntity();\r\n\r\n entity!.addEventId(\"test_event\");\r\n\r\n const vm = pm!.lastVM;\r\n expect(vm!.eventIds).toContain(\"test_event\");\r\n });\r\n\r\n it(\"registers procedure challenge with ChallengeEntity\", () => {\r\n expect(mockRegisterChallenge).toHaveBeenCalledWith(\r\n factory.getProcedureEntity(),\r\n );\r\n });\r\n\r\n it(\"injects the EventEntity category lookup into the entity (#53)\", () => {\r\n const eventEntity = EventEntity.get(appObjects)!;\r\n const entity = factory.getProcedureEntity()!;\r\n\r\n // Registered after setup: the lookup is evaluated at call time, not cached.\r\n eventEntity.register(\"navigate-to-overhead\", \"Go to overhead\", {\r\n category: \"instructional\",\r\n });\r\n eventEntity.register(\"lever\", \"Pull lever\");\r\n\r\n expect(entity.getEventCategory(\"navigate-to-overhead\")).toBe(\r\n \"instructional\",\r\n );\r\n expect(entity.getEventCategory(\"lever\")).toBe(\"assessed\");\r\n expect(entity.getEventCategory(\"never-registered\")).toBe(\"assessed\");\r\n });\r\n\r\n it(\"warns and falls back to an assessed lookup when EventEntity is absent (#53)\", () => {\r\n const submitWarningSpy = jest.fn();\r\n const newAppObjects = makeAppObjectRepo();\r\n newAppObjects.submitWarning = submitWarningSpy;\r\n\r\n // No EventEntity registered on this repo: the category lookup cannot wire.\r\n const newDomainFactoryRepo = new DomainFactoryRepo(\r\n newAppObjects.getOrCreate(\"DomainFactory\"),\r\n );\r\n const newFactory = makeProcedureFeatureFactory(newAppObjects);\r\n newDomainFactoryRepo.setupDomain();\r\n\r\n expect(submitWarningSpy).toHaveBeenCalledWith(\r\n expect.stringContaining(\"Procedure\"),\r\n expect.stringContaining(\"EventEntity not found\"),\r\n );\r\n\r\n // The entity keeps its default lookup, so every step is treated as assessed.\r\n const entity = newFactory.getProcedureEntity()!;\r\n expect(entity.getEventCategory(\"anything\")).toBe(\"assessed\");\r\n });\r\n\r\n it(\"handles missing ChallengeEntity gracefully\", () => {\r\n jest.mocked(ChallengeEntity.get).mockReturnValueOnce(undefined);\r\n\r\n const submitWarningSpy = jest.fn();\r\n const newAppObjects = makeAppObjectRepo();\r\n newAppObjects.submitWarning = submitWarningSpy;\r\n\r\n const newDomainFactoryRepo = new DomainFactoryRepo(\r\n newAppObjects.getOrCreate(\"DomainFactory\"),\r\n );\r\n makeProcedureFeatureFactory(newAppObjects);\r\n newDomainFactoryRepo.setupDomain();\r\n\r\n expect(submitWarningSpy).toHaveBeenCalledWith(\r\n expect.stringContaining(\"Procedure\"),\r\n expect.stringContaining(\"ChallengeEntity not found\"),\r\n );\r\n });\r\n\r\n it(\"all components can communicate\", () => {\r\n const entity = factory.getProcedureEntity()!;\r\n const pm = factory.getProcedurePM()!;\r\n const addEventUC = AddProcedureEventUC.get(appObjects)!;\r\n\r\n addEventUC.addEvent(\"integration_test_event\");\r\n\r\n expect(entity.eventIds).toContain(\"integration_test_event\");\r\n\r\n const vm = pm.lastVM!;\r\n expect(vm.eventIds).toContain(\"integration_test_event\");\r\n });\r\n\r\n it(\"provides access to created components\", () => {\r\n expect(factory.getProcedureEntity()).toBeInstanceOf(Object);\r\n expect(factory.getProcedurePM()).toBeInstanceOf(Object);\r\n });\r\n\r\n it(\"returns undefined for components when not properly initialized\", () => {\r\n const isolatedAppObjects = makeAppObjectRepo();\r\n const isolatedAppObject = isolatedAppObjects.getOrCreate(\"Isolated\");\r\n const isolatedFactory = new ProcedureFeatureFactory(isolatedAppObject);\r\n\r\n expect(isolatedFactory.getProcedureEntity()).toBeUndefined();\r\n });\r\n});\r\n"]}
@@ -81,6 +81,8 @@ export class MockProcedureEntity extends ProcedureEntity {
81
81
  this.setIsRecording = jest.fn((v) => {
82
82
  this._isRecording = v;
83
83
  });
84
+ this.setEventCategoryLookup = jest.fn();
85
+ this.getEventCategory = jest.fn(() => "assessed");
84
86
  this.getProgressPercentage = jest.fn(() => 0);
85
87
  this.calculateScore = jest.fn(() => ({ percentage: 0, comparison: [] }));
86
88
  this.submit = jest.fn();