| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- #!/usr/bin/env node
- /*---------------------------------------------------------
- * Copyright (C) Microsoft Corporation. All rights reserved.
- *--------------------------------------------------------*/
- import * as chokidar from 'chokidar';
- import { resolve } from 'path';
- import { cliArgs, configFileDefault } from './cli/args.mjs';
- import { loadDefaultConfigFile, tryLoadConfigFile, } from './cli/config.mjs';
- import { Coverage } from './cli/coverage.mjs';
- import { platforms } from './cli/platform/index.mjs';
- export const args = cliArgs.parseSync();
- class CliExpectedError extends Error {
- }
- main();
- async function main() {
- let code = 0;
- try {
- const config = args.config !== configFileDefault
- ? await tryLoadConfigFile(resolve(process.cwd(), args.config))
- : await loadDefaultConfigFile();
- const enabledTests = new Set(args.label?.length
- ? args.label.map((label) => {
- const found = config.tests.find((c, i) => typeof label === 'string' ? c.label === label : i === label);
- if (!found) {
- throw new CliExpectedError(`Could not find a configuration with label "${label}"`);
- }
- return found;
- })
- : new Set(config.tests));
- if (args.watch) {
- await watchConfigs(config, enabledTests);
- }
- else {
- code = await runConfigs(config, enabledTests);
- }
- }
- catch (e) {
- code = 1;
- if (e instanceof CliExpectedError) {
- console.error(e.message);
- }
- else {
- console.error(e.stack || e);
- }
- }
- finally {
- process.exit(code);
- }
- }
- async function prepareConfigs(config, enabledTests) {
- return await Promise.all([...enabledTests].map(async (test, i) => {
- for (const platform of platforms) {
- const p = await platform.prepare({ args, config, test });
- if (p) {
- return p;
- }
- }
- throw new CliExpectedError(`Could not find a runner for test configuration ${test.label || i}`);
- }));
- }
- const WATCH_RUN_DEBOUNCE = 500;
- async function watchConfigs(config, enabledTests) {
- let debounceRun;
- let rerun = false;
- let running = true;
- let prepared;
- const runOrDebounce = () => {
- if (debounceRun) {
- clearTimeout(debounceRun);
- }
- debounceRun = setTimeout(async () => {
- running = true;
- rerun = false;
- try {
- prepared ??= await prepareConfigs(config, enabledTests);
- await runPreparedConfigs(config, prepared);
- }
- finally {
- running = false;
- if (rerun) {
- runOrDebounce();
- }
- }
- }, WATCH_RUN_DEBOUNCE);
- };
- const watcher = chokidar.watch(args.watchFiles?.length ? args.watchFiles.map(String) : process.cwd(), {
- ignored: [
- '**/.vscode-test/**',
- '**/node_modules/**',
- ...(args.watchIgnore || []).map(String),
- ],
- ignoreInitial: true,
- });
- watcher.on('all', (evts) => {
- if (evts !== 'change') {
- prepared = undefined; // invalidate since files will need to be re-scanned
- }
- if (running) {
- rerun = true;
- }
- else {
- runOrDebounce();
- }
- });
- watcher.on('ready', () => {
- runOrDebounce();
- });
- // wait until interrupted
- await new Promise(() => {
- /* no-op */
- });
- }
- async function runPreparedConfigs(config, prepared) {
- const coverage = args.coverage ? new Coverage(config, args) : undefined;
- const context = { coverage: coverage?.targetDir };
- let code = 0;
- for (const p of prepared) {
- code = Math.max(code, await p.run(context));
- if (args.bail && code !== 0) {
- return code;
- }
- }
- await coverage?.write();
- return code;
- }
- /** Runs the given test configurations. */
- async function runConfigs(config, enabledTests) {
- const prepared = await prepareConfigs(config, enabledTests);
- if (args.listConfiguration) {
- await new Promise((r) => process.stdout.write(JSON.stringify(prepared.map((p) => p.dumpJson())), r));
- return 0;
- }
- return runPreparedConfigs(config, prepared);
- }
|