Skip to content

Commit b782e30

Browse files
Add tests for env helpers and use broken logger (#66)
1 parent 51243aa commit b782e30

File tree

5 files changed

+198
-2
lines changed

5 files changed

+198
-2
lines changed

.github/workflows/main-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ env:
1414
TEST_DB_NAME: test_db
1515
TEST_DB_PORT: 5432
1616
JWT_SECRET: secret
17+
LOGGER_TYPE: broken
1718

1819
jobs:
1920
e2e-tests:

.github/workflows/pull-request.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ env:
2020
TEST_DB_NAME: test_db
2121
TEST_DB_PORT: 5432
2222
JWT_SECRET: secret
23+
LOGGER_TYPE: broken
2324

2425
jobs:
2526
type-check-lint-and-build:

src/app/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const createServer = (container: Container) => {
3636

3737
// This is the last request middleware, if no other middleware handled the request, it means
3838
// the route is not found, so we throw a not found error
39-
app.get('/{*splat}', (req, res) => {
39+
app.use((_req, _res) => {
4040
throw HttpError.notFound('Resource not found');
4141
});
4242

src/core/env/env.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { config } from 'dotenv';
22

33
config();
44

5-
export function isDefined<T>(value: T | undefined): value is T {
5+
function isDefined<T>(value: T | undefined): value is T {
66
return value !== undefined && value !== '';
77
}
88

src/tests/unit/core/env.test.ts

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import {
2+
env,
3+
mandatoryEnv,
4+
integerEnv,
5+
mandatoryIntegerEnv,
6+
booleanEnv,
7+
mandatoryBooleanEnv,
8+
unionEnv,
9+
} from '@/core/env/env';
10+
11+
describe('Env helpers', () => {
12+
const ORIGINAL_ENV = process.env;
13+
14+
beforeEach(() => {
15+
process.env = { ...ORIGINAL_ENV };
16+
});
17+
18+
afterEach(() => {
19+
process.env = ORIGINAL_ENV;
20+
});
21+
22+
describe('env', () => {
23+
const KEY = 'TEST_STRING_ENV';
24+
25+
test('returns value when defined', () => {
26+
process.env[KEY] = 'hello';
27+
expect(env(KEY, 'default')).toBe('hello');
28+
});
29+
30+
test('returns default when undefined', () => {
31+
delete process.env[KEY];
32+
expect(env(KEY, 'default')).toBe('default');
33+
});
34+
35+
test('returns default when empty string', () => {
36+
process.env[KEY] = '';
37+
expect(env(KEY, 'default')).toBe('default');
38+
});
39+
});
40+
41+
describe('mandatoryEnv', () => {
42+
const KEY = 'TEST_MANDATORY_STRING_ENV';
43+
44+
test('returns value when defined', () => {
45+
process.env[KEY] = 'present';
46+
expect(mandatoryEnv(KEY)).toBe('present');
47+
});
48+
49+
test('throws when undefined', () => {
50+
delete process.env[KEY];
51+
expect(() => mandatoryEnv(KEY)).toThrow(`Variable ${KEY} not found in environment`);
52+
});
53+
54+
test('throws when empty string', () => {
55+
process.env[KEY] = '';
56+
expect(() => mandatoryEnv(KEY)).toThrow(`Variable ${KEY} not found in environment`);
57+
});
58+
});
59+
60+
describe('integerEnv', () => {
61+
const KEY = 'TEST_INT_ENV';
62+
63+
test('parses integer when defined', () => {
64+
process.env[KEY] = '42';
65+
expect(integerEnv(KEY, 5)).toBe(42);
66+
});
67+
68+
test('returns default when undefined', () => {
69+
delete process.env[KEY];
70+
expect(integerEnv(KEY, 5)).toBe(5);
71+
});
72+
73+
test('returns default when empty string', () => {
74+
process.env[KEY] = '';
75+
expect(integerEnv(KEY, 5)).toBe(5);
76+
});
77+
78+
test('returns NaN when non-numeric string is provided', () => {
79+
process.env[KEY] = 'abc';
80+
expect(Number.isNaN(integerEnv(KEY, 5))).toBe(true);
81+
});
82+
});
83+
84+
describe('mandatoryIntegerEnv', () => {
85+
const KEY = 'TEST_MANDATORY_INT_ENV';
86+
87+
test('parses integer when defined', () => {
88+
process.env[KEY] = '10';
89+
expect(mandatoryIntegerEnv(KEY)).toBe(10);
90+
});
91+
92+
test('throws when undefined', () => {
93+
delete process.env[KEY];
94+
expect(() => mandatoryIntegerEnv(KEY)).toThrow(`Variable ${KEY} not found in environment`);
95+
});
96+
97+
test('throws when empty string', () => {
98+
process.env[KEY] = '';
99+
expect(() => mandatoryIntegerEnv(KEY)).toThrow(`Variable ${KEY} not found in environment`);
100+
});
101+
102+
test('returns NaN when non-numeric string is provided', () => {
103+
process.env[KEY] = 'abc';
104+
expect(Number.isNaN(mandatoryIntegerEnv(KEY))).toBe(true);
105+
});
106+
});
107+
108+
describe('booleanEnv', () => {
109+
const KEY = 'TEST_BOOL_ENV';
110+
111+
test('returns true when value is "true"', () => {
112+
process.env[KEY] = 'true';
113+
expect(booleanEnv(KEY, false)).toBe(true);
114+
});
115+
116+
test('returns false when value is "false"', () => {
117+
process.env[KEY] = 'false';
118+
expect(booleanEnv(KEY, true)).toBe(false);
119+
});
120+
121+
test('returns default when undefined', () => {
122+
delete process.env[KEY];
123+
expect(booleanEnv(KEY, true)).toBe(true);
124+
});
125+
126+
test('returns default when empty string', () => {
127+
process.env[KEY] = '';
128+
expect(booleanEnv(KEY, true)).toBe(true);
129+
});
130+
131+
test('throws when value is not "true" or "false"', () => {
132+
process.env[KEY] = 'yes';
133+
expect(() => booleanEnv(KEY, false)).toThrow(`Variable ${KEY} must be a boolean`);
134+
});
135+
});
136+
137+
describe('mandatoryBooleanEnv', () => {
138+
const KEY = 'TEST_MANDATORY_BOOL_ENV';
139+
140+
test('returns true when value is "true"', () => {
141+
process.env[KEY] = 'true';
142+
expect(mandatoryBooleanEnv(KEY)).toBe(true);
143+
});
144+
145+
test('returns false when value is "false"', () => {
146+
process.env[KEY] = 'false';
147+
expect(mandatoryBooleanEnv(KEY)).toBe(false);
148+
});
149+
150+
test('throws when undefined', () => {
151+
delete process.env[KEY];
152+
expect(() => mandatoryBooleanEnv(KEY)).toThrow(`Variable ${KEY} not found in environment`);
153+
});
154+
155+
test('throws when empty string', () => {
156+
process.env[KEY] = '';
157+
expect(() => mandatoryBooleanEnv(KEY)).toThrow(`Variable ${KEY} not found in environment`);
158+
});
159+
160+
test('throws when value is not "true" or "false"', () => {
161+
process.env[KEY] = 'yes';
162+
expect(() => mandatoryBooleanEnv(KEY)).toThrow(`Variable ${KEY} must be a boolean`);
163+
});
164+
});
165+
166+
describe('unionEnv', () => {
167+
const KEY = 'TEST_UNION_ENV';
168+
const allowed = ['dev', 'prod'];
169+
170+
test('returns value when it is in allowed values', () => {
171+
process.env[KEY] = 'prod';
172+
expect(unionEnv(KEY, allowed, 'dev')).toBe('prod');
173+
});
174+
175+
test('returns default when undefined', () => {
176+
delete process.env[KEY];
177+
expect(unionEnv(KEY, allowed, 'dev')).toBe('dev');
178+
});
179+
180+
test('returns default when empty string', () => {
181+
process.env[KEY] = '';
182+
expect(unionEnv(KEY, allowed, 'dev')).toBe('dev');
183+
});
184+
185+
test('throws when value not in allowed values', () => {
186+
process.env[KEY] = 'staging';
187+
expect(() => unionEnv(KEY, allowed, 'dev')).toThrow(
188+
`Variable ${KEY} must be one of ${allowed.join(', ')}`,
189+
);
190+
});
191+
});
192+
});
193+
194+

0 commit comments

Comments
 (0)