scorm-again 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.github/workflows/stale.yml +14 -0
  2. package/.run/{Mocha Unit Tests.run.xml → Mocha Unit Tests (watch).run.xml } +1 -1
  3. package/.run/Template Mocha.run.xml +17 -0
  4. package/README.md +180 -72
  5. package/dist/aicc.js +1520 -1149
  6. package/dist/aicc.js.map +1 -1
  7. package/dist/aicc.min.js +1 -1
  8. package/dist/aicc.min.js.map +1 -1
  9. package/dist/scorm-again.js +2812 -2205
  10. package/dist/scorm-again.js.map +1 -1
  11. package/dist/scorm-again.min.js +1 -1
  12. package/dist/scorm-again.min.js.map +1 -1
  13. package/dist/scorm12.js +1129 -842
  14. package/dist/scorm12.js.map +1 -1
  15. package/dist/scorm12.min.js +1 -1
  16. package/dist/scorm12.min.js.map +1 -1
  17. package/dist/scorm2004.js +1921 -1564
  18. package/dist/scorm2004.js.map +1 -1
  19. package/dist/scorm2004.min.js +1 -1
  20. package/dist/scorm2004.min.js.map +1 -1
  21. package/package.json +20 -17
  22. package/src/AICC.ts +15 -17
  23. package/src/BaseAPI.ts +283 -420
  24. package/src/Scorm12API.ts +133 -41
  25. package/src/Scorm2004API.ts +224 -120
  26. package/src/cmi/aicc/attempts.ts +94 -0
  27. package/src/cmi/aicc/cmi.ts +100 -0
  28. package/src/cmi/aicc/core.ts +360 -0
  29. package/src/cmi/aicc/evaluation.ts +157 -0
  30. package/src/cmi/aicc/paths.ts +180 -0
  31. package/src/cmi/aicc/student_data.ts +86 -0
  32. package/src/cmi/aicc/student_demographics.ts +367 -0
  33. package/src/cmi/aicc/student_preferences.ts +176 -0
  34. package/src/cmi/aicc/tries.ts +116 -0
  35. package/src/cmi/aicc/validation.ts +25 -0
  36. package/src/cmi/common/array.ts +77 -0
  37. package/src/cmi/common/base_cmi.ts +46 -0
  38. package/src/cmi/common/score.ts +203 -0
  39. package/src/cmi/common/validation.ts +60 -0
  40. package/src/cmi/scorm12/cmi.ts +224 -0
  41. package/src/cmi/scorm12/interactions.ts +368 -0
  42. package/src/cmi/scorm12/nav.ts +54 -0
  43. package/src/cmi/scorm12/objectives.ts +112 -0
  44. package/src/cmi/scorm12/student_data.ts +130 -0
  45. package/src/cmi/scorm12/student_preference.ts +158 -0
  46. package/src/cmi/scorm12/validation.ts +48 -0
  47. package/src/cmi/scorm2004/adl.ts +272 -0
  48. package/src/cmi/scorm2004/cmi.ts +599 -0
  49. package/src/cmi/scorm2004/comments.ts +163 -0
  50. package/src/cmi/scorm2004/interactions.ts +466 -0
  51. package/src/cmi/scorm2004/learner_preference.ts +152 -0
  52. package/src/cmi/scorm2004/objectives.ts +212 -0
  53. package/src/cmi/scorm2004/score.ts +78 -0
  54. package/src/cmi/scorm2004/validation.ts +42 -0
  55. package/src/constants/default_settings.ts +82 -0
  56. package/src/constants/enums.ts +17 -0
  57. package/src/constants/regex.ts +2 -2
  58. package/src/constants/response_constants.ts +2 -0
  59. package/src/exceptions.ts +22 -1
  60. package/src/helpers/scheduled_commit.ts +42 -0
  61. package/src/interfaces/IBaseAPI.ts +35 -0
  62. package/src/types/api_types.ts +50 -0
  63. package/src/utilities/debounce.ts +31 -0
  64. package/src/utilities.ts +56 -0
  65. package/test/AICC.spec.ts +11 -1
  66. package/test/Scorm12API.spec.ts +372 -9
  67. package/test/Scorm2004API.spec.ts +558 -2
  68. package/test/cmi/aicc_cmi.spec.ts +188 -11
  69. package/test/cmi/scorm12_cmi.spec.ts +5 -5
  70. package/test/cmi/scorm2004_cmi.spec.ts +8 -8
  71. package/test/cmi_helpers.ts +1 -1
  72. package/test/types/api_types.spec.ts +126 -0
  73. package/test/utilities/debounce.spec.ts +56 -0
  74. package/src/cmi/aicc_cmi.ts +0 -1248
  75. package/src/cmi/common.ts +0 -411
  76. package/src/cmi/scorm12_cmi.ts +0 -1426
  77. package/src/cmi/scorm2004_cmi.ts +0 -1874
