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
@@ -1,19 +1,17 @@
1
1
  import { describe, it } from "mocha";
2
2
  import APIConstants from "../../src/constants/api_constants";
3
3
  import ErrorCodes from "../../src/constants/error_codes";
4
- import {
5
- CMI,
6
- CMIEvaluationCommentsObject,
7
- CMITriesObject,
8
- } from "../../src/cmi/aicc_cmi";
4
+ import { CMI } from "../../src/cmi/aicc/cmi";
9
5
  import * as h from "../cmi_helpers";
10
- import {
11
- CMIInteractionsObject,
12
- CMIObjectivesObject,
13
- NAV,
14
- } from "../../src/cmi/scorm12_cmi";
15
6
  import { expect } from "expect";
16
7
  import { scorm12Values } from "../field_values";
8
+ import { CMITriesObject } from "../../src/cmi/aicc/tries";
9
+ import { CMIEvaluationCommentsObject } from "../../src/cmi/aicc/evaluation";
10
+ import { CMIObjectivesObject } from "../../src/cmi/scorm12/objectives";
11
+ import { CMIInteractionsObject } from "../../src/cmi/scorm12/interactions";
12
+ import { NAV } from "../../src/cmi/scorm12/nav";
13
+ import { CMIPathsObject } from "../../src/cmi/aicc/paths";
14
+ import { CMIStudentDemographics } from "../../src/cmi/aicc/student_demographics";
17
15
 
18
16
  const aicc_constants = APIConstants.aicc;
19
17
  const scorm12_error_codes = ErrorCodes.scorm12;
@@ -524,7 +522,7 @@ describe("AICC CMI Tests", () => {
524
522
  );
525
523
  cmiObj.student_data.tries.childArray.push(new CMITriesObject());
526
524
  expect(JSON.stringify(cmiObj)).toEqual(
527
- '{"suspend_data":"","launch_data":"","comments":"","comments_from_lms":"","core":{"student_id":"","student_name":"","lesson_location":"","credit":"","lesson_status":"not attempted","entry":"","lesson_mode":"normal","exit":"","session_time":"00:00:00","score":{"raw":"","min":"","max":"100"}},"objectives":{"0":{"id":"","status":"","score":{"raw":"","min":"","max":"100"}}},"student_data":{"mastery_score":"","max_time_allowed":"","time_limit_action":"","tries":{"0":{"status":"","time":"","score":{"raw":"","min":"","max":"100"}}}},"student_preference":{"audio":"","language":"","lesson_type":"","speed":"","text":"","text_color":"","text_location":"","text_size":"","video":"","windows":{}},"student_demographics":{"city":"","class":"","company":"","country":"","experience":"","familiar_name":"","instructor_name":"","title":"","native_language":"","state":"","street_address":"","telephone":"","years_experience":""},"interactions":{"0":{"id":"","time":"","type":"","weighting":"","student_response":"","result":"","latency":"","objectives":{},"correct_responses":{}}},"evaluation":{"comments":{"0":{"content":"","location":"","time":""}}},"paths":{}}',
525
+ '{"suspend_data":"","launch_data":"","comments":"","comments_from_lms":"","core":{"student_id":"","student_name":"","lesson_location":"","credit":"","lesson_status":"not attempted","entry":"","lesson_mode":"normal","exit":"","session_time":"00:00:00","score":{"raw":"","min":"","max":"100"}},"objectives":{"0":{"id":"","status":"","score":{"raw":"","min":"","max":"100"}}},"student_data":{"mastery_score":"","max_time_allowed":"","time_limit_action":"","tries":{"0":{"status":"","time":"","score":{"raw":"","min":"","max":"100"}}},"attempt_records":{}},"student_preference":{"audio":"","language":"","lesson_type":"","speed":"","text":"","text_color":"","text_location":"","text_size":"","video":"","windows":{}},"student_demographics":{"city":"","class":"","company":"","country":"","experience":"","familiar_name":"","instructor_name":"","title":"","native_language":"","state":"","street_address":"","telephone":"","years_experience":""},"interactions":{"0":{"id":"","time":"","type":"","weighting":"","student_response":"","result":"","latency":"","objectives":{},"correct_responses":{}}},"evaluation":{"comments":{"0":{"content":"","location":"","time":""}}},"paths":{}}',
528
526
  );
529
527
  });
530
528
  });
