> ## Documentation Index
> Fetch the complete documentation index at: https://exosphere-auto-translate-docs-20260623-1106.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# परीक्षण

> यूनिट परीक्षण, E2E परीक्षण, और परीक्षण सहायक

failproofai के दो परीक्षण सेट हैं: **यूनिट परीक्षण** (तेज़, मॉक किए गए) और **end-to-end परीक्षण** (असली subprocess आमंत्रण)।

***

## परीक्षण चलाना

```bash theme={null}
# सभी यूनिट परीक्षण एक बार चलाएं
bun run test:run

# यूनिट परीक्षण watch मोड में चलाएं
bun run test

# E2E परीक्षण चलाएं (सेटअप आवश्यक है - नीचे देखें)
bun run test:e2e

# प्रकार की जांच बिना बिल्ड किए
bunx tsc --noEmit

# लिंट करें
bun run lint
```

***

## यूनिट परीक्षण

यूनिट परीक्षण `__tests__/` में रहते हैं और [Vitest](https://vitest.dev) के साथ `jsdom` का उपयोग करते हैं।

```text theme={null}
__tests__/
  hooks/
    builtin-policies.test.ts      # प्रत्येक बिल्ट-इन के लिए नीति तर्क
    hooks-config.test.ts          # कॉन्फ़िग लोडिंग और स्कोप मर्ज करना
    policy-evaluator.test.ts      # पैरामीटर इंजेक्शन और मूल्यांकन क्रम
    custom-hooks-registry.test.ts # globalThis रजिस्ट्री add/get/clear
    custom-hooks-loader.test.ts   # ESM लोडर, transitive आयात, त्रुटि हैंडलिंग
    manager.test.ts               # install/remove/list संचालन
  components/
    sessions-list.test.tsx        # सत्र सूची घटक
    project-list.test.tsx         # प्रोजेक्ट सूची घटक
    ...
  lib/
    logger.test.ts
    paths.test.ts
    date-filters.test.ts
    telemetry.test.ts
    ...
  actions/
    get-hooks-config.test.ts
    get-hook-activity.test.ts
    ...
  contexts/
    ThemeContext.test.tsx
    AutoRefreshContext.test.tsx
```

### नीति यूनिट परीक्षण लिखना

```typescript theme={null}
import { describe, it, expect, beforeEach } from "vitest";
import { getBuiltinPolicies } from "../../src/hooks/builtin-policies";
import { allow, deny } from "../../src/hooks/policy-types";

describe("block-sudo", () => {
  const policy = getBuiltinPolicies().find((p) => p.name === "block-sudo")!;

  it("denies sudo commands", () => {
    const ctx = {
      eventType: "PreToolUse" as const,
      payload: {},
      toolName: "Bash",
      toolInput: { command: "sudo apt install nodejs" },
      params: { allowPatterns: [] },
    };
    expect(policy.fn(ctx)).toEqual(deny("sudo command blocked by failproofai"));
  });

  it("allows non-sudo commands", () => {
    const ctx = {
      eventType: "PreToolUse" as const,
      payload: {},
      toolName: "Bash",
      toolInput: { command: "ls -la" },
      params: { allowPatterns: [] },
    };
    expect(policy.fn(ctx)).toEqual(allow());
  });

  it("allows patterns in allowPatterns", () => {
    const ctx = {
      eventType: "PreToolUse" as const,
      payload: {},
      toolName: "Bash",
      toolInput: { command: "sudo systemctl status nginx" },
      params: { allowPatterns: ["sudo systemctl status"] },
    };
    expect(policy.fn(ctx)).toEqual(allow());
  });
});
```

***

## End-to-end परीक्षण

E2E परीक्षण असली `failproofai` बाइनरी को subprocess के रूप में आमंत्रित करते हैं, JSON पेलोड को stdin में पाइप करते हैं, और stdout आउटपुट और exit कोड पर assertion करते हैं। यह उस संपूर्ण एकीकरण पथ को परीक्षण करता है जो Claude Code उपयोग करता है।

### सेटअप

E2E परीक्षण रेपो स्रोत से सीधे बाइनरी चलाते हैं। पहली बार चलाने से पहले, CJS बंडल बनाएं जो कस्टम हुक फाइलें `'failproofai'` से आयात करते समय उपयोग करती हैं:

```bash theme={null}
bun build src/index.ts --outdir dist --target node --format cjs
```

फिर परीक्षण चलाएं:

```bash theme={null}
bun run test:e2e
```

जब भी आप सार्वजनिक हुक API (`src/hooks/custom-hooks-registry.ts`, `src/hooks/policy-helpers.ts`, या `src/hooks/policy-types.ts`) को परिवर्तित करें, `dist/` को पुनः बनाएं।

### E2E परीक्षण संरचना

```text theme={null}
__tests__/e2e/
  helpers/
    hook-runner.ts      # बाइनरी spawn करें, पेलोड JSON पाइप करें, exit कोड + stdout + stderr कैप्चर करें
    fixture-env.ts      # प्रति-परीक्षण अलग अस्थायी निर्देशिकाएं कॉन्फ़िग फाइलों के साथ
    payloads.ts         # प्रत्येक इवेंट प्रकार के लिए Claude-सटीक पेलोड फैक्ट्रीज
  hooks/
    builtin-policies.e2e.test.ts   # असली subprocess के साथ प्रत्येक बिल्ट-इन नीति
    custom-hooks.e2e.test.ts       # कस्टम हुक लोडिंग और मूल्यांकन
    config-scopes.e2e.test.ts      # project/local/global में कॉन्फ़िग मर्ज करना
    policy-params.e2e.test.ts      # प्रत्येक पैरामीटरयुक्त नीति के लिए पैरामीटर इंजेक्शन
```

### E2E सहायकों का उपयोग करना

**`FixtureEnv`** - प्रति-परीक्षण अलग पर्यावरण:

```typescript theme={null}
import { createFixtureEnv } from "../helpers/fixture-env";

const env = createFixtureEnv();
// env.cwd    - अस्थायी निर्देशिका; .failproofai/policies-config.json उठाने के लिए payload.cwd के रूप में पास करें
// env.home   - अलग होम निर्देशिका; कोई वास्तविक ~/.failproofai लीक नहीं होता

env.writeConfig({
  enabledPolicies: ["block-sudo"],
  policyParams: {
    "block-sudo": { allowPatterns: ["sudo systemctl status"] },
  },
});
```

`createFixtureEnv()` स्वचालित रूप से `afterEach` क्लीनअप पंजीकृत करता है।

**`runHook`** - बाइनरी को आमंत्रित करें:

```typescript theme={null}
import { runHook } from "../helpers/hook-runner";
import { Payloads } from "../helpers/payloads";

const result = await runHook(
  "PreToolUse",
  Payloads.preToolUse.bash("sudo apt install nodejs", env.cwd),
  { homeDir: env.home }
);

expect(result.exitCode).toBe(0);
expect(result.parsed?.hookSpecificOutput?.permissionDecision).toBe("deny");
```

**`Payloads`** - तैयार पेलोड फैक्ट्रीज:

```typescript theme={null}
Payloads.preToolUse.bash(command, cwd)
Payloads.preToolUse.write(filePath, content, cwd)
Payloads.preToolUse.read(filePath, cwd)
Payloads.postToolUse.bash(command, output, cwd)
Payloads.postToolUse.read(filePath, content, cwd)
Payloads.notification(message, cwd)
Payloads.stop(cwd)
```

### E2E परीक्षण लिखना

```typescript theme={null}
import { describe, it, expect } from "vitest";
import { createFixtureEnv } from "../helpers/fixture-env";
import { runHook } from "../helpers/hook-runner";
import { Payloads } from "../helpers/payloads";

describe("block-rm-rf (E2E)", () => {
  it("denies rm -rf", async () => {
    const env = createFixtureEnv();
    env.writeConfig({ enabledPolicies: ["block-rm-rf"] });

    const result = await runHook(
      "PreToolUse",
      Payloads.preToolUse.bash("rm -rf /", env.cwd),
      { homeDir: env.home }
    );

    expect(result.exitCode).toBe(0);
    expect(result.parsed?.hookSpecificOutput?.permissionDecision).toBe("deny");
  });

  it("allows non-recursive rm", async () => {
    const env = createFixtureEnv();
    env.writeConfig({ enabledPolicies: ["block-rm-rf"] });

    const result = await runHook(
      "PreToolUse",
      Payloads.preToolUse.bash("rm /tmp/file.txt", env.cwd),
      { homeDir: env.home }
    );

    expect(result.exitCode).toBe(0);
    expect(result.stdout).toBe("");  // allow → खाली stdout
  });
});
```

### E2E प्रतिक्रिया आकार

| निर्णय              | Exit कोड | stdout                                                                                  |
| ------------------- | -------- | --------------------------------------------------------------------------------------- |
| `PreToolUse` deny   | `0`      | `{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"..."}}` |
| `PostToolUse` deny  | `0`      | `{"hookSpecificOutput":{"additionalContext":"Blocked ... because: ..."}}`               |
| Instruct (non-Stop) | `0`      | `{"hookSpecificOutput":{"additionalContext":"Instruction from failproofai: ..."}}`      |
| Stop निर्देश        | `2`      | खाली stdout; stderr में कारण                                                            |
| Allow               | `0`      | खाली स्ट्रिंग                                                                           |

### Vitest कॉन्फ़िग

E2E परीक्षण `vitest.config.e2e.mts` का उपयोग करते हैं जिसमें है:

* `environment: "node"` - कोई ब्राउज़र globals आवश्यक नहीं
* `pool: "forks"` - सच्चा प्रक्रिया अलगाव (परीक्षण subprocesses spawn करते हैं)
* `testTimeout: 20_000` - प्रति परीक्षण 20s (बाइनरी स्टार्टअप + हुक eval)

`forks` पूल महत्वपूर्ण है: thread-आधारित workers `globalThis` साझा करते हैं, जो subprocess-spawning परीक्षणों में हस्तक्षेप कर सकता है। Process-आधारित forks इससे बचते हैं।

***

## CI

संपूर्ण CI चलाव (`bun run lint && bunx tsc --noEmit && bun run test:run && bun run build`) को मर्ज करने से पहले पास होना आवश्यक है। E2E सेट एक अलग CI कार्य के रूप में समानांतर में चलता है।

पूर्ण प्री-मर्ज चेकलिस्ट के लिए [Contributing](../CONTRIBUTING.md) देखें।
