scorm-again 2.1.0 → 2.3.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.
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import Scorm2004API from "./src/Scorm2004API.ts";
2
+ import Scorm12API from "./src/Scorm12API.ts";
3
+ import AICC from "./src/AICC.ts";
4
+
5
+ export { Scorm2004API, Scorm12API, AICC };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "scorm-again",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "A modern SCORM JavaScript run-time library for AICC, SCORM 1.2, and SCORM 2004",
5
- "main": "dist/scorm-again.min.js",
5
+ "main": "index.d.ts",
6
6
  "type": "module",
7
7
  "browser": {
8
8
  "electron": false
@@ -20,17 +20,16 @@
20
20
  "test": "test"
21
21
  },
22
22
  "devDependencies": {
23
- "@babel/cli": "^7.25.7",
24
- "@babel/core": "^7.25.7",
25
- "@babel/eslint-parser": "^7.25.7",
26
- "@babel/node": "^7.25.7",
27
- "@babel/preset-env": "^7.25.7",
28
- "@babel/preset-typescript": "^7.25.7",
23
+ "@babel/cli": "^7.25.9",
24
+ "@babel/core": "^7.25.9",
25
+ "@babel/eslint-parser": "^7.25.9",
26
+ "@babel/node": "^7.25.9",
27
+ "@babel/preset-env": "^7.25.9",
28
+ "@babel/preset-typescript": "^7.25.9",
29
29
  "@eslint/eslintrc": "^3.1.0",
30
- "@eslint/js": "^9.12.0",
30
+ "@eslint/js": "^9.13.0",
31
31
  "@istanbuljs/nyc-config-typescript": "^1.0.2",
32
32
  "@types/eslint__js": "^8.42.3",
33
- "@types/expect": "^24.3.0",
34
33
  "@types/mocha": "^10.0.9",
35
34
  "@types/sinon": "^17.0.3",
36
35
  "babel-eslint": "^11.0.0-beta.2",
@@ -39,15 +38,15 @@
39
38
  "browserify": "^17.0.1",
40
39
  "c8": "^10.1.2",
41
40
  "c8-as-nyc": "^1.1.11",
42
- "eslint": "^9.12.0",
41
+ "eslint": "^9.13.0",
43
42
  "eslint-formatter-junit": "^8.40.0",
44
43
  "eslint-plugin-import": "^2.31.0",
45
- "eslint-plugin-jsdoc": "^50.3.1",
44
+ "eslint-plugin-jsdoc": "^50.4.3",
46
45
  "eslint-webpack-plugin": "^4.2.0",
47
46
  "expect": "^29.7.0",
48
47
  "fetch-pretender": "https://github.com/jcputney/fetch-pretender#master",
49
48
  "globals": "^15.11.0",
50
- "jsdoc": "^4.0.3",
49
+ "jsdoc": "^4.0.4",
51
50
  "jsdoc-babel": "^0.5.0",
52
51
  "minimist": "^1.2.8",
53
52
  "miragejs": "^0.2.0-alpha.3",
@@ -60,7 +59,7 @@
60
59
  "ts-loader": "^9.5.1",
61
60
  "tsx": "^4.19.1",
62
61
  "typescript": "^5.6.3",
63
- "typescript-eslint": "^8.8.1",
62
+ "typescript-eslint": "^8.11.0",
64
63
  "webpack": "^5.91.0",
65
64
  "webpack-cli": "^5.1.4"
66
65
  },
package/src/BaseAPI.ts CHANGED
@@ -5,7 +5,12 @@ import APIConstants from "./constants/api_constants";
5
5
  import { formatMessage, stringMatches, unflatten } from "./utilities";
6
6
  import { BaseCMI } from "./cmi/common/base_cmi";
7
7
  import { debounce } from "./utilities/debounce";
8
- import { RefObject, ResultObject, Settings } from "./types/api_types";
8
+ import {
9
+ RefObject,
10
+ CommitObject,
11
+ ResultObject,
12
+ Settings,
13
+ } from "./types/api_types";
9
14
  import { DefaultSettings } from "./constants/default_settings";
10
15
  import { IBaseAPI } from "./interfaces/IBaseAPI";
