factorio-test-cli 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { program } from "commander";
3
2
  import chalk from "chalk";
3
+ import { program } from "commander";
4
4
  import { CliError } from "./cli-error.js";
5
5
  import "./run.js";
6
6
  try {
@@ -13,9 +13,14 @@ export function parseEvent(line) {
13
13
  }
14
14
  export class FactorioOutputHandler extends EventEmitter {
15
15
  inMessage = false;
16
+ resultMessage;
17
+ getResultMessage() {
18
+ return this.resultMessage;
19
+ }
16
20
  handleLine(line) {
17
21
  if (line.startsWith("FACTORIO-TEST-RESULT:")) {
18
- this.emit("result", line.slice("FACTORIO-TEST-RESULT:".length));
22
+ this.resultMessage = line.slice("FACTORIO-TEST-RESULT:".length);
23
+ this.emit("result", this.resultMessage);
19
24
  return;
20
25
  }
21
26
  if (line === "FACTORIO-TEST-MESSAGE-START") {
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { parseEvent } from "./factorio-output-parser.js";
2
+ import { FactorioOutputHandler, parseEvent } from "./factorio-output-parser.js";
3
3
  describe("parseEvent", () => {
4
4
  it("parses valid testStarted event", () => {
5
5
  const line = 'FACTORIO-TEST-EVENT:{"type":"testStarted","test":{"path":"root > mytest"}}';
@@ -36,3 +36,22 @@ describe("parseEvent", () => {
36
36
  expect(parseEvent("FACTORIO-TEST-EVENT:")).toBeUndefined();
37
37
  });
38
38
  });
39
+ describe("FactorioOutputHandler", () => {
40
+ it("getResultMessage returns undefined before result received", () => {
41
+ const handler = new FactorioOutputHandler();
42
+ expect(handler.getResultMessage()).toBeUndefined();
43
+ });
44
+ it("getResultMessage returns result after receiving FACTORIO-TEST-RESULT", () => {
45
+ const handler = new FactorioOutputHandler();
46
+ handler.handleLine("FACTORIO-TEST-RESULT:passed");
47
+ expect(handler.getResultMessage()).toBe("passed");
48
+ });
49
+ it("emits result event with message", () => {
50
+ const handler = new FactorioOutputHandler();
51
+ const results = [];
52
+ handler.on("result", (msg) => results.push(msg));
53
+ handler.handleLine("FACTORIO-TEST-RESULT:failed:focused");
54
+ expect(results).toEqual(["failed:focused"]);
55
+ expect(handler.getResultMessage()).toBe("failed:focused");
56
+ });
57
+ });
@@ -1,13 +1,84 @@
1
- import { spawn } from "child_process";
1
+ import { EventEmitter } from "events";
2
+ import { spawn, spawnSync } from "child_process";
3
+ import * as fs from "fs";
4
+ import * as os from "os";
2
5
  import * as path from "path";
3
6
  import { fileURLToPath } from "url";
4
- import BufferLineSplitter from "./buffer-line-splitter.js";
5
7
  import { FactorioOutputHandler } from "./factorio-output-parser.js";
6
- import { OutputPrinter } from "./output-formatter.js";
7
- import { ProgressRenderer } from "./progress-renderer.js";
8
- import { TestRunCollector } from "./test-run-collector.js";
8
+ import { OutputPrinter, ProgressRenderer } from "./test-output.js";
9
+ import { TestRunCollector } from "./test-results.js";
9
10
  import { CliError } from "./cli-error.js";
10
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ class BufferLineSplitter extends EventEmitter {
13
+ buf = "";
14
+ constructor(stream) {
15
+ super();
16
+ stream.on("close", () => {
17
+ if (this.buf.length > 0)
18
+ this.emit("line", this.buf);
19
+ });
20
+ stream.on("end", () => {
21
+ if (this.buf.length > 0)
22
+ this.emit("line", this.buf);
23
+ });
24
+ stream.on("data", (chunk) => {
25
+ this.buf += chunk.toString();
26
+ let index;
27
+ while ((index = this.buf.search(/\r?\n/)) !== -1) {
28
+ this.emit("line", this.buf.slice(0, index));
29
+ this.buf = this.buf.slice(index + 1);
30
+ }
31
+ });
32
+ }
33
+ }
34
+ export function getFactorioPlayerDataPath() {
35
+ const platform = os.platform();
36
+ if (platform === "win32") {
37
+ return path.join(process.env.APPDATA, "Factorio", "player-data.json");
38
+ }
39
+ if (platform === "darwin") {
40
+ return path.join(os.homedir(), "Library", "Application Support", "factorio", "player-data.json");
41
+ }
42
+ return path.join(os.homedir(), ".factorio", "player-data.json");
43
+ }
44
+ function factorioIsInPath() {
45
+ const result = spawnSync("factorio", ["--version"], { stdio: "ignore" });
46
+ return result.status === 0;
47
+ }
48
+ export function autoDetectFactorioPath() {
49
+ if (factorioIsInPath()) {
50
+ return "factorio";
51
+ }
52
+ let pathsToTry;
53
+ if (os.platform() === "linux" || os.platform() === "darwin") {
54
+ pathsToTry = [
55
+ "~/.local/share/Steam/steamapps/common/Factorio/bin/x64/factorio",
56
+ "~/Library/Application Support/Steam/steamapps/common/Factorio/factorio.app/Contents/MacOS/factorio",
57
+ "~/.factorio/bin/x64/factorio",
58
+ "/Applications/factorio.app/Contents/MacOS/factorio",
59
+ "/usr/share/factorio/bin/x64/factorio",
60
+ "/usr/share/games/factorio/bin/x64/factorio",
61
+ ];
62
+ }
63
+ else if (os.platform() === "win32") {
64
+ pathsToTry = [
65
+ "factorio.exe",
66
+ process.env["ProgramFiles(x86)"] + "\\Steam\\steamapps\\common\\Factorio\\bin\\x64\\factorio.exe",
67
+ process.env["ProgramFiles"] + "\\Factorio\\bin\\x64\\factorio.exe",
68
+ ];
69
+ }
70
+ else {
71
+ throw new CliError(`Cannot auto-detect factorio path on platform ${os.platform()}`);
72
+ }
73
+ pathsToTry = pathsToTry.map((p) => p.replace(/^~\//, os.homedir() + "/"));
74
+ for (const testPath of pathsToTry) {
75
+ if (fs.statSync(testPath, { throwIfNoEntry: false })?.isFile()) {
76
+ return path.resolve(testPath);
77
+ }
78
+ }
79
+ throw new CliError(`Could not auto-detect factorio executable. Tried: ${pathsToTry.join(", ")}. ` +
80
+ "Either add the factorio bin to your path, or specify the path with --factorio-path");
81
+ }
11
82
  export function getHeadlessSavePath(overridePath) {
12
83
  if (overridePath) {
13
84
  return path.resolve(overridePath);
@@ -29,11 +100,12 @@ export function parseResultMessage(message) {
29
100
  function createOutputComponents(options) {
30
101
  const handler = new FactorioOutputHandler();
31
102
  const collector = new TestRunCollector();
103
+ const isTTY = process.stdout.isTTY ?? false;
32
104
  const printer = new OutputPrinter({
33
105
  verbose: options.verbose,
34
106
  quiet: options.quiet,
35
107
  });
36
- const progress = new ProgressRenderer();
108
+ const progress = new ProgressRenderer(isTTY);
37
109
  handler.on("event", (event) => {
38
110
  collector.handleEvent(event);
39
111
  progress.handleEvent(event);
@@ -52,7 +124,11 @@ function createOutputComponents(options) {
52
124
  progress.handleTestFinished(test);
53
125
  progress.withPermanentOutput(() => printer.printTestResult(test));
54
126
  });
55
- return { handler, collector, printer, progress };
127
+ handler.on("result", () => {
128
+ progress.finish();
129
+ printer.resetMessage();
130
+ });
131
+ return { handler, collector };
56
132
  }
57
133
  export async function runFactorioTestsHeadless(factorioPath, dataDir, savePath, additionalArgs, options) {
58
134
  const args = [
@@ -70,16 +146,10 @@ export async function runFactorioTestsHeadless(factorioPath, dataDir, savePath,
70
146
  const factorioProcess = spawn(factorioPath, args, {
71
147
  stdio: ["inherit", "pipe", "pipe"],
72
148
  });
73
- const { handler, collector, printer, progress } = createOutputComponents(options);
74
- let resultMessage;
149
+ const { handler, collector } = createOutputComponents(options);
75
150
  let testRunStarted = false;
76
151
  let startupTimedOut = false;
77
152
  let wasCancelled = false;
78
- handler.on("result", (msg) => {
79
- resultMessage = msg;
80
- progress.finish();
81
- printer.resetMessage();
82
- });
83
153
  handler.on("event", (event) => {
84
154
  if (event.type === "testRunStarted") {
85
155
  testRunStarted = true;
@@ -109,7 +179,7 @@ export async function runFactorioTestsHeadless(factorioPath, dataDir, savePath,
109
179
  else if (startupTimedOut) {
110
180
  reject(new CliError("Factorio unresponsive: no test run started within 10 seconds"));
111
181
  }
112
- else if (resultMessage !== undefined) {
182
+ else if (handler.getResultMessage() !== undefined) {
113
183
  resolve();
114
184
  }
115
185
  else {
@@ -120,6 +190,7 @@ export async function runFactorioTestsHeadless(factorioPath, dataDir, savePath,
120
190
  if (wasCancelled) {
121
191
  return { status: "cancelled", hasFocusedTests: false };
122
192
  }
193
+ const resultMessage = handler.getResultMessage();
123
194
  const parsed = parseResultMessage(resultMessage);
124
195
  return { ...parsed, message: resultMessage, data: collector.getData() };
125
196
  }
@@ -137,22 +208,16 @@ export async function runFactorioTestsGraphics(factorioPath, dataDir, savePath,
137
208
  const factorioProcess = spawn(factorioPath, args, {
138
209
  stdio: ["inherit", "pipe", "inherit"],
139
210
  });
140
- const { handler, collector, printer, progress } = createOutputComponents(options);
141
- let resultMessage;
211
+ const { handler, collector } = createOutputComponents(options);
142
212
  let resolvePromise;
143
- handler.on("result", (msg) => {
144
- resultMessage = msg;
145
- progress.finish();
146
- printer.resetMessage();
147
- if (options.resolveOnResult && resolvePromise) {
148
- resolvePromise();
149
- }
150
- });
213
+ if (options.resolveOnResult) {
214
+ handler.on("result", () => resolvePromise?.());
215
+ }
151
216
  new BufferLineSplitter(factorioProcess.stdout).on("line", (line) => handler.handleLine(line));
152
217
  await new Promise((resolve, reject) => {
153
218
  resolvePromise = resolve;
154
219
  factorioProcess.on("exit", (code, signal) => {
155
- if (resultMessage !== undefined) {
220
+ if (handler.getResultMessage() !== undefined) {
156
221
  resolve();
157
222
  }
158
223
  else {
@@ -160,6 +225,7 @@ export async function runFactorioTestsGraphics(factorioPath, dataDir, savePath,
160
225
  }
161
226
  });
162
227
  });
228
+ const resultMessage = handler.getResultMessage();
163
229
  const parsed = parseResultMessage(resultMessage);
164
230
  return { ...parsed, message: resultMessage, data: collector.getData() };
165
231
  }
@@ -1,5 +1,12 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
2
  import { parseResultMessage } from "./factorio-process.js";
3
+ vi.mock("child_process", async (importOriginal) => {
4
+ const original = await importOriginal();
5
+ return {
6
+ ...original,
7
+ spawnSync: vi.fn(() => ({ status: 1 })),
8
+ };
9
+ });
3
10
  describe("parseResultMessage", () => {
4
11
  it.each([
5
12
  ["passed", { status: "passed", hasFocusedTests: false }],
@@ -13,3 +20,23 @@ describe("parseResultMessage", () => {
13
20
  expect(parseResultMessage(input)).toEqual(expected);
14
21
  });
15
22
  });
23
+ describe("autoDetectFactorioPath", () => {
24
+ beforeEach(() => {
25
+ vi.resetModules();
26
+ });
27
+ afterEach(() => {
28
+ vi.restoreAllMocks();
29
+ });
30
+ it("returns 'factorio' if in PATH", async () => {
31
+ const { spawnSync } = await import("child_process");
32
+ vi.mocked(spawnSync).mockReturnValue({ status: 0 });
33
+ const { autoDetectFactorioPath } = await import("./factorio-process.js");
34
+ expect(autoDetectFactorioPath()).toBe("factorio");
35
+ });
36
+ it("throws if no path found and factorio not in PATH", async () => {
37
+ const { spawnSync } = await import("child_process");
38
+ vi.mocked(spawnSync).mockReturnValue({ status: 1 });
39
+ const { autoDetectFactorioPath } = await import("./factorio-process.js");
40
+ expect(() => autoDetectFactorioPath()).toThrow(/Could not auto-detect/);
41
+ });
42
+ });
package/mod-setup.js CHANGED
@@ -2,7 +2,7 @@ import * as fsp from "fs/promises";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
4
  import { runScript, runProcess } from "./process-utils.js";
5
- import { getFactorioPlayerDataPath } from "./factorio-discovery.js";
5
+ import { getFactorioPlayerDataPath } from "./factorio-process.js";
6
6
  import { CliError } from "./cli-error.js";
7
7
  const MIN_FACTORIO_TEST_VERSION = "3.0.0";
8
8
  function parseVersion(version) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "factorio-test-cli",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "A CLI to run FactorioTest.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/run.js CHANGED
@@ -1,16 +1,16 @@
1
+ import chalk from "chalk";
1
2
  import { program } from "commander";
3
+ import * as dgram from "dgram";
2
4
  import * as fsp from "fs/promises";
3
5
  import * as path from "path";
4
- import * as dgram from "dgram";
5
- import chalk from "chalk";
6
- import { loadConfig, mergeCliConfig, buildTestConfig, registerAllCliOptions, } from "./config/index.js";
7
- import { setVerbose, runScript } from "./process-utils.js";
8
- import { autoDetectFactorioPath } from "./factorio-discovery.js";
9
6
  import { CliError } from "./cli-error.js";
10
- import { configureModToTest, installFactorioTest, installModDependencies, ensureConfigIni, setSettingsForAutorun, resetAutorunSettings, resolveModWatchTarget, } from "./mod-setup.js";
11
- import { writeResultsFile, readPreviousFailedTests, getDefaultOutputPath } from "./results-writer.js";
12
- import { getHeadlessSavePath, runFactorioTestsHeadless, runFactorioTestsGraphics, } from "./factorio-process.js";
7
+ import { buildTestConfig, loadConfig, mergeCliConfig, registerAllCliOptions, } from "./config/index.js";
8
+ import { autoDetectFactorioPath } from "./factorio-process.js";
9
+ import { getHeadlessSavePath, runFactorioTestsGraphics, runFactorioTestsHeadless, } from "./factorio-process.js";
13
10
  import { watchDirectory, watchFile } from "./file-watcher.js";
11
+ import { configureModToTest, ensureConfigIni, installFactorioTest, installModDependencies, resetAutorunSettings, resolveModWatchTarget, setSettingsForAutorun, } from "./mod-setup.js";
12
+ import { runScript, setVerbose } from "./process-utils.js";
13
+ import { getDefaultOutputPath, readPreviousFailedTests, writeResultsFile } from "./test-results.js";
14
14
  const thisCommand = program
15
15
  .command("run")
16
16
  .summary("Runs tests with Factorio test.")
@@ -146,68 +146,70 @@ async function executeTestRun(ctx, execOptions) {
146
146
  return { exitCode: resultStatus === "passed" ? 0 : 1, status: resultStatus };
147
147
  }
148
148
  const DEFAULT_WATCH_PATTERNS = ["info.json", "**/*.lua"];
149
+ async function runGraphicsWatchMode(ctx) {
150
+ const watchPatterns = ctx.options.watchPatterns ?? ctx.fileConfig.watchPatterns ?? DEFAULT_WATCH_PATTERNS;
151
+ const target = await resolveModWatchTarget(ctx.modsDir, ctx.options.modPath, ctx.options.modName);
152
+ console.log(chalk.gray(`Watching ${target.path} for patterns: ${watchPatterns.join(", ")}`));
153
+ await executeTestRun(ctx, { skipResetAutorun: true, resolveOnResult: true });
154
+ const udpClient = dgram.createSocket("udp4");
155
+ const onFileChange = () => {
156
+ console.log(chalk.cyan("File change detected, triggering rerun..."));
157
+ udpClient.send("rerun", ctx.udpPort, "127.0.0.1");
158
+ };
159
+ const watcher = target.type === "directory"
160
+ ? watchDirectory(target.path, onFileChange, { patterns: watchPatterns })
161
+ : watchFile(target.path, onFileChange);
162
+ process.on("SIGINT", () => {
163
+ watcher.close();
164
+ udpClient.close();
165
+ process.exit(0);
166
+ });
167
+ return new Promise(() => { });
168
+ }
169
+ async function runHeadlessWatchMode(ctx) {
170
+ const watchPatterns = ctx.options.watchPatterns ?? ctx.fileConfig.watchPatterns ?? DEFAULT_WATCH_PATTERNS;
171
+ const target = await resolveModWatchTarget(ctx.modsDir, ctx.options.modPath, ctx.options.modName);
172
+ let abortController;
173
+ const runOnce = async () => {
174
+ abortController?.abort();
175
+ abortController = new AbortController();
176
+ console.log("\n" + "─".repeat(60));
177
+ try {
178
+ await executeTestRun(ctx, { signal: abortController.signal });
179
+ }
180
+ catch (e) {
181
+ if (e instanceof CliError) {
182
+ console.error(chalk.red(e.message));
183
+ }
184
+ else {
185
+ throw e;
186
+ }
187
+ }
188
+ finally {
189
+ abortController = undefined;
190
+ }
191
+ };
192
+ await runOnce();
193
+ const onFileChange = () => {
194
+ console.log(chalk.cyan("File change detected, rerunning tests..."));
195
+ runOnce();
196
+ };
197
+ const watcher = target.type === "directory"
198
+ ? watchDirectory(target.path, onFileChange, { patterns: watchPatterns })
199
+ : watchFile(target.path, onFileChange);
200
+ process.on("SIGINT", () => {
201
+ watcher.close();
202
+ process.exit(0);
203
+ });
204
+ return new Promise(() => { });
205
+ }
149
206
  async function runTests(patterns, options) {
150
207
  const ctx = await setupTestRun(patterns, options);
151
208
  if (options.watch && options.graphics) {
152
- const watchPatterns = options.watchPatterns ?? ctx.fileConfig.watchPatterns ?? DEFAULT_WATCH_PATTERNS;
153
- const target = await resolveModWatchTarget(ctx.modsDir, options.modPath, options.modName);
154
- console.log(chalk.gray(`Watching ${target.path} for patterns: ${watchPatterns.join(", ")}`));
155
- await executeTestRun(ctx, { skipResetAutorun: true, resolveOnResult: true });
156
- const udpClient = dgram.createSocket("udp4");
157
- const onFileChange = () => {
158
- console.log(chalk.cyan("File change detected, triggering rerun..."));
159
- udpClient.send("rerun", ctx.udpPort, "127.0.0.1");
160
- };
161
- const watcher = target.type === "directory"
162
- ? watchDirectory(target.path, onFileChange, { patterns: watchPatterns })
163
- : watchFile(target.path, onFileChange);
164
- process.on("SIGINT", () => {
165
- watcher.close();
166
- udpClient.close();
167
- process.exit(0);
168
- });
169
- await new Promise(() => { });
209
+ await runGraphicsWatchMode(ctx);
170
210
  }
171
211
  else if (options.watch) {
172
- const watchPatterns = options.watchPatterns ?? ctx.fileConfig.watchPatterns ?? DEFAULT_WATCH_PATTERNS;
173
- const target = await resolveModWatchTarget(ctx.modsDir, options.modPath, options.modName);
174
- let abortController;
175
- let isRunning = false;
176
- const runOnce = async () => {
177
- if (isRunning) {
178
- abortController?.abort();
179
- }
180
- abortController = new AbortController();
181
- isRunning = true;
182
- console.log("\n" + "─".repeat(60));
183
- try {
184
- await executeTestRun(ctx, { signal: abortController.signal });
185
- }
186
- catch (e) {
187
- if (e instanceof CliError) {
188
- console.error(chalk.red(e.message));
189
- }
190
- else {
191
- throw e;
192
- }
193
- }
194
- finally {
195
- isRunning = false;
196
- }
197
- };
198
- await runOnce();
199
- const onFileChange = () => {
200
- console.log(chalk.cyan("File change detected, rerunning tests..."));
201
- runOnce();
202
- };
203
- const watcher = target.type === "directory"
204
- ? watchDirectory(target.path, onFileChange, { patterns: watchPatterns })
205
- : watchFile(target.path, onFileChange);
206
- process.on("SIGINT", () => {
207
- watcher.close();
208
- process.exit(0);
209
- });
210
- await new Promise(() => { });
212
+ await runHeadlessWatchMode(ctx);
211
213
  }
212
214
  else {
213
215
  const result = await executeTestRun(ctx);
@@ -1,4 +1,78 @@
1
1
  import chalk from "chalk";
2
+ import logUpdate from "log-update";
3
+ export class ProgressRenderer {
4
+ isTTY;
5
+ active = false;
6
+ total = 0;
7
+ ran = 0;
8
+ passed = 0;
9
+ failed = 0;
10
+ skipped = 0;
11
+ todo = 0;
12
+ currentTest;
13
+ constructor(isTTY = process.stdout.isTTY ?? false) {
14
+ this.isTTY = isTTY;
15
+ }
16
+ handleEvent(event) {
17
+ if (event.type === "testRunStarted") {
18
+ this.total = event.total;
19
+ }
20
+ else if (event.type === "testStarted") {
21
+ this.currentTest = event.test.path;
22
+ this.render();
23
+ }
24
+ }
25
+ handleTestFinished(test) {
26
+ this.currentTest = undefined;
27
+ if (test.result === "passed") {
28
+ this.ran++;
29
+ this.passed++;
30
+ }
31
+ else if (test.result === "failed") {
32
+ this.ran++;
33
+ this.failed++;
34
+ }
35
+ else if (test.result === "skipped") {
36
+ this.skipped++;
37
+ }
38
+ else if (test.result === "todo") {
39
+ this.todo++;
40
+ }
41
+ }
42
+ withPermanentOutput(callback) {
43
+ if (!this.isTTY || !this.active) {
44
+ callback();
45
+ return;
46
+ }
47
+ logUpdate.clear();
48
+ callback();
49
+ this.render();
50
+ }
51
+ finish() {
52
+ if (this.active)
53
+ logUpdate.clear();
54
+ }
55
+ render() {
56
+ if (!this.isTTY)
57
+ return;
58
+ this.active = true;
59
+ const percent = this.total > 0 ? Math.floor((this.ran / this.total) * 100) : 0;
60
+ const barWidth = 20;
61
+ const filled = Math.min(barWidth, Math.floor((percent / 100) * barWidth));
62
+ const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);
63
+ const counts = [
64
+ chalk.green(`✓${this.passed}`),
65
+ this.failed > 0 ? chalk.red(`✗${this.failed}`) : null,
66
+ this.skipped > 0 ? chalk.yellow(`○${this.skipped}`) : null,
67
+ this.todo > 0 ? chalk.magenta(`◌${this.todo}`) : null,
68
+ ]
69
+ .filter(Boolean)
70
+ .join(" ");
71
+ const progress = `[${bar}] ${percent}% ${this.ran}/${this.total} ${counts}`;
72
+ const current = this.currentTest ? `Running: ${this.currentTest}` : " ";
73
+ logUpdate(progress + "\n" + current);
74
+ }
75
+ }
2
76
  function formatDuration(ms) {
3
77
  if (ms >= 1000) {
4
78
  return `${(ms / 1000).toFixed(2)}s`;
@@ -61,19 +135,12 @@ export class OutputPrinter {
61
135
  });
62
136
  }
63
137
  printTestResult(test) {
64
- if (this.options.quiet || this.options.useProgressBar)
138
+ if (this.options.quiet)
65
139
  return;
66
- if ((test.result === "skipped" || test.result === "todo") && !this.options.verbose)
140
+ if (test.result === "skipped" && !this.options.verbose)
67
141
  return;
68
142
  this.formatter.formatTestResult(test);
69
143
  }
70
- printFailures(tests) {
71
- for (const test of tests) {
72
- if (test.result === "failed") {
73
- this.formatter.formatTestResult(test);
74
- }
75
- }
76
- }
77
144
  printMessage(line) {
78
145
  if (this.options.quiet)
79
146
  return;