UNPKG

@oat-sa/tao-test-runner-qti

Version:
299 lines (274 loc) 13.5 kB
define(['jquery', 'lodash', 'i18n', 'core/polling', 'ui/waitingDialog/waitingDialog', 'taoTests/runner/plugin', 'handlebars', 'lib/handlebars/helpers', 'util/namespace'], function ($$1, _, __, pollingFactory, waitingDialog, pluginFactory, Handlebars, Helpers0, namespaceHelper) { 'use strict'; $$1 = $$1 && Object.prototype.hasOwnProperty.call($$1, 'default') ? $$1['default'] : $$1; _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _; __ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __; pollingFactory = pollingFactory && Object.prototype.hasOwnProperty.call(pollingFactory, 'default') ? pollingFactory['default'] : pollingFactory; waitingDialog = waitingDialog && Object.prototype.hasOwnProperty.call(waitingDialog, 'default') ? waitingDialog['default'] : waitingDialog; pluginFactory = pluginFactory && Object.prototype.hasOwnProperty.call(pluginFactory, 'default') ? pluginFactory['default'] : pluginFactory; Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars; Helpers0 = Helpers0 && Object.prototype.hasOwnProperty.call(Helpers0, 'default') ? Helpers0['default'] : Helpers0; namespaceHelper = namespaceHelper && Object.prototype.hasOwnProperty.call(namespaceHelper, 'default') ? namespaceHelper['default'] : namespaceHelper; if (!Helpers0.__initialized) { Helpers0(Handlebars); Helpers0.__initialized = true; } var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) { this.compilerInfo = [4,'>= 1.0.0']; helpers = this.merge(helpers, Handlebars.helpers); data = data || {}; var buffer = "", stack1, helper, options, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, functionType="function", self=this; function program1(depth0,data) { return " with-message"; } function program3(depth0,data) { var buffer = "", helper, options; buffer += "<span class=\"message-connect\">" + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Online", options) : helperMissing.call(depth0, "__", "Online", options))) + "</span>"; return buffer; } function program5(depth0,data) { var buffer = "", helper, options; buffer += "<span class=\"message-disconnected\">" + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Offline", options) : helperMissing.call(depth0, "__", "Offline", options))) + "</span>"; return buffer; } buffer += "<div class=\"connectivity-box "; if (helper = helpers.state) { stack1 = helper.call(depth0, {hash:{},data:data}); } else { helper = (depth0 && depth0.state); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; } buffer += escapeExpression(stack1); stack1 = helpers['if'].call(depth0, (depth0 && depth0.message), {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data}); if(stack1 || stack1 === 0) { buffer += stack1; } buffer += "\">\n "; stack1 = helpers['if'].call(depth0, (depth0 && depth0.message), {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data}); if(stack1 || stack1 === 0) { buffer += stack1; } buffer += "<span data-control=\"connectivity-connected\" class=\"qti-controls icon-connect\" title=\"" + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Connected to server", options) : helperMissing.call(depth0, "__", "Connected to server", options))) + "\"></span>\n "; stack1 = helpers['if'].call(depth0, (depth0 && depth0.message), {hash:{},inverse:self.noop,fn:self.program(5, program5, data),data:data}); if(stack1 || stack1 === 0) { buffer += stack1; } buffer += "<span data-control=\"connectivity-disconnected\" class=\"qti-controls icon-disconnect\" title=\"" + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Disconnected from server", options) : helperMissing.call(depth0, "__", "Disconnected from server", options))) + "\"></span>\n</div>\n"; return buffer; }); function connectivityTpl(data, options, asString) { var html = Template(data, options); return (asString || true) ? html : $(html); } /** * 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-2021 (original work) Open Assessment Technologies SA ; */ /** * The plugin default configuration * @type {Object} * @property {Number} checkInterval - when offline, interval to check if we're back online * @property {Boolean} indicator - do we display the indicator in the test UI * @property {Boolean} message - do we display the message in the test UI */ var defaultConfig = { checkInterval: 30 * 1000, indicator: true, message: false }; /** * Creates the connectivity plugin. * Detects connectivity issues */ var connectivity = pluginFactory({ name: 'connectivity', /** * Initializes the plugin (called during runner's init) */ init: function init() { var self = this; var testRunner = this.getTestRunner(); var proxy = testRunner.getProxy(); var config = Object.assign({}, defaultConfig, this.getConfig()); //Displays a connectivity indicator if (config && config.indicator) { //create the indicator this.$element = $$1(connectivityTpl({ state: proxy.isOnline() ? 'connected' : 'disconnected', message: config.message })); testRunner.on('disconnect', function () { self.$element.removeClass('connected').addClass('disconnected'); }).on('reconnect', function () { self.$element.removeClass('disconnected').addClass('connected'); }); } //update the interval, with the new value if (this.polling && _.isNumber(config.checkInterval)) { this.polling.setInterval(config.checkInterval); } }, /** * Installs the plugin (called when the runner bind the plugin) * We do it before init to catch even offline during the init sequence */ install: function install() { var self = this; var waiting = false; var testRunner = this.getTestRunner(); var proxy = testRunner.getProxy(); /** * Display the waiting dialog, while waiting the connection to be back * @param {String} [messsage] - additional message for the dialog * @returns {Promise} resolves once the wait is over and the user click on 'proceed' */ this.displayWaitingDialog = function displayWaitingDialog() { let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var dialog; return new Promise(function (resolve) { if (!waiting) { waiting = true; //if a pause event occurs while waiting, //we also wait the connection to be back testRunner.before('pause.waiting', function () { return new Promise(function (pauseResolve) { proxy.off('reconnect.pausing').after('reconnect.pausing', pauseResolve); }); }); //creates the waiting modal dialog dialog = waitingDialog({ message: __('You are encountering a prolonged connectivity loss. ') + message, waitContent: __('Please wait while we try to restore the connection.'), proceedContent: __('The connection seems to be back, please proceed') }).on('proceed', function () { resolve(); }).on('render', function () { proxy.off('reconnect.waiting').after('reconnect.waiting', function () { testRunner.off('pause.waiting'); waiting = false; dialog.endWait(); }); }); } }); }; //Last chance to check the connection, //by regular polling on the "up" signal this.polling = pollingFactory({ action: function action() { testRunner.getProxy().telemetry(testRunner.getTestContext().itemIdentifier, 'up').catch(_.noop); }, interval: defaultConfig.checkInterval, autoStart: false }); //the Proxy is the only one to know something about connectivity proxy.on('disconnect', function disconnect(source) { if (!testRunner.getState('disconnected')) { testRunner.setState('disconnected', true); testRunner.trigger('disconnect', source); self.polling.start(); } }).on('reconnect', function reconnect() { if (testRunner.getState('disconnected')) { testRunner.setState('disconnected', false); testRunner.trigger('reconnect'); self.polling.stop(); } }); //intercept tries to leave while offline //this could be caused by pauses for example. //If caused by an action like exitTest it will be handled //by navigation errors (see below) testRunner.before('leave', function (e, data) { if (proxy.isOffline()) { self.displayWaitingDialog(data.message).then(function () { testRunner.trigger('leave', data); }).catch(function (generalErr) { testRunner.trigger('error', generalErr); }); return false; } }); //intercept offline navigation errors testRunner.before('error.connectivity', function (e, err) { // detect and prevent connectivity errors if (proxy.isConnectivityError(err)) { return false; } if (proxy.isOffline()) { self.displayWaitingDialog().then(function () { if (err.type === 'nav') { testRunner.loadItem(testRunner.getTestContext().itemIdentifier); } if (err.type === 'finish') { testRunner.finish(); } if (err.type === 'pause') { testRunner.trigger('pause', { reasons: err.data && err.data.reasons, message: err.data && err.data.comment }); } }).catch(function (generalErr) { testRunner.trigger('error', generalErr); }); return false; } }); testRunner.before('loaditem.connectivity', function (e, itemRef, item) { const testContext = testRunner.getTestContext(); const { flags } = item; if (!flags) { return true; } if (flags.hasFeedbacks) { testContext.hasFeedbacks = true; } if ((flags.containsNonPreloadedAssets || flags.hasPci) && proxy.isOffline()) { self.displayWaitingDialog().then(() => { testRunner.loadItem(itemRef); }); return false; } }); testRunner.before(namespaceHelper.namespaceAll('move skip timeout', 'connectivity'), function (e) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } var testContext = testRunner.getTestContext(); var currentItem = testRunner.getCurrentItem(); if (proxy.isOffline() && (currentItem.hasFeedbacks || testContext.hasFeedbacks)) { testRunner.trigger('disableitem'); self.displayWaitingDialog().then(function () { testRunner.trigger('enableitem').trigger(e.name, ...args); }); return false; } }); }, destroy() { this.getTestRunner().off('.connectivity'); }, /** * Called during the runner's render phase */ render: function render() { var $container = this.getAreaBroker().getControlArea(); if (this.$element) { $container.append(this.$element); } } }); return connectivity; });