Minor code cleanup and additional test cases

This commit is contained in:
Jonathan Putney
2020-08-17 09:09:52 -04:00
parent 576d417365
commit ab1f3b061b
4 changed files with 171 additions and 79 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "scorm-again",
"version": "1.4.0",
"version": "1.4.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -199,36 +199,14 @@ export default class Scorm2004API extends BaseAPI {
this.throwSCORMError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
const interaction_type = interaction.type;
const interaction_count = interaction.correct_responses._count;
if (interaction_type === 'choice') {
for (let i = 0; i < interaction_count && this.lastErrorCode ===
0; i++) {
const response = interaction.correct_responses.childArray[i];
if (response.pattern === value) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
}
}
}
this.checkDuplicateChoiceResponse(interaction, value);
const response_type = correct_responses[interaction_type];
const response_type = correct_responses[interaction.type];
if (response_type) {
let nodes = [];
if (response_type?.delimiter) {
nodes = String(value).split(response_type.delimiter);
} else {
nodes[0] = value;
}
if (nodes.length > 0 && nodes.length <= response_type.max) {
this.checkCorrectResponseValue(interaction_type, nodes, value);
} else if (nodes.length > response_type.max) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Pattern Too Long');
}
this.checkValidResponseType(response_type, value, interaction.type);
} else {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Incorrect Response Type: ' + interaction_type);
'Incorrect Response Type: ' + interaction.type);
}
}
}
@@ -252,6 +230,46 @@ export default class Scorm2004API extends BaseAPI {
return newChild;
}
/**
* Checks for valid response types
* @param {object} response_type
* @param {any} value
* @param {string} interaction_type
*/
checkValidResponseType(response_type, value, interaction_type) {
let nodes = [];
if (response_type?.delimiter) {
nodes = String(value).split(response_type.delimiter);
} else {
nodes[0] = value;
}
if (nodes.length > 0 && nodes.length <= response_type.max) {
this.checkCorrectResponseValue(interaction_type, nodes, value);
} else if (nodes.length > response_type.max) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Pattern Too Long');
}
}
/**
* Checks for duplicate 'choice' responses.
* @param {CMIInteractionsObject} interaction
* @param {any} value
*/
checkDuplicateChoiceResponse(interaction, value) {
const interaction_count = interaction.correct_responses._count;
if (interaction.type === 'choice') {
for (let i = 0; i < interaction_count && this.lastErrorCode ===
0; i++) {
const response = interaction.correct_responses.childArray[i];
if (response.pattern === value) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
}
}
}
}
/**
* Validate correct response.
* @param {string} CMIElement
@@ -263,33 +281,13 @@ export default class Scorm2004API extends BaseAPI {
const pattern_index = Number(parts[4]);
const interaction = this.cmi.interactions.childArray[index];
const interaction_type = interaction.type;
const interaction_count = interaction.correct_responses._count;
if (interaction_type === 'choice') {
for (let i = 0; i < interaction_count && this.lastErrorCode === 0; i++) {
const response = interaction.correct_responses.childArray[i];
if (response.pattern === value) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
}
}
}
this.checkDuplicateChoiceResponse(interaction, value);
const response_type = correct_responses[interaction_type];
const response_type = correct_responses[interaction.type];
if (typeof response_type.limit === 'undefined' || interaction_count <=
response_type.limit) {
let nodes = [];
if (response_type?.delimiter) {
nodes = String(value).split(response_type.delimiter);
} else {
nodes[0] = value;
}
if (nodes.length > 0 && nodes.length <= response_type.max) {
this.checkCorrectResponseValue(interaction_type, nodes, value);
} else if (nodes.length > response_type.max) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Pattern Too Long');
}
this.checkValidResponseType(response_type, value, interaction.type);
if (this.lastErrorCode === 0 &&
(!response_type.duplicate ||

View File

@@ -819,7 +819,7 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} type
*/
set type(type) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -842,7 +842,7 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} timestamp
*/
set timestamp(timestamp) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -865,7 +865,7 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} weighting
*/
set weighting(weighting) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -889,8 +889,7 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} learner_response
*/
set learner_response(learner_response) {
if (this.initialized && (typeof this.type === 'undefined' ||
typeof this.id === 'undefined')) {
if (this.initialized && (this.#type === '' || this.#id === '')) {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -975,7 +974,7 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} latency
*/
set latency(latency) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -998,7 +997,7 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} description
*/
set description(description) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -1104,7 +1103,7 @@ export class CMIObjectivesObject extends BaseCMI {
* @param {string} success_status
*/
set success_status(success_status) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -1127,7 +1126,7 @@ export class CMIObjectivesObject extends BaseCMI {
* @param {string} completion_status
*/
set completion_status(completion_status) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -1150,7 +1149,7 @@ export class CMIObjectivesObject extends BaseCMI {
* @param {string} progress_measure
*/
set progress_measure(progress_measure) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {
@@ -1175,7 +1174,7 @@ export class CMIObjectivesObject extends BaseCMI {
* @param {string} description
*/
set description(description) {
if (this.initialized && typeof this.id === 'undefined') {
if (this.initialized && this.#id === '') {
throw new ValidationError(
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else {

View File

@@ -17,9 +17,7 @@ const api = (settings = {}, startingData = {}) => {
};
const apiInitialized = (startingData) => {
const API = api();
if (startingData) {
API.startingData = startingData;
}
API.loadFromJSON(startingData, '');
API.lmsInitialize();
return API;
};
@@ -299,61 +297,151 @@ describe('SCORM 2004 API Tests', () => {
it('should allow cmi.interactions.0.correct_responses.0.pattern to be set - T/F',
() => {
const scorm2004API = apiInitialized();
scorm2004API.setCMIValue('cmi.interactions.0.id',
'Scene1_Slide3_MultiChoice_0_0');
scorm2004API.setCMIValue('cmi.interactions.0.type', 'true-false');
scorm2004API.setCMIValue('cmi.interactions.0.correct_responses.0.pattern', 'true');
scorm2004API.setCMIValue(
'cmi.interactions.0.correct_responses.0.pattern', 'true');
expect(
String(scorm2004API.lmsGetLastError())
String(scorm2004API.lmsGetLastError()),
).to.equal(String(0));
});
it('should allow cmi.interactions.10.correct_responses.0.pattern to be set - T/F',
() => {
const scorm2004API = apiInitialized();
scorm2004API.setCMIValue('cmi.interactions.0.id',
'Scene1_Slide3_MultiChoice_0_0');
scorm2004API.setCMIValue('cmi.interactions.0.type', 'true-false');
scorm2004API.setCMIValue('cmi.interactions.0.correct_responses.0.pattern', 'true');
scorm2004API.setCMIValue(
'cmi.interactions.0.correct_responses.0.pattern', 'true');
expect(
String(scorm2004API.lmsGetLastError())
String(scorm2004API.lmsGetLastError()),
).to.equal(String(0));
});
it('should allow cmi.interactions.0.correct_responses.0.pattern to be set - choice',
() => {
const scorm2004API = apiInitialized();
scorm2004API.setCMIValue('cmi.interactions.0.id', 'Scene1_Slide3_MultiChoice_0_0');
scorm2004API.setCMIValue('cmi.interactions.0.id',
'Scene1_Slide3_MultiChoice_0_0');
scorm2004API.setCMIValue('cmi.interactions.0.type', 'choice');
scorm2004API.setCMIValue('cmi.interactions.0.correct_responses.0.pattern', 'VP_on-call_or_President');
scorm2004API.setCMIValue(
'cmi.interactions.0.correct_responses.0.pattern',
'VP_on-call_or_President');
expect(
String(scorm2004API.lmsGetLastError())
String(scorm2004API.lmsGetLastError()),
).to.equal(String(0));
});
it('should allow cmi.interactions.0.objectives.0.id to be set',
() => {
const scorm2004API = apiInitialized();
scorm2004API.setCMIValue('cmi.interactions.0.objectives.0.id', 'ID of the Obj - ID 2');
scorm2004API.setCMIValue('cmi.interactions.0.objectives.0.id',
'ID of the Obj - ID 2');
expect(
String(scorm2004API.lmsGetLastError())
String(scorm2004API.lmsGetLastError()),
).to.equal(String(0));
});
it('should allow cmi.interactions.0.learner_response to be set',
() => {
const scorm2004API = apiInitialized();
scorm2004API.setCMIValue('cmi.interactions.0.id', 'Scene1_Slide3_MultiChoice_0_0');
scorm2004API.setCMIValue('cmi.interactions.0.id',
'Scene1_Slide3_MultiChoice_0_0');
scorm2004API.setCMIValue('cmi.interactions.0.type', 'choice');
scorm2004API.setCMIValue('cmi.interactions.0.learner_response', 'VP_on-call_or_President');
scorm2004API.setCMIValue('cmi.interactions.0.learner_response',
'VP_on-call_or_President');
expect(
String(scorm2004API.lmsGetLastError())
String(scorm2004API.lmsGetLastError()),
).to.equal(String(0));
expect(
scorm2004API.getCMIValue('cmi.interactions.0.id')
scorm2004API.getCMIValue('cmi.interactions.0.id'),
).to.equal('Scene1_Slide3_MultiChoice_0_0');
expect(
scorm2004API.getCMIValue('cmi.interactions.0.type')
scorm2004API.getCMIValue('cmi.interactions.0.type'),
).to.equal('choice');
expect(
scorm2004API.getCMIValue('cmi.interactions.0.learner_response')
scorm2004API.getCMIValue('cmi.interactions.0.learner_response'),
).to.equal('VP_on-call_or_President');
});
});
describe('Initialized - Should Fail', () => {
h.checkLMSSetValue({
api: apiInitialized(
{cmi: {interactions: {'0': {id: 'interaction-id-1'}}}}),
fieldName: 'cmi.interactions.0.type',
valueToTest: 'unknown',
errorThrown: false,
expectedError: scorm2004_error_codes.TYPE_MISMATCH,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.interactions.0.type',
valueToTest: 'true-false',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.interactions.0.description',
valueToTest: 'this is an interaction',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.interactions.0.timestamp',
valueToTest: 'PT1S',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.interactions.0.weighting',
valueToTest: 1.0,
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.interactions.0.learner_response',
valueToTest: 'true',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.interactions.0.latency',
valueToTest: 'PT1S',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.objectives.0.success_status',
valueToTest: 'passed',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.objectives.0.completion_status',
valueToTest: 'completed',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.objectives.0.progress_measure',
valueToTest: 1.0,
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.objectives.0.description',
valueToTest: 'this is an objective',
errorThrown: false,
expectedError: scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.comments_from_lms.0.comment',
@@ -375,6 +463,13 @@ describe('SCORM 2004 API Tests', () => {
errorThrown: false,
expectedError: scorm2004_error_codes.READ_ONLY_ELEMENT,
});
h.checkLMSSetValue({
api: apiInitialized(),
fieldName: 'cmi.unknown',
valueToTest: 'uknown',
errorThrown: false,
expectedError: scorm2004_error_codes.UNDEFINED_DATA_MODEL,
});
});
});