@@ -0,0 +1,35 @@
1
+ import { RefObject, ResultObject } from "../types/api_types";
2
+ import { BaseCMI } from "../cmi/common/base_cmi";
3
+
4
+ export interface IBaseAPI {
5
+ cmi: BaseCMI;
6
+ startingData?: RefObject;
7
+
8
+ initialize(
9
+ callbackName: string,
10
+ initializeMessage?: string,
11
+ terminationMessage?: string,
12
+ ): string;
13
+ lmsInitialize(): string;
14
+ lmsFinish(): string;
15
+ lmsGetValue(CMIElement: string): string;
16
+ lmsSetValue(CMIElement: string, value: any): string;
17
+ lmsCommit(): string;
18
+ lmsGetLastError(): string;
19
+ lmsGetErrorString(CMIErrorCode: string | number): string;
20
+ lmsGetDiagnostic(CMIErrorCode: string | number): string;
21
+ storeData(_calculateTotalTime: boolean): Promise<ResultObject>;
22
+ renderCommitCMI(_terminateCommit: boolean): RefObject | Array<any>;
23
+ getLmsErrorMessageDetails(
24
+ _errorNumber: string | number,
25
+ _detail?: boolean,
26
+ ): string;
27
+ getCMIValue(_CMIElement: string): string;
28
+ setCMIValue(_CMIElement: string, _value: any): string;
29
+ validateCorrectResponse(_CMIElement: string, _value: any): void;
30
+ getChildElement(
31
+ _CMIElement: string,
32
+ _value: any,
33
+ _foundFirstIndex: boolean,
34
+ ): BaseCMI | null;
35
+ }
@@ -0,0 +1,50 @@
1
+ import { CompletionStatus, SuccessStatus } from "../constants/enums";
2
+
3
+ export type Settings = {
4
+ autocommit?: boolean;
5
+ autocommitSeconds?: number;
6
+ asyncCommit?: boolean;
7
+ sendFullCommit?: boolean;
8
+ lmsCommitUrl?: boolean | string;
9
+ dataCommitFormat?: string;
10
+ commitRequestDataType?: string;
11
+ autoProgress?: boolean;
12
+ logLevel?: number;
13
+ selfReportSessionTime?: boolean;
14
+ alwaysSendTotalTime?: boolean;
15
+ strict_errors?: boolean;
16
+ xhrHeaders?: RefObject;
17
+ xhrWithCredentials?: boolean;
18
+ responseHandler?: (response: Response) => Promise<ResultObject>;
19
+ requestHandler?: (commitObject: any) => any;
20
+ onLogMessage?: (messageLevel: number, logMessage: string) => void;
21
+ scoItemIds?: string[];
22
+ scoItemIdValidator?: false | ((scoItemId: string) => boolean);
23
+ mastery_override?: boolean;
24
+ renderCommonCommitFields?: boolean;
25
+ };
26
+
27
+ export type RefObject = {
28
+ [key: string]: any;
29
+ };
30
+
31
+ export type ResultObject = {
32
+ result: string;
33
+ errorCode: number;
34
+ navRequest?: string;
35
+ };
36
+
37
+ export type ScoreObject = {
38
+ raw?: number;
39
+ min?: number;
40
+ max?: number;
41
+ scaled?: number;
42
+ };
43
+
44
+ export type CommitObject = {
45
+ successStatus: SuccessStatus;
46
+ completionStatus: CompletionStatus;
47
+ totalTimeSeconds: number;
48
+ runtimeData: RefObject;
49
+ score?: ScoreObject;
50
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Debounce function to delay the execution of a given function.
3
+ *
4
+ * @param func - The function to debounce.
5
+ * @param wait - The number of milliseconds to delay.
6
+ * @param immediate - If `true`, the function will be triggered on the leading edge instead of the trailing.
7
+ * @returns A debounced version of the provided function.
8
+ */
9
+ export function debounce<T extends (...args: any[]) => void>(
10
+ func: T,
11
+ wait: number,
12
+ immediate = false,
13
+ ): (...args: Parameters<T>) => void {
14
+ let timeout: ReturnType<typeof setTimeout> | null;
15
+
16
+ return function (this: any, ...args: Parameters<T>) {
17
+ const context = this;
18
+
19
+ const later = () => {
20
+ timeout = null;
21
+ if (!immediate) func.apply(context, args);
22
+ };
23
+
24
+ const callNow = immediate && !timeout;
25
+
26
+ if (timeout) clearTimeout(timeout);
27
+ timeout = setTimeout(later, wait);
28
+
29
+ if (callNow) func.apply(context, args);
30
+ };
31
+ }
package/src/utilities.ts CHANGED
@@ -280,3 +280,59 @@ export function countDecimals(num: number): number {
280
280
  const parts = num.toString().split(".")[1];
281
281
  return parts.length || 0;
282
282
  }
283
+
284
+ /**
285
+ * Formats the SCORM messages for easy reading
286
+ *
287
+ * @param {string} functionName
288
+ * @param {string} message
289
+ * @param {string} CMIElement
290
+ * @return {string}
291
+ */
292
+ export function formatMessage(
293
+ functionName: string,
294
+ message: string,
295
+ CMIElement?: string,
296
+ ): string {
297
+ const baseLength = 20;
298
+ let messageString = "";
299
+
300
+ messageString += functionName;
301
+
302
+ let fillChars = baseLength - messageString.length;
303
+
304
+ for (let i = 0; i < fillChars; i++) {
305
+ messageString += " ";
306
+ }
307
+
308
+ messageString += ": ";
309
+
310
+ if (CMIElement) {
311
+ const CMIElementBaseLength = 70;
312
+
313
+ messageString += CMIElement;
314
+
315
+ fillChars = CMIElementBaseLength - messageString.length;
316
+
317
+ for (let j = 0; j < fillChars; j++) {
318
+ messageString += " ";
319
+ }
320
+ }
321
+
322
+ if (message) {
323
+ messageString += message;
324
+ }
325
+
326
+ return messageString;
327
+ }
328
+
329
+ /**
330
+ * Checks to see if {str} contains {tester}
331
+ *
332
+ * @param {string} str String to check against
333
+ * @param {string} tester String to check for
334
+ * @return {boolean}
335
+ */
336
+ export function stringMatches(str: string, tester: string): boolean {
337
+ return str?.match(tester) !== null;
338
+ }
package/test/AICC.spec.ts CHANGED
@@ -8,7 +8,7 @@ const scorm12_error_codes = ErrorCodes.scorm12;
8
8
 
9
9
  const api = () => {
10
10
  const API = new AICC();
11
- API.apiLogLevel = 5;
11
+ API.apiLogLevel = 1;
12
12
  return API;
13
13
  };
14
14
  const apiInitialized = () => {
@@ -256,6 +256,16 @@ describe("AICC API Tests", () => {
256
256
  fieldName: "cmi.student_data.tries.0.score.max",
257
257
  valueToTest: "100",
258
258
  });
259
+ h.checkLMSSetValue({
260
+ api: apiInitialized(),
261
+ fieldName: "cmi.student_data.attempt_records.0.score.max",
262
+ valueToTest: "100",
263
+ });
264
+ h.checkLMSSetValue({
265
+ api: apiInitialized(),
266
+ fieldName: "cmi.paths.0.location_id",
267
+ valueToTest: "xyz",
268
+ });
259
269
  });
