Env 구성 테스트 및 디버깅

작성자

카테고리:

← 피드로
DEV Community · Odejobi Abiola Samuel · 2026-07-02 개발(SW)
Cover image for Testing and Debugging Your Env Config

Odejobi Abiola Samuel

Environment variables are global state. Testing them usually means mutating process.env and hoping you clean up after. CtroEnv gives you better tools.

Testing with objectSource

objectSource() wraps a plain object as an environment source — no globals involved:

import { describe, expect, it } from "vitest"
import { defineEnv, objectSource, string, number } from "@ctroenv/core"

function makeEnv(overrides: Record<string, string> = {}) {
  return defineEnv(
    {
      DATABASE_URL: string().url(),
      PORT: number().port().default(3000),
      JWT_SECRET: string().min(32).secret(),
    },
    { source: objectSource(overrides) },
  )
}

it("parses valid env vars", () => {
  const env = makeEnv({
    DATABASE_URL: "postgresql://localhost:5432/db",
    JWT_SECRET: "a".repeat(32),
  })
  expect(env.DATABASE_URL).toBe("postgresql://localhost:5432/db")
  expect(env.PORT).toBe(3000) // default
})

it("throws on missing required vars", () => {
  expect(() => makeEnv({ PORT: "4000" })).toThrow()
})

Enter fullscreen mode Exit fullscreen mode

No beforeEach/afterEach cleanup. No global mutation. Each test gets a fresh environment.

Testing Validation Errors

Catch and inspect specific errors:

import { CtroEnvError } from "@ctroenv/core"

it("reports invalid URL", () => {
  try {
    makeEnv({
      DATABASE_URL: "not-a-url",
      JWT_SECRET: "a".repeat(32),
    })
  } catch (e) {
    expect(e).toBeInstanceOf(CtroEnvError)
    expect((e as CtroEnvError).errors[0].code).toBe("invalid_value")
    expect((e as CtroEnvError).errors[0].key).toBe("DATABASE_URL")
  }
})

it("collects all errors at once", () => {
  try {
    makeEnv({}) // both required vars missing
  } catch (e) {
    expect((e as CtroEnvError).errors).toHaveLength(2)
  }
})

Enter fullscreen mode Exit fullscreen mode

No fix-one-find-another cycle. Every error surfaces in one throw.

Testing Secret Masking

it("masks secret values", () => {
  const env = makeEnv({
    DATABASE_URL: "postgresql://localhost:5432/db",
    JWT_SECRET: "x".repeat(32),
  })
  expect(env.JWT_SECRET).toBe("********")
  expect(env.meta.get("JWT_SECRET")).toBe("x".repeat(32))
})

it("supports custom mask", () => {
  const env = defineEnv(
    { KEY: string().secret() },
    { source: objectSource({ KEY: "value" }), maskWith: "***" },
  )
  expect(env.KEY).toBe("***")
})

Enter fullscreen mode Exit fullscreen mode

Debugging with Error Codes

CtroEnv has four error codes. Each tells you exactly what went wrong:

Code Meaning Example missing_required Variable not in source DATABASE_URL not set type_mismatch Wrong JavaScript type String for number validator invalid_value Failed refinement Invalid URL, port out of range validation_failed Custom .validate() rejected API key format wrong

formatErrors

import { formatErrors } from "@ctroenv/core"

try {
  defineEnv(schema)
} catch (e) {
  if (e instanceof CtroEnvError) {
    process.stderr.write(formatErrors(e.errors))
    // Groups errors by type with colors
  }
}

Enter fullscreen mode Exit fullscreen mode

CI/CD Integration

CtroEnv’s CLI runs in CI without importing your schema — it parses config files directly.

Fast Key Check

npx ctroenv check --source .env.example

Enter fullscreen mode Exit fullscreen mode

Compares keys only. Runs in under a second. Perfect for every PR.

Strict Validation

npx ctroenv check --source .env.staging --strict

Enter fullscreen mode Exit fullscreen mode

Validates values against their validators — catches invalid URLs, out-of-range ports.

Unknown Key Warnings

npx ctroenv check --source .env --warn-unknown

Enter fullscreen mode Exit fullscreen mode

Detects keys in your .env that aren’t in the schema. Uses Levenshtein distance for suggestions:

⚠ Unknown key: "DATABSE_URL"
  → Did you mean "DATABASE_URL"?

Enter fullscreen mode Exit fullscreen mode

JSON Output

npx ctroenv check --source .env --json

Enter fullscreen mode Exit fullscreen mode

{
  "clean": false,
  "summary": { "missing": 1, "unused": 0, "matched": 4 },
  "validationErrors": null
}

Enter fullscreen mode Exit fullscreen mode

Pipe into Slack notifications, monitoring dashboards, or your own tooling.

GitHub Actions

name: Env Check
on: [pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx ctroenv check --source .env.example

Enter fullscreen mode Exit fullscreen mode

Build-Time Validation

Framework plugins validate during the build:

// Vite
ctroenvPlugin({ schema: "./src/env.ts", failOnError: true })

// Next.js
export default withCtroEnv(schema, nextConfig)

Enter fullscreen mode Exit fullscreen mode

If validation fails, the build exits with code 1. No deployment reaches production with a missing DATABASE_URL.

Links: GitHub · Docs · npm

Previous: Framework-Specific Env Patterns
Next: Shipping Reusable Env Schemas

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다