UNPKG

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