-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest.js
More file actions
214 lines (193 loc) · 6.05 KB
/
test.js
File metadata and controls
214 lines (193 loc) · 6.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*!
* Copyright 2012 - 2024 Digital Bazaar, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
import * as bedrock from '@bedrock/core';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import cycle from 'cycle';
import fs from 'node:fs';
import {logger} from './logger.js';
import Mocha from 'mocha';
import path from 'node:path';
const {config, util: {BedrockError}} = bedrock;
const {
EVENT_FILE_PRE_REQUIRE,
EVENT_FILE_POST_REQUIRE,
EVENT_FILE_REQUIRE
} = Mocha.Suite.constants;
bedrock.events.on('bedrock-cli.init', async () => {
// add test command
const command = bedrock.program
.command('test')
.description('run tests')
.option(
'--framework <frameworks>',
'A set of comma-delimited test frameworks to run. [all] ' +
'(' + config.test.frameworks.join(', ') + ')')
.action(function() {
config.cli.command = command;
});
// allow special test configs to load
await bedrock.events.emit('bedrock-cli.test.configure', command);
});
bedrock.events.on('bedrock-cli.ready', async () => {
const command = config.cli.command;
if(command.name() !== 'test') {
return;
}
// set reporter
const opts = command.opts();
if(opts.mochaReporter) {
config.mocha.options.reporter = opts.mochaReporter;
}
await bedrock.events.emit('bedrock.test.configure');
});
bedrock.events.on('bedrock.started', async () => {
if(config.cli.command.name() === 'test') {
const state = {pass: true};
await bedrock.runOnce('bedrock.test', async () => {
console.log('Running Test Frameworks...\n');
logger.info('running test frameworks...');
try {
await bedrock.events.emit('bedrock.tests.run', state);
if(!state.pass) {
console.log('Tests failed.');
logger.error('tests failed.');
process.exit(1);
} else {
console.log('All tests passed.');
logger.info('all tests passed.');
bedrock.exit();
}
} catch(err) {
console.log('Tests exited with error', err);
logger.error('tests exited with error', err);
process.exit(err.code || 0);
}
});
return false;
}
});
bedrock.events.on('bedrock-cli.test.configure', function(command) {
command
.option(
'--mocha-test <files>',
'A set of comma-delimited mocha test files to run.')
.option('--mocha-reporter <reporter>',
'Mocha test reporter [spec]', 'spec');
});
bedrock.events.on('bedrock.tests.run', async state => {
if(shouldRunFramework('mocha')) {
return runMocha(state);
}
});
/**
* Check if a test framework is runnable.
*
* @param {string} framework - The framework to check.
*
* @returns {boolean} True if the framework is runnable, false if not.
*/
export function shouldRunFramework(framework) {
const frameworks = config.cli.command.opts().framework;
// default to run, else check for name in frameworks list
return !frameworks || frameworks.split(/[ ,]+/).includes(framework);
}
/**
* Run Mocha-based tests.
*
* @param {object} state - The global test state.
*/
async function runMocha(state) {
// setup chai / chai-as-promised
chai.use(chaiAsPromised);
// set globals for tests to use
global.chai = chai;
global.should = chai.should();
global.assertNoError = err => {
if(err) {
const obj = err instanceof BedrockError ? err.toObject() : err;
let pretty = null;
try {
pretty = JSON.stringify(obj, null, 2);
} catch {
// we need to remove circular references from the json
// in order to pretty print with JSON.stringify
pretty = JSON.stringify(cycle.decycle(obj), null, 2);
}
console.error('An unexpected error occurred: ', pretty);
throw err;
}
};
const mocha = new Mocha(config.mocha.options);
// add test files
const opts = config.cli.command.opts();
if(opts.mochaTest) {
opts.mochaTest.split(',').forEach(function(path) {
_add(path);
});
} else {
config.mocha.tests.forEach(function(path) {
_add(path);
});
}
// console.log w/o eol
process.stdout.write('Running Mocha tests...');
// load all test files
await _loadFilesAsync();
return new Promise(resolve => {
state.mocha = {};
mocha.run(function(failures) {
if(failures) {
state.mocha.failures = failures;
state.pass = false;
}
resolve();
});
});
// add a file or directory
function _add(_path) {
if(fs.existsSync(_path)) {
const stats = fs.statSync(_path);
if(stats.isDirectory()) {
fs.readdirSync(_path).sort().forEach(function(file) {
if(path.extname(file) === '.js') {
file = path.join(_path, file);
logger.debug('adding test file', {file});
mocha.addFile(file);
}
});
} else if(path.extname(_path) === '.js') {
logger.debug('adding test file', {file: _path});
mocha.addFile(_path);
}
}
}
// loads all test files asynchronously; this function must execute here
// and not inside mocha's CJS file due to a segfault that will occur during
// dynamic imports: https://github.com/nodejs/node/issues/35889
async function _loadFilesAsync() {
const suite = mocha.suite;
mocha.lazyLoadFiles(true);
for(const file of mocha.files) {
suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, mocha);
const resultModule = await import(file);
suite.emit(EVENT_FILE_REQUIRE, resultModule, file, mocha);
suite.emit(EVENT_FILE_POST_REQUIRE, global, file, mocha);
}
}
}