diff --git a/src/AICC.js b/src/AICC.js index 6744d89..75b1176 100644 --- a/src/AICC.js +++ b/src/AICC.js @@ -17,8 +17,8 @@ export default class AICC extends Scorm12API { constructor() { super(); - this.cmi = new CMI(this); - this.nav = new NAV(this); + this.cmi = new CMI(); + this.nav = new NAV(); } /** diff --git a/src/BaseAPI.js b/src/BaseAPI.js index f922b10..ef6522f 100644 --- a/src/BaseAPI.js +++ b/src/BaseAPI.js @@ -609,7 +609,6 @@ export default class BaseAPI { this.throwSCORMError(203); } } - return; } else { return refObject; } @@ -776,6 +775,14 @@ export default class BaseAPI { return JSON.parse(JSON.stringify(cmi)); } + /** + * Gets the current total time as total_time + session_time + * APIs that inherit BaseAPI should override this function + */ + getCurrentTotalTime() { + this.cmi.getCurrentTotalTime(); + } + /** * Throws a SCORM error * diff --git a/src/Scorm12API.js b/src/Scorm12API.js index a620f87..9730325 100644 --- a/src/Scorm12API.js +++ b/src/Scorm12API.js @@ -24,7 +24,7 @@ export default class Scorm12API extends BaseAPI { constructor() { super(scorm12_error_codes); - this.cmi = new CMI(this); + this.cmi = new CMI(); // Rename functions to match 1.2 Spec and expose to modules this.LMSInitialize = this.lmsInitialize; this.LMSFinish = this.lmsFinish; @@ -192,20 +192,6 @@ export default class Scorm12API extends BaseAPI { return detail ? detailMessage : basicMessage; } - /** - * Adds the current session time to the existing total time. - * - * @return {string} - */ - getCurrentTotalTime() { - const timeRegex = new RegExp(scorm12_regex.CMITime); - - const totalTime = this.cmi.core.total_time; - const sessionTime = this.cmi.core.session_time; - - return Utilities.addHHMMSSTimeStrings(totalTime, sessionTime, timeRegex); - } - /** * Replace the whole API with another * diff --git a/src/Scorm2004API.js b/src/Scorm2004API.js index 32ebcac..fb197b0 100644 --- a/src/Scorm2004API.js +++ b/src/Scorm2004API.js @@ -30,8 +30,8 @@ export default class Scorm2004API extends BaseAPI { constructor() { super(scorm2004_error_codes); - this.cmi = new CMI(this); - this.adl = new ADL(this); + this.cmi = new CMI(); + this.adl = new ADL(); // Rename functions to match 2004 Spec and expose to modules this.Initialize = this.lmsInitialize; @@ -420,17 +420,4 @@ export default class Scorm2004API extends BaseAPI { this.cmi = newAPI.cmi; this.adl = newAPI.adl; } - - /** - * Adds the current session time to the existing total time. - * - * @return {string} ISO8601 Duration - */ - getCurrentTotalTime() { - const totalTime = this.cmi.total_time; - const sessionTime = this.cmi.session_time; - - return Util.addTwoDurations(totalTime, sessionTime, - scorm2004_regex.CMITimespan); - } } diff --git a/src/cmi/scorm12_cmi.js b/src/cmi/scorm12_cmi.js index cff7452..9d40773 100644 --- a/src/cmi/scorm12_cmi.js +++ b/src/cmi/scorm12_cmi.js @@ -10,6 +10,7 @@ import {scorm12_constants} from '../constants/api_constants'; import {scorm12_error_codes} from '../constants/error_codes'; import {scorm12_regex} from '../constants/regex'; import {ValidationError} from '../exceptions'; +import * as Utilities from '../utilities'; const constants = scorm12_constants; const regex = scorm12_regex; @@ -244,6 +245,15 @@ export class CMI extends BaseCMI { this.#comments_from_lms = comments_from_lms : throwReadOnlyError(); } + + /** + * Adds the current session time to the existing total time. + * + * @return {string} + */ + getCurrentTotalTime() { + return this.core.getCurrentTotalTime(); + } } /** @@ -475,6 +485,19 @@ class CMICore extends BaseCMI { } } + /** + * Adds the current session time to the existing total time. + * + * @return {string} + */ + getCurrentTotalTime() { + return Utilities.addHHMMSSTimeStrings( + this.#total_time, + this.#session_time, + new RegExp(scorm12_regex.CMITimespan) + ); + } + /** * toJSON for cmi.core * diff --git a/src/cmi/scorm2004_cmi.js b/src/cmi/scorm2004_cmi.js index 40d664b..0cc0786 100644 --- a/src/cmi/scorm2004_cmi.js +++ b/src/cmi/scorm2004_cmi.js @@ -11,6 +11,7 @@ import {scorm2004_regex} from '../constants/regex'; import {scorm2004_error_codes} from '../constants/error_codes'; import {learner_responses} from '../constants/response_constants'; import {ValidationError} from '../exceptions'; +import * as Util from '../utilities'; const constants = scorm2004_constants; const regex = scorm2004_regex; @@ -466,6 +467,19 @@ export class CMI extends BaseCMI { !this.initialized ? this.#total_time = total_time : throwReadOnlyError(); } + /** + * Adds the current session time to the existing total time. + * + * @return {string} ISO8601 Duration + */ + getCurrentTotalTime() { + return Util.addTwoDurations( + this.#total_time, + this.#session_time, + scorm2004_regex.CMITimespan, + ); + } + /** * toJSON for cmi * diff --git a/src/utilities.js b/src/utilities.js index 9e58dbc..c2f7347 100644 --- a/src/utilities.js +++ b/src/utilities.js @@ -44,7 +44,7 @@ export function getSecondsAsHHMMSS(totalSeconds: Number) { export function getSecondsAsISODuration(seconds: Number) { // SCORM spec does not deal with negative durations, give zero back if (!seconds || seconds <= 0) { - return 'P0S'; + return 'PT0S'; } let duration = 'P'; @@ -61,6 +61,11 @@ export function getSecondsAsISODuration(seconds: Number) { } if (value) { + if ((duration.indexOf('D') > 0 || + sign === 'H' || sign === 'M' || sign === 'S') && + duration.indexOf('T') === -1) { + duration += 'T'; + } duration += `${value}${sign}`; } }); diff --git a/test/Scorm2004API.spec.js b/test/Scorm2004API.spec.js index 98c7b04..da29356 100644 --- a/test/Scorm2004API.spec.js +++ b/test/Scorm2004API.spec.js @@ -11,7 +11,7 @@ const api = () => { return API; }; const apiInitialized = () => { - const API = api(true); + const API = api(); API.lmsInitialize(); return API; }; diff --git a/test/abstract_classes.spec.js b/test/abstract_classes.spec.js new file mode 100644 index 0000000..3432c10 --- /dev/null +++ b/test/abstract_classes.spec.js @@ -0,0 +1,17 @@ +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import BaseAPI from '../src/BaseAPI'; +import {BaseCMI} from '../src/cmi/common'; + +describe('Abstract Class Tests', () => { + it('BaseAPI should not be instantiated', () => { + expect( + () => new BaseAPI(), + ).to.throw('Cannot construct BaseAPI instances directly'); + }); + it('BaseCMI should not be instantiated', () => { + expect( + () => new BaseCMI(), + ).to.throw('Cannot construct BaseCMI instances directly'); + }); +}); diff --git a/test/cmi/scorm12_cmi.spec.js b/test/cmi/scorm12_cmi.spec.js index 3a01d62..b15fb8b 100644 --- a/test/cmi/scorm12_cmi.spec.js +++ b/test/cmi/scorm12_cmi.spec.js @@ -17,13 +17,78 @@ const type_mismatch = scorm12_error_codes.TYPE_MISMATCH; const write_only = scorm12_error_codes.WRITE_ONLY_ELEMENT; const read_only = scorm12_error_codes.READ_ONLY_ELEMENT; +const cmi = () => { + return new CMI(); +}; +const cmiInitialized = () => { + const obj = new CMI(); + obj.initialize(); + return obj; +}; +const interaction = () => { + return new CMIInteractionsObject(); +}; +const interactionInitialized = () => { + const cmi = new CMIInteractionsObject(); + cmi.initialize(); + return cmi; +}; +const interactionObjective = () => { + return new CMIInteractionsObjectivesObject(); +}; +const correctResponse = () => { + return new CMIInteractionsCorrectResponsesObject(); +}; +const objective = () => { + return new CMIObjectivesObject(); +}; + describe('SCORM 1.2 CMI Tests', () => { + describe('getCurrentTotalTime()', () => { + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: '00:00:00', + sessionTime: '00:15:45', + expectedTotal: '00:15:45', + totalFieldName: 'cmi.core.total_time', + sessionFieldName: 'cmi.core.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: '00:01:00', + sessionTime: '00:15:45', + expectedTotal: '00:16:45', + totalFieldName: 'cmi.core.total_time', + sessionFieldName: 'cmi.core.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: '00:01:00', + sessionTime: '00:00:00', + expectedTotal: '00:01:00', + totalFieldName: 'cmi.core.total_time', + sessionFieldName: 'cmi.core.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: '25:01:00', + sessionTime: '13:00:00', + expectedTotal: '38:01:00', + totalFieldName: 'cmi.core.total_time', + sessionFieldName: 'cmi.core.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: '48:01:45', + sessionTime: '13:00:16', + expectedTotal: '61:02:01', + totalFieldName: 'cmi.core.total_time', + sessionFieldName: 'cmi.core.session_time', + }); + }); + describe('CMI Spec Tests', () => { describe('Pre-Initialize Tests', () => { - const cmi = () => { - return new CMI(); - }; - /** * Base CMI Properties */ @@ -279,46 +344,40 @@ describe('SCORM 1.2 CMI Tests', () => { }); describe('Post-Initialize Tests', () => { - const cmi = () => { - const obj = new CMI(); - obj.initialize(); - return obj; - }; - /** * Base CMI Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi._version', expectedValue: '3.4', expectedError: invalid_set, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi._children', expectedValue: scorm12_constants.cmi_children, expectedError: invalid_set, }); h.checkFieldConstraintSize({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.suspend_data', limit: 4096, expectedError: type_mismatch, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.launch_data', expectedError: read_only, }); h.checkFieldConstraintSize({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.comments', limit: 4096, expectedError: type_mismatch, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.comments_from_lms', expectedError: read_only, }); @@ -327,77 +386,77 @@ describe('SCORM 1.2 CMI Tests', () => { * cmi.core Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core._children', expectedValue: scorm12_constants.core_children, expectedError: invalid_set, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.student_id', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.student_name', expectedError: read_only, }); h.checkFieldConstraintSize({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.lesson_location', limit: 255, expectedError: type_mismatch, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.credit', expectedError: read_only, }); h.checkRead({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.lesson_status', }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.lesson_status', validValues: scorm12_values.validLessonStatus, invalidValues: scorm12_values.invalidLessonStatus, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.entry', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.total_time', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.lesson_mode', expectedValue: 'normal', expectedError: read_only, }); h.checkWrite({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.exit', valueToTest: 'suspend', }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.exit', validValues: scorm12_values.validExit, invalidValues: scorm12_values.invalidExit, }); h.checkWriteOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.session_time', valueToTest: '00:00:00', expectedError: write_only, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.session_time', validValues: scorm12_values.validHHMMSS, invalidValues: scorm12_values.invalidHHMMSS, @@ -407,25 +466,25 @@ describe('SCORM 1.2 CMI Tests', () => { * cmi.core.score Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.score._children', expectedValue: scorm12_constants.score_children, expectedError: invalid_set, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.score.raw', validValues: scorm12_values.validScoreRange, invalidValues: scorm12_values.invalidScoreRange, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.score.min', validValues: scorm12_values.validScoreRange, invalidValues: scorm12_values.invalidScoreRange, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.core.score.max', validValues: scorm12_values.validScoreRange, invalidValues: scorm12_values.invalidScoreRange, @@ -435,13 +494,13 @@ describe('SCORM 1.2 CMI Tests', () => { * cmi.objectives Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.objectives._children', expectedValue: scorm12_constants.objectives_children, expectedError: invalid_set, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.objectives._count', expectedValue: 0, expectedError: invalid_set, @@ -451,23 +510,23 @@ describe('SCORM 1.2 CMI Tests', () => { * cmi.student_data Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_data._children', expectedValue: scorm12_constants.student_data_children, expectedError: invalid_set, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_data.mastery_score', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_data.max_time_allowed', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_data.time_limit_action', expectedError: read_only, }); @@ -476,31 +535,31 @@ describe('SCORM 1.2 CMI Tests', () => { * cmi.student_preference Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_preference._children', expectedValue: scorm12_constants.student_preference_children, expectedError: invalid_set, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_preference.audio', validValues: scorm12_values.valid0To100Range.concat(['-1']), invalidValues: scorm12_values.invalid0To100Range, }); h.checkFieldConstraintSize({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_preference.language', limit: 255, expectedError: type_mismatch, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_preference.speed', validValues: scorm12_values.validSpeedRange, invalidValues: scorm12_values.invalidSpeedRange, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.student_preference.text', validValues: scorm12_values.validIntegerScaledRange, invalidValues: scorm12_values.invalidIntegerScaledRange, @@ -510,20 +569,20 @@ describe('SCORM 1.2 CMI Tests', () => { * cmi.interactions Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.interactions._children', expectedValue: scorm12_constants.interactions_children, expectedError: invalid_set, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.interactions._count', expectedValue: 0, expectedError: invalid_set, }); it('should export JSON', () => { - const cmiObj = cmi(); + const cmiObj = cmiInitialized(); cmiObj.objectives.childArray.push(new CMIObjectivesObject()); cmiObj.interactions.childArray.push(new CMIInteractionsObject()); expect( @@ -536,15 +595,6 @@ describe('SCORM 1.2 CMI Tests', () => { }); describe('CMIInteractionsObject Tests', () => { - const interaction = () => { - return new CMIInteractionsObject(); - }; - const interactionInitialized = () => { - const cmi = new CMIInteractionsObject(); - cmi.initialize(); - return cmi; - }; - /** * cmi.interactions.n object */ @@ -655,10 +705,6 @@ describe('SCORM 1.2 CMI Tests', () => { }); describe('CMIInteractionsObjectivesObject Tests', () => { - const interactionObjective = () => { - return new CMIInteractionsObjectivesObject(); - }; - /** * cmi.interactions.n.objectives.n object */ @@ -676,9 +722,6 @@ describe('SCORM 1.2 CMI Tests', () => { }); describe('CMIInteractionsCorrectResponsesObject Tests', () => { - const correctResponse = () => { - return new CMIInteractionsCorrectResponsesObject(); - }; /** * cmi.interactions.n.correct_responses.n object @@ -698,10 +741,6 @@ describe('SCORM 1.2 CMI Tests', () => { }); describe('CMIObjectivesObject Tests', () => { - const objective = () => { - return new CMIObjectivesObject(); - }; - /** * cmi.objectives.n object */ diff --git a/test/cmi/scorm2004_cmi.spec.js b/test/cmi/scorm2004_cmi.spec.js index 4f7878a..4b72410 100644 --- a/test/cmi/scorm2004_cmi.spec.js +++ b/test/cmi/scorm2004_cmi.spec.js @@ -5,7 +5,7 @@ import { ADL, CMI, CMICommentsObject, - CMICommentsFromLMSObject, CMIInteractionsCorrectResponsesObject, + CMIInteractionsCorrectResponsesObject, CMIInteractionsObject, CMIInteractionsObjectivesObject, CMIObjectivesObject, @@ -16,16 +16,99 @@ import {scorm2004_values} from '../../src/constants/field_values'; const read_only = scorm2004_error_codes.READ_ONLY_ELEMENT; const write_only = scorm2004_error_codes.WRITE_ONLY_ELEMENT; -const invalid_set = scorm2004_error_codes.INVALID_SET_VALUE; const type_mismatch = scorm2004_error_codes.TYPE_MISMATCH; +const cmi = () => { + return new CMI(); +}; +const cmiInitialized = () => { + const cmiObj = new CMI(); + cmiObj.initialize(); + return cmiObj; +}; +const comments = () => { + return new CMICommentsObject(); +}; +const lmsComments = () => { + return new CMICommentsObject(true); +}; +const lmsCommentsInitialized = () => { + const cmi = lmsComments(); + cmi.initialize(); + return cmi; +}; +const interaction = () => { + return new CMIInteractionsObject(); +}; +const interactionInitialized = () => { + const cmi = new CMIInteractionsObject(); + cmi.initialize(); + return cmi; +}; +const objective = () => { + return new CMIObjectivesObject(); +}; +const objectiveInitialized = () => { + const cmi = new CMIObjectivesObject(); + cmi.initialize(); + return cmi; +}; +const interactionObjective = () => { + return new CMIInteractionsObjectivesObject(); +}; +const correctResponse = () => { + return new CMIInteractionsCorrectResponsesObject(); +}; +const adl = () => { + return new ADL(); +}; + describe('SCORM 2004 CMI Tests', () => { + describe('getCurrentTotalTime()', () => { + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: 'PT0S', + sessionTime: 'PT15M45S', + expectedTotal: 'PT15M45S', + totalFieldName: 'cmi.total_time', + sessionFieldName: 'cmi.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: 'PT60S', + sessionTime: 'PT15M45S', + expectedTotal: 'PT16M45S', + totalFieldName: 'cmi.total_time', + sessionFieldName: 'cmi.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: 'PT60S', + sessionTime: 'PT0S', + expectedTotal: 'PT1M', + totalFieldName: 'cmi.total_time', + sessionFieldName: 'cmi.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: 'PT25H1M0S', + sessionTime: 'PT13H', + expectedTotal: 'P1DT14H1M', + totalFieldName: 'cmi.total_time', + sessionFieldName: 'cmi.session_time', + }); + h.checkGetCurrentTotalTime({ + cmi: cmi(), + startingTotal: 'PT48H1M45S', + sessionTime: 'PT13H16S', + expectedTotal: 'P2DT13H2M1S', + totalFieldName: 'cmi.total_time', + sessionFieldName: 'cmi.session_time', + }); + }); + describe('CMI Spec Tests', () => { describe('Pre-Initialize Tests', () => { - const cmi = () => { - return new CMI(); - }; - /** * Base CMI Properties */ @@ -324,147 +407,141 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('Post-Initialize Tests', () => { - const cmi = () => { - const cmiObj = new CMI(); - cmiObj.initialize(); - return cmiObj; - }; - /** * Base CMI Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi._version', expectedValue: '1.0', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi._children', expectedValue: scorm2004_constants.cmi_children, expectedError: read_only, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.completion_status', expectedError: type_mismatch, validValues: scorm2004_values.validCStatus, invalidValues: scorm2004_values.invalidCStatus, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.completion_threshold', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.credit', expectedValue: 'credit', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.entry', expectedError: read_only, }); h.checkWriteOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.exit', expectedError: write_only, valueToTest: 'time-out', }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.exit', validValues: scorm2004_values.validExit, invalidValues: scorm2004_values.invalidExit, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.launch_data', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_id', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_name', expectedError: read_only, }); h.checkFieldConstraintSize({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.location', limit: 1000, expectedError: type_mismatch, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.max_time_allowed', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.mode', expectedValue: 'normal', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.max_time_allowed', expectedError: read_only, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.progress_measure', validValues: scorm2004_values.valid0To1Range, invalidValues: scorm2004_values.invalid0To1Range, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.scaled_passing_score', expectedError: read_only, }); h.checkWriteOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.session_time', valueToTest: 'P0S', expectedError: write_only, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.session_time', validValues: scorm2004_values.validISO8601Durations, invalidValues: scorm2004_values.invalidISO8601Durations, }); h.checkRead({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.success_status', expectedValue: 'unknown', }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.success_status', validValues: scorm2004_values.validSStatus, invalidValues: scorm2004_values.invalidSStatus, }); h.checkFieldConstraintSize({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.suspend_data', limit: 64000, expectedError: type_mismatch, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.time_limit_action', expectedValue: 'continue,no message', expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.total_time', expectedValue: '0', expectedError: read_only, @@ -474,19 +551,19 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.learner_preference Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_preference._children', expectedValue: scorm2004_constants.student_preference_children, expectedError: read_only, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_preference.audio_level', validValues: scorm2004_values.valid0To100Range, invalidValues: scorm2004_values.invalid0To100Range, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_preference.language', validValues: [ 'en', @@ -500,13 +577,13 @@ describe('SCORM 2004 CMI Tests', () => { ], }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_preference.delivery_speed', validValues: scorm2004_values.valid0To100Range, invalidValues: scorm2004_values.invalid0To100Range, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.learner_preference.audio_captioning', validValues: scorm2004_values.validIntegerScaledRange, invalidValues: scorm2004_values.invalidIntegerScaledRange, @@ -516,13 +593,13 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.objectives Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.objectives._children', expectedValue: scorm2004_constants.objectives_children, expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.objectives._count', expectedValue: 0, expectedError: read_only, @@ -532,31 +609,31 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.score Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.score._children', expectedValue: scorm2004_constants.score_children, expectedError: read_only, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.score.scaled', validValues: scorm2004_values.validScaledRange, invalidValues: scorm2004_values.invalidScaledRange, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.score.raw', validValues: scorm2004_values.validScoreRange, invalidValues: scorm2004_values.invalidScoreRange, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.score.min', validValues: scorm2004_values.validScoreRange, invalidValues: scorm2004_values.invalidScoreRange, }); h.checkValidValues({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.score.max', validValues: scorm2004_values.validScoreRange, invalidValues: scorm2004_values.invalidScoreRange, @@ -566,13 +643,13 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.comments_from_learner Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.comments_from_learner._children', expectedValue: scorm2004_constants.comments_children, expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.comments_from_learner._count', expectedValue: 0, expectedError: read_only, @@ -582,13 +659,13 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.comments_from_lms Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.comments_from_lms._children', expectedValue: scorm2004_constants.comments_children, expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.comments_from_lms._count', expectedValue: 0, expectedError: read_only, @@ -598,13 +675,13 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.interactions Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.interactions._children', expectedValue: scorm2004_constants.interactions_children, expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.interactions._count', expectedValue: 0, expectedError: read_only, @@ -614,20 +691,20 @@ describe('SCORM 2004 CMI Tests', () => { * cmi.objectives Properties */ h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.objectives._children', expectedValue: scorm2004_constants.objectives_children, expectedError: read_only, }); h.checkReadOnly({ - cmi: cmi(), + cmi: cmiInitialized(), fieldName: 'cmi.objectives._count', expectedValue: 0, expectedError: read_only, }); it('should export JSON', () => { - const cmiObj = cmi(); + const cmiObj = cmiInitialized(); cmiObj.objectives.childArray.push(new CMIObjectivesObject()); cmiObj.interactions.childArray.push(new CMIInteractionsObject()); expect( @@ -640,10 +717,6 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('CMICommentsObject Tests', () => { - const comments = () => { - return new CMICommentsObject(); - }; - /** * cmi.comments_from_learner.n object */ @@ -682,62 +755,53 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('CMICommentsFromLMSObject Tests', () => { - const comments = () => { - return new CMICommentsObject(true); - }; - const commentsInitialized = () => { - const cmi = new CMICommentsObject(true); - cmi.initialize(); - return cmi; - }; - /** * cmi.comments_from_lms.n object */ h.checkValidValues({ - cmi: comments(), + cmi: lmsComments(), fieldName: 'cmi.comment', validValues: scorm2004_values.validComment, invalidValues: scorm2004_values.invalidComment, }); h.checkFieldConstraintSize({ - cmi: comments(), + cmi: lmsComments(), fieldName: 'cmi.location', expectedError: type_mismatch, limit: 250, }); h.checkReadAndWrite({ - cmi: comments(), + cmi: lmsComments(), fieldName: 'cmi.timestamp', valueToTest: scorm2004_values.validTimestamps[0], }); h.checkValidValues({ - cmi: comments(), + cmi: lmsComments(), fieldName: 'cmi.timestamp', validValues: scorm2004_values.validTimestamps, invalidValues: scorm2004_values.invalidTimestamps, }); h.checkReadOnly({ - cmi: commentsInitialized(), + cmi: lmsCommentsInitialized(), fieldName: 'cmi.comment', expectedError: read_only, }); h.checkReadOnly({ - cmi: commentsInitialized(), + cmi: lmsCommentsInitialized(), fieldName: 'cmi.location', expectedError: read_only, }); h.checkReadOnly({ - cmi: commentsInitialized(), + cmi: lmsCommentsInitialized(), fieldName: 'cmi.timestamp', expectedError: read_only, }); it('should export JSON', () => { - const cmi = comments(); + const cmi = lmsComments(); expect( JSON.stringify(cmi), ).to.equal('{"comment":"","location":"","timestamp":""}'); @@ -745,15 +809,6 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('CMIInteractionsObject Tests', () => { - const interaction = () => { - return new CMIInteractionsObject(); - }; - const interactionInitialized = () => { - const cmi = new CMIInteractionsObject(); - cmi.initialize(); - return cmi; - }; - /** * cmi.interactions.n object */ @@ -853,15 +908,6 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('CMIObjectivesObject Tests', () => { - const objective = () => { - return new CMIObjectivesObject(); - }; - const objectiveInitialized = () => { - const cmi = new CMIObjectivesObject(); - cmi.initialize(); - return cmi; - }; - /** * cmi.objectives.n object */ @@ -954,10 +1000,6 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('CMIInteractionsObjectivesObject Tests', () => { - const interactionObjective = () => { - return new CMIInteractionsObjectivesObject(); - }; - /** * cmi.interactions.n.objectives.n object */ @@ -975,10 +1017,6 @@ describe('SCORM 2004 CMI Tests', () => { }); describe('CMIInteractionsCorrectResponsesObject Tests', () => { - const correctResponse = () => { - return new CMIInteractionsCorrectResponsesObject(); - }; - /** * cmi.interactions.n.correct_responses.n object */ @@ -997,10 +1035,6 @@ describe('SCORM 2004 CMI Tests', () => { describe('ADL Tests', () => { describe('ADLNav Tests', () => { - const adl = () => { - return new ADL(); - }; - /** * cmi.interactions.n.correct_responses.n object */ diff --git a/test/cmi_helpers.js b/test/cmi_helpers.js index 48113cb..123c878 100644 --- a/test/cmi_helpers.js +++ b/test/cmi_helpers.js @@ -140,3 +140,22 @@ export const checkValidValues = ( } }); }; + +export const checkGetCurrentTotalTime = ( + { + cmi: cmi, + totalFieldName, + sessionFieldName, + startingTotal, + sessionTime, + expectedTotal, + }) => { + it(`Should return ${expectedTotal} with a starting time of ${startingTotal} and a session time of ${sessionTime}`, + () => { + eval(`${totalFieldName} = '${startingTotal}'`); + eval(`${sessionFieldName} = '${sessionTime}'`); + expect( + cmi.getCurrentTotalTime(), + ).to.equal(expectedTotal); + }); +}; diff --git a/test/exceptions.spec.js b/test/exceptions.spec.js new file mode 100644 index 0000000..6d3d11c --- /dev/null +++ b/test/exceptions.spec.js @@ -0,0 +1,16 @@ +import {describe, it} from 'mocha'; +import {expect} from 'chai'; +import {ValidationError} from '../src/exceptions'; + +describe('Exception Tests', () => { + it('ValidationException should return message string', () => { + expect( + new ValidationError(0).message, + ).to.equal('0'); + }); + it('ValidationException should return errorCode number', () => { + expect( + new ValidationError(0).errorCode, + ).to.equal(0); + }); +}); diff --git a/test/utilities.spec.js b/test/utilities.spec.js index 0bbf14c..2c0cb53 100644 --- a/test/utilities.spec.js +++ b/test/utilities.spec.js @@ -56,59 +56,59 @@ describe('Utility Tests', () => { }); describe('getSecondsAsISODuration()', () => { - it('10 returns P10S', () => { + it('10 returns PT10S', () => { expect( Utilities.getSecondsAsISODuration(10), - ).to.equal('P10S'); + ).to.equal('PT10S'); }); - it('60 returns P1M', () => { + it('60 returns PT1M', () => { expect( Utilities.getSecondsAsISODuration(60), - ).to.equal('P1M'); + ).to.equal('PT1M'); }); - it('3600 returns P1H', () => { + it('3600 returns PT1H', () => { expect( Utilities.getSecondsAsISODuration(3600), - ).to.equal('P1H'); + ).to.equal('PT1H'); }); - it('70 returns P1M10S', () => { + it('70 returns PT1M10S', () => { expect( Utilities.getSecondsAsISODuration(70), - ).to.equal('P1M10S'); + ).to.equal('PT1M10S'); }); - it('3670 returns P1H1M10S', () => { + it('3670 returns PT1H1M10S', () => { expect( Utilities.getSecondsAsISODuration(3670), - ).to.equal('P1H1M10S'); + ).to.equal('PT1H1M10S'); }); - it('90000 returns P1D1H', () => { + it('90000 returns P1DT1H', () => { expect( Utilities.getSecondsAsISODuration(90000), - ).to.equal('P1D1H'); + ).to.equal('P1DT1H'); }); - it('90061 returns P1D1H1M1S', () => { + it('90061 returns P1DT1H1M1S', () => { expect( Utilities.getSecondsAsISODuration(90061), - ).to.equal('P1D1H1M1S'); + ).to.equal('P1DT1H1M1S'); }); - it('-3600 returns P0S, negative time not allowed in SCORM session times', + it('-3600 returns PT0S, negative time not allowed in SCORM session times', () => { expect( Utilities.getSecondsAsISODuration(-3600), - ).to.equal('P0S'); + ).to.equal('PT0S'); }); - it('Empty seconds returns P0S', () => { + it('Empty seconds returns PT0S', () => { expect( Utilities.getSecondsAsISODuration(null), - ).to.equal('P0S'); + ).to.equal('PT0S'); }); }); @@ -224,27 +224,27 @@ describe('Utility Tests', () => { describe('addTwoDurations()', () => { it('P1H5M30.5S plus PT15M10S equals P1H20M40.5S', () => { expect( - Utilities.addTwoDurations('P1H5M30.5S', 'PT15M10S', + Utilities.addTwoDurations('PT1H5M30.5S', 'PT15M10S', scorm2004_regex.CMITimespan), - ).to.equal('P1H20M40.5S'); + ).to.equal('PT1H20M40.5S'); }); - it('P1Y364D plus P2D1H45M52S equals P732D1H45M52S', () => { + it('P1Y364D plus P2DT1H45M52S equals P732DT1H45M52S', () => { expect( - Utilities.addTwoDurations('P1Y364D', 'P2D1H45M52S', + Utilities.addTwoDurations('P1Y364D', 'P2DT1H45M52S', scorm2004_regex.CMITimespan), - ).to.equal('P732D1H45M52S'); + ).to.equal('P732DT1H45M52S'); }); it('Invalid plus valid equals valid', () => { expect( - Utilities.addTwoDurations('NOT A VALID DURATION', 'P1H30M45S', + Utilities.addTwoDurations('NOT A VALID DURATION', 'PT1H30M45S', scorm2004_regex.CMITimespan), - ).to.equal('P1H30M45S'); + ).to.equal('PT1H30M45S'); }); it('Valid plus invalid equals valid', () => { expect( - Utilities.addTwoDurations('P1H30M45S', 'NOT A VALID DURATION', + Utilities.addTwoDurations('PT1H30M45S', 'NOT A VALID DURATION', scorm2004_regex.CMITimespan), - ).to.equal('P1H30M45S'); + ).to.equal('PT1H30M45S'); }); });