1 | 'use strict'
|
---|
2 |
|
---|
3 | const log = require('./logger').create()
|
---|
4 |
|
---|
5 | class Executor {
|
---|
6 | constructor (capturedBrowsers, config, emitter) {
|
---|
7 | this.capturedBrowsers = capturedBrowsers
|
---|
8 | this.config = config
|
---|
9 | this.emitter = emitter
|
---|
10 |
|
---|
11 | this.executionScheduled = false
|
---|
12 | this.errorsScheduled = []
|
---|
13 | this.pendingCount = 0
|
---|
14 | this.runningBrowsers = null
|
---|
15 |
|
---|
16 | this.emitter.on('run_complete', () => this.onRunComplete())
|
---|
17 | this.emitter.on('browser_complete', () => this.onBrowserComplete())
|
---|
18 | }
|
---|
19 |
|
---|
20 | schedule () {
|
---|
21 | if (this.capturedBrowsers.length === 0) {
|
---|
22 | log.warn(`No captured browser, open ${this.config.protocol}//${this.config.hostname}:${this.config.port}${this.config.urlRoot}`)
|
---|
23 | return false
|
---|
24 | } else if (this.capturedBrowsers.areAllReady()) {
|
---|
25 | log.debug('All browsers are ready, executing')
|
---|
26 | log.debug(`Captured ${this.capturedBrowsers.length} browsers`)
|
---|
27 | this.executionScheduled = false
|
---|
28 | this.capturedBrowsers.clearResults()
|
---|
29 | this.pendingCount = this.capturedBrowsers.length
|
---|
30 | this.runningBrowsers = this.capturedBrowsers.clone()
|
---|
31 | this.emitter.emit('run_start', this.runningBrowsers)
|
---|
32 | this.socketIoSockets.emit('execute', this.config.client)
|
---|
33 | return true
|
---|
34 | } else {
|
---|
35 | log.info('Delaying execution, these browsers are not ready: ' + this.capturedBrowsers.getNonReady().join(', '))
|
---|
36 | this.executionScheduled = true
|
---|
37 | return false
|
---|
38 | }
|
---|
39 | }
|
---|
40 |
|
---|
41 | /**
|
---|
42 | * Schedule an error to be reported
|
---|
43 | * @param {string} errorMessage
|
---|
44 | * @returns {boolean} a boolean indicating whether or not the error was handled synchronously
|
---|
45 | */
|
---|
46 | scheduleError (errorMessage) {
|
---|
47 | // We don't want to interfere with any running test.
|
---|
48 | // Verify that no test is running before reporting the error.
|
---|
49 | if (this.capturedBrowsers.areAllReady()) {
|
---|
50 | log.warn(errorMessage)
|
---|
51 | const errorResult = {
|
---|
52 | success: 0,
|
---|
53 | failed: 0,
|
---|
54 | skipped: 0,
|
---|
55 | error: errorMessage,
|
---|
56 | exitCode: 1
|
---|
57 | }
|
---|
58 | const noBrowsersStartedTests = []
|
---|
59 | this.emitter.emit('run_start', noBrowsersStartedTests) // A run cannot complete without being started
|
---|
60 | this.emitter.emit('run_complete', noBrowsersStartedTests, errorResult)
|
---|
61 | return true
|
---|
62 | } else {
|
---|
63 | this.errorsScheduled.push(errorMessage)
|
---|
64 | return false
|
---|
65 | }
|
---|
66 | }
|
---|
67 |
|
---|
68 | onRunComplete () {
|
---|
69 | if (this.executionScheduled) {
|
---|
70 | this.schedule()
|
---|
71 | }
|
---|
72 | if (this.errorsScheduled.length) {
|
---|
73 | const errorsToReport = this.errorsScheduled
|
---|
74 | this.errorsScheduled = []
|
---|
75 | errorsToReport.forEach((error) => this.scheduleError(error))
|
---|
76 | }
|
---|
77 | }
|
---|
78 |
|
---|
79 | onBrowserComplete () {
|
---|
80 | this.pendingCount--
|
---|
81 |
|
---|
82 | if (!this.pendingCount) {
|
---|
83 | // Ensure run_complete is emitted in the next tick
|
---|
84 | // so it is never emitted before browser_complete
|
---|
85 | setTimeout(() => {
|
---|
86 | this.emitter.emit('run_complete', this.runningBrowsers, this.runningBrowsers.getResults())
|
---|
87 | })
|
---|
88 | }
|
---|
89 | }
|
---|
90 | }
|
---|
91 |
|
---|
92 | Executor.factory = function (capturedBrowsers, config, emitter) {
|
---|
93 | return new Executor(capturedBrowsers, config, emitter)
|
---|
94 | }
|
---|
95 |
|
---|
96 | module.exports = Executor
|
---|