'use strict' const t = require('tap') const Ajv = require('ajv') const makeTest = require('./make-test') const { join } = require('path') process.env.VALUE_FROM_ENV = 'pippo' const tests = [ { name: 'empty ok', schema: { type: 'object' }, data: { }, isOk: true, confExpected: {} }, { name: 'simple object - ok', schema: { type: 'object', properties: { PORT: { type: 'string' } } }, data: { PORT: '44' }, isOk: true, confExpected: { PORT: '44' } }, { name: 'simple object - ok - coerce value', schema: { type: 'object', properties: { PORT: { type: 'integer' } } }, data: { PORT: '44' }, isOk: true, confExpected: { PORT: 44 } }, { name: 'simple object - ok - remove additional properties', schema: { type: 'object', properties: { PORT: { type: 'integer' } } }, data: { PORT: '44', ANOTHER_PORT: '55' }, isOk: true, confExpected: { PORT: 44 } }, { name: 'simple object - ok - use default', schema: { type: 'object', properties: { PORT: { type: 'integer', default: 5555 } } }, data: { }, isOk: true, confExpected: { PORT: 5555 } }, { name: 'simple object - ok - required + default', schema: { type: 'object', required: ['PORT'], properties: { PORT: { type: 'integer', default: 6666 } } }, data: { }, isOk: true, confExpected: { PORT: 6666 } }, { name: 'simple object - ok - allow array', schema: { type: 'object', required: ['PORT'], properties: { PORT: { type: 'integer', default: 6666 } } }, data: [{ }], isOk: true, confExpected: { PORT: 6666 } }, { name: 'simple object - ok - merge multiple object + env', schema: { type: 'object', required: ['PORT', 'MONGODB_URL'], properties: { PORT: { type: 'integer', default: 6666 }, MONGODB_URL: { type: 'string' }, VALUE_FROM_ENV: { type: 'string' } } }, data: [{ PORT: 3333 }, { MONGODB_URL: 'mongodb://localhost/pippo' }], isOk: true, confExpected: { PORT: 3333, MONGODB_URL: 'mongodb://localhost/pippo', VALUE_FROM_ENV: 'pippo' } }, { name: 'simple object - ok - load only from env', schema: { type: 'object', required: ['VALUE_FROM_ENV'], properties: { VALUE_FROM_ENV: { type: 'string' } } }, data: undefined, isOk: true, confExpected: { VALUE_FROM_ENV: 'pippo' } }, { name: 'simple object - ok - opts override environment', schema: { type: 'object', required: ['VALUE_FROM_ENV'], properties: { VALUE_FROM_ENV: { type: 'string' } } }, data: { VALUE_FROM_ENV: 'pluto' }, isOk: true, confExpected: { VALUE_FROM_ENV: 'pluto' } }, { name: 'simple object - ok - load only from .env', schema: { type: 'object', required: ['VALUE_FROM_DOTENV'], properties: { VALUE_FROM_DOTENV: { type: 'string' } } }, data: undefined, isOk: true, dotenv: { path: join(__dirname, '.env') }, confExpected: { VALUE_FROM_DOTENV: 'look ma' } }, { name: 'simple object - KO', schema: { type: 'object', required: ['PORT'], properties: { PORT: { type: 'integer' } } }, data: { }, isOk: false, errorMessage: 'env must have required property \'PORT\'' }, { name: 'simple object - invalid data', schema: { type: 'object', required: ['PORT'], properties: { PORT: { type: 'integer' } } }, data: [], isOk: false, errorMessage: 'opts/data must NOT have fewer than 1 items, opts/data must be object, opts/data must match exactly one schema in oneOf' } ] const ajv = new Ajv({ allErrors: true, removeAdditional: true, useDefaults: true, coerceTypes: true, allowUnionTypes: true }) tests.forEach(function (testConf) { t.test(testConf.name, t => { const options = { schema: testConf.schema, data: testConf.data, dotenv: testConf.dotenv, dotenvConfig: testConf.dotenvConfig, ajv } makeTest(t, options, testConf.isOk, testConf.confExpected, testConf.errorMessage) }) }) const noCoercionTest = { name: 'simple object - not ok - should NOT coerce value', schema: { type: 'object', properties: { PORT: { type: 'integer' } } }, data: { PORT: '44' }, isOk: false, errorMessage: 'env/PORT must be integer', confExpected: { PORT: 44 } } const strictValidator = new Ajv({ allErrors: true, removeAdditional: true, useDefaults: true, coerceTypes: false, allowUnionTypes: true }); [noCoercionTest].forEach(function (testConf) { t.test(testConf.name, t => { const options = { schema: testConf.schema, data: testConf.data, dotenv: testConf.dotenv, dotenvConfig: testConf.dotenvConfig, ajv: strictValidator } makeTest(t, options, testConf.isOk, testConf.confExpected, testConf.errorMessage) }) }) t.test('ajv enhancement', t => { t.plan(2) const testCase = { schema: { type: 'object', required: ['MONGODB_URL'], properties: { MONGODB_URL: { type: 'string', format: 'uri' } } }, data: [{ PORT: 3333 }, { MONGODB_URL: 'mongodb://localhost/pippo' }], isOk: true, confExpected: { MONGODB_URL: 'mongodb://localhost/pippo' } } t.test('return', t => { const options = { schema: testCase.schema, data: testCase.data, ajv: { customOptions (ajvInstance) { require('ajv-formats')(ajvInstance) return ajvInstance } } } makeTest(t, options, testCase.isOk, testCase.confExpected) }) t.test('no return', t => { const options = { schema: testCase.schema, data: testCase.data, ajv: { customOptions (ajvInstance) { // do nothing } } } makeTest(t, options, false, undefined, 'customOptions function must return an instance of Ajv') }) })