UNPKG

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