Skip to content

Commit 13dc7c0

Browse files
committed
feat(config): add tests for environment variable placeholder replacement
1 parent 2626e86 commit 13dc7c0

File tree

2 files changed

+65
-10
lines changed

2 files changed

+65
-10
lines changed

apps/generator-cli/src/app/services/config.service.spec.ts

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ describe('ConfigService', () => {
9494
});
9595

9696
describe('the config has values having placeholders', () => {
97+
let originalEnv: NodeJS.ProcessEnv;
98+
9799
beforeEach(() => {
100+
originalEnv = { ...process.env };
101+
98102
fs.readJSONSync.mockReturnValue({
99103
$schema: 'foo.json',
100104
spaces: 4,
@@ -111,19 +115,16 @@ describe('ConfigService', () => {
111115
});
112116

113117
afterEach(() => {
114-
delete process.env['__unit_test_username'];
115-
delete process.env['__unit_test_password'];
116-
})
118+
process.env = { ...originalEnv };
119+
});
117120

118121
it('verify placeholder replaced with env vars', () => {
119122
const value = fixture.get('generator-cli.repository.queryUrl');
120-
121123
expect(value).toEqual('https://myusername:mypassword@server/api');
122124
});
123125

124126
it('verify placeholders not matching env vars are not replaced', () => {
125127
const value = fixture.get('generator-cli.repository.downloadUrl');
126-
127128
expect(value).toEqual('https://${env.__unit_test_non_matching}@server/api');
128129
expect(error).toHaveBeenCalledWith('Environment variable for placeholder \'__unit_test_non_matching\' not found.');
129130
});
@@ -221,5 +222,60 @@ describe('ConfigService', () => {
221222
});
222223
});
223224
});
225+
226+
describe('replacePlaceholders', () => {
227+
let originalEnv: NodeJS.ProcessEnv;
228+
229+
beforeEach(() => {
230+
jest.clearAllMocks();
231+
originalEnv = { ...process.env };
232+
});
233+
234+
afterEach(() => {
235+
process.env = { ...originalEnv };
236+
});
237+
238+
it('replaces a simple placeholder with an environment variable', () => {
239+
process.env.TEST_VAR = 'value1';
240+
const input = { key: 'Hello ${TEST_VAR}' };
241+
const result = fixture['replacePlaceholders'](input);
242+
expect(result.key).toBe('Hello value1');
243+
});
244+
245+
it('leaves placeholder unchanged and logs error if env var is missing', () => {
246+
delete process.env.MISSING_VAR;
247+
const input = { key: 'Hello ${MISSING_VAR}' };
248+
const result = fixture['replacePlaceholders'](input);
249+
expect(result.key).toBe('Hello ${MISSING_VAR}');
250+
expect(error).toHaveBeenCalledWith(expect.stringContaining('MISSING_VAR'));
251+
});
252+
253+
it('replaces placeholders in nested objects and arrays', () => {
254+
process.env.NESTED_VAR = 'nested';
255+
const input = {
256+
arr: ['${NESTED_VAR}', { inner: '${NESTED_VAR}' }],
257+
obj: { deep: '${NESTED_VAR}' },
258+
};
259+
const result = fixture['replacePlaceholders'](input);
260+
expect(result.arr[0]).toBe('nested');
261+
expect((result.arr[1] as { inner: string }).inner).toBe('nested');
262+
expect((result.obj as { deep: string }).deep).toBe('nested');
263+
});
264+
265+
it('handles env. prefix in placeholders', () => {
266+
process.env.PREFIX_VAR = 'prefix';
267+
const input = { key: 'Value: ${env.PREFIX_VAR}' };
268+
const result = fixture['replacePlaceholders'](input);
269+
expect(result.key).toBe('Value: prefix');
270+
});
271+
272+
it('replaces multiple placeholders in a single string', () => {
273+
process.env.FIRST = 'one';
274+
process.env.SECOND = 'two';
275+
const input = { key: 'Values: ${FIRST}, ${SECOND}' };
276+
const result = fixture['replacePlaceholders'](input);
277+
expect(result.key).toBe('Values: one, two');
278+
});
279+
});
224280
});
225281
});

apps/generator-cli/src/app/services/config.service.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class ConfigService {
7676
return Object.prototype.hasOwnProperty.call(obj, head);
7777
}
7878

79-
return hasPath((obj as Record<string, unknown>)[head] as Record<string, unknown> | undefined, tail);
79+
return hasPath(obj[head] as Record<string, unknown>, tail);
8080
};
8181

8282
return hasPath(this.read(), path.split('.'));
@@ -148,10 +148,9 @@ export class ConfigService {
148148
private replacePlaceholders(config: Record<string, unknown>): Record<string, unknown> {
149149
const replacePlaceholderInString = (inputString: string): string => {
150150
return inputString.replace(/\${(.*?)}/g, (fullMatch, placeholderKey) => {
151-
const trimmedKey = placeholderKey.trim();
152-
const environmentVariableKey = trimmedKey.startsWith('env.')
153-
? trimmedKey.substring(4)
154-
: trimmedKey;
151+
const environmentVariableKey = placeholderKey.startsWith('env.')
152+
? placeholderKey.substring(4)
153+
: placeholderKey;
155154

156155
const environmentVariableValue = process.env[environmentVariableKey];
157156

0 commit comments

Comments
 (0)