envalid
Version:
Validation for your environment variables
148 lines (121 loc) • 5.37 kB
JavaScript
const { createGroup, assert } = require('painless')
const { cleanEnv, EnvError, EnvMissingError, str, num } = require('..')
const { assertPassthrough } = require('./utils')
const test = createGroup()
const makeSilent = { reporter: null }
test('string passthrough', () => {
assertPassthrough({ FOO: 'bar' }, { FOO: str() })
})
test('strict option: only specified fields are passed through', () => {
const opts = { strict: true }
const env = cleanEnv({ FOO: 'bar', BAZ: 'baz' }, {
FOO: str()
}, opts)
assert.deepEqual(env, { FOO: 'bar' })
})
test('transformer option: allow transformation of keys', () => {
const opts = {
transformer: i => Object
.keys(i)
.map(e => [e, i[e]])
.reduce((memo, [key, value]) => Object.assign({}, memo, { [key.toLowerCase()]: value }), {})
}
const env = cleanEnv({ FOO: 'bar', FOO_BAR: 'baz' }, {
FOO: str()
}, opts)
assert.deepEqual(env, { foo: 'bar', foo_bar: 'baz' })
})
test('missing required string field', () => {
assert.throws(() => cleanEnv({}, { FOO: str() }, makeSilent), EnvMissingError)
})
test('output is immutable', () => {
const env = cleanEnv({ FOO: 'bar' }, { FOO: str() })
env.FOO = 'baz'
assert.strictEqual(env.FOO, 'bar')
})
test('using provided default value', () => {
const env = cleanEnv({}, {
FOO: str({ default: 'asdf' })
})
assert.deepEqual(env, { FOO: 'asdf' })
})
test('default value can be blank', () => {
const env = cleanEnv({}, {
FOO: str({ default: '' })
})
assert.deepEqual(env, { FOO: '' })
})
test('devDefault', () => {
const spec = {
FOO: str({ devDefault: 'hi' })
}
// For testing/development environments, devDefault values can make fields optional:
const env = cleanEnv({ NODE_ENV: 'test' }, spec)
assert.deepEqual(env, { NODE_ENV: 'test', FOO: 'hi' })
// For a production environment, the field is required:
assert.throws(() => cleanEnv({ NODE_ENV: 'production' }, spec, makeSilent), EnvMissingError)
})
test('falsy devDefault', () => {
// Falsy values for devDefault work the same as falsy regular defaults
const spec = {
FOO: str({ devDefault: '' })
}
const env = cleanEnv({ NODE_ENV: 'test' }, spec)
assert.deepEqual(env, { NODE_ENV: 'test', FOO: '' })
assert.throws(() => cleanEnv({ NODE_ENV: 'production' }, spec, makeSilent), EnvMissingError)
})
test('devDefault and default together', () => {
const spec = {
FOO: num({ devDefault: 3000, default: 80 })
}
const env = cleanEnv({ NODE_ENV: 'test' }, spec)
assert.deepEqual(env, { NODE_ENV: 'test', FOO: 3000 })
const prodEnv = cleanEnv({ NODE_ENV: 'production' }, spec)
assert.deepEqual(prodEnv, { NODE_ENV: 'production', FOO: 80 })
})
test('choices field', () => {
// Throws when the env var isn't in the given choices:
const spec = {
FOO: str({ choices: ['foo', 'bar', 'baz'] })
}
assert.throws(() => cleanEnv({}, spec, makeSilent), EnvMissingError)
assert.throws(() => cleanEnv({ FOO: 'bad' }, spec, makeSilent), EnvError, 'not in choices')
// Works fine when a valid choice is given
assertPassthrough({ FOO: 'bar' }, spec)
assertPassthrough({ FOO: 'foo' }, spec)
assertPassthrough({ FOO: 'baz' }, spec)
// Throws an error when `choices` is not an array
assert.throws(() => cleanEnv({ FOO: 'hi' }, { FOO: str({ choices: 123 }) }, makeSilent),
Error, 'must be an array')
})
test('misconfigured spec', () => {
// Validation throws with different error if spec is invalid
assert.throws(() => cleanEnv({ FOO: 'asdf' }, { FOO: {} }, makeSilent), EnvError, 'Invalid spec')
})
test('NODE_ENV built-in support', () => {
// By default, envalid will parse and accept 3 standard NODE_ENV values:
assertPassthrough({ NODE_ENV: 'production' }, {})
assertPassthrough({ NODE_ENV: 'development' }, {})
assertPassthrough({ NODE_ENV: 'test' }, {})
// Some convenience helpers are available on the cleaned env object:
assert.strictEqual(cleanEnv({ NODE_ENV: 'production' }, {}).isProduction, true)
assert.strictEqual(cleanEnv({ NODE_ENV: 'test' }, {}).isTest, true)
assert.strictEqual(cleanEnv({ NODE_ENV: 'development' }, {}).isDev, true)
// assume production if NODE_ENV is not specified:
assert.strictEqual(cleanEnv({}, {}).isProduction, true)
assert.strictEqual(cleanEnv({}, {}).isDev, false)
assert.strictEqual(cleanEnv({}, {}).isTest, false)
// Non-standard values throw an error:
assert.throws(() => cleanEnv({ NODE_ENV: 'asdf' }, {}, makeSilent), EnvError, 'not in choices')
// NODE_ENV should always be set. If it is un-set, isProduction & isDev
// still use the default value:
const unsetEnv = cleanEnv({ NODE_ENV: '' }, {})
assert.strictEqual(unsetEnv.isProduction, true)
assert.strictEqual(unsetEnv.isDev, false)
// You can override the built-in NODE_ENV validation if you want
// The built-in convenience helpers can't be overridden though.
const customSpec = { NODE_ENV: str({ default: 'FOO' }) }
assert.deepEqual(cleanEnv({}, customSpec), { NODE_ENV: 'FOO' })
assert.strictEqual(cleanEnv({}, customSpec).isProduction, false)
assert.strictEqual(cleanEnv({}, customSpec).isDev, false)
})