mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-03-15 14:05:47 -05:00
Simplistic watch mode for runtests (#51461)
* Simplistic watch mode for runtests * Use esbuild WatchMode object for testRunner updates * switch AbortController to CancelToken
This commit is contained in:
@@ -2,9 +2,11 @@ import del from "del";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import chalk from "chalk";
|
||||
import cmdLineOptions from "./options.mjs";
|
||||
import { exec } from "./utils.mjs";
|
||||
import { findUpFile, findUpRoot } from "./findUpDir.mjs";
|
||||
import { CancelError } from "@esfx/canceltoken";
|
||||
|
||||
const mochaJs = path.resolve(findUpRoot(), "node_modules", "mocha", "bin", "_mocha");
|
||||
export const localBaseline = "tests/baselines/local/";
|
||||
@@ -17,8 +19,11 @@ export const localTest262Baseline = "internal/baselines/test262/local";
|
||||
* @param {string} runJs
|
||||
* @param {string} defaultReporter
|
||||
* @param {boolean} runInParallel
|
||||
* @param {object} options
|
||||
* @param {import("@esfx/canceltoken").CancelToken} [options.token]
|
||||
* @param {boolean} [options.watching]
|
||||
*/
|
||||
export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
|
||||
export async function runConsoleTests(runJs, defaultReporter, runInParallel, options = {}) {
|
||||
let testTimeout = cmdLineOptions.timeout;
|
||||
const tests = cmdLineOptions.tests;
|
||||
const inspect = cmdLineOptions.break || cmdLineOptions.inspect;
|
||||
@@ -31,7 +36,14 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
|
||||
const shards = +cmdLineOptions.shards || undefined;
|
||||
const shardId = +cmdLineOptions.shardId || undefined;
|
||||
if (!cmdLineOptions.dirty) {
|
||||
if (options.watching) {
|
||||
console.log(chalk.yellowBright(`[watch] cleaning test directories...`));
|
||||
}
|
||||
await cleanTestDirs();
|
||||
|
||||
if (options.token?.signaled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.existsSync(testConfigFile)) {
|
||||
@@ -56,6 +68,10 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
|
||||
testTimeout = 400000;
|
||||
}
|
||||
|
||||
if (options.watching) {
|
||||
console.log(chalk.yellowBright(`[watch] running tests...`));
|
||||
}
|
||||
|
||||
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || shards || shardId) {
|
||||
writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId);
|
||||
}
|
||||
@@ -114,7 +130,8 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
|
||||
|
||||
try {
|
||||
setNodeEnvToDevelopment();
|
||||
const { exitCode } = await exec(process.execPath, args);
|
||||
|
||||
const { exitCode } = await exec(process.execPath, args, { token: options.token });
|
||||
if (exitCode !== 0) {
|
||||
errorStatus = exitCode;
|
||||
error = new Error(`Process exited with status code ${errorStatus}.`);
|
||||
@@ -132,8 +149,17 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
|
||||
await deleteTemporaryProjectOutput();
|
||||
|
||||
if (error !== undefined) {
|
||||
process.exitCode = typeof errorStatus === "number" ? errorStatus : 2;
|
||||
throw error;
|
||||
if (error instanceof CancelError) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (options.watching) {
|
||||
console.error(`${chalk.redBright(error.name)}: ${error.message}`);
|
||||
}
|
||||
else {
|
||||
process.exitCode = typeof errorStatus === "number" ? errorStatus : 2;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import which from "which";
|
||||
import { spawn } from "child_process";
|
||||
import assert from "assert";
|
||||
import JSONC from "jsonc-parser";
|
||||
import { CancelError } from "@esfx/canceltoken";
|
||||
|
||||
/**
|
||||
* Executes the provided command once with the supplied arguments.
|
||||
@@ -18,6 +19,7 @@ import JSONC from "jsonc-parser";
|
||||
* @property {boolean} [ignoreExitCode]
|
||||
* @property {boolean} [hidePrompt]
|
||||
* @property {boolean} [waitForExit=true]
|
||||
* @property {import("@esfx/canceltoken").CancelToken} [token]
|
||||
*/
|
||||
export async function exec(cmd, args, options = {}) {
|
||||
return /**@type {Promise<{exitCode?: number}>}*/(new Promise((resolve, reject) => {
|
||||
@@ -26,16 +28,24 @@ export async function exec(cmd, args, options = {}) {
|
||||
if (!options.hidePrompt) console.log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const proc = spawn(which.sync(cmd), args, { stdio: waitForExit ? "inherit" : "ignore" });
|
||||
if (waitForExit) {
|
||||
const onCanceled = () => {
|
||||
proc.kill();
|
||||
};
|
||||
const subscription = options.token?.subscribe(onCanceled);
|
||||
proc.on("exit", exitCode => {
|
||||
if (exitCode === 0 || ignoreExitCode) {
|
||||
resolve({ exitCode: exitCode ?? undefined });
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Process exited with code: ${exitCode}`));
|
||||
const reason = options.token?.signaled ? options.token.reason ?? new CancelError() :
|
||||
new Error(`Process exited with code: ${exitCode}`);
|
||||
reject(reason);
|
||||
}
|
||||
subscription?.unsubscribe();
|
||||
});
|
||||
proc.on("error", error => {
|
||||
reject(error);
|
||||
subscription?.unsubscribe();
|
||||
});
|
||||
}
|
||||
else {
|
||||
@@ -150,8 +160,12 @@ export function getDirSize(root) {
|
||||
.reduce((acc, num) => acc + num, 0);
|
||||
}
|
||||
|
||||
class Deferred {
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
export class Deferred {
|
||||
constructor() {
|
||||
/** @type {Promise<T>} */
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
@@ -162,13 +176,15 @@ class Deferred {
|
||||
export class Debouncer {
|
||||
/**
|
||||
* @param {number} timeout
|
||||
* @param {() => Promise<any>} action
|
||||
* @param {() => Promise<any> | void} action
|
||||
*/
|
||||
constructor(timeout, action) {
|
||||
this._timeout = timeout;
|
||||
this._action = action;
|
||||
}
|
||||
|
||||
get empty() { return !this._deferred; }
|
||||
|
||||
enqueue() {
|
||||
if (this._timer) {
|
||||
clearTimeout(this._timer);
|
||||
|
||||
Reference in New Issue
Block a user