mirror of
https://github.com/millionco/react-doctor.git
synced 2026-09-14 20:00:24 +08:00
4e04921205
Co-authored-by: Aiden Bai <aiden@million.dev>
132 lines
4.6 KiB
TypeScript
132 lines
4.6 KiB
TypeScript
import { describe, expect, it } from "vite-plus/test";
|
|
import {
|
|
AmbiguousProjectError,
|
|
GitBaseBranchInvalid,
|
|
GitBaseBranchMissing,
|
|
NoReactDependencyError,
|
|
NotADirectoryError,
|
|
OxlintSpawnFailed,
|
|
PackageJsonNotFoundError,
|
|
ProjectDiscoveryFailed,
|
|
ProjectNotFoundError,
|
|
ReactDoctorError,
|
|
} from "@react-doctor/core";
|
|
import { CliInputError } from "../src/cli/utils/cli-input-error.js";
|
|
import { isExpectedUserError } from "../src/cli/utils/is-expected-user-error.js";
|
|
|
|
describe("isExpectedUserError", () => {
|
|
it("classifies every project-discovery failure as an expected user error (kept out of Sentry)", () => {
|
|
// Regression: running react-doctor against a directory with no React
|
|
// (REACT-DOCTOR-1) or a path that doesn't exist (REACT-DOCTOR-4) is
|
|
// expected, user-actionable behavior — not a crash to report.
|
|
expect(isExpectedUserError(new NoReactDependencyError("/var/tmp"))).toBe(true);
|
|
expect(isExpectedUserError(new ProjectNotFoundError("/tmp/audit-v7"))).toBe(true);
|
|
expect(
|
|
isExpectedUserError(new ProjectNotFoundError("/tmp/audit-v7", { kind: "missing-path" })),
|
|
).toBe(true);
|
|
expect(isExpectedUserError(new PackageJsonNotFoundError("/var/tmp"))).toBe(true);
|
|
expect(isExpectedUserError(new NotADirectoryError("/var/tmp/file.txt"))).toBe(true);
|
|
expect(isExpectedUserError(new AmbiguousProjectError("/work", ["a", "b"]))).toBe(true);
|
|
});
|
|
|
|
it("classifies CLI invocation mistakes as expected user errors", () => {
|
|
// REACT-DOCTOR-B/D/G/H: mutually exclusive flags, a malformed
|
|
// "<file>:<line>" argument, or an unknown --project name are user
|
|
// invocation mistakes, not crashes.
|
|
expect(
|
|
isExpectedUserError(new CliInputError("Cannot combine --staged and --diff; pick one mode.")),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
new CliInputError("Cannot combine --score and --json; pick one output mode."),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(new CliInputError('Expected "<file>:<line>", got "package.json".')),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("classifies bad --diff base-branch input as an expected user error", () => {
|
|
expect(
|
|
isExpectedUserError(
|
|
new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "bad ref" }) }),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
new ReactDoctorError({ reason: new GitBaseBranchMissing({ branch: "main" }) }),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("classifies environment failures as expected user errors", () => {
|
|
expect(
|
|
isExpectedUserError(
|
|
Object.assign(new Error("ENOSPC: no space left on device"), { code: "ENOSPC" }),
|
|
),
|
|
).toBe(true);
|
|
expect(isExpectedUserError(Object.assign(new Error("EIO: i/o error"), { code: "EIO" }))).toBe(
|
|
true,
|
|
);
|
|
expect(
|
|
isExpectedUserError(
|
|
Object.assign(new Error("EACCES: permission denied"), { code: "EACCES" }),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
Object.assign(new Error("EPERM: operation not permitted"), { code: "EPERM" }),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
Object.assign(new Error("ENOTDIR: not a directory"), { code: "ENOTDIR" }),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
Object.assign(new Error("spawn git ENOENT"), { code: "ENOENT", syscall: "spawn git" }),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
Object.assign(new Error("EROFS: read-only file system"), { code: "EROFS" }),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
isExpectedUserError(
|
|
new ReactDoctorError({
|
|
reason: new ProjectDiscoveryFailed({
|
|
directory: "/cloud/project",
|
|
cause: Object.assign(new Error("ETIMEDOUT: scandir"), {
|
|
code: "ETIMEDOUT",
|
|
syscall: "scandir",
|
|
}),
|
|
}),
|
|
}),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("classifies incomplete npx installs as expected user errors", () => {
|
|
const cacheError = Object.assign(new Error("Cannot find module './meta/unevaluated.json'"), {
|
|
code: "MODULE_NOT_FOUND",
|
|
requireStack: [
|
|
"/home/user/.npm/_npx/81e833f6d16d6127/node_modules/ajv/dist/refs/json-schema-2020-12/index.js",
|
|
],
|
|
});
|
|
|
|
expect(isExpectedUserError(cacheError)).toBe(true);
|
|
});
|
|
|
|
it("does not mask genuine bugs (those stay reportable)", () => {
|
|
expect(isExpectedUserError(new Error("boom"))).toBe(false);
|
|
expect(isExpectedUserError(undefined)).toBe(false);
|
|
expect(
|
|
isExpectedUserError(
|
|
new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: new Error("nope") }) }),
|
|
),
|
|
).toBe(false);
|
|
});
|
|
});
|