scorm-again 1.7.1 → 2.1.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/.babelrc +18 -7
- package/.github/dependabot.yml +5 -0
- package/.github/workflows/main.yml +79 -0
- package/.github/workflows/stale.yml +14 -0
- package/.jsdoc.json +4 -5
- package/.mocharc.json +8 -0
- package/.run/{Mocha Unit Tests.run.xml → Mocha Unit Tests (watch).run.xml } +6 -3
- package/.run/Template Mocha.run.xml +17 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +183 -71
- package/dist/aicc.js +3822 -7030
- package/dist/aicc.js.map +1 -1
- package/dist/aicc.min.js +2 -40
- package/dist/aicc.min.js.map +1 -0
- package/dist/scorm-again.js +5965 -10498
- package/dist/scorm-again.js.map +1 -1
- package/dist/scorm-again.min.js +2 -52
- package/dist/scorm-again.min.js.map +1 -0
- package/dist/scorm12.js +3028 -5373
- package/dist/scorm12.js.map +1 -1
- package/dist/scorm12.min.js +2 -34
- package/dist/scorm12.min.js.map +1 -0
- package/dist/scorm2004.js +4054 -6693
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +2 -40
- package/dist/scorm2004.min.js.map +1 -0
- package/eslint.config.js +21 -0
- package/package.json +76 -34
- package/results.json +34254 -0
- package/src/AICC.ts +72 -0
- package/src/BaseAPI.ts +1300 -0
- package/src/Scorm12API.ts +387 -0
- package/src/Scorm2004API.ts +688 -0
- package/src/cmi/aicc/attempts.ts +94 -0
- package/src/cmi/aicc/cmi.ts +100 -0
- package/src/cmi/aicc/core.ts +360 -0
- package/src/cmi/aicc/evaluation.ts +157 -0
- package/src/cmi/aicc/paths.ts +180 -0
- package/src/cmi/aicc/student_data.ts +86 -0
- package/src/cmi/aicc/student_demographics.ts +367 -0
- package/src/cmi/aicc/student_preferences.ts +176 -0
- package/src/cmi/aicc/tries.ts +116 -0
- package/src/cmi/aicc/validation.ts +25 -0
- package/src/cmi/common/array.ts +77 -0
- package/src/cmi/common/base_cmi.ts +46 -0
- package/src/cmi/common/score.ts +203 -0
- package/src/cmi/common/validation.ts +60 -0
- package/src/cmi/scorm12/cmi.ts +224 -0
- package/src/cmi/scorm12/interactions.ts +368 -0
- package/src/cmi/scorm12/nav.ts +54 -0
- package/src/cmi/scorm12/objectives.ts +112 -0
- package/src/cmi/scorm12/student_data.ts +130 -0
- package/src/cmi/scorm12/student_preference.ts +158 -0
- package/src/cmi/scorm12/validation.ts +48 -0
- package/src/cmi/scorm2004/adl.ts +272 -0
- package/src/cmi/scorm2004/cmi.ts +599 -0
- package/src/cmi/scorm2004/comments.ts +163 -0
- package/src/cmi/scorm2004/interactions.ts +466 -0
- package/src/cmi/scorm2004/learner_preference.ts +152 -0
- package/src/cmi/scorm2004/objectives.ts +212 -0
- package/src/cmi/scorm2004/score.ts +78 -0
- package/src/cmi/scorm2004/validation.ts +42 -0
- package/src/constants/api_constants.ts +318 -0
- package/src/constants/default_settings.ts +81 -0
- package/src/constants/enums.ts +5 -0
- package/src/constants/error_codes.ts +88 -0
- package/src/constants/language_constants.ts +394 -0
- package/src/constants/regex.ts +97 -0
- package/src/constants/{response_constants.js → response_constants.ts} +69 -62
- package/src/exceptions.ts +154 -0
- package/src/exports/aicc.js +1 -1
- package/src/exports/scorm-again.js +3 -3
- package/src/exports/scorm12.js +1 -1
- package/src/exports/scorm2004.js +1 -1
- package/src/helpers/scheduled_commit.ts +42 -0
- package/src/interfaces/IBaseAPI.ts +35 -0
- package/src/types/api_types.ts +32 -0
- package/src/utilities/debounce.ts +31 -0
- package/src/utilities.ts +338 -0
- package/tea.yaml +6 -0
- package/test/{AICC.spec.js → AICC.spec.ts} +79 -71
- package/test/Scorm12API.spec.ts +833 -0
- package/test/Scorm2004API.spec.ts +1298 -0
- package/test/api_helpers.ts +176 -0
- package/test/cmi/aicc_cmi.spec.ts +845 -0
- package/test/cmi/{scorm12_cmi.spec.js → scorm12_cmi.spec.ts} +253 -271
- package/test/cmi/scorm2004_cmi.spec.ts +1031 -0
- package/test/cmi_helpers.ts +207 -0
- package/test/exceptions.spec.ts +79 -0
- package/test/field_values.ts +202 -0
- package/test/types/api_types.spec.ts +126 -0
- package/test/utilities/debounce.spec.ts +56 -0
- package/test/utilities.spec.ts +322 -0
- package/tsconfig.json +18 -0
- package/webpack.config.js +65 -0
- package/.circleci/config.yml +0 -99
- package/.codeclimate.yml +0 -7
- package/.eslintrc.js +0 -36
- package/src/.flowconfig +0 -11
- package/src/AICC.js +0 -68
- package/src/BaseAPI.js +0 -1275
- package/src/Scorm12API.js +0 -308
- package/src/Scorm2004API.js +0 -572
- package/src/cmi/aicc_cmi.js +0 -1141
- package/src/cmi/common.js +0 -328
- package/src/cmi/scorm12_cmi.js +0 -1312
- package/src/cmi/scorm2004_cmi.js +0 -1692
- package/src/constants/api_constants.js +0 -218
- package/src/constants/error_codes.js +0 -87
- package/src/constants/language_constants.js +0 -76
- package/src/constants/regex.js +0 -84
- package/src/exceptions.js +0 -104
- package/src/utilities.js +0 -242
- package/test/Scorm12API.spec.js +0 -528
- package/test/Scorm2004API.spec.js +0 -775
- package/test/abstract_classes.spec.js +0 -17
- package/test/api_helpers.js +0 -128
- package/test/cmi/aicc_cmi.spec.js +0 -684
- package/test/cmi/scorm2004_cmi.spec.js +0 -1066
- package/test/cmi_helpers.js +0 -161
- package/test/exceptions.spec.js +0 -71
- package/test/field_values.js +0 -353
- package/test/utilities.spec.js +0 -339
- package/webpack.js +0 -78
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { describe, it } from "mocha";
|
|
2
|
+
import { expect } from "expect";
|
|
3
|
+
import { getError } from "./api_helpers";
|
|
4
|
+
import { BaseCMI, BaseRootCMI } from "../src/cmi/common/base_cmi";
|
|
5
|
+
|
|
6
|
+
export type CheckFieldConstraintSize = {
|
|
7
|
+
cmi: BaseCMI;
|
|
8
|
+
fieldName: string;
|
|
9
|
+
limit: number;
|
|
10
|
+
expectedValue?: string;
|
|
11
|
+
expectedError: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type CheckReadOnly = {
|
|
15
|
+
cmi: BaseCMI;
|
|
16
|
+
fieldName: string;
|
|
17
|
+
expectedValue?: string | number;
|
|
18
|
+
expectedError: number;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type CheckRead = {
|
|
22
|
+
cmi: BaseCMI;
|
|
23
|
+
fieldName: string;
|
|
24
|
+
expectedValue?: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type CheckReadAndWrite = {
|
|
28
|
+
cmi: BaseCMI;
|
|
29
|
+
fieldName: string;
|
|
30
|
+
expectedValue?: string;
|
|
31
|
+
valueToTest?: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type CheckWriteOnly = {
|
|
35
|
+
cmi: BaseCMI;
|
|
36
|
+
fieldName: string;
|
|
37
|
+
valueToTest?: string;
|
|
38
|
+
expectedError: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type CheckWrite = {
|
|
42
|
+
cmi: BaseCMI;
|
|
43
|
+
fieldName: string;
|
|
44
|
+
valueToTest?: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type CheckValidValues = {
|
|
48
|
+
cmi: BaseCMI;
|
|
49
|
+
fieldName: string;
|
|
50
|
+
validValues: (string | number)[];
|
|
51
|
+
invalidValues: string[];
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type CheckGetCurrentTotalTime = {
|
|
55
|
+
cmi: BaseRootCMI;
|
|
56
|
+
totalFieldName: string;
|
|
57
|
+
sessionFieldName: string;
|
|
58
|
+
startingTotal: string;
|
|
59
|
+
sessionTime: string;
|
|
60
|
+
expectedTotal: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const checkFieldConstraintSize = ({
|
|
64
|
+
cmi,
|
|
65
|
+
fieldName,
|
|
66
|
+
limit,
|
|
67
|
+
expectedValue = "",
|
|
68
|
+
expectedError,
|
|
69
|
+
}: CheckFieldConstraintSize) => {
|
|
70
|
+
describe(`Field: ${fieldName}`, () => {
|
|
71
|
+
it(`Should be able to read from ${fieldName}`, () => {
|
|
72
|
+
expect(eval(`${fieldName}`)).toEqual(expectedValue);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it(`Should be able to write upto ${limit} characters to ${fieldName}`, () => {
|
|
76
|
+
expect(() => eval(`${fieldName} = 'x'.repeat(${limit})`)).not.toThrow();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it(`Should fail to write more than ${limit} characters to ${fieldName}`, async () => {
|
|
80
|
+
const error = await getError(async () =>
|
|
81
|
+
eval(`${fieldName} = 'x'.repeat(${limit + 1})`),
|
|
82
|
+
);
|
|
83
|
+
expect(error).toHaveProperty("errorCode", expectedError);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const checkReadOnly = ({
|
|
89
|
+
cmi,
|
|
90
|
+
fieldName,
|
|
91
|
+
expectedValue = "",
|
|
92
|
+
expectedError,
|
|
93
|
+
}: CheckReadOnly) => {
|
|
94
|
+
describe(`Field: ${fieldName}`, () => {
|
|
95
|
+
it(`Should be able to read from ${fieldName}`, () => {
|
|
96
|
+
expect(eval(`${fieldName}`)).toEqual(expectedValue);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it(`Should fail to write to ${fieldName}`, async () => {
|
|
100
|
+
const error = await getError(async () => eval(`${fieldName} = 'xxx'`));
|
|
101
|
+
expect(error).toHaveProperty("errorCode", expectedError);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const checkRead = ({
|
|
107
|
+
cmi,
|
|
108
|
+
fieldName,
|
|
109
|
+
expectedValue = "",
|
|
110
|
+
}: CheckRead) => {
|
|
111
|
+
describe(`Field: ${fieldName}`, () => {
|
|
112
|
+
it(`Should be able to read from ${fieldName}`, () => {
|
|
113
|
+
expect(eval(`${fieldName}`)).toEqual(expectedValue);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const checkReadAndWrite = ({
|
|
119
|
+
cmi,
|
|
120
|
+
fieldName,
|
|
121
|
+
expectedValue = "",
|
|
122
|
+
valueToTest = "xxx",
|
|
123
|
+
}: CheckReadAndWrite) => {
|
|
124
|
+
describe(`Field: ${fieldName}`, () => {
|
|
125
|
+
it(`Should be able to read from ${fieldName}`, () => {
|
|
126
|
+
expect(eval(`${fieldName}`)).toEqual(expectedValue);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it(`Should successfully write to ${fieldName}`, () => {
|
|
130
|
+
expect(() => eval(`${fieldName} = '${valueToTest}'`)).not.toThrow();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const checkWriteOnly = ({
|
|
136
|
+
cmi,
|
|
137
|
+
fieldName,
|
|
138
|
+
valueToTest = "xxx",
|
|
139
|
+
expectedError,
|
|
140
|
+
}: CheckWriteOnly) => {
|
|
141
|
+
describe(`Field: ${fieldName}`, () => {
|
|
142
|
+
it(`Should fail to read from ${fieldName}`, async () => {
|
|
143
|
+
const error = await getError(async () => eval(`${fieldName}`));
|
|
144
|
+
expect(error).toHaveProperty("errorCode", expectedError);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it(`Should successfully write to ${fieldName}`, () => {
|
|
148
|
+
expect(() => eval(`${fieldName} = '${valueToTest}'`)).not.toThrow();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const checkWrite = ({
|
|
154
|
+
cmi,
|
|
155
|
+
fieldName,
|
|
156
|
+
valueToTest = "xxx",
|
|
157
|
+
}: CheckWrite) => {
|
|
158
|
+
describe(`Field: ${fieldName}`, () => {
|
|
159
|
+
it(`Should successfully write to ${fieldName}`, () => {
|
|
160
|
+
expect(() => eval(`${fieldName} = '${valueToTest}'`)).not.toThrow();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const checkValidValues = ({
|
|
166
|
+
cmi,
|
|
167
|
+
fieldName,
|
|
168
|
+
validValues,
|
|
169
|
+
invalidValues,
|
|
170
|
+
}: CheckValidValues) => {
|
|
171
|
+
describe(`Field: ${fieldName}`, () => {
|
|
172
|
+
for (const idx in validValues) {
|
|
173
|
+
if ({}.hasOwnProperty.call(validValues, idx)) {
|
|
174
|
+
it(`Should successfully write '${validValues[idx]}' to ${fieldName}`, () => {
|
|
175
|
+
expect(() =>
|
|
176
|
+
eval(`${fieldName} = '${validValues[idx]}'`),
|
|
177
|
+
).not.toThrow();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (const idx in invalidValues) {
|
|
183
|
+
if ({}.hasOwnProperty.call(invalidValues, idx)) {
|
|
184
|
+
it(`Should fail to write '${invalidValues[idx]}' to ${fieldName}`, () => {
|
|
185
|
+
expect(() =>
|
|
186
|
+
eval(`${fieldName} = '${invalidValues[idx]}'`),
|
|
187
|
+
).toThrow();
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const checkGetCurrentTotalTime = ({
|
|
195
|
+
cmi: cmi,
|
|
196
|
+
totalFieldName,
|
|
197
|
+
sessionFieldName,
|
|
198
|
+
startingTotal,
|
|
199
|
+
sessionTime,
|
|
200
|
+
expectedTotal,
|
|
201
|
+
}: CheckGetCurrentTotalTime) => {
|
|
202
|
+
it(`Should return ${expectedTotal} with a starting time of ${startingTotal} and a session time of ${sessionTime}`, () => {
|
|
203
|
+
eval(`${totalFieldName} = '${startingTotal}'`);
|
|
204
|
+
eval(`${sessionFieldName} = '${sessionTime}'`);
|
|
205
|
+
expect(cmi.getCurrentTotalTime()).toEqual(expectedTotal);
|
|
206
|
+
});
|
|
207
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, it } from "mocha";
|
|
2
|
+
import { expect } from "expect";
|
|
3
|
+
import {
|
|
4
|
+
ValidationError,
|
|
5
|
+
AICCValidationError,
|
|
6
|
+
Scorm12ValidationError,
|
|
7
|
+
Scorm2004ValidationError,
|
|
8
|
+
} from "../src/exceptions";
|
|
9
|
+
import APIConstants from "../src/constants/api_constants";
|
|
10
|
+
|
|
11
|
+
const scorm12_errors = APIConstants.scorm12.error_descriptions;
|
|
12
|
+
const aicc_errors = APIConstants.aicc.error_descriptions;
|
|
13
|
+
const scorm2004_errors = APIConstants.scorm2004.error_descriptions;
|
|
14
|
+
|
|
15
|
+
type CheckValidationMessage = {
|
|
16
|
+
errorClass: any;
|
|
17
|
+
errorCodes: number[];
|
|
18
|
+
error_messages: any;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const checkValidationMessage = ({
|
|
22
|
+
errorClass,
|
|
23
|
+
errorCodes,
|
|
24
|
+
error_messages,
|
|
25
|
+
}: CheckValidationMessage) => {
|
|
26
|
+
describe(`ValidationError: ${typeof errorClass}`, () => {
|
|
27
|
+
it(`${typeof errorClass} should return general errorCode number when not recognized`, () => {
|
|
28
|
+
expect(new errorClass.prototype.constructor(53).errorCode).toEqual(101);
|
|
29
|
+
});
|
|
30
|
+
it(`${typeof errorClass} should return general message when not recognized`, () => {
|
|
31
|
+
expect(new errorClass.prototype.constructor(53).message).toEqual(
|
|
32
|
+
error_messages["101"].basicMessage,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < errorCodes.length; i++) {
|
|
37
|
+
const errorCode = errorCodes[i];
|
|
38
|
+
it(`${typeof errorClass} should return proper errorCode number when recognized`, () => {
|
|
39
|
+
expect(
|
|
40
|
+
new errorClass.prototype.constructor(errorCode).errorCode,
|
|
41
|
+
).toEqual(errorCode);
|
|
42
|
+
});
|
|
43
|
+
it(`${typeof errorClass} should return proper ${errorCode} message`, () => {
|
|
44
|
+
expect(new errorClass.prototype.constructor(errorCode).message).toEqual(
|
|
45
|
+
error_messages[String(errorCode)].basicMessage,
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
describe("Exception Tests", () => {
|
|
53
|
+
it("ValidationException should return message string", () => {
|
|
54
|
+
expect(new ValidationError(0, "Error Message").message).toEqual(
|
|
55
|
+
"Error Message",
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
it("ValidationException should return errorCode number", () => {
|
|
59
|
+
expect(new ValidationError(0, "Error Message").errorCode).toEqual(0);
|
|
60
|
+
});
|
|
61
|
+
checkValidationMessage({
|
|
62
|
+
errorClass: AICCValidationError,
|
|
63
|
+
errorCodes: [101, 201, 202, 203, 301, 401, 402, 403, 404, 405, 407, 408],
|
|
64
|
+
error_messages: aicc_errors,
|
|
65
|
+
});
|
|
66
|
+
checkValidationMessage({
|
|
67
|
+
errorClass: Scorm12ValidationError,
|
|
68
|
+
errorCodes: [101, 201, 202, 203, 301, 401, 402, 403, 404, 405, 407, 408],
|
|
69
|
+
error_messages: scorm12_errors,
|
|
70
|
+
});
|
|
71
|
+
checkValidationMessage({
|
|
72
|
+
errorClass: Scorm2004ValidationError,
|
|
73
|
+
errorCodes: [
|
|
74
|
+
0, 101, 102, 103, 104, 111, 112, 113, 122, 123, 132, 133, 142, 143, 201,
|
|
75
|
+
301, 351, 391, 401, 402, 403, 404, 405, 406, 407, 408,
|
|
76
|
+
],
|
|
77
|
+
error_messages: scorm2004_errors,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
type ValueRange = string[];
|
|
2
|
+
|
|
3
|
+
interface CommonValues {
|
|
4
|
+
valid0To1Range: ValueRange;
|
|
5
|
+
invalid0To1Range: ValueRange;
|
|
6
|
+
valid0To100Range: ValueRange;
|
|
7
|
+
invalid0To100Range: ValueRange;
|
|
8
|
+
validScaledRange: ValueRange;
|
|
9
|
+
invalidScaledRange: ValueRange;
|
|
10
|
+
validIntegerScaledRange: ValueRange;
|
|
11
|
+
invalidIntegerScaledRange: ValueRange;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const commonValues: CommonValues = {
|
|
15
|
+
valid0To1Range: ["0.0", "0.25", "0.5", "1.0"],
|
|
16
|
+
invalid0To1Range: ["-1", "-0.1", "1.1", ".25"],
|
|
17
|
+
valid0To100Range: ["1", "50", "100"],
|
|
18
|
+
invalid0To100Range: ["invalid", "a100", "-1"],
|
|
19
|
+
validScaledRange: ["1", "0.5", "0", "-0.5", "-1"],
|
|
20
|
+
invalidScaledRange: ["-101", "25.1", "50.5", "75", "100"],
|
|
21
|
+
validIntegerScaledRange: ["1", "0", "-1"],
|
|
22
|
+
invalidIntegerScaledRange: [
|
|
23
|
+
"-101",
|
|
24
|
+
"-0.5",
|
|
25
|
+
"0.5",
|
|
26
|
+
"25.1",
|
|
27
|
+
"50.5",
|
|
28
|
+
"75",
|
|
29
|
+
"100",
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
interface Scorm12Values extends CommonValues {
|
|
34
|
+
validResult: ValueRange;
|
|
35
|
+
invalidResult: ValueRange;
|
|
36
|
+
validLessonStatus: ValueRange;
|
|
37
|
+
invalidLessonStatus: ValueRange;
|
|
38
|
+
validExit: ValueRange;
|
|
39
|
+
invalidExit: ValueRange;
|
|
40
|
+
validType: ValueRange;
|
|
41
|
+
invalidType: ValueRange;
|
|
42
|
+
validSpeedRange: ValueRange;
|
|
43
|
+
invalidSpeedRange: ValueRange;
|
|
44
|
+
validScoreRange: (string | number)[];
|
|
45
|
+
invalidScoreRange: ValueRange;
|
|
46
|
+
validTime: ValueRange;
|
|
47
|
+
invalidTime: ValueRange;
|
|
48
|
+
validTimespan: ValueRange;
|
|
49
|
+
invalidTimespan: ValueRange;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const scorm12Values: Scorm12Values = {
|
|
53
|
+
...commonValues,
|
|
54
|
+
validResult: ["correct", "wrong", "unanticipated", "neutral"],
|
|
55
|
+
invalidResult: ["-10000", "10000", "invalid", "incorrect"],
|
|
56
|
+
validLessonStatus: ["passed", "completed", "failed", "incomplete", "browsed"],
|
|
57
|
+
invalidLessonStatus: ["Passed", "P", "F", "p", "true", "false", "complete"],
|
|
58
|
+
validExit: ["time-out", "suspend", "logout", ""],
|
|
59
|
+
invalidExit: ["close", "exit", "crash"],
|
|
60
|
+
validType: [
|
|
61
|
+
"true-false",
|
|
62
|
+
"choice",
|
|
63
|
+
"fill-in",
|
|
64
|
+
"matching",
|
|
65
|
+
"performance",
|
|
66
|
+
"sequencing",
|
|
67
|
+
"likert",
|
|
68
|
+
"numeric",
|
|
69
|
+
],
|
|
70
|
+
invalidType: ["correct", "wrong", "logout"],
|
|
71
|
+
validSpeedRange: ["1", "50", "100", "-1", "-50", "-100"],
|
|
72
|
+
invalidSpeedRange: ["invalid", "a100", "-101", "101", "-100000", "100000"],
|
|
73
|
+
validScoreRange: ["1", "50.25", "70", "100", 1, 50.25, 70, 100],
|
|
74
|
+
invalidScoreRange: ["invalid", "a100", "-1", "101", "-100000", "100000"],
|
|
75
|
+
invalid0To100Range: ["invalid", "a100", "-2"],
|
|
76
|
+
validTime: ["10:06:57", "23:59:59", "00:00:00"],
|
|
77
|
+
invalidTime: [
|
|
78
|
+
"47:59:59",
|
|
79
|
+
"00:00:01.56",
|
|
80
|
+
"06:5:13",
|
|
81
|
+
"23:59:59.123",
|
|
82
|
+
"P1DT23H59M59S",
|
|
83
|
+
],
|
|
84
|
+
validTimespan: ["10:06:57", "00:00:01.56", "23:59:59", "47:59:59"],
|
|
85
|
+
invalidTimespan: ["06:5:13", "23:59:59.123", "P1DT23H59M59S"],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
interface Scorm2004Values extends CommonValues {
|
|
89
|
+
validResult: ValueRange;
|
|
90
|
+
invalidResult: ValueRange;
|
|
91
|
+
validTimestamps: ValueRange;
|
|
92
|
+
invalidTimestamps: ValueRange;
|
|
93
|
+
validCStatus: ValueRange;
|
|
94
|
+
invalidCStatus: ValueRange;
|
|
95
|
+
validSStatus: ValueRange;
|
|
96
|
+
invalidSStatus: ValueRange;
|
|
97
|
+
validExit: ValueRange;
|
|
98
|
+
invalidExit: ValueRange;
|
|
99
|
+
validType: ValueRange;
|
|
100
|
+
invalidType: ValueRange;
|
|
101
|
+
validScoreRange: ValueRange;
|
|
102
|
+
invalidScoreRange: ValueRange;
|
|
103
|
+
validISO8601Durations: ValueRange;
|
|
104
|
+
invalidISO8601Durations: ValueRange;
|
|
105
|
+
validComment: ValueRange;
|
|
106
|
+
invalidComment: ValueRange;
|
|
107
|
+
validDescription: ValueRange;
|
|
108
|
+
invalidDescription: ValueRange;
|
|
109
|
+
validNavRequest: ValueRange;
|
|
110
|
+
invalidNavRequest: ValueRange;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const scorm2004Values: Scorm2004Values = {
|
|
114
|
+
...commonValues,
|
|
115
|
+
validResult: ["correct", "incorrect", "unanticipated", "neutral"],
|
|
116
|
+
invalidResult: ["-10000", "10000", "invalid", "wrong"],
|
|
117
|
+
validTimestamps: [
|
|
118
|
+
"2019-06-25",
|
|
119
|
+
"2019-06-25T23:59",
|
|
120
|
+
"2019-06-25T23:59:59.99",
|
|
121
|
+
"1970-01-01",
|
|
122
|
+
],
|
|
123
|
+
invalidTimestamps: [
|
|
124
|
+
"2019-06-25T",
|
|
125
|
+
"2019-06-25T23:59:59.999",
|
|
126
|
+
"2019-06-25T25:59:59.99",
|
|
127
|
+
"2019-13-31",
|
|
128
|
+
"1969-12-31",
|
|
129
|
+
"-00:00:30",
|
|
130
|
+
"0:50:30",
|
|
131
|
+
"23:00:30.",
|
|
132
|
+
],
|
|
133
|
+
validCStatus: ["completed", "incomplete", "not attempted", "unknown"],
|
|
134
|
+
invalidCStatus: ["complete", "passed", "failed"],
|
|
135
|
+
validSStatus: ["passed", "failed", "unknown"],
|
|
136
|
+
invalidSStatus: ["complete", "incomplete", "P", "f"],
|
|
137
|
+
validExit: ["time-out", "suspend", "logout", "normal", ""],
|
|
138
|
+
invalidExit: ["close", "exit", "crash"],
|
|
139
|
+
validType: [
|
|
140
|
+
"true-false",
|
|
141
|
+
"choice",
|
|
142
|
+
"fill-in",
|
|
143
|
+
"long-fill-in",
|
|
144
|
+
"matching",
|
|
145
|
+
"performance",
|
|
146
|
+
"sequencing",
|
|
147
|
+
"likert",
|
|
148
|
+
"numeric",
|
|
149
|
+
"other",
|
|
150
|
+
],
|
|
151
|
+
invalidType: ["correct", "wrong", "logout"],
|
|
152
|
+
validScoreRange: ["1", "50", "100", "-10000", "-1", "10000"],
|
|
153
|
+
invalidScoreRange: ["invalid", "a100", "-100000", "100000"],
|
|
154
|
+
validISO8601Durations: ["P1Y34DT23H45M15S", "PT1M45S", "P0S", "PT75M"],
|
|
155
|
+
invalidISO8601Durations: ["00:08:45", "-P1H", "1y45D", "0"],
|
|
156
|
+
validComment: [
|
|
157
|
+
"{lang=en-98} learner comment",
|
|
158
|
+
"{lang=eng-98-9} learner comment",
|
|
159
|
+
"{lang=eng-98-9fhgj}" + "x".repeat(4000),
|
|
160
|
+
"learner comment",
|
|
161
|
+
"learner comment}",
|
|
162
|
+
"{lang=i-xx}",
|
|
163
|
+
"{lang=i}",
|
|
164
|
+
"",
|
|
165
|
+
],
|
|
166
|
+
invalidComment: [
|
|
167
|
+
"{lang=i-}",
|
|
168
|
+
"{lang=i-x}",
|
|
169
|
+
"{lang=eng-98-9fhgj}{ learner comment",
|
|
170
|
+
"{learner comment",
|
|
171
|
+
"{lang=eng-98-9fhgj}" + "x".repeat(4001),
|
|
172
|
+
"{lang=eng-98-9fhgj}{" + "x".repeat(3999),
|
|
173
|
+
],
|
|
174
|
+
validDescription: [
|
|
175
|
+
"{lang=en-98} learner comment",
|
|
176
|
+
"{lang=eng-98-9} learner comment",
|
|
177
|
+
"{lang=eng-98-9fhgj}" + "x".repeat(250),
|
|
178
|
+
"learner comment",
|
|
179
|
+
"learner comment}",
|
|
180
|
+
"{lang=i-xx}",
|
|
181
|
+
"{lang=i}",
|
|
182
|
+
"",
|
|
183
|
+
],
|
|
184
|
+
invalidDescription: [
|
|
185
|
+
"{lang=i-}",
|
|
186
|
+
"{lang=i-x}",
|
|
187
|
+
"{lang=eng-98-9fhgj}{ learner comment",
|
|
188
|
+
"{learner comment",
|
|
189
|
+
"{lang=eng-98-9fhgj}" + "x".repeat(251),
|
|
190
|
+
"{lang=eng-98-9fhgj}{" + "x".repeat(249),
|
|
191
|
+
],
|
|
192
|
+
validNavRequest: [
|
|
193
|
+
"previous",
|
|
194
|
+
"continue",
|
|
195
|
+
"exit",
|
|
196
|
+
"exitAll",
|
|
197
|
+
"abandon",
|
|
198
|
+
"abandonAll",
|
|
199
|
+
"suspendAll",
|
|
200
|
+
],
|
|
201
|
+
invalidNavRequest: ["close", "quit", "next", "before"],
|
|
202
|
+
};
|
|
@@ -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
|
+
});
|