@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.
- package/dist/cjs/BaseApp/UC/RenderCanvasUC.js +17 -36
- package/dist/cjs/BaseApp/UC/RenderCanvasUC.js.map +1 -1
- package/dist/cjs/BaseApp/UC/RenderCanvasUC.test.js +18 -18
- package/dist/cjs/BaseApp/UC/RenderCanvasUC.test.js.map +1 -1
- package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.js +9 -28
- package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.js.map +1 -1
- package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.test.js +51 -0
- package/dist/cjs/Challenge/Factories/ChallengeFeatureFactory.test.js.map +1 -0
- package/dist/cjs/EventSystem/Entities/EventEntity.js +12 -2
- package/dist/cjs/EventSystem/Entities/EventEntity.js.map +1 -1
- package/dist/cjs/EventSystem/Entities/EventEntity.test.js +45 -0
- package/dist/cjs/EventSystem/Entities/EventEntity.test.js.map +1 -1
- package/dist/cjs/EventSystem/Mocks/MockEventEntity.js +7 -2
- package/dist/cjs/EventSystem/Mocks/MockEventEntity.js.map +1 -1
- package/dist/cjs/EventSystem/types.js.map +1 -1
- package/dist/cjs/ObjectPick/Factories/setupObjectPick.js +18 -1
- package/dist/cjs/ObjectPick/Factories/setupObjectPick.js.map +1 -1
- package/dist/cjs/ObjectPick/Factories/setupObjectPick.test.js +55 -0
- package/dist/cjs/ObjectPick/Factories/setupObjectPick.test.js.map +1 -0
- package/dist/cjs/Procedure/Adapters/procedureAdapter.js +1 -0
- package/dist/cjs/Procedure/Adapters/procedureAdapter.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureAdapter.test.js +1 -0
- package/dist/cjs/Procedure/Adapters/procedureAdapter.test.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.js +2 -0
- package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.test.js +3 -0
- package/dist/cjs/Procedure/Adapters/procedureAuthoringAdapter.test.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureHintAdapter.test.js +1 -0
- package/dist/cjs/Procedure/Adapters/procedureHintAdapter.test.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.js +2 -0
- package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.test.js +3 -0
- package/dist/cjs/Procedure/Adapters/procedureProgressAdapter.test.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.js +2 -0
- package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.js.map +1 -1
- package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.test.js +3 -0
- package/dist/cjs/Procedure/Adapters/procedureQuizResultAdapter.test.js.map +1 -1
- package/dist/cjs/Procedure/Entities/ProcedureEntity.js +163 -24
- package/dist/cjs/Procedure/Entities/ProcedureEntity.js.map +1 -1
- package/dist/cjs/Procedure/Entities/ProcedureEntity.test.js +240 -0
- package/dist/cjs/Procedure/Entities/ProcedureEntity.test.js.map +1 -1
- package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.js +20 -0
- package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.js.map +1 -1
- package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.test.js +25 -0
- package/dist/cjs/Procedure/Factories/ProcedureFeatureFactory.test.js.map +1 -1
- package/dist/cjs/Procedure/Mocks/MockProcedureEntity.js +2 -0
- package/dist/cjs/Procedure/Mocks/MockProcedureEntity.js.map +1 -1
- package/dist/cjs/Procedure/PM/ProcedurePM.js +13 -1
- package/dist/cjs/Procedure/PM/ProcedurePM.js.map +1 -1
- package/dist/cjs/Procedure/PM/ProcedurePM.test.js +34 -0
- package/dist/cjs/Procedure/PM/ProcedurePM.test.js.map +1 -1
- package/dist/cjs/Procedure/UCs/UpdateProcedureEventsUCHook.test.js +3 -0
- package/dist/cjs/Procedure/UCs/UpdateProcedureEventsUCHook.test.js.map +1 -1
- package/dist/cjs/Procedure/types.js.map +1 -1
- package/dist/cjs/TouchController/UC/UpdateTouchInoutBound.test.js +37 -0
- package/dist/cjs/TouchController/UC/UpdateTouchInoutBound.test.js.map +1 -1
- package/dist/cjs/TouchController/UC/UpdateTouchInputBound.js +17 -4
- package/dist/cjs/TouchController/UC/UpdateTouchInputBound.js.map +1 -1
- package/dist/esm/BaseApp/UC/RenderCanvasUC.js +17 -36
- package/dist/esm/BaseApp/UC/RenderCanvasUC.js.map +1 -1
- package/dist/esm/BaseApp/UC/RenderCanvasUC.test.js +18 -18
- package/dist/esm/BaseApp/UC/RenderCanvasUC.test.js.map +1 -1
- package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.js +9 -28
- package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.js.map +1 -1
- package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.test.js +49 -0
- package/dist/esm/Challenge/Factories/ChallengeFeatureFactory.test.js.map +1 -0
- package/dist/esm/EventSystem/Entities/EventEntity.js +12 -2
- package/dist/esm/EventSystem/Entities/EventEntity.js.map +1 -1
- package/dist/esm/EventSystem/Entities/EventEntity.test.js +45 -0
- package/dist/esm/EventSystem/Entities/EventEntity.test.js.map +1 -1
- package/dist/esm/EventSystem/Mocks/MockEventEntity.js +7 -2
- package/dist/esm/EventSystem/Mocks/MockEventEntity.js.map +1 -1
- package/dist/esm/EventSystem/types.js.map +1 -1
- package/dist/esm/ObjectPick/Factories/setupObjectPick.js +18 -1
- package/dist/esm/ObjectPick/Factories/setupObjectPick.js.map +1 -1
- package/dist/esm/ObjectPick/Factories/setupObjectPick.test.js +53 -0
- package/dist/esm/ObjectPick/Factories/setupObjectPick.test.js.map +1 -0
- package/dist/esm/Procedure/Adapters/procedureAdapter.js +1 -0
- package/dist/esm/Procedure/Adapters/procedureAdapter.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureAdapter.test.js +1 -0
- package/dist/esm/Procedure/Adapters/procedureAdapter.test.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.js +2 -0
- package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.test.js +3 -0
- package/dist/esm/Procedure/Adapters/procedureAuthoringAdapter.test.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureHintAdapter.test.js +1 -0
- package/dist/esm/Procedure/Adapters/procedureHintAdapter.test.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureProgressAdapter.js +2 -0
- package/dist/esm/Procedure/Adapters/procedureProgressAdapter.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureProgressAdapter.test.js +3 -0
- package/dist/esm/Procedure/Adapters/procedureProgressAdapter.test.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.js +2 -0
- package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.js.map +1 -1
- package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.test.js +3 -0
- package/dist/esm/Procedure/Adapters/procedureQuizResultAdapter.test.js.map +1 -1
- package/dist/esm/Procedure/Entities/ProcedureEntity.js +163 -24
- package/dist/esm/Procedure/Entities/ProcedureEntity.js.map +1 -1
- package/dist/esm/Procedure/Entities/ProcedureEntity.test.js +240 -0
- package/dist/esm/Procedure/Entities/ProcedureEntity.test.js.map +1 -1
- package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.js +20 -0
- package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.js.map +1 -1
- package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.test.js +26 -1
- package/dist/esm/Procedure/Factories/ProcedureFeatureFactory.test.js.map +1 -1
- package/dist/esm/Procedure/Mocks/MockProcedureEntity.js +2 -0
- package/dist/esm/Procedure/Mocks/MockProcedureEntity.js.map +1 -1
- package/dist/esm/Procedure/PM/ProcedurePM.js +13 -1
- package/dist/esm/Procedure/PM/ProcedurePM.js.map +1 -1
- package/dist/esm/Procedure/PM/ProcedurePM.test.js +34 -0
- package/dist/esm/Procedure/PM/ProcedurePM.test.js.map +1 -1
- package/dist/esm/Procedure/UCs/UpdateProcedureEventsUCHook.test.js +3 -0
- package/dist/esm/Procedure/UCs/UpdateProcedureEventsUCHook.test.js.map +1 -1
- package/dist/esm/Procedure/types.js.map +1 -1
- package/dist/esm/TouchController/UC/UpdateTouchInoutBound.test.js +37 -0
- package/dist/esm/TouchController/UC/UpdateTouchInoutBound.test.js.map +1 -1
- package/dist/esm/TouchController/UC/UpdateTouchInputBound.js +17 -4
- package/dist/esm/TouchController/UC/UpdateTouchInputBound.js.map +1 -1
- package/dist/types/Challenge/Factories/ChallengeFeatureFactory.d.ts +7 -16
- package/dist/types/Challenge/Factories/ChallengeFeatureFactory.d.ts.map +1 -1
- package/dist/types/Challenge/Factories/ChallengeFeatureFactory.test.d.ts +2 -0
- package/dist/types/Challenge/Factories/ChallengeFeatureFactory.test.d.ts.map +1 -0
- package/dist/types/EventSystem/Entities/EventEntity.d.ts +13 -2
- package/dist/types/EventSystem/Entities/EventEntity.d.ts.map +1 -1
- package/dist/types/EventSystem/Mocks/MockEventEntity.d.ts +3 -2
- package/dist/types/EventSystem/Mocks/MockEventEntity.d.ts.map +1 -1
- package/dist/types/EventSystem/types.d.ts +23 -0
- package/dist/types/EventSystem/types.d.ts.map +1 -1
- package/dist/types/ObjectPick/Factories/setupObjectPick.d.ts +10 -0
- package/dist/types/ObjectPick/Factories/setupObjectPick.d.ts.map +1 -1
- package/dist/types/ObjectPick/Factories/setupObjectPick.test.d.ts +2 -0
- package/dist/types/ObjectPick/Factories/setupObjectPick.test.d.ts.map +1 -0
- package/dist/types/Procedure/Adapters/procedureAdapter.d.ts.map +1 -1
- package/dist/types/Procedure/Adapters/procedureAuthoringAdapter.d.ts.map +1 -1
- package/dist/types/Procedure/Adapters/procedureProgressAdapter.d.ts.map +1 -1
- package/dist/types/Procedure/Adapters/procedureQuizResultAdapter.d.ts.map +1 -1
- package/dist/types/Procedure/Entities/ProcedureEntity.d.ts +10 -0
- package/dist/types/Procedure/Entities/ProcedureEntity.d.ts.map +1 -1
- package/dist/types/Procedure/Factories/ProcedureFeatureFactory.d.ts +6 -0
- package/dist/types/Procedure/Factories/ProcedureFeatureFactory.d.ts.map +1 -1
- package/dist/types/Procedure/Mocks/MockProcedureEntity.d.ts +3 -0
- package/dist/types/Procedure/Mocks/MockProcedureEntity.d.ts.map +1 -1
- package/dist/types/Procedure/types.d.ts +17 -1
- package/dist/types/Procedure/types.d.ts.map +1 -1
- package/dist/types/TouchController/UC/UpdateTouchInputBound.d.ts +11 -0
- package/dist/types/TouchController/UC/UpdateTouchInputBound.d.ts.map +1 -1
- package/package.json +6 -3
- package/src/EventSystem/CONTEXT.md +29 -17
- package/dist/cjs/FramedScreen/Factories/setupStandardFramedScreen.test.js +0 -31
- package/dist/cjs/FramedScreen/Factories/setupStandardFramedScreen.test.js.map +0 -1
- package/dist/cjs/StateMachine/Controller/clickRestoreScene.js +0 -14
- package/dist/cjs/StateMachine/Controller/clickRestoreScene.js.map +0 -1
- package/dist/cjs/StateMachine/Controller/clickRestoreScene.test.js +0 -26
- package/dist/cjs/StateMachine/Controller/clickRestoreScene.test.js.map +0 -1
- package/dist/cjs/TestUtils/index.js +0 -18
- package/dist/cjs/TestUtils/index.js.map +0 -1
- package/dist/cjs/TestUtils/setupFeatureForTesting.js +0 -60
- package/dist/cjs/TestUtils/setupFeatureForTesting.js.map +0 -1
- package/dist/esm/FramedScreen/Factories/setupStandardFramedScreen.test.js +0 -29
- package/dist/esm/FramedScreen/Factories/setupStandardFramedScreen.test.js.map +0 -1
- package/dist/esm/StateMachine/Controller/clickRestoreScene.js +0 -11
- package/dist/esm/StateMachine/Controller/clickRestoreScene.js.map +0 -1
- package/dist/esm/StateMachine/Controller/clickRestoreScene.test.js +0 -24
- package/dist/esm/StateMachine/Controller/clickRestoreScene.test.js.map +0 -1
- package/dist/esm/TestUtils/index.js +0 -2
- package/dist/esm/TestUtils/index.js.map +0 -1
- package/dist/esm/TestUtils/setupFeatureForTesting.js +0 -57
- package/dist/esm/TestUtils/setupFeatureForTesting.js.map +0 -1
- package/dist/types/FramedScreen/Factories/setupStandardFramedScreen.test.d.ts +0 -2
- package/dist/types/FramedScreen/Factories/setupStandardFramedScreen.test.d.ts.map +0 -1
- package/dist/types/StateMachine/Controller/clickRestoreScene.d.ts +0 -3
- package/dist/types/StateMachine/Controller/clickRestoreScene.d.ts.map +0 -1
- package/dist/types/StateMachine/Controller/clickRestoreScene.test.d.ts +0 -2
- package/dist/types/StateMachine/Controller/clickRestoreScene.test.d.ts.map +0 -1
- package/dist/types/TestUtils/index.d.ts +0 -2
- package/dist/types/TestUtils/index.d.ts.map +0 -1
- package/dist/types/TestUtils/setupFeatureForTesting.d.ts +0 -48
- package/dist/types/TestUtils/setupFeatureForTesting.d.ts.map +0 -1
|
@@ -219,5 +219,245 @@ describe("ProcedureEntity", () => {
|
|
|
219
219
|
expect(procedureEntity.showHints).toBe(false);
|
|
220
220
|
expect(procedureEntity.isQuiz).toBe(true);
|
|
221
221
|
});
|
|
222
|
+
describe("recordUserEvent revisits (order matters)", () => {
|
|
223
|
+
beforeEach(() => {
|
|
224
|
+
procedureEntity.addEventId("s1");
|
|
225
|
+
procedureEntity.addEventId("s2");
|
|
226
|
+
procedureEntity.addEventId("s3");
|
|
227
|
+
procedureEntity.setOrderMatters(true);
|
|
228
|
+
});
|
|
229
|
+
it("does not log a re-emission of an already-completed step", () => {
|
|
230
|
+
procedureEntity.recordUserEvent("s1");
|
|
231
|
+
procedureEntity.recordUserEvent("s2");
|
|
232
|
+
procedureEntity.recordUserEvent("s1");
|
|
233
|
+
expect(procedureEntity.userEventLog).toEqual(["s1", "s2"]);
|
|
234
|
+
expect(procedureEntity.currentStepIndex).toBe(2);
|
|
235
|
+
});
|
|
236
|
+
it("does not set a validation message for a benign revisit", () => {
|
|
237
|
+
procedureEntity.recordUserEvent("s1");
|
|
238
|
+
procedureEntity.recordUserEvent("s1");
|
|
239
|
+
expect(procedureEntity.validationMessage).toBeNull();
|
|
240
|
+
});
|
|
241
|
+
it("still logs and flags an early emission of a later step", () => {
|
|
242
|
+
procedureEntity.recordUserEvent("s1");
|
|
243
|
+
procedureEntity.recordUserEvent("s3");
|
|
244
|
+
expect(procedureEntity.userEventLog).toEqual(["s1", "s3"]);
|
|
245
|
+
expect(procedureEntity.validationMessage).toBe("Expected 's2', but got 's3'");
|
|
246
|
+
expect(procedureEntity.currentStepIndex).toBe(1);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe("calculateScore (order matters, 10 steps)", () => {
|
|
250
|
+
const steps = [
|
|
251
|
+
"s1",
|
|
252
|
+
"s2",
|
|
253
|
+
"s3",
|
|
254
|
+
"s4",
|
|
255
|
+
"s5",
|
|
256
|
+
"s6",
|
|
257
|
+
"s7",
|
|
258
|
+
"s8",
|
|
259
|
+
"s9",
|
|
260
|
+
"s10",
|
|
261
|
+
];
|
|
262
|
+
const record = (...ids) => ids.forEach((id) => procedureEntity.recordUserEvent(id));
|
|
263
|
+
const correctFlags = () => procedureEntity.calculateScore().comparison.map((c) => c.correct);
|
|
264
|
+
beforeEach(() => {
|
|
265
|
+
steps.forEach((s) => procedureEntity.addEventId(s));
|
|
266
|
+
procedureEntity.setOrderMatters(true);
|
|
267
|
+
});
|
|
268
|
+
it("scores a perfect run 100% with every step correct", () => {
|
|
269
|
+
record(...steps);
|
|
270
|
+
const score = procedureEntity.calculateScore();
|
|
271
|
+
expect(score.percentage).toBe(100);
|
|
272
|
+
expect(score.comparison.map((c) => c.eventId)).toEqual(steps);
|
|
273
|
+
expect(correctFlags()).toEqual(new Array(10).fill(true));
|
|
274
|
+
});
|
|
275
|
+
it("does not penalize one extra authored event emitted early", () => {
|
|
276
|
+
record("s1", "s7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10");
|
|
277
|
+
expect(procedureEntity.calculateScore().percentage).toBe(100);
|
|
278
|
+
expect(correctFlags()).toEqual(new Array(10).fill(true));
|
|
279
|
+
});
|
|
280
|
+
it("scores a skipped step 90% and marks only that step incorrect", () => {
|
|
281
|
+
record("s1", "s2", "s3", "s4", "s6", "s7", "s8", "s9", "s10");
|
|
282
|
+
expect(procedureEntity.calculateScore().percentage).toBe(90);
|
|
283
|
+
expect(correctFlags()).toEqual([
|
|
284
|
+
true,
|
|
285
|
+
true,
|
|
286
|
+
true,
|
|
287
|
+
true,
|
|
288
|
+
false,
|
|
289
|
+
true,
|
|
290
|
+
true,
|
|
291
|
+
true,
|
|
292
|
+
true,
|
|
293
|
+
true,
|
|
294
|
+
]);
|
|
295
|
+
});
|
|
296
|
+
it("scores swapped steps 90%, keeping the earlier expected step (deterministic tie-break)", () => {
|
|
297
|
+
record("s1", "s2", "s3", "s5", "s4", "s6", "s7", "s8", "s9", "s10");
|
|
298
|
+
for (let run = 0; run < 3; run++) {
|
|
299
|
+
const score = procedureEntity.calculateScore();
|
|
300
|
+
expect(score.percentage).toBe(90);
|
|
301
|
+
expect(score.comparison[3].correct).toBe(true);
|
|
302
|
+
expect(score.comparison[4].correct).toBe(false);
|
|
303
|
+
expect(score.comparison.filter((c) => c.correct).length).toBe(9);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
it("scores a repeated first step 100% with no duplicate in the log", () => {
|
|
307
|
+
record("s1", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10");
|
|
308
|
+
expect(procedureEntity.userEventLog).toEqual(steps);
|
|
309
|
+
expect(procedureEntity.validationMessage).toBeNull();
|
|
310
|
+
expect(procedureEntity.calculateScore().percentage).toBe(100);
|
|
311
|
+
expect(correctFlags()).toEqual(new Array(10).fill(true));
|
|
312
|
+
});
|
|
313
|
+
it("scores a fully reversed run 10%", () => {
|
|
314
|
+
record(...[...steps].reverse());
|
|
315
|
+
const score = procedureEntity.calculateScore();
|
|
316
|
+
expect(score.percentage).toBe(10);
|
|
317
|
+
expect(score.comparison[0].correct).toBe(true);
|
|
318
|
+
expect(score.comparison.filter((c) => c.correct).length).toBe(1);
|
|
319
|
+
});
|
|
320
|
+
it("scores an empty log 0% with every step incorrect", () => {
|
|
321
|
+
const score = procedureEntity.calculateScore();
|
|
322
|
+
expect(score.percentage).toBe(0);
|
|
323
|
+
expect(correctFlags()).toEqual(new Array(10).fill(false));
|
|
324
|
+
score.comparison.forEach((c) => {
|
|
325
|
+
expect(c.expected).toBe(true);
|
|
326
|
+
expect(c.actual).toBe(false);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
it("keeps the comparison shape { eventId, expected, actual, correct }", () => {
|
|
330
|
+
record("s1", "s2", "s3", "s4", "s6", "s7", "s8", "s9", "s10");
|
|
331
|
+
const skipped = procedureEntity.calculateScore().comparison[4];
|
|
332
|
+
expect(skipped).toEqual({
|
|
333
|
+
eventId: "s5",
|
|
334
|
+
expected: true,
|
|
335
|
+
actual: false,
|
|
336
|
+
correct: false,
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
describe("calculateScore edge cases", () => {
|
|
341
|
+
it("returns { percentage: 0, comparison: [] } for an empty procedure", () => {
|
|
342
|
+
procedureEntity.setOrderMatters(true);
|
|
343
|
+
expect(procedureEntity.calculateScore()).toEqual({
|
|
344
|
+
percentage: 0,
|
|
345
|
+
comparison: [],
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
it("keeps set-based scoring when order does not matter", () => {
|
|
349
|
+
procedureEntity.addEventId("a");
|
|
350
|
+
procedureEntity.addEventId("b");
|
|
351
|
+
procedureEntity.addEventId("c");
|
|
352
|
+
procedureEntity.setOrderMatters(false);
|
|
353
|
+
procedureEntity.recordUserEvent("c");
|
|
354
|
+
procedureEntity.recordUserEvent("a");
|
|
355
|
+
const score = procedureEntity.calculateScore();
|
|
356
|
+
expect(score.percentage).toBe(67);
|
|
357
|
+
expect(score.comparison.map((c) => c.correct)).toEqual([
|
|
358
|
+
true,
|
|
359
|
+
false,
|
|
360
|
+
true,
|
|
361
|
+
]);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
describe("event category lookup (#53)", () => {
|
|
365
|
+
it("treats every step as assessed when no lookup is injected", () => {
|
|
366
|
+
expect(procedureEntity.getEventCategory("navigate-to-overhead")).toBe("assessed");
|
|
367
|
+
});
|
|
368
|
+
it("resolves a step's category through the injected lookup at call time", () => {
|
|
369
|
+
procedureEntity.setEventCategoryLookup((eventId) => eventId === "navigate-to-overhead" ? "instructional" : "assessed");
|
|
370
|
+
expect(procedureEntity.getEventCategory("navigate-to-overhead")).toBe("instructional");
|
|
371
|
+
expect(procedureEntity.getEventCategory("lever")).toBe("assessed");
|
|
372
|
+
});
|
|
373
|
+
it("notifies observers when the lookup is injected so presenters rebuild", () => {
|
|
374
|
+
const observer = jest.fn();
|
|
375
|
+
procedureEntity.addChangeObserver(observer);
|
|
376
|
+
procedureEntity.setEventCategoryLookup(() => "assessed");
|
|
377
|
+
expect(observer).toHaveBeenCalledTimes(1);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
describe("quiz mode with instructional steps (#53)", () => {
|
|
381
|
+
const NAV = "navigate-to-overhead";
|
|
382
|
+
beforeEach(() => {
|
|
383
|
+
procedureEntity.setEventCategoryLookup((eventId) => eventId === NAV ? "instructional" : "assessed");
|
|
384
|
+
procedureEntity.addEventId(NAV);
|
|
385
|
+
procedureEntity.addEventId("lever");
|
|
386
|
+
procedureEntity.addEventId("valve");
|
|
387
|
+
procedureEntity.setIsQuiz(true);
|
|
388
|
+
});
|
|
389
|
+
it("scores only the assessed subsequence", () => {
|
|
390
|
+
procedureEntity.recordUserEvent("lever");
|
|
391
|
+
procedureEntity.recordUserEvent("valve");
|
|
392
|
+
expect(procedureEntity.calculateScore()).toEqual({
|
|
393
|
+
percentage: 100,
|
|
394
|
+
comparison: [
|
|
395
|
+
{ eventId: "lever", expected: true, actual: true, correct: true },
|
|
396
|
+
{ eventId: "valve", expected: true, actual: true, correct: true },
|
|
397
|
+
],
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
it("logs an instructional emission without advancing or flagging the attempt", () => {
|
|
401
|
+
procedureEntity.recordUserEvent(NAV);
|
|
402
|
+
expect(procedureEntity.userEventLog).toEqual([NAV]);
|
|
403
|
+
expect(procedureEntity.currentStepIndex).toBe(0);
|
|
404
|
+
expect(procedureEntity.validationMessage).toBeNull();
|
|
405
|
+
expect(procedureEntity.getNextExpectedEvent()).toBe("lever");
|
|
406
|
+
});
|
|
407
|
+
it("does not misalign later assessed steps around an instructional emission", () => {
|
|
408
|
+
procedureEntity.recordUserEvent("lever");
|
|
409
|
+
procedureEntity.recordUserEvent(NAV);
|
|
410
|
+
procedureEntity.recordUserEvent("valve");
|
|
411
|
+
expect(procedureEntity.isComplete).toBe(true);
|
|
412
|
+
expect(procedureEntity.getProgressPercentage()).toBe(100);
|
|
413
|
+
expect(procedureEntity.calculateScore().percentage).toBe(100);
|
|
414
|
+
});
|
|
415
|
+
it("treats a quiz made only of instructional steps like an empty procedure", () => {
|
|
416
|
+
procedureEntity.removeEventId("lever");
|
|
417
|
+
procedureEntity.removeEventId("valve");
|
|
418
|
+
procedureEntity.recordUserEvent(NAV);
|
|
419
|
+
expect(procedureEntity.isComplete).toBe(false);
|
|
420
|
+
expect(procedureEntity.getProgressPercentage()).toBe(0);
|
|
421
|
+
expect(procedureEntity.getNextExpectedEvent()).toBeNull();
|
|
422
|
+
expect(procedureEntity.calculateScore()).toEqual({
|
|
423
|
+
percentage: 0,
|
|
424
|
+
comparison: [],
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
it("ignores categories entirely in training mode", () => {
|
|
428
|
+
procedureEntity.setIsQuiz(false);
|
|
429
|
+
procedureEntity.recordUserEvent(NAV);
|
|
430
|
+
expect(procedureEntity.currentStepIndex).toBe(1);
|
|
431
|
+
expect(procedureEntity.getProgressPercentage()).toBe(33);
|
|
432
|
+
procedureEntity.recordUserEvent("lever");
|
|
433
|
+
procedureEntity.recordUserEvent("valve");
|
|
434
|
+
expect(procedureEntity.isComplete).toBe(true);
|
|
435
|
+
expect(procedureEntity.calculateScore().comparison).toHaveLength(3);
|
|
436
|
+
});
|
|
437
|
+
it("logs a repeated instructional emission only once, however often the student revisits", () => {
|
|
438
|
+
procedureEntity.recordUserEvent(NAV);
|
|
439
|
+
procedureEntity.recordUserEvent("lever");
|
|
440
|
+
procedureEntity.recordUserEvent(NAV);
|
|
441
|
+
procedureEntity.recordUserEvent(NAV);
|
|
442
|
+
expect(procedureEntity.userEventLog).toEqual([NAV, "lever"]);
|
|
443
|
+
// The bounded log never changes the assessed score.
|
|
444
|
+
expect(procedureEntity.calculateScore().percentage).toBe(50);
|
|
445
|
+
});
|
|
446
|
+
it("flags a quiz whose steps are all instructional as needing an assessed step", () => {
|
|
447
|
+
procedureEntity.removeEventId("lever");
|
|
448
|
+
procedureEntity.removeEventId("valve");
|
|
449
|
+
expect(procedureEntity.getAuthoringValidationMessage()).toBe("A quiz needs at least one assessed step");
|
|
450
|
+
expect(procedureEntity.validateProgress()).toBe("A quiz needs at least one assessed step");
|
|
451
|
+
});
|
|
452
|
+
it("does not flag a quiz that has assessed steps, nor an all-instructional training procedure", () => {
|
|
453
|
+
// The mixed quiz has assessed steps → no authoring message.
|
|
454
|
+
expect(procedureEntity.getAuthoringValidationMessage()).toBeNull();
|
|
455
|
+
// All-instructional, but training mode is never a quiz problem.
|
|
456
|
+
procedureEntity.removeEventId("lever");
|
|
457
|
+
procedureEntity.removeEventId("valve");
|
|
458
|
+
procedureEntity.setIsQuiz(false);
|
|
459
|
+
expect(procedureEntity.getAuthoringValidationMessage()).toBeNull();
|
|
460
|
+
});
|
|
461
|
+
});
|
|
222
462
|
});
|
|
223
463
|
//# 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":";;AAAA,sCAA+D;AAC/D,uDAAyE;AAEzE,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAChC,IAAI,UAAyB,CAAC;IAC9B,IAAI,eAAgC,CAAC;IAErC,UAAU,CAAC,GAAG,EAAE;QACf,UAAU,GAAG,IAAA,wBAAiB,GAAE,CAAC;QACjC,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QAC1D,eAAe,GAAG,IAAA,qCAAmB,EAAC,SAAS,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7D,MAAM,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC/D,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAChE,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAC5C,+DAA+D,CAC/D,CAAC;QACF,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAC5C,+EAA+E,CAC/E,CAAC;QACF,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAC5C,+DAA+D,CAC/D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC7C,MAAM,SAAS,GAAG,iCAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACtC,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3C,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACpC,eAAe,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC,eAAe,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;QACzD,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3C,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3C,eAAe,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,eAAe,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC/B,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3C,eAAe,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3C,eAAe,CAAC,aAAa,EAAE,CAAC;QAChC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAC1D,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjD,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAChD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAClD,uCAAuC,CACvC,CAAC;QACF,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAChD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC1C,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACnD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC7C,eAAe,CAAC,aAAa,EAAE,CAAC;QAChC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxD,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzD,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzD,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACvD,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxD,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzD,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QACjF,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACtC,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACpF,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC9D,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,eAAe,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,eAAe,CAAC,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACzD,UAAU,CAAC,GAAG,EAAE;YACf,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACjC,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACjC,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACjC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YAClE,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YAC3D,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YACjE,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YACjE,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YAC3D,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAC7C,6BAA6B,CAC7B,CAAC;YACF,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG;YACb,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,KAAK;SACL,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,GAAG,GAAa,EAAE,EAAE,CACnC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;QAE1D,MAAM,YAAY,GAAG,GAAG,EAAE,CACzB,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAEnE,UAAU,CAAC,GAAG,EAAE;YACf,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC5D,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;YACjB,MAAM,KAAK,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9D,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YACnE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1E,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9D,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACvE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9D,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC7D,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC;gBAC9B,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,KAAK;gBACL,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,IAAI;gBACJ,IAAI;aACJ,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uFAAuF,EAAE,GAAG,EAAE;YAChG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACpE,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBAClC,MAAM,KAAK,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC;gBAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAClC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAChD,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClE,CAAC;QACF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;YACzE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1E,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACpD,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9D,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAChC,MAAM,KAAK,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC3D,MAAM,KAAK,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1D,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC9B,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC5E,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC/D,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;gBACvB,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,KAAK;aACd,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;QAC1C,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;YAC3E,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC;gBAChD,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,EAAE;aACd,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC7D,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAChC,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAChC,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAChC,eAAe,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YACvC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;gBACtD,IAAI;gBACJ,KAAK;gBACL,IAAI;aACJ,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YACnE,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CACpE,UAAU,CACV,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;YAC9E,eAAe,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,EAAE,CAClD,OAAO,KAAK,sBAAsB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CACjE,CAAC;YAEF,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CACpE,eAAe,CACf,CAAC;YACF,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;YAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;YAC3B,eAAe,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAE5C,eAAe,CAAC,sBAAsB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;YAEzD,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACzD,MAAM,GAAG,GAAG,sBAAsB,CAAC;QAEnC,UAAU,CAAC,GAAG,EAAE;YACf,eAAe,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,EAAE,CAClD,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAC9C,CAAC;YACF,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAChC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACpC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACpC,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC/C,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACzC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAEzC,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC;gBAChD,UAAU,EAAE,GAAG;gBACf,UAAU,EAAE;oBACX,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;oBACjE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;iBACjE;aACD,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;YACnF,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAErC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpD,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;YACrD,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;YAClF,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACzC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAEzC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1D,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;YACjF,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvC,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAEvC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAErC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/C,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxD,MAAM,CAAC,eAAe,CAAC,oBAAoB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC1D,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC;gBAChD,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,EAAE;aACd,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACvD,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAEjC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEzD,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACzC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sFAAsF,EAAE,GAAG,EAAE;YAC/F,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACzC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACrC,eAAe,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAErC,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7D,oDAAoD;YACpD,MAAM,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;YACrF,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvC,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAEvC,MAAM,CAAC,eAAe,CAAC,6BAA6B,EAAE,CAAC,CAAC,IAAI,CAC3D,yCAAyC,CACzC,CAAC;YACF,MAAM,CAAC,eAAe,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAC9C,yCAAyC,CACzC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2FAA2F,EAAE,GAAG,EAAE;YACpG,4DAA4D;YAC5D,MAAM,CAAC,eAAe,CAAC,6BAA6B,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;YAEnE,gEAAgE;YAChE,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvC,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACvC,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,CAAC,eAAe,CAAC,6BAA6B,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QACpE,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","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"]}
|
|
@@ -4,6 +4,7 @@ exports.ProcedureFeatureComponents = exports.ProcedureFeatureFactory = void 0;
|
|
|
4
4
|
exports.makeProcedureFeatureFactory = makeProcedureFeatureFactory;
|
|
5
5
|
const core_1 = require("@vived/core");
|
|
6
6
|
const Challenge_1 = require("../../Challenge");
|
|
7
|
+
const EventEntity_1 = require("../../EventSystem/Entities/EventEntity");
|
|
7
8
|
const ProcedureEntity_1 = require("../Entities/ProcedureEntity");
|
|
8
9
|
const HintRegistry_1 = require("../Entities/HintRegistry");
|
|
9
10
|
const AddProcedureEventUC_1 = require("../UCs/AddProcedureEventUC");
|
|
@@ -48,8 +49,27 @@ class ProcedureFeatureFactory extends core_1.DomainFactory {
|
|
|
48
49
|
(0, ProcedurePM_1.makeProcedurePM)(this.appObject);
|
|
49
50
|
}
|
|
50
51
|
finalSetup() {
|
|
52
|
+
this.wireEventCategoryLookup();
|
|
51
53
|
this.registerProcedureChallenge();
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Classification is derived at evaluation time from the EventSystem Registry
|
|
57
|
+
* (#53): hand the entity a lookup rather than copying categories into it, so
|
|
58
|
+
* events registered later (and slides authored earlier) are classified too.
|
|
59
|
+
*/
|
|
60
|
+
wireEventCategoryLookup() {
|
|
61
|
+
const procedureEntity = this.getProcedureEntity();
|
|
62
|
+
if (!procedureEntity) {
|
|
63
|
+
this.warn("ProcedureEntity not found - cannot wire event categories");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const eventEntity = EventEntity_1.EventEntity.get(this.appObjects);
|
|
67
|
+
if (!eventEntity) {
|
|
68
|
+
this.warn("EventEntity not found - every procedure step will be treated as assessed");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
procedureEntity.setEventCategoryLookup((eventId) => eventEntity.getEventCategory(eventId));
|
|
72
|
+
}
|
|
53
73
|
registerProcedureChallenge() {
|
|
54
74
|
const challengeEntity = Challenge_1.ChallengeEntity.get(this.appObjects);
|
|
55
75
|
const procedureEntity = this.getProcedureEntity();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProcedureFeatureFactory.js","sourceRoot":"","sources":["../../../../src/Procedure/Factories/ProcedureFeatureFactory.ts"],"names":[],"mappings":";;;
|
|
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"]}
|
|
@@ -100,6 +100,31 @@ describe("ProcedureFeatureFactory", () => {
|
|
|
100
100
|
it("registers procedure challenge with ChallengeEntity", () => {
|
|
101
101
|
expect(mockRegisterChallenge).toHaveBeenCalledWith(factory.getProcedureEntity());
|
|
102
102
|
});
|
|
103
|
+
it("injects the EventEntity category lookup into the entity (#53)", () => {
|
|
104
|
+
const eventEntity = EventEntity_1.EventEntity.get(appObjects);
|
|
105
|
+
const entity = factory.getProcedureEntity();
|
|
106
|
+
// Registered after setup: the lookup is evaluated at call time, not cached.
|
|
107
|
+
eventEntity.register("navigate-to-overhead", "Go to overhead", {
|
|
108
|
+
category: "instructional",
|
|
109
|
+
});
|
|
110
|
+
eventEntity.register("lever", "Pull lever");
|
|
111
|
+
expect(entity.getEventCategory("navigate-to-overhead")).toBe("instructional");
|
|
112
|
+
expect(entity.getEventCategory("lever")).toBe("assessed");
|
|
113
|
+
expect(entity.getEventCategory("never-registered")).toBe("assessed");
|
|
114
|
+
});
|
|
115
|
+
it("warns and falls back to an assessed lookup when EventEntity is absent (#53)", () => {
|
|
116
|
+
const submitWarningSpy = jest.fn();
|
|
117
|
+
const newAppObjects = (0, core_1.makeAppObjectRepo)();
|
|
118
|
+
newAppObjects.submitWarning = submitWarningSpy;
|
|
119
|
+
// No EventEntity registered on this repo: the category lookup cannot wire.
|
|
120
|
+
const newDomainFactoryRepo = new core_1.DomainFactoryRepo(newAppObjects.getOrCreate("DomainFactory"));
|
|
121
|
+
const newFactory = (0, ProcedureFeatureFactory_1.makeProcedureFeatureFactory)(newAppObjects);
|
|
122
|
+
newDomainFactoryRepo.setupDomain();
|
|
123
|
+
expect(submitWarningSpy).toHaveBeenCalledWith(expect.stringContaining("Procedure"), expect.stringContaining("EventEntity not found"));
|
|
124
|
+
// The entity keeps its default lookup, so every step is treated as assessed.
|
|
125
|
+
const entity = newFactory.getProcedureEntity();
|
|
126
|
+
expect(entity.getEventCategory("anything")).toBe("assessed");
|
|
127
|
+
});
|
|
103
128
|
it("handles missing ChallengeEntity gracefully", () => {
|
|
104
129
|
jest.mocked(Challenge_1.ChallengeEntity.get).mockReturnValueOnce(undefined);
|
|
105
130
|
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"]}
|
|
@@ -85,6 +85,8 @@ class MockProcedureEntity extends ProcedureEntity_1.ProcedureEntity {
|
|
|
85
85
|
this.setIsRecording = jest.fn((v) => {
|
|
86
86
|
this._isRecording = v;
|
|
87
87
|
});
|
|
88
|
+
this.setEventCategoryLookup = jest.fn();
|
|
89
|
+
this.getEventCategory = jest.fn(() => "assessed");
|
|
88
90
|
this.getProgressPercentage = jest.fn(() => 0);
|
|
89
91
|
this.calculateScore = jest.fn(() => ({ percentage: 0, comparison: [] }));
|
|
90
92
|
this.submit = jest.fn();
|