11
16
  import { ScheduledCommit } from "./helpers/scheduled_commit";
@@ -165,6 +170,13 @@ export default abstract class BaseAPI implements IBaseAPI {
165
170
  */
166
171
  abstract renderCommitCMI(_terminateCommit: boolean): RefObject | Array<any>;
167
172
 
173
+ /**
174
+ * Render the commit object to the shortened format for LMS commit
175
+ * @param {boolean} _terminateCommit
176
+ * @return {CommitObject}
177
+ */
178
+ abstract renderCommitObject(_terminateCommit: boolean): CommitObject;
179
+
168
180
  /**
169
181
  * Logging for all SCORM actions
170
182
  *
@@ -1114,13 +1126,13 @@ export default abstract class BaseAPI implements IBaseAPI {
1114
1126
  /**
1115
1127
  * Send the request to the LMS
1116
1128
  * @param {string} url
1117
- * @param {RefObject|Array} params
1129
+ * @param {CommitObject|RefObject|Array} params
1118
1130
  * @param {boolean} immediate
1119
1131
  * @return {ResultObject}
1120
1132
  */
1121
1133
  async processHttpRequest(
1122
1134
  url: string,
1123
- params: RefObject | Array<any>,
1135
+ params: CommitObject | RefObject | Array<any>,
1124
1136
  immediate: boolean = false,
1125
1137
  ): Promise<ResultObject> {
1126
1138
  const api = this;
@@ -1143,7 +1155,7 @@ export default abstract class BaseAPI implements IBaseAPI {
1143
1155
 
1144
1156
  const process = async (
1145
1157
  url: string,
1146
- params: RefObject | Array<any>,
1158
+ params: CommitObject | RefObject | Array<any>,
1147
1159
  settings: Settings,
1148
1160
  ): Promise<ResultObject> => {
1149
1161
  try {
package/src/Scorm12API.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import BaseAPI from "./BaseAPI";
2
2
  import { CMI } from "./cmi/scorm12/cmi";
3
3
  import * as Utilities from "./utilities";
4
+ import { stringMatches } from "./utilities";
4
5
  import APIConstants from "./constants/api_constants";
5
6
  import ErrorCodes from "./constants/error_codes";
6
7
 
@@ -12,8 +13,15 @@ import {
12
13
  CMIInteractionsObjectivesObject,
13
14
  } from "./cmi/scorm12/interactions";
14
15
  import { NAV } from "./cmi/scorm12/nav";
15
- import { RefObject, ResultObject, Settings } from "./types/api_types";
16
- import { stringMatches } from "./utilities";
16
+ import {
17
+ CommitObject,
18
+ RefObject,
19
+ ResultObject,
20
+ ScoreObject,
21
+ Settings,
22
+ } from "./types/api_types";
23
+ import Regex from "./constants/regex";
24
+ import { CompletionStatus, SuccessStatus } from "./constants/enums";
17
25
 
18
26
  /**
19
27
  * API class for SCORM 1.2
@@ -320,6 +328,61 @@ export default class Scorm12API extends BaseAPI {
320
328
  }
321
329
  }
322
330
 
331
+ /**
332
+ * Render the cmi object to the proper format for LMS commit
333
+ * @param {boolean} terminateCommit
334
+ * @return {CommitObject}
335
+ */
336
+ renderCommitObject(terminateCommit: boolean): CommitObject {
337
+ const cmiExport = this.renderCommitCMI(terminateCommit);
338
+ const totalTimeHHMMSS = this.cmi.getCurrentTotalTime();
339
+ const totalTimeSeconds = Utilities.getTimeAsSeconds(
340
+ totalTimeHHMMSS,
341
+ Regex.scorm12.CMITimespan,
342
+ );
343
+ const lessonStatus = this.cmi.core.lesson_status;
344
+ let completionStatus = CompletionStatus.unknown;
345
+ let successStatus = SuccessStatus.unknown;
346
+ if (lessonStatus) {
347
+ completionStatus =
348
+ lessonStatus === "completed" || lessonStatus === "passed"
349
+ ? CompletionStatus.completed
350
+ : CompletionStatus.incomplete;
351
+ if (lessonStatus === "passed") {
352
+ successStatus = SuccessStatus.passed;
353
+ } else if (lessonStatus === "failed") {
354
+ successStatus = SuccessStatus.failed;
355
+ }
356
+ }
357
+
358
+ const score = this.cmi.core.score;
359
+ let scoreObject: ScoreObject = null;
360
+ if (score) {
361
+ scoreObject = {};
362
+
363
+ if (!Number.isNaN(Number.parseFloat(score.raw))) {
364
+ scoreObject.raw = Number.parseFloat(score.raw);
365
+ }
366
+ if (!Number.isNaN(Number.parseFloat(score.min))) {
367
+ scoreObject.min = Number.parseFloat(score.min);
368
+ }
369
+ if (!Number.isNaN(Number.parseFloat(score.max))) {
370
+ scoreObject.max = Number.parseFloat(score.max);
371
+ }
372
+ }
373
+
374
+ const commitObject: CommitObject = {
375
+ successStatus: successStatus,
376
+ completionStatus: completionStatus,
377
+ runtimeData: cmiExport,
378
+ totalTimeSeconds: totalTimeSeconds,
379
+ };
380
+ if (scoreObject) {
381
+ commitObject.score = scoreObject;
382
+ }
383
+ return commitObject;
384
+ }
385
+
323
386
  /**
324
387
  * Attempts to store the data to the LMS
325
388
  *
@@ -361,9 +424,11 @@ export default class Scorm12API extends BaseAPI {
361
424
  }
362
425
  }
363
426
 
364
- const commitObject = this.renderCommitCMI(
365
- terminateCommit || this.settings.alwaysSendTotalTime,
366
- );
427
+ const shouldTerminateCommit =
428
+ terminateCommit || this.settings.alwaysSendTotalTime;
429
+ const commitObject = this.settings.renderCommonCommitFields
430
+ ? this.renderCommitObject(shouldTerminateCommit)
431
+ : this.renderCommitCMI(shouldTerminateCommit);
367
432
 
368
433
  if (this.apiLogLevel === APIConstants.global.LOG_LEVEL_DEBUG) {
369
434
  console.debug(
@@ -18,7 +18,14 @@ import {
18
18
  import { CMICommentsObject } from "./cmi/scorm2004/comments";
19
19
  import { CMIObjectivesObject } from "./cmi/scorm2004/objectives";
20
20
  import { ADL } from "./cmi/scorm2004/adl";
21
- import { RefObject, ResultObject, Settings } from "./types/api_types";
21
+ import {
22
+ CommitObject,
23
+ RefObject,
24
+ ResultObject,
25
+ ScoreObject,
26
+ Settings,
27
+ } from "./types/api_types";
28
+ import { CompletionStatus, SuccessStatus } from "./constants/enums";
22
29
 
23
30
  /**
24
31
  * API class for SCORM 2004
@@ -613,6 +620,67 @@ export default class Scorm2004API extends BaseAPI {
613
620
  }
614
621
  }
615
622
 
623
+ /**
624
+ * Render the cmi object to the proper format for LMS commit
625
+ * @param {boolean} terminateCommit
626
+ * @return {CommitObject}
627
+ */
628
+ renderCommitObject(terminateCommit: boolean): CommitObject {
629
+ const cmiExport = this.renderCommitCMI(terminateCommit);
630
+ const totalTimeDuration = this.cmi.getCurrentTotalTime();
631
+ const totalTimeSeconds = Utilities.getDurationAsSeconds(
632
+ totalTimeDuration,
633
+ Regex.scorm2004.CMITimespan,
634
+ );
635
+
636
+ let completionStatus = CompletionStatus.unknown;
637
+ let successStatus = SuccessStatus.unknown;
638
+ if (this.cmi.completion_status) {
639
+ if (this.cmi.completion_status === "completed") {
640
+ completionStatus = CompletionStatus.completed;
641
+ } else if (this.cmi.completion_status === "incomplete") {
642
+ completionStatus = CompletionStatus.incomplete;
643
+ }
644
+ }
645
+ if (this.cmi.success_status) {
646
+ if (this.cmi.success_status === "passed") {
647
+ successStatus = SuccessStatus.passed;
648
+ } else if (this.cmi.success_status === "failed") {
649
+ successStatus = SuccessStatus.failed;
650
+ }
651
+ }
652
+
653
+ const score = this.cmi.score;
654
+ let scoreObject: ScoreObject = null;
655
+ if (score) {
656
+ scoreObject = {};
657
+
658
+ if (!Number.isNaN(Number.parseFloat(score.raw))) {
659
+ scoreObject.raw = Number.parseFloat(score.raw);
660
+ }
661
+ if (!Number.isNaN(Number.parseFloat(score.min))) {
662
+ scoreObject.min = Number.parseFloat(score.min);
663
+ }
664
+ if (!Number.isNaN(Number.parseFloat(score.max))) {
665
+ scoreObject.max = Number.parseFloat(score.max);
666
+ }
667
+ if (!Number.isNaN(Number.parseFloat(score.scaled))) {
668
+ scoreObject.scaled = Number.parseFloat(score.scaled);
669
+ }
670
+ }
671
+
672
+ const commitObject: CommitObject = {
673
+ completionStatus: completionStatus,
674
+ successStatus: successStatus,
675
+ totalTimeSeconds: totalTimeSeconds,
676
+ runtimeData: cmiExport,
677
+ };
678
+ if (scoreObject) {
679
+ commitObject.score = scoreObject;
680
+ }
681
+ return commitObject;
682
+ }
683
+
616
684
  /**
617
685
  * Attempts to store the data to the LMS
618
686
  *
@@ -650,9 +718,11 @@ export default class Scorm2004API extends BaseAPI {
650
718
  navRequest = true;
651
719
  }
652
720
 
653
- const commitObject = this.renderCommitCMI(
654
- terminateCommit || this.settings.alwaysSendTotalTime,
655
- );
721
+ const shouldTerminateCommit =
722
+ terminateCommit || this.settings.alwaysSendTotalTime;
723
+ const commitObject = this.settings.renderCommonCommitFields
724
+ ? this.renderCommitObject(shouldTerminateCommit)
725
+ : this.renderCommitCMI(shouldTerminateCommit);
656
726
 
657
727
  if (this.apiLogLevel === APIConstants.global.LOG_LEVEL_DEBUG) {
658
728
  console.debug(
@@ -16,6 +16,7 @@ export const DefaultSettings: Settings = {
16
16
  logLevel: APIConstants.global.LOG_LEVEL_ERROR,
17
17
  selfReportSessionTime: false,
18
18
  alwaysSendTotalTime: false,
19
+ renderCommonCommitFields: false,
19
20
  strict_errors: true,
20
21
  xhrHeaders: {},
21
22
  xhrWithCredentials: false,
@@ -3,3 +3,15 @@ export enum NAVBoolean {
3
3
  true = "true",
4
4
  false = "false",
5
5
  }
6
+
7
+ export enum SuccessStatus {
8
+ passed = "passed",
9
+ failed = "failed",
10
+ unknown = "unknown",
11
+ }
12
+
13
+ export enum CompletionStatus {
14
+ completed = "completed",
15
+ incomplete = "incomplete",
16
+ unknown = "unknown",
17
+ }
@@ -1,3 +1,5 @@
1
+ import { CompletionStatus, SuccessStatus } from "../constants/enums";
2
+
1
3
  export type Settings = {
2
4
  autocommit?: boolean;
3
5
  autocommitSeconds?: number;
@@ -19,6 +21,7 @@ export type Settings = {
19
21
  scoItemIds?: string[];
20
22
  scoItemIdValidator?: false | ((scoItemId: string) => boolean);
21
23
  mastery_override?: boolean;
24
+ renderCommonCommitFields?: boolean;
22
25
  };
23
26
 
24
27
  export type RefObject = {
@@ -30,3 +33,18 @@ export type ResultObject = {
30
33
  errorCode: number;
31
34
  navRequest?: string;
32
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
+ };
@@ -358,6 +358,116 @@ describe("SCORM 1.2 API Tests", () => {
358
358
  const cmiExport: RefObject = scorm12API.renderCommitCMI(true);
359
359
  expect(cmiExport.cmi.core.total_time).toEqual("23:59:59");
360
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
+ });
361
471
  });
362
472
 
363
473
  describe("storeData()", () => {
@@ -827,6 +827,76 @@ describe("SCORM 2004 API Tests", () => {
827
827
  });
828
828
  });
829
829
 
830
+ describe("renderCommitObject()", () => {
831
+ it("should render commit object with default settings and no score", () => {
832
+ const scorm2004API = api();
833
+ scorm2004API.cmi.completion_status = "incomplete";
834
+ scorm2004API.cmi.total_time = "P12H34M56S";
835
+ scorm2004API.cmi.session_time = "P23H59M59S";
836
+ const commitObject = scorm2004API.renderCommitObject(true);
837
+ expect(commitObject.successStatus).toEqual("unknown");
838
+ expect(commitObject.completionStatus).toEqual("incomplete");
839
+ expect(commitObject.runtimeData.cmi.completion_status).toEqual(
840
+ "incomplete",
841
+ );
842
+ expect(commitObject.totalTimeSeconds).toEqual(
843
+ 12 * 3600 + 34 * 60 + 56 + (23 * 3600 + 59 * 60 + 59),
844
+ );
845
+ });
846
+
847
+ it("should render commit object with score data", () => {
848
+ const scorm2004API = api();
849
+ scorm2004API.cmi.completion_status = "completed";
850
+ scorm2004API.cmi.score.raw = "85";
851
+ scorm2004API.cmi.score.min = "0";
852
+ scorm2004API.cmi.score.max = "100";
853
+ scorm2004API.cmi.score.scaled = "0.85";
854
+ const commitObject = scorm2004API.renderCommitObject(true);
855
+ expect(commitObject.successStatus).toEqual("unknown");
856
+ expect(commitObject.completionStatus).toEqual("completed");
857
+ expect(commitObject.runtimeData.cmi.completion_status).toEqual(
858
+ "completed",
859
+ );
860
+ expect(commitObject.runtimeData.cmi.score.raw).toEqual("85");
861
+ expect(commitObject.runtimeData.cmi.score.min).toEqual("0");
862
+ expect(commitObject.runtimeData.cmi.score.max).toEqual("100");
863
+ expect(commitObject.runtimeData.cmi.score.scaled).toEqual("0.85");
864
+ expect(commitObject.totalTimeSeconds).toEqual(0);
865
+ expect(commitObject.score).toEqual({
866
+ raw: 85,
867
+ min: 0,
868
+ max: 100,
869
+ scaled: 0.85,
870
+ });
871
+ });
872
+
873
+ it("should render commit object with completion and success status", () => {
874
+ const scorm2004API = api();
875
+ scorm2004API.cmi.success_status = "passed";
876
+ const commitObject = scorm2004API.renderCommitObject(true);
877
+ expect(commitObject.successStatus).toEqual("passed");
878
+ expect(commitObject.completionStatus).toEqual("unknown");
879
+ expect(commitObject.runtimeData.cmi.success_status).toEqual("passed");
880
+ });
881
+
882
+ it("should render commit object with failed success status", () => {
883
+ const scorm2004API = api();
884
+ scorm2004API.cmi.success_status = "failed";
885
+ const commitObject = scorm2004API.renderCommitObject(true);
886
+ expect(commitObject.successStatus).toEqual("failed");
887
+ expect(commitObject.completionStatus).toEqual("unknown");
888
+ expect(commitObject.runtimeData.cmi.success_status).toEqual("failed");
889
+ });
890
+
891
+ it("should calculate total time when terminateCommit is true", () => {
892
+ const scorm2004API = api();
893
+ scorm2004API.cmi.total_time = "P12H34M56S";
894
+ scorm2004API.cmi.session_time = "P23H59M59S";
895
+ const commitObject = scorm2004API.renderCommitObject(true);
896
+ expect(commitObject.runtimeData.cmi.total_time).toEqual("P1DT12H34M55S");
897
+ });
898
+ });
899
+
830
900
  describe("lmsGetDiagnostic()", () => {
831
901
  it("should return diagnostic information for a given error code", () => {
832
902
  const scorm2004API = api();