UNPKG

4.04 kBJavaScriptView Raw
1'use strict';
2
3const createInstance = require('./lib/instance');
4const connectClient = require('./lib/client');
5const EventBus = require('./lib/event-bus');
6const chromeOut = require('./lib/chrome-out');
7const network = require('./lib/network');
8
9const deepAssign = require('deep-assign');
10const log = require('loglevel');
11const unmirror = require('chrome-unmirror');
12
13process.on('unhandledRejection', error => {
14 // this should always output to console.error, regardless of loglevel
15 console.error('Promise Rejection: ', error);
16});
17
18class MochaChrome {
19 constructor (options) {
20 options = deepAssign({
21 chromeFlags: [],
22 loadTimeout: 1000,
23 logLevel: 'error',
24 ignoreExceptions: false,
25 ignoreConsole: false,
26 ignoreResourceErrors: false,
27 mocha: {
28 reporter: 'spec',
29 ui: 'bdd',
30 useColors: true
31 }
32 }, options);
33
34 log.setDefaultLevel('error');
35 log.setLevel(options.logLevel);
36
37 const bus = new EventBus(log);
38
39 if (!options.url) {
40 this.fail('`options.url` must be specified to run tests');
41 }
42
43 bus.on('ready', content => {
44 this.client.Runtime.evaluate({ expression: `mocha.setup({ reporter: 'spec' })`});
45 });
46
47 bus.on('mocha', content => {
48 process.stdout.write(content);
49 });
50
51 bus.on('width', content => {
52 const columns = parseInt(process.env.COLUMNS || process.stdout.columns) * .75 | 0;
53 const expression = `Mocha.reporters.Base.window.width = ${columns};`;
54
55 this.client.Runtime.evaluate({ expression });
56 });
57
58 bus.on('config', content => {
59 const config = JSON.stringify(options.mocha);
60 const expression = `mocha.setup(${config})`;
61
62 this.client.Runtime.evaluate({ expression });
63 });
64
65 bus.on('started', (tests) => {
66 this.started = true;
67 log.info(`Test Run Started - Running ${tests} Tests\n`);
68
69 if (tests === 0) {
70 this.fail('mocha.run() was called with no tests');
71 }
72
73 });
74
75 bus.on('ended', stats => {
76 this.ended = true;
77 this.exit(stats.failures);
78 });
79
80 bus.on('resourceFailed', data => {
81 this.loadError = true;
82 });
83
84 this.bus = bus;
85 this.options = options;
86 this.loadError = false;
87 }
88
89 async connect () {
90
91 const instance = await createInstance(log, this.options);
92 const client = await connectClient(instance, log, this.options);
93 const { DOMStorage, Network, Runtime } = client;
94
95 if (!client) {
96 fail('CDP Client could not connect');
97 return;
98 }
99
100 this.bus.watch(DOMStorage);
101
102 chromeOut(log, this.options, Runtime);
103 network(this.bus, log, Network, this.options.ignoreResourceErrors);
104
105 this.client = client;
106 this.instance = instance;
107 }
108
109 async run () {
110 this.client.Page.loadEventFired(() => {
111 if (this.closed) {
112 return;
113 }
114
115 if (this.loadError) {
116 this.fail('Failed to load the page. Check the url: ' + this.options.url);
117 return;
118 }
119
120 setTimeout(async () => {
121 if (this.closed) {
122 return;
123 }
124
125 const expression = '(function () { return !!window.mocha; })()';
126 let res = await this.client.Runtime.evaluate({ expression });
127
128 if (!unmirror(res.result)) {
129 this.fail(`mocha was not found in the page within ${this.options.loadTimeout}ms of the page loading.`);
130 }
131
132 if (!this.started) {
133 this.fail(`mocha.run() was not called within ${this.options.loadTimeout}ms of the page loading.`);
134 }
135 }, this.options.loadTimeout);
136
137 });
138
139 await this.client.Page.navigate({ url: this.options.url });
140 }
141
142 on (name, fn) {
143 this.bus.on(name, fn);
144 }
145
146 fail (message) {
147 log.error('Mocha-Chrome Failed:', message || '');
148
149 if (this.bus) {
150 this.bus.emit('failure', message);
151 }
152
153 this.exit(1);
154 }
155
156 async exit (code) {
157 this.closed = true;
158 await this.client.close();
159 await this.instance.kill();
160
161 this.bus.emit('exit', 1);
162 }
163
164}
165
166
167module.exports = MochaChrome;