UNPKG

siesta-lite

Version:

Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers

302 lines (219 loc) 10.6 kB
/* Siesta 5.6.1 Copyright(c) 2009-2022 Bryntum AB https://bryntum.com/contact https://bryntum.com/products/siesta/license */ Class('Siesta.Launcher.Page.BasePage', { does : [ JooseX.Observable, Siesta.Util.Role.CanParseBrowser, Siesta.Util.Role.HasUniqueGeneratedId, Siesta.Launcher.Role.CanPrintWithLauncher, Siesta.Launcher.Script.CanExecute ], has : { runner : { required : true }, launcher : { required : true }, dispatcher : { required : true }, pollInterval : 1000, pollTimeout : null, width : 1280, height : 1024, getStateExceptionCounter : 0, activityTimeout : null, // the timestamp of the last change of the "lastActivityToken" property lastActivity : null, // the timestamp of the last activity inside of test, the timestamp does not neccessary match the clock // inside Rhino, so we track its updates lastActivityToken : null, isClosed : false, sessionId : { is : 'rw', init : null }, chunkTask : null }, methods : { getOptions : function () { return this.dispatcher.options }, open : function (url, callback) { throw new Error("Abstract method call: `open`") }, close : function () { this.debug("Page close started: " + this.id) clearTimeout(this.pollTimeout) this.isClosed = true this.fireEvent('close') if (this.wsServer) return this.wsServer.stop() else return Promise.resolve() }, // this method should wait until the `Harness.start` method is called // (which assigns the Siesta.my.activeHarness value) // this can happen with delay if project starts with the `startFromUrl` getConfigInfo : function (inc, exc, filter, callback, i) { i = i || 0 var me = this if (i > 10) callback('Timeout while waiting for `project.start()` method') else this.executeHarnessMethod('getConfigInfo', [ inc, exc, filter, this.dispatcher.projectConfig ]).then(function (result) { if (result == 'not_started') // repeat after 1.5s setTimeout(function () { me.getConfigInfo(inc, exc, filter, callback, i++) }, 1500) else callback(null, result) }, function (e) { callback(e) }) }, executeHarnessMethod : function (methodName, args) { var func = function (args) { var me = Siesta.my.activeHarness return me ? me[ METHOD_NAME ].apply(me, args) : 'not_started' } args = JSON.stringify(args || []) var start = new Date() var options = this.dispatcher.options var me = this this.debug('PageId: ' + this.id + ', method : ' + methodName + ' starting, args size: ' + args.length) return this.executeScript( 'return (' + func.toString().replace(/METHOD_NAME/, "'" + methodName + "'") + ')(' + args + ')' ).then(function (result) { var message = 'PageId: ' + me.id + ', method : ' + methodName + ', took ' + (new Date() - start) / 1000 + 's' if (Number(options.debug) > 1) message += ', result : ' + JSON.stringify(result) else if (options.debug) message += ', result size : ' + JSON.stringify(result).length me.debug(message) return result }) }, pageShouldNotBeUsedAfterException : function (e) { return false }, doPoll : function (callback) { var me = this this.executeHarnessMethod('getAutomationState', []).then(function (state) { if (me.shouldStopScriptExecution()) return me.getStateExceptionCounter = 0 // `state.activityTimeout` will be `null` until the start of the 1st test // allow 3 min for that me.activityTimeout = state.activityTimeout || 180000 var newActivityToken = state.lastActivity // state has not changed if (me.lastActivityToken && newActivityToken == me.lastActivityToken) { if (new Date() - me.lastActivity > me.activityTimeout) { me.dispatcher.onPageInactivityTimeout(state.activeTestAutomationId, me.activityTimeout) callback('inactivity_timeout', state.notLaunched) return } } else { // state has changed (or no previous state) me.lastActivityToken = newActivityToken me.lastActivity = new Date() } me.dispatcher.consumeTestStateUpdate(state, me).then(function (res) { if (res == 'all_done' || res == 'force_exit') { callback(null) } else if (res == 'focus_lost') { callback(null, state.notLaunched) } else { me.pollTimeout = setTimeout(function () { me.doPoll(callback) }, me.pollInterval) } }) }, function (e) { if (me.shouldStopScriptExecution()) return me.getStateExceptionCounter++ me.debug("Exception #" + me.getStateExceptionCounter + " during `doPoll`, pageId=" + me.id + ": " + e) // allow up to 2 exceptions from the `getAutomationState` method before really fail // (weirdly happens sometimes, guess in which browser) if (me.getStateExceptionCounter >= 2 || me.pageShouldNotBeUsedAfterException(e)) callback(e) else me.pollTimeout = setTimeout(function () { me.doPoll(callback) }, me.pollInterval) }) }, runChunk : function (chunkTask, callback) { var me = this this.chunkTask = chunkTask var dispatcher = this.dispatcher var options = this.getOptions() var coverage = options.coverage var params = { pause : options.pause, streamAssertions : dispatcher.streamAssertions, showCursor : Boolean(options[ 'show-cursor' ]), restartOnBlur : Boolean(options[ 'restart-on-blur' ]), projectConfig : Joose.O.copy(dispatcher.projectConfig) } var wsServer = this.wsServer || dispatcher.wsServer if (wsServer) { params.projectConfig.simulatorPort = wsServer.port } // SauceLabs testing // if (wsServer) { // // params.projectConfig.simulatorPort = wsServer.port // params.projectConfig.simulatorConnectionTimeout = 1500000 // } if (coverage) { Joose.O.extend(params, { enableCodeCoverage : true, manuallyProcessCoverageResults : this.launcher.manuallyProcessCoverageResults }) } var onChunkProcessed = function (e, notLaunchedById) { me.runner.onPageCompleted(me, e, notLaunchedById).then(function () { callback(e, notLaunchedById) }) } this.executeHarnessMethod('launchAutomatedTests', [ chunkTask, params ]).then(function (result) { me.debug("Page polling has started") me.pollTimeout = setTimeout(function () { me.doPoll(onChunkProcessed) }, me.pollInterval) }, function (e) { me.debug("Page polling failed to start") onChunkProcessed(e) }) }, openHarness : function (projectUrl, callback) { var me = this this.open(projectUrl, function (e) { if (e) { callback(e); return } var errorCodes = { 'no-siesta' : "Can't find Siesta on the project page - page loading failed?", 'no-automation' : "The project page you are targeting contains Siesta Lite distribution. To use automation facilities, \nmake sure project page uses `siesta-all.js` from Standard or Trial packages" } var sanityChecker = function () { if (typeof Siesta == 'undefined') return 'no-siesta' try { if (typeof Siesta.Project.Browser.Automation == 'undefined') return 'no-automation' } catch (e) { return 'no-automation' } return 'success' } me.executeSmallScriptPromised( 'return (' + sanityChecker.toString() + ')()', true ).then(function (result) { // IE can just throw exception when trying execute script on 404 page, result will be null/undefined in this case if (result != 'success') { var error = errorCodes[ result ] if (error) me.printError(error) callback(5) return } callback() }) }) }, // promised method executeSmallScriptPromised : function (text, ignoreException) { throw new Error("Abstract method call: `executeSmallScriptPromised`") } } // eof methods })