Skip to content

Commit

Permalink
feat(httpConfig): add default config support and unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Miaskowski committed Oct 19, 2018
1 parent ad925e2 commit 4f0a062
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getHttpConfigFromRequest() extracts code 1`] = `
exports[`getHttpConfigFromRequest() given default config function and that function returns a mock should combine with query params 1`] = `
Object {
"code": "202",
"mock": Object {
"code": "400",
"exampleKey": "key",
},
}
`;

exports[`getHttpConfigFromRequest() extracts dynamic 1`] = `
exports[`getHttpConfigFromRequest() given default config object that is a map and matching query should return combined 1`] = `
Object {
"dynamic": true,
"mock": Object {
"code": "200",
"exampleKey": "bear",
"mediaType": "plain/text",
},
}
`;

exports[`getHttpConfigFromRequest() extracts example 1`] = `
exports[`getHttpConfigFromRequest() given default config object that is boolean and matching query should return that query 1`] = `
Object {
"exampleKey": "bear",
"mock": Object {
"code": "200",
"exampleKey": "bear",
},
}
`;

exports[`getHttpConfigFromRequest() extracts mediaType 1`] = `
exports[`getHttpConfigFromRequest() given default config object that is boolean and no matching query params should return that config object 1`] = `
Object {
"mediaType": "application/json",
"mock": false,
}
`;

exports[`getHttpConfigFromRequest() given no default config and no matching query should return my own default 1`] = `
Object {
"mock": true,
}
`;

exports[`getHttpConfigFromRequest() given no default config and no query should return my own default 1`] = `
Object {
"mock": true,
}
`;

exports[`getHttpConfigFromRequest() given no default config extracts code 1`] = `
Object {
"mock": Object {
"code": "202",
},
}
`;

exports[`getHttpConfigFromRequest() given no default config extracts dynamic 1`] = `
Object {
"mock": Object {
"dynamic": true,
},
}
`;

exports[`getHttpConfigFromRequest() given no default config extracts example 1`] = `
Object {
"mock": Object {
"exampleKey": "bear",
},
}
`;

exports[`getHttpConfigFromRequest() given no default config extracts mediaType 1`] = `
Object {
"mock": Object {
"mediaType": "application/json",
},
}
`;
141 changes: 110 additions & 31 deletions packages/http-server/src/__tests__/getHttpConfigFromRequest.spec.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,116 @@
import { IHttpRequest } from '@stoplight/prism-http';
import { getHttpConfigFromRequest } from '../getHttpConfigFromRequest';

describe('getHttpConfigFromRequest()', () => {
test('extracts code', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __code: '202' } },
} as IHttpRequest)
).resolves.toMatchSnapshot();
describe.only('getHttpConfigFromRequest()', () => {
describe('given no default config', () => {
test('and no query should return my own default', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/' },
})
).resolves.toMatchSnapshot();
});
test('and no matching query should return my own default', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: {} },
})
).resolves.toMatchSnapshot();
});
test('extracts code', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __code: '202' } },
})
).resolves.toMatchSnapshot();
});
test('extracts mediaType', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __contentType: 'application/json' } },
})
).resolves.toMatchSnapshot();
});
test('extracts example', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __example: 'bear' } },
})
).resolves.toMatchSnapshot();
});
test('extracts dynamic', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __dynamic: 'true' } },
})
).resolves.toMatchSnapshot();
});
});
test('extracts mediaType', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __contentType: 'application/json' } },
} as IHttpRequest)
).resolves.toMatchSnapshot();
});
test('extracts example', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __example: 'bear' } },
} as IHttpRequest)
).resolves.toMatchSnapshot();

describe('given default config function', () => {
test('and that function returns a mock should combine with query params', () => {
const spy = jest.fn().mockReturnValue({
mock: {
exampleKey: 'key',
},
});
return expect(
getHttpConfigFromRequest(
{
method: 'get',
url: { path: '/', query: { __code: '400' } },
},
spy
)
).resolves.toMatchSnapshot();
});
});
test('extracts dynamic', () => {
return expect(
getHttpConfigFromRequest({
method: 'get',
url: { path: '/', query: { __dynamic: 'true' } },
} as IHttpRequest)
).resolves.toMatchSnapshot();

describe('given default config object', () => {
test('that is boolean and no matching query params should return that config object', () => {
return expect(
getHttpConfigFromRequest(
{
method: 'get',
url: { path: '/', query: {} },
},
{ mock: false }
)
).resolves.toMatchSnapshot();
});

test('that is boolean and matching query should return that query', () => {
return expect(
getHttpConfigFromRequest(
{
method: 'get',
url: { path: '/', query: { __code: '200', __example: 'bear' } },
},
{ mock: false }
)
).resolves.toMatchSnapshot();
});

test('that is a map and matching query should return combined', () => {
return expect(
getHttpConfigFromRequest(
{
method: 'get',
url: { path: '/', query: { __code: '200', __example: 'bear' } },
},
{
mock: {
exampleKey: 'wolf',
mediaType: 'plain/text',
},
}
)
).resolves.toMatchSnapshot();
});
});
});
59 changes: 47 additions & 12 deletions packages/http-server/src/getHttpConfigFromRequest.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,58 @@
import { IHttpConfig, IHttpRequest } from '@stoplight/prism-http/types';
import { PrismConfig, PrismConfigFactory } from '@stoplight/prism-core/types';
import { IHttpConfig, IHttpOperationConfig, IHttpRequest } from '@stoplight/prism-http/types';

export async function getHttpConfigFromRequest(req: IHttpRequest): Promise<IHttpConfig> {
const config: any = {};
async function getConfig<Config, Input>(
input: Input,
config: PrismConfig<Config, Input>,
defaultConfig?: PrismConfig<Config, Input>
): Promise<Config> {
if (typeof config === 'function') {
// config factory function
return await (config as PrismConfigFactory<Config, Input>)(input, defaultConfig);
}
return config as Config;
}

export const getHttpConfigFromRequest: PrismConfigFactory<IHttpConfig, IHttpRequest> = async (
req: IHttpRequest,
defaultConfig?: PrismConfig<IHttpConfig, IHttpRequest>
) => {
const config: IHttpConfig = defaultConfig
? await getConfig<IHttpConfig, IHttpRequest>(req, defaultConfig)
: { mock: true };
const httpOperationConfig: IHttpOperationConfig = {};
const query = req.url.query;

if (req.url.query!.__code) {
config.code = req.url.query!.__code;
if (!query) {
return config;
}

if (req.url.query!.__dynamic) {
config.dynamic = req.url.query!.__dynamic.toLowerCase() === 'true';
const { __code, __dynamic, __contentType, __example } = query;

if (__code) {
httpOperationConfig.code = __code;
}

if (req.url.query!.__contentType) {
config.mediaType = req.url.query!.__contentType;
if (__dynamic) {
httpOperationConfig.dynamic = __dynamic.toLowerCase() === 'true';
}

if (req.url.query!.__example) {
config.exampleKey = req.url.query!.__example;
if (__contentType) {
httpOperationConfig.mediaType = __contentType;
}

if (__example) {
httpOperationConfig.exampleKey = __example;
}

if (Object.keys(httpOperationConfig).length) {
if (typeof config.mock === 'boolean') {
config.mock = httpOperationConfig;
} else {
config.mock = Object.assign({}, config.mock, httpOperationConfig);
}
return config;
}

return config;
}
};
5 changes: 3 additions & 2 deletions packages/http/src/mocker/__tests__/functional.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { JSONSchemaExampleGenerator } from '@stoplight/prism-http/mocker/generator/JSONSchemaExampleGenerator';
import { ISchema } from '@stoplight/types/schema';
import * as Ajv from 'ajv';

import { httpOperations, httpRequests } from '../../__tests__/fixtures';
Expand Down Expand Up @@ -55,7 +56,7 @@ describe('http mocker', () => {
}

const ajv = new Ajv();
const validate = ajv.compile(httpOperations[1].responses[0].content[0].schema);
const validate = ajv.compile(httpOperations[1].responses[0].content[0].schema as ISchema);

const response = await mocker.mock({
resource: httpOperations[1],
Expand Down Expand Up @@ -95,7 +96,7 @@ describe('http mocker', () => {
});

const ajv = new Ajv();
const validate = ajv.compile(httpOperations[1].responses[1].content[0].schema);
const validate = ajv.compile(httpOperations[1].responses[1].content[0].schema as ISchema);

expect(validate(JSON.parse(response.body))).toBe(true);
});
Expand Down
8 changes: 4 additions & 4 deletions packages/http/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export type IHttpMethod =
| 'trace'; // ... etc

export interface IHttpOperationConfig {
readonly mediaType?: string;
readonly code?: string;
readonly exampleKey?: string;
readonly dynamic?: boolean;
mediaType?: string;
code?: string;
exampleKey?: string;
dynamic?: boolean;
}

export interface IHttpConfig extends IPrismConfig {
Expand Down

0 comments on commit 4f0a062

Please sign in to comment.