UNPKG

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