test-input-validation.helper.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /**
  2. * Module dependencies
  3. */
  4. var util = require('util');
  5. var _ = require('@sailshq/lodash');
  6. var rttc = require('rttc');
  7. var Machine = require('../../');
  8. var isEquivalent = require('../../node_modules/rttc/spec/helpers/is-equivalent');
  9. module.exports = function testInputValidation(expectations, cb){
  10. // Determine type schema of the value.
  11. // (using inference to pull it from the `example`, if provided)
  12. var typeSchema;
  13. if (!_.isUndefined(expectations.typeclass)) {
  14. if (expectations.typeclass==='dictionary') {
  15. typeSchema = {};
  16. }
  17. else if (expectations.typeclass==='array') {
  18. typeSchema = [];
  19. }
  20. else {
  21. typeSchema = 'ref';
  22. }
  23. }
  24. else {
  25. typeSchema = rttc.infer(expectations.example);
  26. }
  27. var _inputsInFn;
  28. var machine = Machine.build({
  29. inputs: {
  30. x: (function _determineInputDefinition(){
  31. var def = {};
  32. if (_.isUndefined(expectations.required)) {
  33. // Act like `required` is always present so we can
  34. // use the existing test suite from `rttc()`.
  35. def.required = true;
  36. }
  37. if (!_.isUndefined(expectations.example)) {
  38. def.example = expectations.example;
  39. }
  40. if (!_.isUndefined(expectations.typeclass)) {
  41. def.typeclass = expectations.typeclass;
  42. }
  43. if (!_.isUndefined(expectations.getExample)) {
  44. def.getExample = expectations.getExample;
  45. }
  46. if (!_.isUndefined(expectations.validate)) {
  47. def.validate = expectations.validate;
  48. }
  49. return def;
  50. })()
  51. },
  52. exits: {
  53. error: {},
  54. success: {}
  55. },
  56. fn: function (inputs, exits) {
  57. _inputsInFn = inputs;
  58. exits();
  59. }
  60. })
  61. .configure({
  62. x: expectations.actual
  63. })
  64. .exec(function (err){
  65. // validate that error exit was traversed, if expected
  66. if (err){
  67. if (expectations.error) return cb();
  68. return cb(new Error('did not expect machine to call `error`, but it did:\n' + util.inspect(err)));
  69. }
  70. else if (expectations.error) {
  71. // console.log('\nTEST:',expectations);
  72. // if (_.isObject(expectations.actual)) {
  73. // console.log('\nactual constructor name:',expectations.actual.constructor.name);
  74. // }
  75. // console.log('\nTYPESCHEMA:',typeSchema);
  76. return cb(new Error('expected machine to call `error` exit due to input validation error, but it did not. ' + ('Instead got '+util.inspect(_inputsInFn.x, false, null))+'.' ));
  77. }
  78. if (!_.isObject(_inputsInFn)) {
  79. return cb(new Error('`inputs` argument in machine fn was corrupted!'));
  80. }
  81. // If an expected `result` is provided, compare the actual result against that.
  82. // Otherwise compare it against the original value (`actual`)
  83. var compareTo = expectations.hasOwnProperty('result') ? expectations.result : expectations.actual;
  84. // Provide direct access to actual result for clarity in comparisons below.
  85. var actualResult = _inputsInFn.x;
  86. // use `isEquivalent` from `rttc`
  87. if (!isEquivalent(actualResult, compareTo, typeSchema)) {
  88. return cb(new Error('returned incorrect value: '+util.inspect(actualResult, false, null)));
  89. }
  90. // Test using strict equality (===) if explicitly requested
  91. if (expectations.strictEq) {
  92. if (actualResult !== compareTo) {
  93. return cb(new Error('returned value is equivalent (but not ===)'));
  94. }
  95. }
  96. // Test AGAINST strict equality using `isNew` if requested
  97. // (i.e. guarantees this is a new value and is !== what was passed in)
  98. if (expectations.isNew) {
  99. // Check both the expected result and the actual value, just to be safe.
  100. // (should never even be possible for it to be a direct reference to the expected result)
  101. if (actualResult === compareTo || actualResult === expectations.actual) {
  102. return cb(new Error('returned value === value that was passed in -- but should have been a new value!'));
  103. }
  104. }
  105. // If we made it here, everything's good!
  106. return cb();
  107. });
  108. };