scorm-again 2.6.4 → 2.6.6
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/.claude/.claude/settings.local.json +13 -0
- package/.claude/settings.local.json +33 -0
- package/dist/aicc.js +1 -0
- package/dist/aicc.js.map +1 -1
- package/dist/aicc.min.js +1 -1
- package/dist/aicc.min.js.map +1 -1
- package/dist/esm/aicc.js +1 -0
- package/dist/esm/aicc.js.map +1 -1
- package/dist/esm/aicc.min.js +1 -1
- package/dist/esm/aicc.min.js.map +1 -1
- package/dist/esm/scorm-again.js +17 -9
- package/dist/esm/scorm-again.js.map +1 -1
- package/dist/esm/scorm-again.min.js +1 -1
- package/dist/esm/scorm-again.min.js.map +1 -1
- package/dist/esm/scorm12.js +1 -0
- package/dist/esm/scorm12.js.map +1 -1
- package/dist/esm/scorm12.min.js +1 -1
- package/dist/esm/scorm12.min.js.map +1 -1
- package/dist/esm/scorm2004.js +17 -9
- package/dist/esm/scorm2004.js.map +1 -1
- package/dist/esm/scorm2004.min.js +1 -1
- package/dist/esm/scorm2004.min.js.map +1 -1
- package/dist/scorm-again.js +17 -9
- package/dist/scorm-again.js.map +1 -1
- package/dist/scorm-again.min.js +1 -1
- package/dist/scorm-again.min.js.map +1 -1
- package/dist/scorm12.js +1 -0
- package/dist/scorm12.js.map +1 -1
- package/dist/scorm12.min.js +1 -1
- package/dist/scorm12.min.js.map +1 -1
- package/dist/scorm2004.js +17 -9
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +1 -1
- package/dist/scorm2004.min.js.map +1 -1
- package/dist/types/cmi/scorm2004/adl.d.ts +8 -2
- package/dist/types/cmi/scorm2004/cmi.d.ts +1 -1
- package/package.json +1 -1
- package/src/BaseAPI.ts +3 -1
- package/src/cmi/scorm2004/adl.ts +20 -17
- package/src/cmi/scorm2004/cmi.ts +2 -2
- package/test/BaseAPI.requestHandler.spec.ts +126 -0
- package/tsconfig.json +2 -0
|
@@ -56,16 +56,22 @@ export declare class ADLNavRequestValid extends BaseCMI {
|
|
|
56
56
|
[key: string]: NAVBoolean;
|
|
57
57
|
};
|
|
58
58
|
set choice(choice: {
|
|
59
|
-
[key: string]: string;
|
|
59
|
+
[key: string]: string | NAVBoolean;
|
|
60
60
|
});
|
|
61
61
|
get jump(): {
|
|
62
62
|
[key: string]: NAVBoolean;
|
|
63
63
|
};
|
|
64
64
|
set jump(jump: {
|
|
65
|
-
[key: string]: string;
|
|
65
|
+
[key: string]: string | NAVBoolean;
|
|
66
66
|
});
|
|
67
67
|
toJSON(): {
|
|
68
68
|
previous: string;
|
|
69
69
|
continue: string;
|
|
70
|
+
choice: {
|
|
71
|
+
[key: string]: NAVBoolean;
|
|
72
|
+
};
|
|
73
|
+
jump: {
|
|
74
|
+
[key: string]: NAVBoolean;
|
|
75
|
+
};
|
|
70
76
|
};
|
|
71
77
|
}
|
|
@@ -37,7 +37,7 @@ export declare class CMI extends BaseRootCMI {
|
|
|
37
37
|
get _version(): string;
|
|
38
38
|
set _version(_version: string);
|
|
39
39
|
get _children(): string;
|
|
40
|
-
set _children(_children:
|
|
40
|
+
set _children(_children: string);
|
|
41
41
|
get completion_status(): string;
|
|
42
42
|
set completion_status(completion_status: string);
|
|
43
43
|
get completion_threshold(): string;
|
package/package.json
CHANGED
package/src/BaseAPI.ts
CHANGED
|
@@ -1123,7 +1123,7 @@ export default abstract class BaseAPI implements IBaseAPI {
|
|
|
1123
1123
|
* @return {object}
|
|
1124
1124
|
*/
|
|
1125
1125
|
renderCMIToJSONObject(): object {
|
|
1126
|
-
return JSON.parse(this.renderCMIToJSONString());
|
|
1126
|
+
return JSON.parse(this.renderCMIToJSONString()) as object;
|
|
1127
1127
|
}
|
|
1128
1128
|
|
|
1129
1129
|
/**
|
|
@@ -1147,6 +1147,8 @@ export default abstract class BaseAPI implements IBaseAPI {
|
|
|
1147
1147
|
// if we are terminating the module or closing the browser window/tab, we need to make this fetch ASAP.
|
|
1148
1148
|
// Some browsers, especially Chrome, do not like synchronous requests to be made when the window is closing.
|
|
1149
1149
|
if (immediate) {
|
|
1150
|
+
// Apply requestHandler even for immediate requests
|
|
1151
|
+
params = this.settings.requestHandler(params);
|
|
1150
1152
|
this.performFetch(url, params).then(async (response) => {
|
|
1151
1153
|
await this.transformResponse(response);
|
|
1152
1154
|
});
|
package/src/cmi/scorm2004/adl.ts
CHANGED
|
@@ -312,9 +312,9 @@ export class ADLNavRequestValid extends BaseCMI {
|
|
|
312
312
|
|
|
313
313
|
/**
|
|
314
314
|
* Setter for _choice
|
|
315
|
-
* @param {{ [key: string]: string }} choice
|
|
315
|
+
* @param {{ [key: string]: string | NAVBoolean }} choice
|
|
316
316
|
*/
|
|
317
|
-
set choice(choice: { [key: string]: string }) {
|
|
317
|
+
set choice(choice: { [key: string]: string | NAVBoolean }) {
|
|
318
318
|
if (this.initialized) {
|
|
319
319
|
throw new Scorm2004ValidationError(
|
|
320
320
|
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
@@ -327,13 +327,13 @@ export class ADLNavRequestValid extends BaseCMI {
|
|
|
327
327
|
}
|
|
328
328
|
for (const key in choice) {
|
|
329
329
|
if ({}.hasOwnProperty.call(choice, key)) {
|
|
330
|
-
if (
|
|
331
|
-
choice[key]
|
|
332
|
-
check2004ValidFormat(
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
330
|
+
if (choice[key] !== undefined && check2004ValidFormat(key, scorm2004_regex.NAVTarget)) {
|
|
331
|
+
const value = choice[key];
|
|
332
|
+
if (typeof value === 'string' && check2004ValidFormat(value, scorm2004_regex.NAVBoolean)) {
|
|
333
|
+
this._choice[key] = NAVBoolean[value as keyof typeof NAVBoolean];
|
|
334
|
+
} else if (Object.values(NAVBoolean).includes(value as NAVBoolean)) {
|
|
335
|
+
this._choice[key] = value as NAVBoolean;
|
|
336
|
+
}
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
}
|
|
@@ -349,9 +349,9 @@ export class ADLNavRequestValid extends BaseCMI {
|
|
|
349
349
|
|
|
350
350
|
/**
|
|
351
351
|
* Setter for _jump
|
|
352
|
-
* @param {{ [key: string]: string }} jump
|
|
352
|
+
* @param {{ [key: string]: string | NAVBoolean }} jump
|
|
353
353
|
*/
|
|
354
|
-
set jump(jump: { [key: string]: string }) {
|
|
354
|
+
set jump(jump: { [key: string]: string | NAVBoolean }) {
|
|
355
355
|
if (this.initialized) {
|
|
356
356
|
throw new Scorm2004ValidationError(
|
|
357
357
|
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
@@ -364,12 +364,13 @@ export class ADLNavRequestValid extends BaseCMI {
|
|
|
364
364
|
}
|
|
365
365
|
for (const key in jump) {
|
|
366
366
|
if ({}.hasOwnProperty.call(jump, key)) {
|
|
367
|
-
if (
|
|
368
|
-
jump[key]
|
|
369
|
-
check2004ValidFormat(
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
367
|
+
if (jump[key] !== undefined && check2004ValidFormat(key, scorm2004_regex.NAVTarget)) {
|
|
368
|
+
const value = jump[key];
|
|
369
|
+
if (typeof value === 'string' && check2004ValidFormat(value, scorm2004_regex.NAVBoolean)) {
|
|
370
|
+
this._jump[key] = NAVBoolean[value as keyof typeof NAVBoolean];
|
|
371
|
+
} else if (Object.values(NAVBoolean).includes(value as NAVBoolean)) {
|
|
372
|
+
this._jump[key] = value as NAVBoolean;
|
|
373
|
+
}
|
|
373
374
|
}
|
|
374
375
|
}
|
|
375
376
|
}
|
|
@@ -388,6 +389,8 @@ export class ADLNavRequestValid extends BaseCMI {
|
|
|
388
389
|
toJSON(): {
|
|
389
390
|
previous: string;
|
|
390
391
|
continue: string;
|
|
392
|
+
choice: { [key: string]: NAVBoolean };
|
|
393
|
+
jump: { [key: string]: NAVBoolean };
|
|
391
394
|
} {
|
|
392
395
|
this.jsonString = true;
|
|
393
396
|
const result = {
|
package/src/cmi/scorm2004/cmi.ts
CHANGED
|
@@ -123,10 +123,10 @@ export class CMI extends BaseRootCMI {
|
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* Setter for __children. Just throws an error.
|
|
126
|
-
* @param {
|
|
126
|
+
* @param {string} _children
|
|
127
127
|
* @private
|
|
128
128
|
*/
|
|
129
|
-
set _children(_children:
|
|
129
|
+
set _children(_children: string) {
|
|
130
130
|
throw new Scorm2004ValidationError(
|
|
131
131
|
scorm2004_errors.READ_ONLY_ELEMENT as number,
|
|
132
132
|
);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { expect } from "expect";
|
|
2
|
+
import * as sinon from "sinon";
|
|
3
|
+
import { Scorm12API } from "../src/Scorm12API";
|
|
4
|
+
import { global_constants } from "../src/constants/api_constants";
|
|
5
|
+
|
|
6
|
+
describe("BaseAPI requestHandler Tests", () => {
|
|
7
|
+
let api: Scorm12API;
|
|
8
|
+
let requestHandlerSpy: sinon.SinonSpy;
|
|
9
|
+
let fetchStub: sinon.SinonStub;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// Stub the global fetch to prevent actual HTTP requests
|
|
13
|
+
fetchStub = sinon.stub(global, "fetch");
|
|
14
|
+
fetchStub.resolves(
|
|
15
|
+
new Response(
|
|
16
|
+
JSON.stringify({
|
|
17
|
+
result: global_constants.SCORM_TRUE,
|
|
18
|
+
errorCode: 0,
|
|
19
|
+
}),
|
|
20
|
+
{
|
|
21
|
+
status: 200,
|
|
22
|
+
headers: { "Content-Type": "application/json" },
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Create a spy for requestHandler
|
|
28
|
+
requestHandlerSpy = sinon.spy((params) => {
|
|
29
|
+
// Add a marker to verify the handler was called
|
|
30
|
+
if (typeof params === "object" && !Array.isArray(params)) {
|
|
31
|
+
params._requestHandlerCalled = true;
|
|
32
|
+
}
|
|
33
|
+
return params;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Initialize API with requestHandler
|
|
37
|
+
api = new Scorm12API({
|
|
38
|
+
lmsCommitUrl: "http://example.com/commit",
|
|
39
|
+
requestHandler: requestHandlerSpy,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
sinon.restore();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("requestHandler with immediate requests", () => {
|
|
48
|
+
it("should call requestHandler during normal commit", async () => {
|
|
49
|
+
api.lmsInitialize();
|
|
50
|
+
api.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
51
|
+
|
|
52
|
+
// Force a commit
|
|
53
|
+
await api.lmsCommit();
|
|
54
|
+
|
|
55
|
+
// Wait a bit for async operations
|
|
56
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
57
|
+
|
|
58
|
+
expect(requestHandlerSpy.calledOnce).toBe(true);
|
|
59
|
+
|
|
60
|
+
// Verify the params were transformed
|
|
61
|
+
const callArgs = fetchStub.firstCall.args[1];
|
|
62
|
+
const bodyData = JSON.parse(callArgs.body);
|
|
63
|
+
expect(bodyData._requestHandlerCalled).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should call requestHandler during terminate (immediate request)", async () => {
|
|
67
|
+
api.lmsInitialize();
|
|
68
|
+
api.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
69
|
+
|
|
70
|
+
// Call finish which triggers immediate commit
|
|
71
|
+
const result = api.lmsFinish();
|
|
72
|
+
expect(result).toBe(global_constants.SCORM_TRUE);
|
|
73
|
+
|
|
74
|
+
// Wait a bit for async operations
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
76
|
+
|
|
77
|
+
// requestHandler should have been called
|
|
78
|
+
expect(requestHandlerSpy.called).toBe(true);
|
|
79
|
+
|
|
80
|
+
// Verify the params were transformed even for immediate request
|
|
81
|
+
const callArgs = fetchStub.firstCall.args[1];
|
|
82
|
+
const bodyData = JSON.parse(callArgs.body);
|
|
83
|
+
expect(bodyData._requestHandlerCalled).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should pass through params when no requestHandler is provided", async () => {
|
|
87
|
+
// Create API without requestHandler
|
|
88
|
+
const apiNoHandler = new Scorm12API({
|
|
89
|
+
lmsCommitUrl: "http://example.com/commit",
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
apiNoHandler.lmsInitialize();
|
|
93
|
+
apiNoHandler.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
94
|
+
|
|
95
|
+
// Call finish
|
|
96
|
+
const result = apiNoHandler.lmsFinish();
|
|
97
|
+
expect(result).toBe(global_constants.SCORM_TRUE);
|
|
98
|
+
|
|
99
|
+
// Wait a bit for async operations
|
|
100
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
101
|
+
|
|
102
|
+
// Verify fetch was called but params don't have the marker
|
|
103
|
+
expect(fetchStub.called).toBe(true);
|
|
104
|
+
const callArgs = fetchStub.firstCall.args[1];
|
|
105
|
+
const bodyData = JSON.parse(callArgs.body);
|
|
106
|
+
expect(bodyData._requestHandlerCalled).toBeUndefined();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should handle requestHandler errors gracefully", async () => {
|
|
110
|
+
// Create API with error-throwing requestHandler
|
|
111
|
+
const errorApi = new Scorm12API({
|
|
112
|
+
lmsCommitUrl: "http://example.com/commit",
|
|
113
|
+
requestHandler: () => {
|
|
114
|
+
throw new Error("RequestHandler error");
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
errorApi.lmsInitialize();
|
|
119
|
+
errorApi.lmsSetValue("cmi.core.student_name", "Test Student");
|
|
120
|
+
|
|
121
|
+
// Call finish - should not throw
|
|
122
|
+
const result = errorApi.lmsFinish();
|
|
123
|
+
expect(result).toBe(global_constants.SCORM_TRUE);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|