mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
1ea72dca97
NODE_ENV="production " passed the boot check but matched none of the
exact production comparisons, so the web UI was never served and every
page answered {"error":"Cannot GET /"}, while the banner showed a clean
"production". The boot import now trims these three variables in
process.env before anything else reads them, so Express, the plugin
children and readEnv() agree, and reports each change as a process
warning. Casing stays as it was. A padded "test" is only reported, so an
instance cannot switch to an in-memory database after an update. The
banner prints NODE_ENV as set instead of lowercasing it.
Refs #2565
71 lines
3.0 KiB
TypeScript
71 lines
3.0 KiB
TypeScript
import { normalizeEnvAtBoot, readEnv } from '../../../src/app-config/env';
|
|
|
|
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
|
|
/** Everything one normalisation printed as a warning. */
|
|
function warnings(raw: Record<string, string | undefined>): string {
|
|
const warn = vi.spyOn(process, 'emitWarning').mockImplementation(() => {});
|
|
normalizeEnvAtBoot(raw);
|
|
const printed = warn.mock.calls.map((c) => String(c[0])).join('\n');
|
|
warn.mockRestore();
|
|
return printed;
|
|
}
|
|
|
|
describe('normalizeEnvAtBoot (#2565)', () => {
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
vi.unstubAllEnvs();
|
|
vi.resetModules();
|
|
});
|
|
|
|
it('trims a padded NODE_ENV in place and says so', () => {
|
|
for (const padded of ['production ', ' production', 'production\r', '\tproduction\n']) {
|
|
const raw: Record<string, string | undefined> = { NODE_ENV: padded };
|
|
const printed = warnings(raw);
|
|
expect(raw.NODE_ENV, JSON.stringify(padded)).toBe('production');
|
|
expect(printed).toContain(`NODE_ENV=${JSON.stringify(padded)}`);
|
|
expect(printed).toContain('"production"');
|
|
}
|
|
});
|
|
|
|
it('trims LOG_LEVEL and DEFAULT_LANGUAGE the same way', () => {
|
|
const raw: Record<string, string | undefined> = { LOG_LEVEL: 'debug ', DEFAULT_LANGUAGE: ' de' };
|
|
const printed = warnings(raw);
|
|
expect(raw.LOG_LEVEL).toBe('debug');
|
|
expect(raw.DEFAULT_LANGUAGE).toBe('de');
|
|
expect(printed).toContain('LOG_LEVEL="debug "');
|
|
expect(printed).toContain('DEFAULT_LANGUAGE=" de"');
|
|
});
|
|
|
|
it('leaves clean, unset and differently cased values alone and stays quiet', () => {
|
|
const raw: Record<string, string | undefined> = { NODE_ENV: 'Production', LOG_LEVEL: 'info' };
|
|
expect(warnings(raw)).toBe('');
|
|
expect(raw).toEqual({ NODE_ENV: 'Production', LOG_LEVEL: 'info' });
|
|
});
|
|
|
|
it('does not turn a padded "test" into the test runtime', () => {
|
|
// NODE_ENV=test means an in-memory database and no crons. An instance that
|
|
// has been running on "test " with its file database must not wake up on
|
|
// an empty one after an update, so this one is only reported.
|
|
const raw: Record<string, string | undefined> = { NODE_ENV: 'test ' };
|
|
const printed = warnings(raw);
|
|
expect(raw.NODE_ENV).toBe('test ');
|
|
expect(printed).toContain('NODE_ENV="test "');
|
|
});
|
|
|
|
it('never touches other variables, secrets keep their surrounding spaces', () => {
|
|
const raw: Record<string, string | undefined> = { SMTP_PASS: ' pass ', TZ: 'UTC ' };
|
|
expect(warnings(raw)).toBe('');
|
|
expect(raw).toEqual({ SMTP_PASS: ' pass ', TZ: 'UTC ' });
|
|
});
|
|
|
|
it('runs from the boot import, so everything reading process.env sees the trimmed value', async () => {
|
|
vi.stubEnv('NODE_ENV', 'production ');
|
|
vi.spyOn(process, 'emitWarning').mockImplementation(() => {});
|
|
await import('../../../src/app-config/boot-validate');
|
|
expect(process.env.NODE_ENV).toBe('production');
|
|
expect(readEnv().app.nodeEnv).toBe('production');
|
|
expect(readEnv().app.isProduction).toBe(true);
|
|
});
|
|
});
|