tao-test/app/taoQtiTest/views/js/controller/runner/runner.js

249 lines
8.8 KiB
JavaScript

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2016-2019 (original work) Open Assessment Technologies SA ;
*/
/**
* Test runner controller entry
*
* @author Bertrand Chevrier <bertrand@taotesting.com>
*/
define([
'jquery',
'lodash',
'i18n',
'context',
'module',
'core/router',
'core/logger',
'layout/loading-bar',
'ui/feedback',
'util/url',
'util/locale',
'taoTests/runner/providerLoader',
'taoTests/runner/runner',
'css!taoQtiTestCss/new-test-runner'
], function (
$,
_,
__,
context,
module,
router,
loggerFactory,
loadingBar,
feedback,
urlUtil,
locale,
providerLoader,
runner
) {
'use strict';
/**
* List of options required by the controller
* @type {String[]}
*/
const requiredOptions = [
'testDefinition',
'testCompilation',
'serviceCallId',
'bootstrap',
'options',
'providers'
];
/**
* The runner controller
*/
return {
/**
* Controller entry point
*
* @param {Object} config - the testRunner config
* @param {String} config.testDefinition - the test definition id
* @param {String} config.testCompilation - the test compilation id
* @param {String} config.serviceCallId - the service call id
* @param {Object} config.bootstrap - contains the extension and the controller to call
* @param {Object} config.options - the full URL where to return at the final end of the test
* @param {Object[]} config.providers - the collection of providers to load
*/
start(config) {
let exitReason;
const $container = $('.runner');
const logger = loggerFactory('controller/runner', {
serviceCallId : config.serviceCallId,
plugins : config && config.providers && Object.keys(config.providers.plugins)
});
let preventFeedback = false;
let errorFeedback = null;
/**
* Exit the test runner using the configured exitUrl
* @param {String} [reason] - to add a warning once left
* @param {String} [level] - error level
*/
const exit = function exit(reason, level){
let url = config.options.exitUrl;
const params = {};
if (reason) {
if (!level) {
level = 'warning';
}
params[level] = reason;
url = urlUtil.build(url, params);
}
window.location = url;
};
/**
* Handles errors
* @param {Error} err - the thrown error
* @param {String} [displayMessage] - an alternate message to display
*/
const onError = function onError(err, displayMessage) {
onFeedback(err, displayMessage, "error");
};
/**
* Handles warnings
* @param {Error} err - the thrown error
* @param {String} [displayMessage] - an alternate message to display
*/
const onWarning = function onWarning(err, displayMessage) {
onFeedback(err, displayMessage, "warning");
};
/**
* Handles errors & warnings
* @param {Error} err - the thrown error
* @param {String} [displayMessage] - an alternate message to display
* @param {String} [type] - "error" or "warning"
*/
const onFeedback = function onFeedback(err, displayMessage, type) {
const typeMap = {
warning: {
logger: "warn",
feedback: "warning"
},
error: {
logger: "error",
feedback: "error"
}
};
const loggerByType = logger[typeMap[type].logger];
const feedbackByType = feedback()[typeMap[type].feedback];
displayMessage = displayMessage || err.message;
if(!_.isString(displayMessage)){
displayMessage = JSON.stringify(displayMessage);
}
loadingBar.stop();
loggerByType({ displayMessage : displayMessage }, err);
if(type === "error" && (err.code === 403 || err.code === 500)) {
displayMessage = `${__('An error occurred during the test, please content your administrator.')} ${displayMessage}`;
return exit(displayMessage, 'error');
}
if (!preventFeedback) {
errorFeedback = feedbackByType(displayMessage, {timeout: -1});
}
};
const moduleConfig = module.config();
loadingBar.start();
// adding attr for RTL languages
$('.delivery-scope').attr({dir: locale.getLanguageDirection(context.locale)});
// verify required config
if ( ! requiredOptions.every( option => typeof config[option] !== 'undefined') ) {
return onError(new TypeError(__('Missing required configuration option %s', name)));
}
// dispatch any extra registered routes
if (moduleConfig && _.isArray(moduleConfig.extraRoutes) && moduleConfig.extraRoutes.length) {
router.dispatch(moduleConfig.extraRoutes);
}
//for the qti provider to be selected here
config.provider = Object.assign( config.provider || {}, { runner: 'qti' });
//load the plugins and the proxy provider
providerLoader(config.providers, context.bundle)
.then(function (results) {
const testRunnerConfig = _.omit(config, ['providers']);
testRunnerConfig.renderTo = $container;
if (results.proxy && typeof results.proxy.getAvailableProviders === 'function') {
const loadedProxies = results.proxy.getAvailableProviders();
testRunnerConfig.provider.proxy = loadedProxies[0];
}
logger.debug({
config: testRunnerConfig,
providers : config.providers
}, 'Start test runner');
//instantiate the QtiTestRunner
runner(config.provider.runner, results.plugins, testRunnerConfig)
.on('error', onError)
.on('warning', onWarning)
.on('ready', function () {
_.defer(function () {
$container.removeClass('hidden');
});
})
.on('pause', function(data) {
if (data && data.reason) {
exitReason = data.reason;
}
})
.after('destroy', function () {
this.removeAllListeners();
// at the end, we are redirected to the exit URL
exit(exitReason);
})
//FIXME this event should not be triggered on the test runner
.on('disablefeedbackalerts', function() {
if (errorFeedback) {
errorFeedback.close();
}
preventFeedback = true;
})
//FIXME this event should not be triggered on the test runner
.on('enablefeedbackalerts', function() {
preventFeedback = false;
})
.init();
})
.catch(function(err){
onError(err, __('An error occurred during the test initialization!'));
});
}
};
});