folio
Version:
A customizable test framework to build your own test frameworks. Foundation for the [Playwright test runner](https://github.com/microsoft/playwright-test).
247 lines • 11.4 kB
JavaScript
/**
* Copyright (c) Microsoft Corporation.
*
* 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.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.reporters = void 0;
const fstream_ignore_1 = __importDefault(require("fstream-ignore"));
const commander = __importStar(require("commander"));
const fs = __importStar(require("fs"));
const minimatch_1 = __importDefault(require("minimatch"));
const path = __importStar(require("path"));
const reporter_1 = require("./reporter");
const dot_1 = __importDefault(require("./reporters/dot"));
const json_1 = __importDefault(require("./reporters/json"));
const junit_1 = __importDefault(require("./reporters/junit"));
const line_1 = __importDefault(require("./reporters/line"));
const list_1 = __importDefault(require("./reporters/list"));
const multiplexer_1 = require("./reporters/multiplexer");
const runner_1 = require("./runner");
const fixtures_1 = require("./fixtures");
const config_1 = require("./config");
exports.reporters = {
'dot': dot_1.default,
'json': json_1.default,
'junit': junit_1.default,
'line': line_1.default,
'list': list_1.default,
'null': reporter_1.EmptyReporter,
};
const availableReporters = Object.keys(exports.reporters).map(r => `"${r}"`).join();
const loadProgram = new commander.Command();
addRunnerOptions(loadProgram, true);
loadProgram.helpOption(false);
loadProgram.action(async (command) => {
try {
await runTests(command);
}
catch (e) {
console.log(e);
process.exit(1);
}
});
loadProgram.parse(process.argv);
async function runTests(command) {
fixtures_1.assignConfig(config_1.defaultConfig);
let shard;
if (command.shard) {
const pair = command.shard.split('/').map((t) => parseInt(t, 10));
shard = { current: pair[0] - 1, total: pair[1] };
}
const testDir = path.resolve(process.cwd(), command.args[0] || '.');
const reporterList = command.reporter.split(',');
const reporterObjects = reporterList.map(c => {
if (exports.reporters[c])
return new exports.reporters[c]();
try {
const p = path.resolve(process.cwd(), c);
return new (require(p).default)();
}
catch (e) {
console.error('Invalid reporter ' + c, e);
process.exit(1);
}
});
if (!fs.existsSync(testDir))
throw new Error(`${testDir} does not exist`);
let files;
if (fs.statSync(testDir).isDirectory())
files = filterFiles(testDir, await collectFiles(testDir), command.args.slice(1), command.testMatch, command.testIgnore);
else
files = [testDir];
const reporter = new multiplexer_1.Multiplexer(reporterObjects);
const runner = new runner_1.Runner(reporter);
const parameterRegistrations = runner.loadFiles(files).parameters;
const parameters = {};
for (const param of command.param || []) {
const match = param.match(/([^=]+)=(.*)/);
const [_, name, value] = match ? match : ['', param, 'true'];
if (!parameterRegistrations.has(name)) {
console.error(`unknown parameter '${name}'`);
process.exit(1);
}
const registration = parameterRegistrations.get(name);
let list = parameters[name];
if (!list) {
list = [];
parameters[name] = list;
}
if (typeof registration.defaultValue === 'string')
list.push(value);
else if (typeof registration.defaultValue === 'number')
list.push(parseFloat(value));
else if (typeof registration.defaultValue === 'boolean')
list.push(value === 'true');
}
if (command.help === undefined) {
printParametersHelp([...parameterRegistrations.values()]);
process.exit(0);
}
// Assign config values after runner.loadFiles to set defaults from the command
// line.
fixtures_1.config.testDir = testDir;
if (command.forbidOnly)
fixtures_1.config.forbidOnly = true;
if (command.globalTimeout)
fixtures_1.config.globalTimeout = parseInt(command.globalTimeout, 10);
if (command.grep)
fixtures_1.config.grep = command.grep;
if (command.maxFailures || command.x)
fixtures_1.config.maxFailures = command.x ? 1 : parseInt(command.maxFailures, 10);
if (command.outputDir)
fixtures_1.config.outputDir = command.output;
if (command.quiet)
fixtures_1.config.quiet = command.quiet;
if (command.repeatEach)
fixtures_1.config.repeatEach = parseInt(command.repeatEach, 10);
if (command.retries)
fixtures_1.config.retries = parseInt(command.retries, 10);
if (shard)
fixtures_1.config.shard = shard;
if (command.snapshotDir)
fixtures_1.config.snapshotDir = command.snapshotDir;
if (command.timeout)
fixtures_1.config.timeout = parseInt(command.timeout, 10);
if (command.updateSnapshots)
fixtures_1.config.updateSnapshots = !!command.updateSnapshots;
if (command.workers)
fixtures_1.config.workers = parseInt(command.workers, 10);
runner.generateTests({ parameters });
if (command.list) {
runner.list();
return;
}
const result = await runner.run();
if (result === 'sigint')
process.exit(130);
if (result === 'forbid-only') {
console.error('=====================================');
console.error(' --forbid-only found a focused test.');
console.error('=====================================');
process.exit(1);
}
if (result === 'no-tests') {
console.error('=================');
console.error(' no tests found.');
console.error('=================');
process.exit(1);
}
process.exit(result === 'failed' ? 1 : 0);
}
async function collectFiles(testDir) {
const list = [];
let callback;
const result = new Promise(f => callback = f);
fstream_ignore_1.default({ path: testDir, ignoreFiles: ['.gitignore'] })
.on('child', (c) => list.push(c.path))
.on('end', () => callback(list));
return result;
}
function filterFiles(base, files, filters, testMatch, testIgnore) {
if (!testIgnore.includes('/') && !testIgnore.includes('\\'))
testIgnore = '**/' + testIgnore;
if (!testMatch.includes('/') && !testMatch.includes('\\'))
testMatch = '**/' + testMatch;
return files.filter(file => {
file = path.relative(base, file);
if (testIgnore && minimatch_1.default(file, testIgnore))
return false;
if (testMatch && !minimatch_1.default(file, testMatch))
return false;
if (filters.length && !filters.find(filter => file.includes(filter)))
return false;
return true;
});
}
function addRunnerOptions(program, param) {
program = program
.version('Version ' + /** @type {any} */ (require)('../package.json').version)
.option('--forbid-only', `Fail if exclusive test(s) encountered (default: ${config_1.defaultConfig.forbidOnly})`)
.option('-g, --grep <grep>', `Only run tests matching this string or regexp (default: "${config_1.defaultConfig.grep}")`)
.option('--global-timeout <timeout>', `Specify maximum time this test suite can run in milliseconds (default: 0 for unlimited)`)
.option('-h, --help', `Display help`)
.option('-j, --workers <workers>', `Number of concurrent workers, use 1 to run in single worker (default: number of CPU cores / 2)`)
.option('--list', `Only collect all the test and report them`)
.option('--max-failures <N>', `Stop after the first N failures (default: ${config_1.defaultConfig.maxFailures})`)
.option('--output <outputDir>', `Folder for output artifacts (default: "test-results")`);
if (param)
program = program.option('-p, --param <name=value...>', `Specify fixture parameter value`);
program = program
.option('--quiet', `Suppress stdio`)
.option('--repeat-each <repeat-each>', `Specify how many times to run the tests (default: ${config_1.defaultConfig.repeatEach})`)
.option('--reporter <reporter>', `Specify reporter to use, comma-separated, can be ${availableReporters}`, process.env.CI ? 'dot' : 'line')
.option('--retries <retries>', `Specify retry count (default: ${config_1.defaultConfig.retries})`)
.option('--shard <shard>', `Shard tests and execute only selected shard, specify in the form "current/all", 1-based, for example "3/5"`)
.option('--snapshot-dir <dir>', `Snapshot directory, relative to tests directory (default: "${config_1.defaultConfig.snapshotDir}"`)
.option('--test-ignore <pattern>', `Pattern used to ignore test files`, 'node_modules/**')
.option('--test-match <pattern>', `Pattern used to find test files`, '**/?(*.)+(spec|test).[jt]s')
.option('--timeout <timeout>', `Specify test timeout threshold in milliseconds (default: ${config_1.defaultConfig.timeout})`)
.option('-u, --update-snapshots', `Whether to update snapshots with actual results (default: ${config_1.defaultConfig.updateSnapshots})`)
.option('-x', `Stop after the first failure`);
}
function printParametersHelp(parameterRegistrations) {
const program = new commander.Command();
for (const registration of parameterRegistrations) {
if (typeof registration.defaultValue === 'boolean')
program.option(`-p, --param*${registration.name}`, registration.description, registration.defaultValue);
else
program.option(`-p, --param*${registration.name}=<value>`, registration.description, String(registration.defaultValue));
}
addRunnerOptions(program, false);
console.log(program.helpInformation().replace(/--param\*/g, '--param '));
}
//# sourceMappingURL=cli.js.map
;