Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

Commit

Permalink
feat: adds "method" field validation
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-zakharchenko committed Jun 4, 2019
1 parent 71a02bc commit b575e93
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 4 deletions.
38 changes: 34 additions & 4 deletions lib/next/test/integration/validateMessage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,14 @@ describe('validateMessage', () => {
});

it('contains all validatable keys', () => {
assert.hasAllKeys(result.field, ['headers', 'body']);
assert.hasAllKeys(result.field, ['method', 'headers', 'body']);
});

describe('method', () => {
validator(result.field.method, null);
expectedType(result.field.method, 'text/vnd.apiary.method');
realType(result.field.method, 'text/vnd.apiary.method');
noErrors(result.field.method);
});

describe('headers', () => {
Expand Down Expand Up @@ -90,12 +97,35 @@ describe('validateMessage', () => {
});

it('contains all validatable keys', () => {
assert.hasAllKeys(result.field, ['headers', 'body']);
assert.hasAllKeys(result.field, ['method', 'headers', 'body']);
});

describe('method', () => {
// See https://github.com/apiaryio/gavel.js/issues/158
it.skip('compares methods');
validator(result.field.method, null);
expectedType(result.field.method, 'text/vnd.apiary.method');
realType(result.field.method, 'text/vnd.apiary.method');

describe('produces one error', () => {
it('exactly one error', () => {
assert.lengthOf(result.field.method.errors, 1);
});

it('has "error" severity', () => {
assert.propertyVal(
result.field.method.errors[0],
'severity',
'error'
);
});

it('has explanatory message', () => {
assert.propertyVal(
result.field.method.errors[0],
'message',
'Expected "method" field to equal "PUT", but got "POST".'
);
});
});
});

describe('headers', () => {
Expand Down
14 changes: 14 additions & 0 deletions lib/next/test/unit/units/normalize/normalizeMethod.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { assert } = require('chai');
const {
normalizeMethod
} = require('../../../../units/normalize/normalizeMethod');

describe('normalizeMethod', () => {
it('removes trailing spaces', () => {
assert.equal(normalizeMethod(' POST '), 'POST');
});

it('converts to uppercase', () => {
assert.equal(normalizeMethod('pUt'), 'PUT');
});
});
104 changes: 104 additions & 0 deletions lib/next/test/unit/units/validateMethod.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
const { assert } = require('chai');
const { validateMethod } = require('../../../units/validateMethod');

describe('validateMethod', () => {
describe('given matching methods', () => {
const result = validateMethod({ method: 'GET' }, { method: 'GET' });

it('has "isValid" as "true"', () => {
assert.propertyVal(result, 'isValid', true);
});

it('has "null" validator', () => {
assert.isNull(result.validator);
});

it('has "text/vnd.apiary.method" real type', () => {
assert.propertyVal(result, 'realType', 'text/vnd.apiary.method');
});

it('has "text/vnd.apiary.method" expected type', () => {
assert.propertyVal(result, 'expectedType', 'text/vnd.apiary.method');
});

it('has no errors', () => {
assert.lengthOf(result.errors, 0);
});
});

describe('given non-matching methods', () => {
const result = validateMethod({ method: 'GET' }, { method: 'POST' });

it('returns "isValid" as "false"', () => {
assert.propertyVal(result, 'isValid', false);
});

it('has "null" validator', () => {
assert.propertyVal(result, 'validator', null);
});

it('has "text/vnd.apiary.method" real type', () => {
assert.propertyVal(result, 'realType', 'text/vnd.apiary.method');
});

it('has "text/vnd.apiary.method" expected type', () => {
assert.propertyVal(result, 'expectedType', 'text/vnd.apiary.method');
});

describe('produces an error', () => {
it('exactly one error', () => {
assert.lengthOf(result.errors, 1);
});

it('has "error" severity', () => {
assert.propertyVal(result.errors[0], 'severity', 'error');
});

it('has explanatory message', () => {
assert.propertyVal(
result.errors[0],
'message',
'Expected "method" field to equal "POST", but got "GET".'
);
});
});
});

describe('given expected, but no real method', () => {
const result = validateMethod({ method: '' }, { method: 'PATCH' });

it('returns "isValid" as "false"', () => {
assert.propertyVal(result, 'isValid', false);
});

it('has "null" validator', () => {
assert.propertyVal(result, 'validator', null);
});

it('has "text/vnd.apiary.method" real type', () => {
assert.propertyVal(result, 'realType', 'text/vnd.apiary.method');
});

it('has "text/vnd.apiary.method" expected type', () => {
assert.propertyVal(result, 'expectedType', 'text/vnd.apiary.method');
});

describe('produces an error', () => {
it('exactly one error', () => {
assert.lengthOf(result.errors, 1);
});

it('has "error" severity', () => {
assert.propertyVal(result.errors[0], 'severity', 'error');
});

it('has explanatory message', () => {
assert.propertyVal(
result.errors[0],
'message',
'Expected "method" field to equal "PATCH", but got "".'
);
});
});
});
});
1 change: 1 addition & 0 deletions lib/next/units/coerce/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const evolve = require('../../utils/evolve');
const { coerceHeaders } = require('./coerceHeaders');

const coercionMap = {
method: (method) => method || '',
headers: coerceHeaders
};

Expand Down
2 changes: 2 additions & 0 deletions lib/next/units/normalize/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const evolve = require('../../utils/evolve');
const { normalizeMethod } = require('./normalizeMethod');
const { normalizeStatusCode } = require('./normalizeStatusCode');
const { normalizeHeaders } = require('./normalizeHeaders');

const normalize = evolve({
method: normalizeMethod,
statusCode: normalizeStatusCode,
headers: normalizeHeaders
});
Expand Down
9 changes: 9 additions & 0 deletions lib/next/units/normalize/normalizeMethod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Normalizes given HTTP message method.
* @param {string} method
*/
const normalizeMethod = (method) => {
return method.trim().toUpperCase();
};

module.exports = { normalizeMethod };
25 changes: 25 additions & 0 deletions lib/next/units/validateMethod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const APIARY_METHOD_TYPE = 'text/vnd.apiary.method';

function validateMethod(real, expected) {
const { method: realMethod } = real;
const { method: expectedMethod } = expected;
const errors = [];
const isValid = realMethod === expectedMethod;

if (!isValid) {
errors.push({
message: `Expected "method" field to equal "${expectedMethod}", but got "${realMethod}".`,
severity: 'error'
});
}

return {
isValid,
validator: null,
realType: APIARY_METHOD_TYPE,
expectedType: APIARY_METHOD_TYPE,
errors
};
}

module.exports = { validateMethod };
5 changes: 5 additions & 0 deletions lib/next/validateMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const isset = require('../utils/isset');
const { coerce, coerceWeak } = require('./units/coerce');
const { normalize } = require('./units/normalize');
const { isValid } = require('./units/isValid');
const { validateMethod } = require('./units/validateMethod');
const { validateStatusCode } = require('./units/validateStatusCode');
const { validateHeaders } = require('./units/validateHeaders');
const { validateBody } = require('./units/validateBody');
Expand All @@ -22,6 +23,10 @@ function validateMessage(realMessage, expectedMessage) {
// However, we want to use the same coercion logic for any coercion type.
const expected = normalize(coerceWeak(expectedMessage));

if (expected.method) {
results.field.method = validateMethod(real, expected);
}

if (expected.statusCode) {
results.field.statusCode = validateStatusCode(real, expected);
}
Expand Down

0 comments on commit b575e93

Please sign in to comment.