tsoa-custom-decorators
Version:
Build swagger-compliant REST APIs using TypeScript and Node
386 lines (333 loc) • 13.9 kB
text/typescript
import 'mocha';
import { server } from '../fixtures/hapi/server';
import { GenericModel, GenericRequest, TestModel, TestClassModel, Model, ParameterTestModel, Gender } from '../fixtures/testModel';
import * as chai from 'chai';
import * as request from 'supertest';
const expect = chai.expect;
const basePath = '/v1';
describe('Hapi Server', () => {
it('can handle get request with no path argument', () => {
return verifyGetRequest(basePath + '/GetTest', (err, res) => {
const model = res.body as TestModel;
expect(model.id).to.equal(1);
});
});
it('can handle get request with path argument', () => {
return verifyGetRequest(basePath + '/GetTest/Current', (err, res) => {
const model = res.body as TestModel;
expect(model.id).to.equal(1);
});
});
it('can handle get request with collection return value', () => {
return verifyGetRequest(basePath + '/GetTest/Multi', (err, res) => {
const models = res.body as TestModel[];
expect(models.length).to.equal(3);
models.forEach(m => {
expect(m.id).to.equal(1);
});
});
});
it('can handle get request with path and query parameters', () => {
return verifyGetRequest(basePath + `/GetTest/${1}/${true}/test?booleanParam=true&stringParam=test1234&numberParam=1234`, (err, res) => {
const model = res.body as TestModel;
expect(model.id).to.equal(1);
});
});
it('returns error if missing required query parameter', () => {
return verifyGetRequest(basePath + `/GetTest/${1}/${true}/test?booleanParam=true&stringParam=test1234`, (err: any, res: any) => {
expect(JSON.parse(err.text).message).to.equal(`'numberParam' is a required query parameter.`);
}, 400);
});
it('parses path parameters', () => {
const numberValue = 600;
const boolValue = false;
const stringValue = 'the-string';
return verifyGetRequest(basePath + `/GetTest/${numberValue}/${boolValue}/${stringValue}?booleanParam=true&stringParam=test1234&numberParam=1234`, (err, res) => {
const model = res.body as TestModel;
expect(model.numberValue).to.equal(numberValue);
expect(model.boolValue).to.equal(boolValue);
expect(model.stringValue).to.equal(stringValue);
});
});
it('parses query parameters', () => {
const numberValue = 600;
const stringValue = 'the-string';
return verifyGetRequest(basePath + `/GetTest/1/true/testing?booleanParam=true&stringParam=test1234&numberParam=${numberValue}&optionalStringParam=${stringValue}`, (err, res) => {
const model = res.body as TestModel;
expect(model.optionalString).to.equal(stringValue);
});
});
it('parsed body parameters', () => {
const data = getFakeModel();
return verifyPostRequest(basePath + '/PostTest', data, (err: any, res: any) => {
const model = res.body as TestModel;
expect(model).to.deep.equal(model);
});
});
it('parses class model as body parameter', () => {
const data = getFakeClassModel();
return verifyPostRequest(basePath + '/PostTest/WithClassModel', data, (err: any, res: any) => {
const model = res.body as TestClassModel;
expect(model.id).to.equal(700); // this gets changed on the server
});
});
it('should reject invalid strings', () => {
const invalidValues = [null, 1, undefined, {}];
return Promise.all(invalidValues.map((value: any) => {
const data = getFakeModel();
data.stringValue = value;
return verifyPostRequest(basePath + '/PostTest', data, (err: any, res: any) => null, 400);
}));
});
it('should parse valid date', () => {
const data = getFakeModel();
data.dateValue = '2016-01-01T00:00:00Z' as any;
return verifyPostRequest(basePath + '/PostTest', data, (err: any, res: any) => {
expect(res.body.dateValue).to.equal('2016-01-01T00:00:00.000Z');
}, 200);
});
it('should parse valid date as query param', () => {
return verifyGetRequest(basePath + '/GetTest/DateParam?date=2016-01-01T00:00:00Z', (err: any, res: any) => {
expect(res.body.dateValue).to.equal('2016-01-01T00:00:00.000Z');
}, 200);
});
it('should reject invalid dates', () => {
const invalidValues = [1, {}];
return Promise.all(invalidValues.map((value: any) => {
const data = getFakeModel();
data.dateValue = value;
return verifyPostRequest(basePath + '/PostTest', data, (err: any, res: any) => null, 400);
}));
});
it('should reject invalid numbers', () => {
const invalidValues = ['test', null, undefined, {}];
return Promise.all(invalidValues.map((value: any) => {
const data = getFakeModel();
data.numberValue = value;
return verifyPostRequest(basePath + '/PostTest', data, (err: any, res: any) => null, 400);
}));
});
it('returns error if missing required path parameter', () => {
return verifyGetRequest(basePath + `/GetTest/${1}/${true}?booleanParam=true&stringParam=test1234`, (err: any, res: any) => {
expect(JSON.parse(err.text).error).to.equal('Not Found');
}, 404);
});
it('returns error if invalid request', () => {
const data = getFakeModel();
data.dateValue = 1 as any;
return verifyPostRequest(basePath + '/PostTest', data, (err: any, res: any) => {
expect(JSON.parse(err.text).message).to.equal('dateValue should be a valid ISO 8601 date, i.e. YYYY-MM-DDTHH:mm:ss');
}, 400);
});
it('returns error if thrown in controller', () => {
return verifyGetRequest(basePath + '/GetTest/ThrowsError', (err: any, res: any) => {
expect(JSON.parse(err.text).message).to.equal('error thrown');
}, 400);
});
describe('Security', () => {
it('can handle get request with access_token user id == 1', () => {
return verifyGetRequest(basePath + '/SecurityTest?access_token=abc123456', (err, res) => {
const model = res.body as Model;
expect(model.id).to.equal(1);
});
});
it('can handle get request with access_token user id == 2', () => {
return verifyGetRequest(basePath + '/SecurityTest?access_token=xyz123456', (err, res) => {
const model = res.body as Model;
expect(model.id).to.equal(2);
});
});
});
describe('Parameter data', () => {
it('parses query parameters', () => {
return verifyGetRequest(basePath + '/ParameterTest/Query?firstname=Tony&last_name=Stark&age=45&weight=82.1&human=true&gender=MALE', (err, res) => {
const model = res.body as ParameterTestModel;
expect(model.firstname).to.equal('Tony');
expect(model.lastname).to.equal('Stark');
expect(model.age).to.equal(45);
expect(model.weight).to.equal(82.1);
expect(model.human).to.equal(true);
expect(model.gender).to.equal(Gender.MALE);
});
});
it('parses path parameters', () => {
return verifyGetRequest(basePath + '/ParameterTest/Path/Tony/Stark/45/82.1/true/MALE', (err, res) => {
const model = res.body as ParameterTestModel;
expect(model.firstname).to.equal('Tony');
expect(model.lastname).to.equal('Stark');
expect(model.age).to.equal(45);
expect(model.weight).to.equal(82.1);
expect(model.human).to.equal(true);
expect(model.gender).to.equal(Gender.MALE);
});
});
it('parses header parameters', () => {
return verifyRequest((err, res) => {
const model = res.body as ParameterTestModel;
expect(model.firstname).to.equal('Tony');
expect(model.lastname).to.equal('Stark');
expect(model.age).to.equal(45);
expect(model.weight).to.equal(82.1);
expect(model.human).to.equal(true);
expect(model.gender).to.equal(Gender.MALE);
}, (request) => {
return request
.get(basePath + '/ParameterTest/Header')
.set({
'age': 45,
'firstname': 'Tony',
'gender': Gender.MALE,
'human': true,
'last_name': 'Stark',
'weight': 82.1
});
}, 200);
});
it('parses request parameters', () => {
return verifyGetRequest(basePath + '/ParameterTest/Request?firstname=Tony&lastname=Stark&age=45&weight=82.1&human=true&gender=MALE', (err, res) => {
const model = res.body as ParameterTestModel;
expect(model.firstname).to.equal('Tony');
expect(model.lastname).to.equal('Stark');
expect(model.age).to.equal(45);
expect(model.weight).to.equal(82.1);
expect(model.human).to.equal(true);
expect(model.gender).to.equal(Gender.MALE);
});
});
it('parses body parameters', () => {
const data: ParameterTestModel = {
age: 45,
firstname: 'Tony',
gender: Gender.MALE,
human: true,
lastname: 'Stark',
weight: 82.1
};
return verifyPostRequest(basePath + '/ParameterTest/Body', data, (err, res) => {
const model = res.body as ParameterTestModel;
expect(model.firstname).to.equal('Tony');
expect(model.lastname).to.equal('Stark');
expect(model.age).to.equal(45);
expect(model.weight).to.equal(82.1);
expect(model.human).to.equal(true);
expect(model.gender).to.equal(Gender.MALE);
});
});
it('parses body field parameters', () => {
const data: ParameterTestModel = {
age: 45,
firstname: 'Tony',
gender: Gender.MALE,
human: true,
lastname: 'Stark',
weight: 82.1
};
return verifyPostRequest(basePath + '/ParameterTest/BodyProps', data, (err, res) => {
const model = res.body as ParameterTestModel;
expect(model.firstname).to.equal('Tony');
expect(model.lastname).to.equal('Stark');
expect(model.age).to.equal(45);
expect(model.weight).to.equal(82.1);
expect(model.human).to.equal(true);
expect(model.gender).to.equal(Gender.MALE);
});
});
it('can get request with generic type', () => {
return verifyGetRequest(basePath + '/GetTest/GenericModel', (err, res) => {
const model = res.body as GenericModel<TestModel>;
expect(model.result.id).to.equal(1);
});
});
it('can get request with generic array', () => {
return verifyGetRequest(basePath + '/GetTest/GenericModelArray', (err, res) => {
const model = res.body as GenericModel<TestModel[]>;
expect(model.result[0].id).to.equal(1);
});
});
it('can get request with generic primative type', () => {
return verifyGetRequest(basePath + '/GetTest/GenericPrimitive', (err, res) => {
const model = res.body as GenericModel<string>;
expect(model.result).to.equal('a string');
});
});
it('can get request with generic primative array', () => {
return verifyGetRequest(basePath + '/GetTest/GenericPrimitiveArray', (err, res) => {
const model = res.body as GenericModel<string[]>;
expect(model.result[0]).to.equal('string one');
});
});
it('can post request with a generic body', () => {
const data: GenericRequest<TestModel> = {
name: 'something',
value: getFakeModel()
};
return verifyPostRequest(basePath + '/PostTest/GenericBody', data, (err, res) => {
const model = res.body as TestModel;
expect(model.id).to.equal(1);
});
});
});
function verifyGetRequest(path: string, verifyResponse: (err: any, res: request.Response) => any, expectedStatus?: number) {
return verifyRequest(verifyResponse, request => request.get(path), expectedStatus);
}
function verifyPostRequest(path: string, data: any, verifyResponse: (err: any, res: request.Response) => any, expectedStatus?: number) {
return verifyRequest(verifyResponse, request => request.post(path).send(data), expectedStatus);
}
function verifyRequest(
verifyResponse: (err: any, res: any) => any,
methodOperation: (request: request.SuperTest<any>) => request.Test,
expectedStatus = 200
) {
return new Promise((resolve, reject) => {
methodOperation(request(server.listener))
.expect(expectedStatus)
.end((err: any, res: any) => {
let parsedError: any;
try {
parsedError = JSON.parse((res.error as any));
} catch (err) {
parsedError = (res.error as any);
}
if (err) {
reject({
error: err,
response: parsedError
});
return;
}
verifyResponse(parsedError, res);
resolve();
});
});
}
function getFakeModel(): TestModel {
return {
boolArray: [true, false],
boolValue: false,
id: 1,
modelValue: { email: 'test@test.com', id: 2 },
modelsArray: [{ email: 'test@test.com', id: 1 }],
modelsObjectIndirect: {
key: {
email: 'test@test.com',
id: 1,
testSubModel2: false
}
},
numberArray: [1, 2],
numberValue: 5,
optionalString: 'test1234',
strLiteralArr: ['Foo', 'Bar'],
strLiteralVal: 'Foo',
stringArray: ['test', 'testtwo'],
stringValue: 'test1234'
};
}
function getFakeClassModel() {
const model = new TestClassModel('test', 'test', 'test');
model.id = 100;
model.publicStringProperty = 'test';
model.stringProperty = 'test';
return model;
}
});