

























@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
22import {
33isAbortError,
44isBenignUncaughtExceptionError,
5+isTransientFileWatchError,
56isTransientNetworkError,
67isTransientSqliteError,
78isTransientUnhandledRejectionError,
@@ -258,6 +259,104 @@ describe("isTransientSqliteError", () => {
258259});
259260});
260261262+describe("isTransientFileWatchError", () => {
263+it("returns true for ENOSPC with inotify message", () => {
264+const error = Object.assign(new Error("inotify watches exhausted"), { code: "ENOSPC" });
265+expect(isTransientFileWatchError(error)).toBe(true);
266+});
267+268+it("returns true for ENOSPC with file watcher message", () => {
269+const error = Object.assign(new Error("System limit for number of file watchers reached"), {
270+code: "ENOSPC",
271+});
272+expect(isTransientFileWatchError(error)).toBe(true);
273+});
274+275+it("returns true for ENOSPC with watcher error message", () => {
276+const error = Object.assign(new Error("watcher error: ENOSPC"), { code: "ENOSPC" });
277+expect(isTransientFileWatchError(error)).toBe(true);
278+});
279+280+it("returns false for ENOSPC without watch indicator (general disk full)", () => {
281+const error = Object.assign(new Error("write failed: no space left on device"), {
282+code: "ENOSPC",
283+});
284+expect(isTransientFileWatchError(error)).toBe(false);
285+});
286+287+it("returns false for ENOSPC with only 'disk full' message", () => {
288+const error = Object.assign(new Error("ENOSPC: disk full"), { code: "ENOSPC" });
289+expect(isTransientFileWatchError(error)).toBe(false);
290+});
291+292+it("returns false for message-only disk full without watch indicator", () => {
293+expect(isTransientFileWatchError(new Error("write failed: no space left on device"))).toBe(
294+false,
295+);
296+expect(isTransientFileWatchError(new Error("ENOSPC: no space left on device"))).toBe(false);
297+});
298+299+it("returns true for 'no space left on device' message with watcher context", () => {
300+const error = new Error("file watcher: no space left on device");
301+expect(isTransientFileWatchError(error)).toBe(true);
302+});
303+304+it("returns true for inotify-related error messages", () => {
305+expect(isTransientFileWatchError(new Error("inotify watches exhausted"))).toBe(true);
306+expect(
307+isTransientFileWatchError(new Error("System limit for number of file watchers reached")),
308+).toBe(true);
309+});
310+311+it("returns true for watcher-related no-space messages", () => {
312+expect(isTransientFileWatchError(new Error("file watcher: no space left on device"))).toBe(
313+true,
314+);
315+});
316+317+it("returns false for generic code-less watcher messages", () => {
318+expect(isTransientFileWatchError(new Error("file watcher failed"))).toBe(false);
319+expect(isTransientFileWatchError(new Error("watcher error: boom"))).toBe(false);
320+expect(isTransientFileWatchError(new Error("watcher error: ENOSPC"))).toBe(false);
321+expect(isTransientUnhandledRejectionError(new Error("file watcher failed"))).toBe(false);
322+expect(isTransientUnhandledRejectionError(new Error("watcher error: boom"))).toBe(false);
323+expect(isTransientUnhandledRejectionError(new Error("watcher error: ENOSPC"))).toBe(false);
324+});
325+326+it("returns true for ENOSPC with cause chain containing watch indicator", () => {
327+const cause = Object.assign(new Error("inotify watches exhausted"), { code: "ENOSPC" });
328+const error = Object.assign(new Error("watcher failed"), { cause });
329+expect(isTransientFileWatchError(error)).toBe(true);
330+});
331+332+it("returns false for 'watchdog timeout' (unrelated watch error)", () => {
333+expect(isTransientFileWatchError(new Error("watchdog timeout"))).toBe(false);
334+expect(isTransientFileWatchError(new Error("cannot watch process"))).toBe(false);
335+});
336+337+it("returns false for regular errors without file watch indicators", () => {
338+expect(isTransientFileWatchError(new Error("Something went wrong"))).toBe(false);
339+expect(isTransientFileWatchError(new TypeError("Cannot read property"))).toBe(false);
340+expect(isTransientFileWatchError(new RangeError("Invalid array length"))).toBe(false);
341+});
342+343+it("returns false for other disk errors without ENOSPC", () => {
344+expect(isTransientFileWatchError(new Error("disk quota exceeded"))).toBe(false);
345+expect(
346+isTransientFileWatchError(
347+Object.assign(new Error("read only file system"), { code: "EROFS" }),
348+),
349+).toBe(false);
350+});
351+352+it.each([null, undefined, "string error", 42, { message: "plain object" }])(
353+"returns false for non-file-watch input %#",
354+(value) => {
355+expect(isTransientFileWatchError(value)).toBe(false);
356+},
357+);
358+});
359+261360describe("isTransientUnhandledRejectionError", () => {
262361it("treats raw pre-connect network uncaught exceptions as benign", () => {
263362const epipe = Object.assign(new Error("write EPIPE"), { code: "EPIPE" });
@@ -287,4 +386,30 @@ describe("isTransientUnhandledRejectionError", () => {
287386288387expect(isTransientUnhandledRejectionError(error)).toBe(true);
289388});
389+390+it("returns true for transient file watcher errors (ENOSPC + inotify)", () => {
391+const error = Object.assign(new Error("inotify watches exhausted"), { code: "ENOSPC" });
392+expect(isTransientUnhandledRejectionError(error)).toBe(true);
393+});
394+395+it("returns true for file watcher errors with message only", () => {
396+const error = new Error("System limit for number of file watchers reached");
397+expect(isTransientUnhandledRejectionError(error)).toBe(true);
398+});
399+400+it("returns false for ENOSPC without watch indicator (general disk full)", () => {
401+const error = Object.assign(new Error("write failed: no space left on device"), {
402+code: "ENOSPC",
403+});
404+expect(isTransientUnhandledRejectionError(error)).toBe(false);
405+});
406+407+it("returns false for code-less disk full messages without watch indicator", () => {
408+expect(
409+isTransientUnhandledRejectionError(new Error("write failed: no space left on device")),
410+).toBe(false);
411+expect(isTransientUnhandledRejectionError(new Error("ENOSPC: no space left on device"))).toBe(
412+false,
413+);
414+});
290415});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。