UNPKG

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