97 lines
3 KiB
JavaScript
97 lines
3 KiB
JavaScript
|
'use strict'
|
||
|
|
||
|
const log = require('./logger').create()
|
||
|
|
||
|
class Executor {
|
||
|
constructor (capturedBrowsers, config, emitter) {
|
||
|
this.capturedBrowsers = capturedBrowsers
|
||
|
this.config = config
|
||
|
this.emitter = emitter
|
||
|
|
||
|
this.executionScheduled = false
|
||
|
this.errorsScheduled = []
|
||
|
this.pendingCount = 0
|
||
|
this.runningBrowsers = null
|
||
|
|
||
|
this.emitter.on('run_complete', () => this.onRunComplete())
|
||
|
this.emitter.on('browser_complete', () => this.onBrowserComplete())
|
||
|
}
|
||
|
|
||
|
schedule () {
|
||
|
if (this.capturedBrowsers.length === 0) {
|
||
|
log.warn(`No captured browser, open ${this.config.protocol}//${this.config.hostname}:${this.config.port}${this.config.urlRoot}`)
|
||
|
return false
|
||
|
} else if (this.capturedBrowsers.areAllReady()) {
|
||
|
log.debug('All browsers are ready, executing')
|
||
|
log.debug(`Captured ${this.capturedBrowsers.length} browsers`)
|
||
|
this.executionScheduled = false
|
||
|
this.capturedBrowsers.clearResults()
|
||
|
this.pendingCount = this.capturedBrowsers.length
|
||
|
this.runningBrowsers = this.capturedBrowsers.clone()
|
||
|
this.emitter.emit('run_start', this.runningBrowsers)
|
||
|
this.socketIoSockets.emit('execute', this.config.client)
|
||
|
return true
|
||
|
} else {
|
||
|
log.info('Delaying execution, these browsers are not ready: ' + this.capturedBrowsers.getNonReady().join(', '))
|
||
|
this.executionScheduled = true
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Schedule an error to be reported
|
||
|
* @param {string} errorMessage
|
||
|
* @returns {boolean} a boolean indicating whether or not the error was handled synchronously
|
||
|
*/
|
||
|
scheduleError (errorMessage) {
|
||
|
// We don't want to interfere with any running test.
|
||
|
// Verify that no test is running before reporting the error.
|
||
|
if (this.capturedBrowsers.areAllReady()) {
|
||
|
log.warn(errorMessage)
|
||
|
const errorResult = {
|
||
|
success: 0,
|
||
|
failed: 0,
|
||
|
skipped: 0,
|
||
|
error: errorMessage,
|
||
|
exitCode: 1
|
||
|
}
|
||
|
const noBrowsersStartedTests = []
|
||
|
this.emitter.emit('run_start', noBrowsersStartedTests) // A run cannot complete without being started
|
||
|
this.emitter.emit('run_complete', noBrowsersStartedTests, errorResult)
|
||
|
return true
|
||
|
} else {
|
||
|
this.errorsScheduled.push(errorMessage)
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onRunComplete () {
|
||
|
if (this.executionScheduled) {
|
||
|
this.schedule()
|
||
|
}
|
||
|
if (this.errorsScheduled.length) {
|
||
|
const errorsToReport = this.errorsScheduled
|
||
|
this.errorsScheduled = []
|
||
|
errorsToReport.forEach((error) => this.scheduleError(error))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onBrowserComplete () {
|
||
|
this.pendingCount--
|
||
|
|
||
|
if (!this.pendingCount) {
|
||
|
// Ensure run_complete is emitted in the next tick
|
||
|
// so it is never emitted before browser_complete
|
||
|
setTimeout(() => {
|
||
|
this.emitter.emit('run_complete', this.runningBrowsers, this.runningBrowsers.getResults())
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Executor.factory = function (capturedBrowsers, config, emitter) {
|
||
|
return new Executor(capturedBrowsers, config, emitter)
|
||
|
}
|
||
|
|
||
|
module.exports = Executor
|