260
270
  });
261
271
 
@@ -6,18 +6,21 @@ import ErrorCodes from "../src/constants/error_codes";
6
6
  import { scorm12Values } from "./field_values";
7
7
  import * as sinon from "sinon";
8
8
  import Pretender from "fetch-pretender";
9
- import { RefObject, Settings, DefaultSettings } from "../src/BaseAPI";
9
+ import { RefObject, Settings } from "../src/types/api_types";
10
+ import { DefaultSettings } from "../src/constants/default_settings";
10
11
 
11
12
  const scorm12_error_codes = ErrorCodes.scorm12;
12
13
 
13
14
  let clock: sinon.SinonFakeTimers;
14
- const api = (settings?: Settings) => {
15
+ const api = (settings?: Settings, startingData: RefObject = {}) => {
15
16
  const API = new Scorm12API(settings);
16
17
  API.apiLogLevel = 5;
18
+ API.startingData = startingData;
17
19
  return API;
18
20
  };
19
- const apiInitialized = (settings?: Settings) => {
21
+ const apiInitialized = (settings?: Settings, startingData: RefObject = {}) => {
20
22
  const API = api(settings);
23
+ API.loadFromJSON(startingData ? startingData : {}, "");
21
24
  API.lmsInitialize();
22
25
  return API;
23
26
  };
@@ -323,14 +326,16 @@ describe("SCORM 1.2 API Tests", () => {
323
326
  });
324
327
 
325
328
  describe("replaceWithAnotherScormAPI()", () => {
326
- const firstAPI = api();
327
- const secondAPI = api();
329
+ it("should replace the current API with another API", () => {
330
+ const firstAPI = api();
331
+ const secondAPI = api();
328
332
 
329
- firstAPI.cmi.core.student_id = "student_1";
330
- secondAPI.cmi.core.student_id = "student_2";
333
+ firstAPI.cmi.core.student_id = "student_1";
334
+ secondAPI.cmi.core.student_id = "student_2";
331
335
 
332
- firstAPI.replaceWithAnotherScormAPI(secondAPI);
333
- expect(firstAPI.cmi.core.student_id).toEqual("student_2");
336
+ firstAPI.replaceWithAnotherScormAPI(secondAPI);
337
+ expect(firstAPI.cmi.core.student_id).toEqual("student_2");
338
+ });
334
339
  });
335
340
 
336
341
  describe("renderCommitCMI()", () => {
@@ -353,6 +358,116 @@ describe("SCORM 1.2 API Tests", () => {
353
358
  const cmiExport: RefObject = scorm12API.renderCommitCMI(true);
354
359
  expect(cmiExport.cmi.core.total_time).toEqual("23:59:59");
355
360
  });
361
+ it("should return flattened format when dataCommitFormat is 'flattened'", function () {
362
+ const scorm12API = api({
363
+ ...DefaultSettings,
364
+ ...{ dataCommitFormat: "flattened" },
365
+ });
366
+ scorm12API.cmi.core.student_id = "student_1";
367
+ scorm12API.cmi.core.student_name = "Student 1";
368
+ scorm12API.cmi.core.lesson_status = "completed";
369
+ scorm12API.cmi.core.score.raw = "100";
370
+ scorm12API.cmi.core.score.max = "100";
371
+ scorm12API.cmi.core.score.min = "0";
372
+ scorm12API.cmi.core.session_time = "23:59:59";
373
+ const cmiExport: RefObject = scorm12API.renderCommitCMI(true);
374
+ expect(cmiExport["cmi.core.student_id"]).toEqual("student_1");
375
+ expect(cmiExport["cmi.core.student_name"]).toEqual("Student 1");
376
+ expect(cmiExport["cmi.core.lesson_status"]).toEqual("completed");
377
+ expect(cmiExport["cmi.core.score.raw"]).toEqual("100");
378
+ expect(cmiExport["cmi.core.score.max"]).toEqual("100");
379
+ expect(cmiExport["cmi.core.score.min"]).toEqual("0");
380
+ expect(cmiExport["cmi.core.session_time"]).toEqual("23:59:59");
381
+ });
382
+ it("should return params format when dataCommitFormat is 'params'", function () {
383
+ const scorm12API = api({
384
+ ...DefaultSettings,
385
+ ...{ dataCommitFormat: "params" },
386
+ });
387
+ scorm12API.cmi.core.student_id = "student_1";
388
+ scorm12API.cmi.core.student_name = "Student 1";
389
+ scorm12API.cmi.core.lesson_status = "completed";
390
+ scorm12API.cmi.core.score.raw = "100";
391
+ scorm12API.cmi.core.score.max = "100";
392
+ scorm12API.cmi.core.score.min = "0";
393
+ scorm12API.cmi.core.session_time = "23:59:59";
394
+ const result = scorm12API.renderCommitCMI(true);
395
+ expect(result).toBeInstanceOf(Array);
396
+ expect(result).toContain("cmi.core.lesson_status=completed");
397
+ expect(result).toContain("cmi.core.score.max=100");
398
+ expect(result).toContain("cmi.core.score.min=0");
399
+ expect(result).toContain("cmi.core.score.raw=100");
400
+ expect(result).toContain("cmi.core.session_time=23:59:59");
401
+ expect(result).toContain("cmi.core.student_id=student_1");
402
+ });
403
+ });
404
+
405
+ describe("renderCommitObject()", () => {
406
+ it("should render commit object with default settings and no score", () => {
407
+ const scorm12API = api();
408
+ scorm12API.cmi.core.lesson_status = "incomplete";
409
+ scorm12API.cmi.core.total_time = "12:34:56";
410
+ scorm12API.cmi.core.session_time = "23:59:59";
411
+ const commitObject = scorm12API.renderCommitObject(true);
412
+ expect(commitObject.successStatus).toEqual("unknown");
413
+ expect(commitObject.completionStatus).toEqual("incomplete");
414
+ expect(commitObject.runtimeData.cmi.core.lesson_status).toEqual(
415
+ "incomplete",
416
+ );
417
+ expect(commitObject.totalTimeSeconds).toEqual(
418
+ 12 * 3600 + 34 * 60 + 56 + (23 * 3600 + 59 * 60 + 59),
419
+ );
420
+ expect(commitObject.score.max).toEqual(100);
421
+ });
422
+
423
+ it("should render commit object with score data", () => {
424
+ const scorm12API = api();
425
+ scorm12API.cmi.core.lesson_status = "completed";
426
+ scorm12API.cmi.core.score.raw = "85";
427
+ scorm12API.cmi.core.score.min = "0";
428
+ scorm12API.cmi.core.score.max = "100";
429
+ const commitObject = scorm12API.renderCommitObject(true);
430
+ expect(commitObject.successStatus).toEqual("unknown");
431
+ expect(commitObject.completionStatus).toEqual("completed");
432
+ expect(commitObject.runtimeData.cmi.core.lesson_status).toEqual(
433
+ "completed",
434
+ );
435
+ expect(commitObject.runtimeData.cmi.core.score.raw).toEqual("85");
436
+ expect(commitObject.runtimeData.cmi.core.score.min).toEqual("0");
437
+ expect(commitObject.runtimeData.cmi.core.score.max).toEqual("100");
438
+ expect(commitObject.totalTimeSeconds).toEqual(0);
439
+ expect(commitObject.score).toEqual({
440
+ raw: 85,
441
+ min: 0,
442
+ max: 100,
443
+ });
444
+ });
445
+
446
+ it("should render commit object with completion and success status", () => {
447
+ const scorm12API = api();
448
+ scorm12API.cmi.core.lesson_status = "passed";
449
+ const commitObject = scorm12API.renderCommitObject(true);
450
+ expect(commitObject.successStatus).toEqual("passed");
451
+ expect(commitObject.completionStatus).toEqual("completed");
452
+ expect(commitObject.runtimeData.cmi.core.lesson_status).toEqual("passed");
453
+ });
454
+
455
+ it("should render commit object with failed success status", () => {
456
+ const scorm12API = api();
457
+ scorm12API.cmi.core.lesson_status = "failed";
458
+ const commitObject = scorm12API.renderCommitObject(true);
459
+ expect(commitObject.successStatus).toEqual("failed");
460
+ expect(commitObject.completionStatus).toEqual("incomplete");
461
+ expect(commitObject.runtimeData.cmi.core.lesson_status).toEqual("failed");
462
+ });
463
+
464
+ it("should calculate total time when terminateCommit is true", () => {
465
+ const scorm12API = api();
466
+ scorm12API.cmi.core.total_time = "12:34:56";
467
+ scorm12API.cmi.core.session_time = "23:59:59";
468
+ const commitObject = scorm12API.renderCommitObject(true);
469
+ expect(commitObject.runtimeData.cmi.core.total_time).toEqual("36:34:55");
470
+ });
356
471
  });
357
472
 
358
473
  describe("storeData()", () => {
@@ -577,4 +692,252 @@ describe("SCORM 1.2 API Tests", () => {
577
692
  expect(callback.called).toBe(true);
578
693
  });
579
694
  });
695
+
696
+ describe("Test issues from users", () => {
697
+ it("Should be able to load the JSON data from issue #587", () => {
698
+ const scorm12api = api({
699
+ ...DefaultSettings,
700
+ autocommit: false,
701
+ lmsCommitUrl: "/scorm12",
702
+ dataCommitFormat: "flattened",
703
+ logLevel: 1,
704
+ });
705
+
706
+ scorm12api.loadFromFlattenedJSON(
707
+ {
708
+ "cmi.comments": "",
709
+ "cmi.comments_from_lms": "",
710
+ "cmi.core.credit": "",
711
+ "cmi.core.entry": "",
712
+ "cmi.core.exit": "",
713
+ "cmi.core.lesson_location": "topic-nOmtUy",
714
+ "cmi.core.lesson_mode": "normal",
715
+ "cmi.core.lesson_status": "completed",
716
+ "cmi.core.score.max": "100",
717
+ "cmi.core.score.min": "",
718
+ "cmi.core.score.raw": "",
719
+ "cmi.core.session_time": "00:03:50",
720
+ "cmi.core.student_id": "student1",
721
+ "cmi.core.student_name": "Student 1",
722
+ "cmi.core.total_time": "00:03:50",
723
+ "cmi.interactions": {},
724
+ "cmi.launch_data": "",
725
+ "cmi.objectives.0.id": "topic-aMMlFF",
726
+ "cmi.objectives.0.score.max": "100",
727
+ "cmi.objectives.0.score.min": "",
728
+ "cmi.objectives.0.score.raw": "",
729
+ "cmi.objectives.0.status": "completed",
730
+ "cmi.objectives.1.id": "topic-6ReD72",
731
+ "cmi.objectives.1.score.max": "100",
732
+ "cmi.objectives.1.score.min": "",
733
+ "cmi.objectives.1.score.raw": "",
734
+ "cmi.objectives.1.status": "completed",
735
+ "cmi.objectives.10.id": "topic-MllWvr",
736
+ "cmi.objectives.10.score.max": "100",
737
+ "cmi.objectives.10.score.min": "",
738
+ "cmi.objectives.10.score.raw": "",
739
+ "cmi.objectives.10.status": "completed",
740
+ "cmi.objectives.11.id": "topic-m0dnP3",
741
+ "cmi.objectives.11.score.max": "100",
742
+ "cmi.objectives.11.score.min": "",
743
+ "cmi.objectives.11.score.raw": "",
744
+ "cmi.objectives.11.status": "completed",
745
+ "cmi.objectives.12.id": "topic-so4hKC",
746
+ "cmi.objectives.12.score.max": "100",
747
+ "cmi.objectives.12.score.min": "",
748
+ "cmi.objectives.12.score.raw": "",
749
+ "cmi.objectives.12.status": "completed",
750
+ "cmi.objectives.13.id": "topic-S9p8FE",
751
+ "cmi.objectives.13.score.max": "100",
752
+ "cmi.objectives.13.score.min": "",
753
+ "cmi.objectives.13.score.raw": "",
754
+ "cmi.objectives.13.status": "completed",
755
+ "cmi.objectives.14.id": "topic-E97B5s",
756
+ "cmi.objectives.14.score.max": "100",
757
+ "cmi.objectives.14.score.min": "",
758
+ "cmi.objectives.14.score.raw": "",
759
+ "cmi.objectives.14.status": "completed",
760
+ "cmi.objectives.15.id": "topic-TTyEf0",
761
+ "cmi.objectives.15.score.max": "100",
762
+ "cmi.objectives.15.score.min": "",
763
+ "cmi.objectives.15.score.raw": "",
764
+ "cmi.objectives.15.status": "completed",
765
+ "cmi.objectives.16.id": "topic-Bk8ZLK",
766
+ "cmi.objectives.16.score.max": "100",
767
+ "cmi.objectives.16.score.min": "",
768
+ "cmi.objectives.16.score.raw": "",
769
+ "cmi.objectives.16.status": "completed",
770
+ "cmi.objectives.17.id": "topic-5rxzyV",
771
+ "cmi.objectives.17.score.max": "100",
772
+ "cmi.objectives.17.score.min": "",
773
+ "cmi.objectives.17.score.raw": "",
774
+ "cmi.objectives.17.status": "completed",
775
+ "cmi.objectives.18.id": "topic-Q3rjln",
776
+ "cmi.objectives.18.score.max": "100",
777
+ "cmi.objectives.18.score.min": "",
778
+ "cmi.objectives.18.score.raw": "",
779
+ "cmi.objectives.18.status": "completed",
780
+ "cmi.objectives.19.id": "topic-eIbwi4",
781
+ "cmi.objectives.19.score.max": "100",
782
+ "cmi.objectives.19.score.min": "",
783
+ "cmi.objectives.19.score.raw": "",
784
+ "cmi.objectives.19.status": "completed",
785
+ "cmi.objectives.2.id": "topic-sfvmuO",
786
+ "cmi.objectives.2.score.max": "100",
787
+ "cmi.objectives.2.score.min": "",
788
+ "cmi.objectives.2.score.raw": "",
789
+ "cmi.objectives.2.status": "completed",
790
+ "cmi.objectives.20.id": "topic-AzAspy",
791
+ "cmi.objectives.20.score.max": "100",
792
+ "cmi.objectives.20.score.min": "",
793
+ "cmi.objectives.20.score.raw": "",
794
+ "cmi.objectives.20.status": "completed",
795
+ "cmi.objectives.21.id": "topic-ehMV4A",
796
+ "cmi.objectives.21.score.max": "100",
797
+ "cmi.objectives.21.score.min": "",
798
+ "cmi.objectives.21.score.raw": "",
799
+ "cmi.objectives.21.status": "completed",
800
+ "cmi.objectives.22.id": "topic-U52hDp",
801
+ "cmi.objectives.22.score.max": "100",
802
+ "cmi.objectives.22.score.min": "",
803
+ "cmi.objectives.22.score.raw": "",
804
+ "cmi.objectives.22.status": "completed",
805
+ "cmi.objectives.23.id": "topic-mmAPuC",
806
+ "cmi.objectives.23.score.max": "100",
807
+ "cmi.objectives.23.score.min": "",
808
+ "cmi.objectives.23.score.raw": "",
809
+ "cmi.objectives.23.status": "completed",
810
+ "cmi.objectives.24.id": "topic-UyqqeN",
811
+ "cmi.objectives.24.score.max": "100",
812
+ "cmi.objectives.24.score.min": "",
813
+ "cmi.objectives.24.score.raw": "",
814
+ "cmi.objectives.24.status": "completed",
815
+ "cmi.objectives.25.id": "topic-UIALBn",
816
+ "cmi.objectives.25.score.max": "100",
817
+ "cmi.objectives.25.score.min": "",
818
+ "cmi.objectives.25.score.raw": "",
819
+ "cmi.objectives.25.status": "completed",
820
+ "cmi.objectives.26.id": "topic-oLGCQE",
821
+ "cmi.objectives.26.score.max": "100",
822
+ "cmi.objectives.26.score.min": "",
823
+ "cmi.objectives.26.score.raw": "",
824
+ "cmi.objectives.26.status": "completed",
825
+ "cmi.objectives.27.id": "topic-JhRmY0",
826
+ "cmi.objectives.27.score.max": "100",
827
+ "cmi.objectives.27.score.min": "",
828
+ "cmi.objectives.27.score.raw": "",
829
+ "cmi.objectives.27.status": "completed",
830
+ "cmi.objectives.28.id": "topic-677fLH",
831
+ "cmi.objectives.28.score.max": "100",
832
+ "cmi.objectives.28.score.min": "",
833
+ "cmi.objectives.28.score.raw": "",
834
+ "cmi.objectives.28.status": "completed",
835
+ "cmi.objectives.29.id": "topic-rKvnIL",
836
+ "cmi.objectives.29.score.max": "100",
837
+ "cmi.objectives.29.score.min": "",
838
+ "cmi.objectives.29.score.raw": "",
839
+ "cmi.objectives.29.status": "completed",
840
+ "cmi.objectives.3.id": "topic-IObzTr",
841
+ "cmi.objectives.3.score.max": "100",
842
+ "cmi.objectives.3.score.min": "",
843
+ "cmi.objectives.3.score.raw": "",
844
+ "cmi.objectives.3.status": "completed",
845
+ "cmi.objectives.30.id": "topic-Vjd6mO",
846
+ "cmi.objectives.30.score.max": "100",
847
+ "cmi.objectives.30.score.min": "",
848
+ "cmi.objectives.30.score.raw": "",
849
+ "cmi.objectives.30.status": "completed",
850
+ "cmi.objectives.31.id": "topic-jUsEtX",
851
+ "cmi.objectives.31.score.max": "100",
852
+ "cmi.objectives.31.score.min": "",
853
+ "cmi.objectives.31.score.raw": "",
854
+ "cmi.objectives.31.status": "completed",
855
+ "cmi.objectives.32.id": "topic-SvCWWr",
856
+ "cmi.objectives.32.score.max": "100",
857
+ "cmi.objectives.32.score.min": "",
858
+ "cmi.objectives.32.score.raw": "",
859
+ "cmi.objectives.32.status": "completed",
860
+ "cmi.objectives.33.id": "topic-knRFfG",
861
+ "cmi.objectives.33.score.max": "100",
862
+ "cmi.objectives.33.score.min": "",
863
+ "cmi.objectives.33.score.raw": "",
864
+ "cmi.objectives.33.status": "completed",
865
+ "cmi.objectives.34.id": "topic-wlFwhf",
866
+ "cmi.objectives.34.score.max": "100",
867
+ "cmi.objectives.34.score.min": "",
868
+ "cmi.objectives.34.score.raw": "",
869
+ "cmi.objectives.34.status": "completed",
870
+ "cmi.objectives.35.id": "topic-3b86fq",
871
+ "cmi.objectives.35.score.max": "100",
872
+ "cmi.objectives.35.score.min": "",
873
+ "cmi.objectives.35.score.raw": "",
874
+ "cmi.objectives.35.status": "completed",
875
+ "cmi.objectives.36.id": "topic-ZjIFKf",
876
+ "cmi.objectives.36.score.max": "100",
877
+ "cmi.objectives.36.score.min": "",
878
+ "cmi.objectives.36.score.raw": "",
879
+ "cmi.objectives.36.status": "completed",
880
+ "cmi.objectives.37.id": "topic-A9spZz",
881
+ "cmi.objectives.37.score.max": "100",
882
+ "cmi.objectives.37.score.min": "",
883
+ "cmi.objectives.37.score.raw": "",
884
+ "cmi.objectives.37.status": "completed",
885
+ "cmi.objectives.38.id": "topic-nOmtUy",
886
+ "cmi.objectives.38.score.max": "100",
887
+ "cmi.objectives.38.score.min": "",
888
+ "cmi.objectives.38.score.raw": "",
889
+ "cmi.objectives.38.status": "completed",
890
+ "cmi.objectives.39.id": "topic-jxtabl",
891
+ "cmi.objectives.39.score.max": "100",
892
+ "cmi.objectives.39.score.min": "",
893
+ "cmi.objectives.39.score.raw": "",
894
+ "cmi.objectives.39.status": "completed",
895
+ "cmi.objectives.4.id": "topic-Bq3O5v",
896
+ "cmi.objectives.4.score.max": "100",
897
+ "cmi.objectives.4.score.min": "",
898
+ "cmi.objectives.4.score.raw": "",
899
+ "cmi.objectives.4.status": "completed",
900
+ "cmi.objectives.5.id": "topic-HmnDxg",
901
+ "cmi.objectives.5.score.max": "100",
902
+ "cmi.objectives.5.score.min": "",
903
+ "cmi.objectives.5.score.raw": "",
904
+ "cmi.objectives.5.status": "completed",
905
+ "cmi.objectives.6.id": "topic-4YswmY",
906
+ "cmi.objectives.6.score.max": "100",
907
+ "cmi.objectives.6.score.min": "",
908
+ "cmi.objectives.6.score.raw": "",
909
+ "cmi.objectives.6.status": "completed",
910
+ "cmi.objectives.7.id": "topic-LuAS5e",
911
+ "cmi.objectives.7.score.max": "100",
912
+ "cmi.objectives.7.score.min": "",
913
+ "cmi.objectives.7.score.raw": "",
914
+ "cmi.objectives.7.status": "completed",
915
+ "cmi.objectives.8.id": "topic-K6ECXa",
916
+ "cmi.objectives.8.score.max": "100",
917
+ "cmi.objectives.8.score.min": "",
918
+ "cmi.objectives.8.score.raw": "",
919
+ "cmi.objectives.8.status": "completed",
920
+ "cmi.objectives.9.id": "topic-2lpxvN",
921
+ "cmi.objectives.9.score.max": "100",
922
+ "cmi.objectives.9.score.min": "",
923
+ "cmi.objectives.9.score.raw": "",
924
+ "cmi.objectives.9.status": "completed",
925
+ "cmi.student_data.mastery_score": "",
926
+ "cmi.student_data.max_time_allowed": "",
927
+ "cmi.student_data.time_limit_action": "",
928
+ "cmi.student_preference.audio": "",
929
+ "cmi.student_preference.language": "",
930
+ "cmi.student_preference.speed": "",
931
+ "cmi.student_preference.text": "",
932
+ "cmi.suspend_data": "",
933
+ },
934
+ "",
935
+ );
936
+ scorm12api.lmsInitialize();
937
+
938
+ expect(scorm12api.getCMIValue("cmi.objectives.10.id")).toEqual(
939
+ "topic-MllWvr",
940
+ );
941
+ });
942
+ });
580
943
  });