You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							347 lines
						
					
					
						
							6.6 KiB
						
					
					
				
			
		
		
	
	
							347 lines
						
					
					
						
							6.6 KiB
						
					
					
				'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')
 | 
						|
  })
 | 
						|
})
 |