Skip to content

Commit 4444d7e

Browse files
author
A.P.A. Slaa
committed
fix: added coverage in tests and updated docs
1 parent 2c6e935 commit 4444d7e

3 files changed

Lines changed: 53 additions & 4 deletions

File tree

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ No dependencies, focus on runtime safety.
1313
Key features:
1414
- Load `.env` file (ignores comments, blank lines, quotes) and merge into `process.env`.
1515
- Access variables via `.string()`, `.number()`, `.boolean()` with defaults.
16-
- Check keys with `.has()`, `.defined()`.
16+
- Check keys with `.has()`, `.defined()`, `.assert()`.
1717
- Get `env.dev` boolean for “development vs production” mode.
1818
- Collect variables with a common prefix via `.collection()`, optional prefix removal & reviver.
1919
- Utility method `.utils.select()` for feature‐flag style branching.
@@ -84,7 +84,7 @@ When you have many environment variables prefixed in a group:
8484
8585
```ts
8686
// .env
87-
API_URL=https://api.example.com
87+
API_URL="https://api.example.com"
8888
API_KEY=abcdef
8989
API_TIMEOUT=5000
9090
@@ -120,11 +120,12 @@ const mode = env.utils.select("FEATURE_X", "enabled", "disabled");
120120
## API Reference
121121
122122
| Method | Description |
123-
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
123+
|--------------------------------------------------|-----------------------------------------------------------------------------------------------------|
124124
| `env.string(key, default?)` | Return the variable as a string (or default). |
125125
| `env.number(key, default?)` | Parse variable to number (or default). |
126126
| `env.boolean(key, default?)` | Parse variable to boolean (or default). |
127127
| `env.has(key)` | Returns true if key exists in `process.env`. |
128+
| `env.assert([keys], error_builder?)` | Throws an error if one or more keys doesn't exists in `process.env`. |
128129
| `env.defined(key)` | Returns true if key exists and value is not `undefined`. |
129130
| `env.dev` | Boolean flag: true if `NODE_ENV !== "production"`. |
130131
| `env.collection(prefix, options?)` | Get an object of all env keys starting with `prefix`. Options include `removePrefix` and `reviver`. |

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const env = Object.freeze({
6767
},
6868
assert(keys: Uppercase<string>[], error_builder: (missing_keys: string[]) => string | Error = ((missing_keys) => new Error(`Missing required keys(${missing_keys.join()}) in environment`)),) {
6969
const missing_keys: string[] = [];
70-
keys.forEach((key) => this.has(key) ? missing_keys.push(key) : void 0);
70+
keys.forEach((key) => this.has(key) ? void 0: missing_keys.push(key));
7171
if (missing_keys.length > 0) {
7272
const result = error_builder(missing_keys);
7373
if (typeof result === "string") throw new Error(result);

tests/env.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,52 @@ describe("env library", () => {
122122
env = (await import("../src")).env;
123123
expect(env.raw).toBeTypeOf('object');
124124
});
125+
126+
it("assert throws error when required keys are missing (default error)", async () => {
127+
mockExistsSync.mockReturnValue(false);
128+
env = (await import("../src")).env;
129+
130+
// Define one key
131+
env.string("EXISTING_KEY", "present");
132+
133+
// Assert on a missing key
134+
expect(() => env.assert(["MISSING_KEY"])).toThrow(
135+
'Missing required keys(MISSING_KEY) in environment'
136+
);
137+
});
138+
139+
it("assert throws custom error when required keys are missing", async () => {
140+
mockExistsSync.mockReturnValue(false);
141+
env = (await import("../src")).env;
142+
143+
const customErrorBuilder = (missing: string[]) =>
144+
new Error(`Custom: ${missing.join(", ")} are missing!`);
145+
146+
expect(() => env.assert(["A", "B"], customErrorBuilder)).toThrow(
147+
"Custom: A, B are missing!"
148+
);
149+
});
150+
151+
it("assert throws custom string error (converted to Error)", async () => {
152+
mockExistsSync.mockReturnValue(false);
153+
env = (await import("../src")).env;
154+
155+
const stringErrorBuilder = (missing: string[]) =>
156+
`STRING ERROR: missing ${missing.join("+")}`;
157+
158+
expect(() => env.assert(["X"], stringErrorBuilder)).toThrow(
159+
"STRING ERROR: missing X"
160+
);
161+
});
162+
163+
it("assert does nothing when all required keys exist", async () => {
164+
mockExistsSync.mockReturnValue(false);
165+
env = (await import("../src")).env;
166+
167+
env.string("KEY1", "val1");
168+
env.string("KEY2", "val2");
169+
170+
// Should not throw
171+
expect(() => env.assert(["KEY1", "KEY2"])).not.toThrow();
172+
});
125173
});

0 commit comments

Comments
 (0)