UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

260 lines (230 loc) 7.28 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ /*global QUnit */ (function() { "use strict"; var PAUSE_RULES = { NONE: "none", TIMEOUT: "timeout", ASSERT: "assert", POLL: "poll" }; var mTestTimeouts = {}; var _mListeners = { pause: [], resume: [] }; var _mTestTimeout = {}; var paused = false; var _pauseRule = PAUSE_RULES.NONE; var _bQUnitDone = false; function shouldPause () { return _pauseRule !== PAUSE_RULES.NONE && _pauseRule !== PAUSE_RULES.POLL; } function shouldPauseOnAssert () { return _pauseRule.indexOf(PAUSE_RULES.ASSERT) > -1; } function shouldPoll () { return _pauseRule.indexOf(PAUSE_RULES.POLL) > -1; } function isQUnit2 () { return QUnit.test.length === 2; } // hook into QUnit timeout. // should be called before QUnit is loaded function setupBeforeQUnit () { var fnOriginal = window.setTimeout; window.setTimeout = function wrappedSetTimeout (fnCallback, iDelay) { var iId = fnOriginal.apply(null, arguments); mTestTimeouts[iId] = { delay: iDelay || 0, callback: fnCallback, startTime: Date.now() }; return iId; }; } // hook into QUnit assertions. // should be called after QUnit is loaded e.g. in opaQunit function setupAfterQUnit () { var sPushMethod = isQUnit2() ? "pushResult" : "push"; var origPush = QUnit.assert[sPushMethod]; QUnit.assert[sPushMethod] = function () { var that = this; var aAssertArgs = arguments; var bPassed = isQUnit2() ? arguments[0].result : arguments[0]; var Opa = sap.ui.require("sap/ui/test/Opa"); var bIsOpaTest = that.test && Opa && Opa.config.testName === that.test.testName; // if this is an OPA test and the rule says to pause - add a new promise to the OPA queue. // assuming that the assert is inside a success function, // the promise will be executed after the success and before other promises in the test if (bIsOpaTest && !bPassed && shouldPauseOnAssert()) { // - assertions are supposed to be added in a success; waitfors added in success are pushed to top of the queue -> this should be the very next waitfor after a fail // - on timeout an assertion result is pushed -> test is paused // - there is only one queue - it's ok to create a new Opa var oOpa = new Opa(); var bPromisePending = true; emitPause(); var oPausePromise = new Promise(function (resolve) { onResume(function () { if (bPromisePending) { bPromisePending = false; resolve(); } }); // the error message should be visible between pause and resume // => first add the assertion, then pause origPush.apply(that, aAssertArgs); }); oOpa.iWaitForPromise(oPausePromise); } else { origPush.apply(that, aAssertArgs); } }; } // QUnit (or OPA) should never timeout while the test is 'paused' // i.e. OPA should wait until 'resume' is called, and not timeout, even if OpaTimeout is reached. // => override the QUnit timeout function. // should be called at the beginning of test execution - right before Opa.emptyQueue() function setupBeforeOpaTest () { if (shouldPause()) { _mTestTimeout = mTestTimeouts[QUnit.config.timeout]; if (!_mTestTimeout) { throw new Error("QUnitPause should be loaded before QUnit!"); } _mTestTimeout.originalCallback = _mTestTimeout.callback; _mTestTimeout.callback = function () { emitPause(); onResume(function () { // reduce the timeout with the time that has already elapsed var iNewTestTimeout = Math.max(0, _mTestTimeout.delay - (Date.now() - _mTestTimeout.startTime)); // set a new timeout after 'resume' QUnit.config.timeout = setTimeout(_mTestTimeout.originalCallback, iNewTestTimeout); }); }; // clear the 'original' QUnit timeout and override it clearTimeout(QUnit.config.timeout); QUnit.config.timeout = setTimeout(_mTestTimeout.callback, QUnit.config.testTimeout); // clean up mTestTimeouts = {}; } } function onPause () { return _addListener("pause").apply(this, arguments); } function onResume () { return _addListener("resume").apply(this, arguments); } function emitPause () { // pause only once and only if the rules require it if (shouldPause() && !paused) { paused = true; _callListeners("pause"); // stop QUnit from timing out while the test is 'paused' clearTimeout(QUnit.config.timeout); } else if (!shouldPauseOnAssert()) { // if pausing on assert and already paused: assert failures may happen multiple times per waitFor -> just wait for the previous pause-on-assert to finish. // else (i.e. pause on timeout): call any attached listeners setTimeout(function () { emitResume(); }, 0); } } function emitResume () { _callListeners("resume", true); paused = false; } // checks if QUnit is done. Will call fnCallback with the result of the check. // iPollInterval (ms) - the time to wait before checking if QUnit is done function pollForQUnitDone (iPollInterval, fnCallback) { QUnit.begin(function () { _bQUnitDone = false; }); var bCalled = false; if (!QUnit) { throw new Error("QUnitPause should start polling after QUnit is loaded!"); } else if (_bQUnitDone) { fnCallback({ qunitDone: true }); } else if (shouldPoll()) { QUnit.done(function () { _bQUnitDone = true; if (!bCalled) { fnCallback({ qunitDone: true }); } }); setTimeout(function () { if (!_bQUnitDone && !bCalled) { bCalled = true; fnCallback({ qunitDone: false }); } }, iPollInterval); } } function _isKnownRule (sRule) { var bIsKnown = false; for (var sKey in PAUSE_RULES) { if (PAUSE_RULES[sKey] === sRule) { bIsKnown = true; } } return bIsKnown; } function _addListener (sEvent) { return function (fnCallback, vThis, aArgs) { _mListeners[sEvent].push({ cb: fnCallback, context: vThis, args: aArgs, called: false // call each listener only once }); }; } function _callListeners (sEvent, bCallOnce) { _mListeners[sEvent].forEach(function (mListener) { if (!bCallOnce || !mListener.called) { mListener.cb.apply(mListener.context, mListener.args); mListener.called = true; } }); } const qunitPause = { PAUSE_RULES: PAUSE_RULES, paused: paused, get pauseRule() { return _pauseRule; }, set pauseRule(sRules) { // should accept multiple rules e.g. "timeout,assert" var aRules = sRules.split(","); _pauseRule = ""; var sNewRule = aRules.filter(_isKnownRule).join(","); _pauseRule = sNewRule ? sNewRule : PAUSE_RULES.NONE; }, shouldPause: shouldPause, shouldPauseOnAssert: shouldPauseOnAssert, shouldPoll: shouldPoll, setupAfterQUnit: setupAfterQUnit, setupBeforeQUnit: setupBeforeQUnit, setupBeforeOpaTest: setupBeforeOpaTest, onPause: onPause, onResume: onResume, emitPause: emitPause, emitResume: emitResume, pollForQUnitDone: pollForQUnitDone }; setupBeforeQUnit(); sap.ui.loader._.defineModuleSync("sap/ui/test/qunitPause.js", qunitPause); /** @deprecated */ sap.ui.test ??= {}; /** @deprecated */ sap.ui.test.qunitPause = qunitPause; }());