diff --git a/src/BaseAPI.js b/src/BaseAPI.js index 503f039..87c8984 100644 --- a/src/BaseAPI.js +++ b/src/BaseAPI.js @@ -1,5 +1,6 @@ // @flow import {CMIArray} from './cmi/common'; +import {ValidationError} from './exceptions'; const api_constants = { SCORM_TRUE: 'true', @@ -139,15 +140,25 @@ export default class BaseAPI { checkTerminated: boolean, CMIElement, value) { - let returnValue = ''; + let returnValue = api_constants.SCORM_FALSE; if (this.checkState(checkTerminated, this.#error_codes.STORE_BEFORE_INIT, this.#error_codes.STORE_AFTER_TERM)) { if (checkTerminated) this.lastErrorCode = 0; - returnValue = this.setCMIValue(CMIElement, value); + try { + returnValue = this.setCMIValue(CMIElement, value); + } catch (e) { + if (e instanceof ValidationError) { + returnValue = api_constants.SCORM_FALSE; + } else { + this.throwSCORMError(this.#error_codes.GENERAL); + } + } this.processListeners(callbackName, CMIElement, value); } + if (returnValue === undefined) returnValue = api_constants.SCORM_FALSE; + this.apiLog(callbackName, CMIElement, ': ' + value + ': result: ' + returnValue, api_constants.LOG_LEVEL_INFO); @@ -373,9 +384,10 @@ export default class BaseAPI { * * @param {string} _CMIElement * @param {any} _value + * @return {string} */ setCMIValue(_CMIElement, _value) { - // just a stub method + return api_constants.SCORM_FALSE; } /** @@ -409,7 +421,9 @@ export default class BaseAPI { if (scorm2004 && (attribute.substr(0, 8) === '{target=') && (typeof refObject._isTargetValid == 'function')) { this.throwSCORMError(this.#error_codes.READ_ONLY_ELEMENT); - } else if (!{}.hasOwnProperty.call(refObject, attribute)) { + } else if (!Object.hasOwnProperty.call(refObject, attribute) && + !Object.getOwnPropertyDescriptor( + Object.getPrototypeOf(refObject), attribute)) { this.throwSCORMError(invalidErrorCode, invalidErrorMessage); } else { if (this.stringContains(CMIElement, '.correct_responses')) { diff --git a/src/Scorm12API.js b/src/Scorm12API.js index 7576485..ac0e591 100644 --- a/src/Scorm12API.js +++ b/src/Scorm12API.js @@ -119,9 +119,10 @@ export default class Scorm12API extends BaseAPI { * * @param {string} CMIElement * @param {*} value + * @return {string} */ setCMIValue(CMIElement, value) { - this._commonSetCMIValue('LMSSetValue', false, CMIElement, value); + return this._commonSetCMIValue('LMSSetValue', false, CMIElement, value); } /** diff --git a/test/Scorm12API.spec.js b/test/Scorm12API.spec.js new file mode 100644 index 0000000..ac2aa1a --- /dev/null +++ b/test/Scorm12API.spec.js @@ -0,0 +1,48 @@ +import {expect} from 'chai'; +import {describe, it} from 'mocha'; +import Scorm12API from '../src/Scorm12API'; +import * as h from './api_helpers'; +import {scorm12_error_codes} from '../src/constants/error_codes'; + +describe('SCORM 1.2 API Tests', () => { + describe('Pre-Initialization', () => { + describe('LMSSetValue', () => { + const api = () => { + const API = new Scorm12API(); + API.apiLogLevel = 1; + return API; + }; + const apiInitialized = () => { + const API = api(); + API.lmsInitialize(); + return API; + }; + + describe('Should throw errors', () => { + h.checkWrite({ + api: api(), + fieldName: 'cmi.objectives.0.id', + expectedError: scorm12_error_codes.STORE_BEFORE_INIT, + }); + h.checkWrite({ + api: api(), + fieldName: 'cmi.interactions.0.id', + expectedError: scorm12_error_codes.STORE_BEFORE_INIT, + }); + }); + + describe('Should succeed', () => { + h.checkWrite({ + api: apiInitialized(), + fieldName: 'cmi.objectives.0.id', + valueToTest: 'AAA', + }); + h.checkWrite({ + api: apiInitialized(), + fieldName: 'cmi.interactions.0.id', + valueToTest: 'AAA', + }); + }); + }); + }); +}); diff --git a/test/api_helpers.js b/test/api_helpers.js new file mode 100644 index 0000000..07ba8f3 --- /dev/null +++ b/test/api_helpers.js @@ -0,0 +1,18 @@ +import {describe, it} from 'mocha'; +import {expect} from 'chai'; + +export const checkWrite = ( + { + api, + fieldName, + valueToTest = 'xxx', + expectedError = 0, + }) => { + describe(`Field: ${fieldName}`, () => { + const status = expectedError > 0 ? 'fail to' : 'successfully'; + it(`Should ${status} write to ${fieldName}`, () => { + eval(`api.lmsSetValue('${fieldName}', '${valueToTest}')`); + expect(String(api.lastErrorCode)).to.equal(String(expectedError)); + }); + }); +}; diff --git a/test/cmi/aicc_cmi.spec.js b/test/cmi/aicc_cmi.spec.js index 51fa461..468630b 100644 --- a/test/cmi/aicc_cmi.spec.js +++ b/test/cmi/aicc_cmi.spec.js @@ -6,7 +6,7 @@ import { CMIEvaluationCommentsObject, CMITriesObject, NAV, } from '../../src/cmi/aicc_cmi'; -import * as h from '../helpers'; +import * as h from '../cmi_helpers'; import { CMIInteractionsObject, CMIObjectivesObject, @@ -29,13 +29,13 @@ describe('AICC CMI Tests', () => { /** * Base CMI Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._version', expectedValue: '3.4', expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._children', expectedValue: aicc_constants.cmi_children, @@ -64,7 +64,7 @@ describe('AICC CMI Tests', () => { /** * cmi.core Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core._children', expectedValue: aicc_constants.core_children, @@ -139,7 +139,7 @@ describe('AICC CMI Tests', () => { /** * cmi.core.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core.score._children', expectedValue: aicc_constants.score_children, @@ -168,13 +168,13 @@ describe('AICC CMI Tests', () => { /** * cmi.objectives Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._children', expectedValue: aicc_constants.objectives_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._count', expectedValue: 0, expectedError: invalid_set, @@ -183,7 +183,7 @@ describe('AICC CMI Tests', () => { /** * cmi.student_data Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_data._children', expectedValue: aicc_constants.student_data_children, @@ -209,7 +209,7 @@ describe('AICC CMI Tests', () => { /** * cmi.student_preference Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_preference._children', expectedValue: aicc_constants.student_preference_children, @@ -245,13 +245,13 @@ describe('AICC CMI Tests', () => { /** * cmi.interactions Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._children', expectedValue: aicc_constants.interactions_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._count', expectedValue: 0, expectedError: invalid_set, @@ -268,13 +268,13 @@ describe('AICC CMI Tests', () => { /** * Base CMI Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._version', expectedValue: '3.4', expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._children', expectedValue: aicc_constants.cmi_children, @@ -304,7 +304,7 @@ describe('AICC CMI Tests', () => { /** * cmi.core Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core._children', expectedValue: aicc_constants.core_children, @@ -384,7 +384,7 @@ describe('AICC CMI Tests', () => { /** * cmi.core.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core.score._children', expectedValue: aicc_constants.score_children, @@ -412,13 +412,13 @@ describe('AICC CMI Tests', () => { /** * cmi.objectives Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._children', expectedValue: aicc_constants.objectives_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._count', expectedValue: 0, expectedError: invalid_set, @@ -427,7 +427,7 @@ describe('AICC CMI Tests', () => { /** * cmi.student_data Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_data._children', expectedValue: aicc_constants.student_data_children, @@ -457,7 +457,7 @@ describe('AICC CMI Tests', () => { /** * cmi.student_preference Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_preference._children', expectedValue: aicc_constants.student_preference_children, @@ -493,13 +493,13 @@ describe('AICC CMI Tests', () => { /** * cmi.interactions Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._children', expectedValue: aicc_constants.interactions_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._count', expectedValue: 0, expectedError: invalid_set, @@ -566,7 +566,7 @@ describe('AICC CMI Tests', () => { /** * cmi.student_data.tries.n.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: triesObject(), fieldName: 'cmi.score._children', expectedValue: aicc_constants.score_children, diff --git a/test/cmi/scorm12_cmi.spec.js b/test/cmi/scorm12_cmi.spec.js index 45c1167..3a01d62 100644 --- a/test/cmi/scorm12_cmi.spec.js +++ b/test/cmi/scorm12_cmi.spec.js @@ -9,7 +9,7 @@ import { CMIInteractionsObjectivesObject, CMIObjectivesObject, } from '../../src/cmi/scorm12_cmi'; -import * as h from '../helpers'; +import * as h from '../cmi_helpers'; import {scorm12_values} from '../../src/constants/field_values'; const invalid_set = scorm12_error_codes.INVALID_SET_VALUE; @@ -27,13 +27,13 @@ describe('SCORM 1.2 CMI Tests', () => { /** * Base CMI Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._version', expectedValue: '3.4', expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._children', expectedValue: scorm12_constants.cmi_children, @@ -63,7 +63,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.core Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core._children', expectedValue: scorm12_constants.core_children, @@ -137,7 +137,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.core.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core.score._children', expectedValue: scorm12_constants.score_children, @@ -178,13 +178,13 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.objectives Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._children', expectedValue: scorm12_constants.objectives_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._count', expectedValue: 0, @@ -194,7 +194,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.student_data Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_data._children', expectedValue: scorm12_constants.student_data_children, @@ -216,7 +216,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.student_preference Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_preference._children', expectedValue: scorm12_constants.student_preference_children, @@ -264,13 +264,13 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.interactions Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._children', expectedValue: scorm12_constants.interactions_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._count', expectedValue: 0, @@ -288,13 +288,13 @@ describe('SCORM 1.2 CMI Tests', () => { /** * Base CMI Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._version', expectedValue: '3.4', expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi._children', expectedValue: scorm12_constants.cmi_children, @@ -326,7 +326,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.core Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core._children', expectedValue: scorm12_constants.core_children, @@ -406,7 +406,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.core.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.core.score._children', expectedValue: scorm12_constants.score_children, @@ -434,13 +434,13 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.objectives Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._children', expectedValue: scorm12_constants.objectives_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.objectives._count', expectedValue: 0, @@ -450,7 +450,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.student_data Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_data._children', expectedValue: scorm12_constants.student_data_children, @@ -475,7 +475,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.student_preference Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.student_preference._children', expectedValue: scorm12_constants.student_preference_children, @@ -509,13 +509,13 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.interactions Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._children', expectedValue: scorm12_constants.interactions_children, expectedError: invalid_set, }); - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.interactions._count', expectedValue: 0, @@ -725,7 +725,7 @@ describe('SCORM 1.2 CMI Tests', () => { /** * cmi.objectives.n.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: objective(), fieldName: 'cmi.score._children', expectedValue: scorm12_constants.score_children, diff --git a/test/cmi/scorm2004_cmi.spec.js b/test/cmi/scorm2004_cmi.spec.js index e445df5..33bea3f 100644 --- a/test/cmi/scorm2004_cmi.spec.js +++ b/test/cmi/scorm2004_cmi.spec.js @@ -10,10 +10,9 @@ import { CMIInteractionsObjectivesObject, CMIObjectivesObject, } from '../../src/cmi/scorm2004_cmi'; -import * as h from '../helpers'; +import * as h from '../cmi_helpers'; import {expect} from 'chai'; import {scorm2004_values} from '../../src/constants/field_values'; -import {valid_languages} from '../../src/constants/language_constants'; const read_only = scorm2004_error_codes.READ_ONLY_ELEMENT; const write_only = scorm2004_error_codes.WRITE_ONLY_ELEMENT; @@ -158,7 +157,7 @@ describe('SCORM 2004 CMI Tests', () => { /** * cmi.learner_preference Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.learner_preference._children', expectedValue: scorm2004_constants.student_preference_children, @@ -216,7 +215,7 @@ describe('SCORM 2004 CMI Tests', () => { /** * cmi.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.score._children', expectedValue: scorm2004_constants.score_children, @@ -474,7 +473,7 @@ describe('SCORM 2004 CMI Tests', () => { /** * cmi.learner_preference Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.learner_preference._children', expectedValue: scorm2004_constants.student_preference_children, @@ -532,7 +531,7 @@ describe('SCORM 2004 CMI Tests', () => { /** * cmi.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: cmi(), fieldName: 'cmi.score._children', expectedValue: scorm2004_constants.score_children, @@ -912,7 +911,7 @@ describe('SCORM 2004 CMI Tests', () => { /** * cmi.objectives.n.score Properties */ - h.checkInvalidSet({ + h.checkReadOnly({ cmi: objective(), fieldName: 'cmi.score._children', expectedValue: scorm2004_constants.score_children, diff --git a/test/helpers.js b/test/cmi_helpers.js similarity index 88% rename from test/helpers.js rename to test/cmi_helpers.js index c63a378..48113cb 100644 --- a/test/helpers.js +++ b/test/cmi_helpers.js @@ -28,25 +28,6 @@ export const checkFieldConstraintSize = ( }); }; -export const checkInvalidSet = ( - { - cmi, - fieldName, - expectedValue = '', - expectedError, - }) => { - describe(`Field: ${fieldName}`, () => { - it(`Should be able to read from ${fieldName}`, () => { - expect(eval(`${fieldName}`)).to.equal(expectedValue); - }); - - it(`Should fail to write to ${fieldName}`, () => { - expect(() => eval(`${fieldName} = 'xxx'`)). - to.throw(expectedError + ''); - }); - }); -}; - export const checkReadOnly = ( { cmi,