@@ -604,6 +602,185 @@ describe("AICC CMI Tests", () => {
604
602
  });
605
603
  });
606
604
 
605
+ describe("CMIPathsObject Tests", () => {
606
+ const paths = () => {
607
+ return new CMIPathsObject();
608
+ };
609
+
610
+ h.checkFieldConstraintSize({
611
+ cmi: paths(),
612
+ fieldName: "cmi.location_id",
613
+ expectedError: type_mismatch,
614
+ limit: 255,
615
+ });
616
+ h.checkReadAndWrite({
617
+ cmi: paths(),
618
+ fieldName: "cmi.date",
619
+ valueToTest: "2021-01-01",
620
+ });
621
+ h.checkValidValues({
622
+ cmi: paths(),
623
+ fieldName: "cmi.time",
624
+ validValues: scorm12Values.validTime,
625
+ invalidValues: scorm12Values.invalidTime,
626
+ });
627
+ h.checkValidValues({
628
+ cmi: paths(),
629
+ fieldName: "cmi.status",
630
+ validValues: scorm12Values.validLessonStatus,
631
+ invalidValues: scorm12Values.invalidLessonStatus,
632
+ });
633
+ h.checkFieldConstraintSize({
634
+ cmi: paths(),
635
+ fieldName: "cmi.why_left",
636
+ expectedError: type_mismatch,
637
+ limit: 255,
638
+ });
639
+ h.checkValidValues({
640
+ cmi: paths(),
641
+ fieldName: "cmi.time_in_element",
642
+ validValues: scorm12Values.validTime,
643
+ invalidValues: scorm12Values.invalidTime,
644
+ });
645
+
646
+ it("should export JSON", () => {
647
+ const cmi = paths();
648
+ expect(JSON.stringify(cmi)).toEqual(
649
+ '{"location_id":"","date":"","time":"","status":"","why_left":"","time_in_element":""}',
650
+ );
651
+ });
652
+ });
653
+
654
+ describe("CMIStudentDemographicsObject Tests", () => {
655
+ const cmiInit = () => {
656
+ const cmiStudentDemographics = new CMIStudentDemographics();
657
+ cmiStudentDemographics.initialize();
658
+ return cmiStudentDemographics;
659
+ };
660
+ const cmi = () => {
661
+ return new CMIStudentDemographics();
662
+ };
663
+
664
+ h.checkReadOnly({
665
+ cmi: cmiInit(),
666
+ fieldName: "cmi.city",
667
+ expectedError: read_only,
668
+ });
669
+ h.checkReadOnly({
670
+ cmi: cmiInit(),
671
+ fieldName: "cmi.class",
672
+ expectedError: read_only,
673
+ });
674
+ h.checkReadOnly({
675
+ cmi: cmiInit(),
676
+ fieldName: "cmi.company",
677
+ expectedError: read_only,
678
+ });
679
+ h.checkReadOnly({
680
+ cmi: cmiInit(),
681
+ fieldName: "cmi.country",
682
+ expectedError: read_only,
683
+ });
684
+ h.checkReadOnly({
685
+ cmi: cmiInit(),
686
+ fieldName: "cmi.experience",
687
+ expectedError: read_only,
688
+ });
689
+ h.checkReadOnly({
690
+ cmi: cmiInit(),
691
+ fieldName: "cmi.familiar_name",
692
+ expectedError: read_only,
693
+ });
694
+ h.checkReadOnly({
695
+ cmi: cmiInit(),
696
+ fieldName: "cmi.instructor_name",
697
+ expectedError: read_only,
698
+ });
699
+ h.checkReadOnly({
700
+ cmi: cmiInit(),
701
+ fieldName: "cmi.title",
702
+ expectedError: read_only,
703
+ });
704
+ h.checkReadOnly({
705
+ cmi: cmiInit(),
706
+ fieldName: "cmi.native_language",
707
+ expectedError: read_only,
708
+ });
709
+ h.checkReadOnly({
710
+ cmi: cmiInit(),
711
+ fieldName: "cmi.state",
712
+ expectedError: read_only,
713
+ });
714
+ h.checkReadOnly({
715
+ cmi: cmiInit(),
716
+ fieldName: "cmi.street_address",
717
+ expectedError: read_only,
718
+ });
719
+ h.checkReadOnly({
720
+ cmi: cmiInit(),
721
+ fieldName: "cmi.telephone",
722
+ expectedError: read_only,
723
+ });
724
+ h.checkReadOnly({
725
+ cmi: cmiInit(),
726
+ fieldName: "cmi.years_experience",
727
+ expectedError: read_only,
728
+ });
729
+
730
+ h.checkReadAndWrite({
731
+ cmi: cmi(),
732
+ fieldName: "cmi.city",
733
+ });
734
+ h.checkReadAndWrite({
735
+ cmi: cmi(),
736
+ fieldName: "cmi.class",
737
+ });
738
+ h.checkReadAndWrite({
739
+ cmi: cmi(),
740
+ fieldName: "cmi.company",
741
+ });
742
+ h.checkReadAndWrite({
743
+ cmi: cmi(),
744
+ fieldName: "cmi.country",
745
+ });
746
+ h.checkReadAndWrite({
747
+ cmi: cmi(),
748
+ fieldName: "cmi.experience",
749
+ });
750
+ h.checkReadAndWrite({
751
+ cmi: cmi(),
752
+ fieldName: "cmi.familiar_name",
753
+ });
754
+ h.checkReadAndWrite({
755
+ cmi: cmi(),
756
+ fieldName: "cmi.instructor_name",
757
+ });
758
+ h.checkReadAndWrite({
759
+ cmi: cmi(),
760
+ fieldName: "cmi.title",
761
+ });
762
+ h.checkReadAndWrite({
763
+ cmi: cmi(),
764
+ fieldName: "cmi.native_language",
765
+ });
766
+ h.checkReadAndWrite({
767
+ cmi: cmi(),
768
+ fieldName: "cmi.state",
769
+ });
770
+ h.checkReadAndWrite({
771
+ cmi: cmi(),
772
+ fieldName: "cmi.street_address",
773
+ });
774
+ h.checkReadAndWrite({
775
+ cmi: cmi(),
776
+ fieldName: "cmi.telephone",
777
+ });
778
+ h.checkReadAndWrite({
779
+ cmi: cmi(),
780
+ fieldName: "cmi.years_experience",
781
+ });
782
+ });
783
+
607
784
  describe("CMIEvaluationCommentsObject Tests", () => {
608
785
  const evaluationComment = () => {
609
786
  return new CMIEvaluationCommentsObject();
@@ -2,15 +2,15 @@ import { expect } from "expect";
2
2
  import { describe, it } from "mocha";
3
3
  import APIConstants from "../../src/constants/api_constants";
4
4
  import ErrorCodes from "../../src/constants/error_codes";
5
+ import { CMI } from "../../src/cmi/scorm12/cmi";
6
+ import * as h from "../cmi_helpers";
7
+ import { scorm12Values } from "../field_values";
8
+ import { CMIObjectivesObject } from "../../src/cmi/scorm12/objectives";
5
9
  import {
6
- CMI,
7
10
  CMIInteractionsCorrectResponsesObject,
8
11
  CMIInteractionsObject,
9
12
  CMIInteractionsObjectivesObject,
10
- CMIObjectivesObject,
11
- } from "../../src/cmi/scorm12_cmi";
12
- import * as h from "../cmi_helpers";
13
- import { scorm12Values } from "../field_values";
13
+ } from "../../src/cmi/scorm12/interactions";
14
14
 
15
15
  const scorm12 = APIConstants.scorm12;
16
16
  const scorm12_error_codes = ErrorCodes.scorm12;
@@ -1,18 +1,18 @@
1
1
  import { describe, it } from "mocha";
2
2
  import ErrorCodes from "../../src/constants/error_codes";
3
3
  import APIConstants from "../../src/constants/api_constants";
4
+ import { CMI } from "../../src/cmi/scorm2004/cmi";
5
+ import * as h from "../cmi_helpers";
6
+ import { expect } from "expect";
7
+ import { scorm2004Values } from "../field_values";
4
8
  import {
5
- ADL,
6
- CMI,
7
- CMICommentsObject,
8
9
  CMIInteractionsCorrectResponsesObject,
9
10
  CMIInteractionsObject,
10
11
  CMIInteractionsObjectivesObject,
11
- CMIObjectivesObject,
12
- } from "../../src/cmi/scorm2004_cmi";
13
- import * as h from "../cmi_helpers";
14
- import { expect } from "expect";
15
- import { scorm2004Values } from "../field_values";
12
+ } from "../../src/cmi/scorm2004/interactions";
13
+ import { CMICommentsObject } from "../../src/cmi/scorm2004/comments";
14
+ import { CMIObjectivesObject } from "../../src/cmi/scorm2004/objectives";
15
+ import { ADL } from "../../src/cmi/scorm2004/adl";
16
16
 
17
17
  const scorm2004_constants = APIConstants.scorm2004;
18
18
  const scorm2004_error_codes = ErrorCodes.scorm2004;
@@ -1,7 +1,7 @@
1
1
  import { describe, it } from "mocha";
2
2
  import { expect } from "expect";
3
- import { BaseCMI, BaseRootCMI } from "../src/cmi/common";
4
3
  import { getError } from "./api_helpers";
4
+ import { BaseCMI, BaseRootCMI } from "../src/cmi/common/base_cmi";
5
5
 
6
6
  export type CheckFieldConstraintSize = {
7
7
  cmi: BaseCMI;
@@ -0,0 +1,126 @@
1
+ import { expect } from "expect";
2
+ import * as sinon from "sinon";
3
+ import { ResultObject, Settings } from "../../src/types/api_types";
4
+ import APIConstants from "../../src/constants/api_constants";
5
+
6
+ describe("Settings Type", () => {
7
+ const defaultSettings: Settings = {
8
+ autocommit: false,
9
+ autocommitSeconds: 10,
10
+ asyncCommit: false,
11
+ sendFullCommit: true,
12
+ lmsCommitUrl: false,
13
+ dataCommitFormat: "json",
14
+ commitRequestDataType: "application/json;charset=UTF-8",
15
+ autoProgress: false,
16
+ logLevel: APIConstants.global.LOG_LEVEL_ERROR,
17
+ selfReportSessionTime: false,
18
+ alwaysSendTotalTime: false,
19
+ strict_errors: true,
20
+ xhrHeaders: {},
21
+ xhrWithCredentials: false,
22
+ responseHandler: async (response: Response): Promise<ResultObject> => {
23
+ const httpResult = JSON.parse(await response.text());
24
+ return {
25
+ result: httpResult.result || APIConstants.global.SCORM_FALSE,
26
+ errorCode:
27
+ httpResult.errorCode !== undefined ? httpResult.errorCode : 101,
28
+ };
29
+ },
30
+ requestHandler: (commitObject: any) => commitObject,
31
+ onLogMessage: (messageLevel: number, logMessage: string) => {
32
+ switch (messageLevel) {
33
+ case APIConstants.global.LOG_LEVEL_ERROR:
34
+ console.error(logMessage);
35
+ break;
36
+ case APIConstants.global.LOG_LEVEL_WARNING:
37
+ console.warn(logMessage);
38
+ break;
39
+ case APIConstants.global.LOG_LEVEL_INFO:
40
+ console.info(logMessage);
41
+ break;
42
+ case APIConstants.global.LOG_LEVEL_DEBUG:
43
+ if (console.debug) {
44
+ console.debug(logMessage);
45
+ } else {
46
+ console.log(logMessage);
47
+ }
48
+ break;
49
+ }
50
+ },
51
+ };
52
+
53
+ it("should have correct default values", () => {
54
+ expect(defaultSettings.autocommit).toBe(false);
55
+ expect(defaultSettings.autocommitSeconds).toEqual(10);
56
+ expect(defaultSettings.asyncCommit).toBe(false);
57
+ expect(defaultSettings.sendFullCommit).toBe(true);
58
+ expect(defaultSettings.lmsCommitUrl).toBe(false);
59
+ expect(defaultSettings.dataCommitFormat).toEqual("json");
60
+ expect(defaultSettings.commitRequestDataType).toEqual(
61
+ "application/json;charset=UTF-8",
62
+ );
63
+ expect(defaultSettings.autoProgress).toBe(false);
64
+ expect(defaultSettings.logLevel).toEqual(
65
+ APIConstants.global.LOG_LEVEL_ERROR,
66
+ );
67
+ expect(defaultSettings.selfReportSessionTime).toBe(false);
68
+ expect(defaultSettings.alwaysSendTotalTime).toBe(false);
69
+ expect(defaultSettings.strict_errors).toBe(true);
70
+ expect(defaultSettings.xhrHeaders).toEqual({});
71
+ expect(defaultSettings.xhrWithCredentials).toBe(false);
72
+ });
73
+
74
+ it("should handle response correctly in responseHandler", async () => {
75
+ const response = new Response(
76
+ JSON.stringify({ result: "true", errorCode: 0 }),
77
+ );
78
+ const result = await defaultSettings.responseHandler(response);
79
+ expect(result.result).toEqual("true");
80
+ expect(result.errorCode).toEqual(0);
81
+ });
82
+
83
+ it("should handle request correctly in requestHandler", () => {
84
+ const commitObject = { data: "test" };
85
+ const result = defaultSettings.requestHandler(commitObject);
86
+ expect(result).toEqual(commitObject);
87
+ });
88
+
89
+ it("should log messages correctly in onLogMessage", () => {
90
+ const consoleErrorStub = sinon.stub(console, "error");
91
+ const consoleWarnStub = sinon.stub(console, "warn");
92
+ const consoleInfoStub = sinon.stub(console, "info");
93
+ const consoleDebugStub = sinon.stub(console, "debug");
94
+ const consoleLogStub = sinon.stub(console, "log");
95
+
96
+ defaultSettings.onLogMessage(
97
+ APIConstants.global.LOG_LEVEL_ERROR,
98
+ "Error message",
99
+ );
100
+ expect(consoleErrorStub.calledWith("Error message")).toBe(true);
101
+
102
+ defaultSettings.onLogMessage(
103
+ APIConstants.global.LOG_LEVEL_WARNING,
104
+ "Warning message",
105
+ );
106
+ expect(consoleWarnStub.calledWith("Warning message")).toBe(true);
107
+
108
+ defaultSettings.onLogMessage(
109
+ APIConstants.global.LOG_LEVEL_INFO,
110
+ "Info message",
111
+ );
112
+ expect(consoleInfoStub.calledWith("Info message")).toBe(true);
113
+
114
+ defaultSettings.onLogMessage(
115
+ APIConstants.global.LOG_LEVEL_DEBUG,
116
+ "Debug message",
117
+ );
118
+ expect(consoleDebugStub.calledWith("Debug message")).toBe(true);
119
+
120
+ consoleErrorStub.restore();
121
+ consoleWarnStub.restore();
122
+ consoleInfoStub.restore();
123
+ consoleDebugStub.restore();
124
+ consoleLogStub.restore();
125
+ });
126
+ });
@@ -0,0 +1,56 @@
1
+ import { expect } from "expect";
2
+ import * as sinon from "sinon";
3
+ import { debounce } from "../../src/utilities/debounce";
4
+
5
+ describe("debounce", () => {
6
+ it("executes the function after the specified wait time", (done) => {
7
+ const mockFunction = sinon.spy();
8
+ const debouncedFunction = debounce(mockFunction, 100);
9
+
10
+ debouncedFunction();
11
+ expect(mockFunction.called).toBe(false);
12
+
13
+ setTimeout(() => {
14
+ expect(mockFunction.called).toBe(true);
15
+ done();
16
+ }, 150);
17
+ });
18
+
19
+ it("executes the function immediately if immediate is true", () => {
20
+ const mockFunction = sinon.spy();
21
+ const debouncedFunction = debounce(mockFunction, 100, true);
22
+
23
+ debouncedFunction();
24
+ expect(mockFunction.called).toBe(true);
25
+ });
26
+
27
+ it("does not execute the function if called again within the wait time", (done) => {
28
+ const mockFunction = sinon.spy();
29
+ const debouncedFunction = debounce(mockFunction, 100);
30
+
31
+ debouncedFunction();
32
+ debouncedFunction();
33
+
34
+ setTimeout(() => {
35
+ expect(mockFunction.calledOnce).toBe(true);
36
+ done();
37
+ }, 150);
38
+ });
39
+
40
+ it("executes the function again after the wait time if called again", (done) => {
41
+ const mockFunction = sinon.spy();
42
+ const debouncedFunction = debounce(mockFunction, 100);
43
+
44
+ debouncedFunction();
45
+
46
+ setTimeout(() => {
47
+ debouncedFunction();
48
+ expect(mockFunction.calledOnce).toBe(true);
49
+
50
+ setTimeout(() => {
51
+ expect(mockFunction.calledTwice).toBe(true);
52
+ done();
53
+ }, 150);
54
+ }, 150);
55
+ });
56
+ });