mirror of https://github.com/Seich/Beau.git
Reindenting. (#17)
I normally prefer tabs for everything, it's nice to have the ability to set to whatever your preferred width is. Since this project uses a lot of yaml stuff I've had to indent those tests with spaces, for consistency's sake I've decided to use spaces everywhere.
This commit is contained in:
parent
64de56d51c
commit
59f85fac8c
|
|
@ -1,6 +1,7 @@
|
||||||
printWidth: 80
|
printWidth: 80
|
||||||
|
tabWidth: 4
|
||||||
singleQuote: true
|
singleQuote: true
|
||||||
useTabs: true
|
useTabs: false
|
||||||
trailingComma: none
|
trailingComma: none
|
||||||
bracketSpacing: true
|
bracketSpacing: true
|
||||||
jsxBracketSameLine: true
|
jsxBracketSameLine: true
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
class DynamicValues {
|
class DynamicValues {
|
||||||
constructor(registry, settings = {}) {
|
constructor(registry, settings = {}) {
|
||||||
registry.defineDynamicValue('add', this.add);
|
registry.defineDynamicValue('add', this.add);
|
||||||
}
|
}
|
||||||
|
|
||||||
add(x, y) {
|
add(x, y) {
|
||||||
return x + y;
|
return x + y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DynamicValues;
|
module.exports = DynamicValues;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
class Modifiers {
|
class Modifiers {
|
||||||
constructor(registry, settings = {}) {
|
constructor(registry, settings = {}) {
|
||||||
registry.addPreRequestModifier(this.preRequest);
|
registry.addPreRequestModifier(this.preRequest);
|
||||||
registry.addPostRequestModifier(this.postRequest);
|
registry.addPostRequestModifier(this.postRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
preRequest(request, orig) {
|
preRequest(request, orig) {
|
||||||
request.headers = request.headers || {};
|
request.headers = request.headers || {};
|
||||||
request.headers.preRequestModifier = true;
|
request.headers.preRequestModifier = true;
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
postRequest(response, orig) {
|
postRequest(response, orig) {
|
||||||
response.body = 'Hello World';
|
response.body = 'Hello World';
|
||||||
response.response.body = 'Hello World';
|
response.response.body = 'Hello World';
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Modifiers;
|
module.exports = Modifiers;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
function Request(request) {
|
function Request(request) {
|
||||||
if (Request.fail) {
|
if (Request.fail) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
request: {
|
request: {
|
||||||
headers: request.headers,
|
headers: request.headers,
|
||||||
body: request.body,
|
body: request.body,
|
||||||
uri: {
|
uri: {
|
||||||
href: `${request.baseUrl}${request.uri}`
|
href: `${request.baseUrl}${request.uri}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
headers: [],
|
headers: [],
|
||||||
body: '{"hello": "world"}'
|
body: '{"hello": "world"}'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Request.fail = false;
|
Request.fail = false;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
module.exports = function(name) {
|
module.exports = function(name) {
|
||||||
return require(name);
|
return require(name);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,21 @@ const yaml = require('js-yaml');
|
||||||
const Config = require('../config');
|
const Config = require('../config');
|
||||||
|
|
||||||
describe('Config', () => {
|
describe('Config', () => {
|
||||||
it('should load valid config keys', () => {
|
it('should load valid config keys', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
version: 1
|
version: 1
|
||||||
endpoint: http://martianwabbit.com
|
endpoint: http://martianwabbit.com
|
||||||
shouldntBeAdded: true
|
shouldntBeAdded: true
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const config = new Config(doc);
|
const config = new Config(doc);
|
||||||
expect(config.ENDPOINT).toBe(doc.endpoint);
|
expect(config.ENDPOINT).toBe(doc.endpoint);
|
||||||
expect(config.VERSION).toBe(doc.version);
|
expect(config.VERSION).toBe(doc.version);
|
||||||
expect(config.shouldntBeAdded).toBeUndefined();
|
expect(config.shouldntBeAdded).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load requests', () => {
|
it('should load requests', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
endpoint: http://example.com
|
endpoint: http://example.com
|
||||||
|
|
||||||
GET /profile: get-profile
|
GET /profile: get-profile
|
||||||
|
|
@ -28,12 +28,12 @@ describe('Config', () => {
|
||||||
hello: world
|
hello: world
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const config = new Config(doc);
|
const config = new Config(doc);
|
||||||
expect(Object.keys(config.REQUESTS).length).toBe(4);
|
expect(Object.keys(config.REQUESTS).length).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set up defaults for all requests', () => {
|
it('should set up defaults for all requests', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
version: 1
|
version: 1
|
||||||
endpoint: 'http://jsonplaceholder.typicode.com'
|
endpoint: 'http://jsonplaceholder.typicode.com'
|
||||||
|
|
||||||
|
|
@ -48,16 +48,16 @@ describe('Config', () => {
|
||||||
hello: world
|
hello: world
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const config = new Config(doc);
|
const config = new Config(doc);
|
||||||
|
|
||||||
expect(config).toMatchSnapshot();
|
expect(config).toMatchSnapshot();
|
||||||
Object.values(config.REQUESTS).forEach(r => {
|
Object.values(config.REQUESTS).forEach(r => {
|
||||||
expect(r.HEADERS.authentication).toMatch('hello');
|
expect(r.HEADERS.authentication).toMatch('hello');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should load multiple hosts', () => {
|
it('should load multiple hosts', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
endpoint: http://example.org
|
endpoint: http://example.org
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
|
|
@ -95,13 +95,13 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
|
|
||||||
expect(config).toMatchSnapshot();
|
expect(config).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should namespace all aliases within an host', () => {
|
it('should namespace all aliases within an host', () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
hosts:
|
hosts:
|
||||||
- host: test1
|
- host: test1
|
||||||
endpoint: http://example.com
|
endpoint: http://example.com
|
||||||
|
|
@ -111,14 +111,14 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
|
|
||||||
expect(config.REQUESTS[0].ALIAS).toBe('test1:posts');
|
expect(config.REQUESTS[0].ALIAS).toBe('test1:posts');
|
||||||
expect(config.REQUESTS[1].ALIAS).toBe('test2:posts');
|
expect(config.REQUESTS[1].ALIAS).toBe('test2:posts');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should throw if host doesn't have a host key`, () => {
|
it(`should throw if host doesn't have a host key`, () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
hosts:
|
hosts:
|
||||||
- endpoint: http://example.com
|
- endpoint: http://example.com
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
|
|
@ -128,11 +128,11 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
expect(() => new Config(doc)).toThrow();
|
expect(() => new Config(doc)).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should merge host settings with global settings`, () => {
|
it(`should merge host settings with global settings`, () => {
|
||||||
const doc = yaml.safeLoad(`
|
const doc = yaml.safeLoad(`
|
||||||
defaults:
|
defaults:
|
||||||
headers:
|
headers:
|
||||||
hello: 1
|
hello: 1
|
||||||
|
|
@ -150,7 +150,7 @@ describe('Config', () => {
|
||||||
GET /posts: posts
|
GET /posts: posts
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
expect(config.REQUESTS[0].HEADERS.hello).toBe(1);
|
expect(config.REQUESTS[0].HEADERS.hello).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,74 +4,74 @@ const RequestList = require('../requestList');
|
||||||
const requestPromiseNativeMock = require('request-promise-native');
|
const requestPromiseNativeMock = require('request-promise-native');
|
||||||
|
|
||||||
describe('Request', () => {
|
describe('Request', () => {
|
||||||
let cache;
|
let cache;
|
||||||
let validRequestConfig;
|
let validRequestConfig;
|
||||||
let invalidRequestConfig;
|
let invalidRequestConfig;
|
||||||
let request;
|
let request;
|
||||||
let requestWithoutDependencies;
|
let requestWithoutDependencies;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
validRequestConfig = {
|
validRequestConfig = {
|
||||||
request: 'POST /user',
|
request: 'POST /user',
|
||||||
endpoint: 'http://martianwabbit.com',
|
endpoint: 'http://martianwabbit.com',
|
||||||
alias: 'update',
|
alias: 'update',
|
||||||
params: {
|
params: {
|
||||||
userId: '$profile.UserId'
|
userId: '$profile.UserId'
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
authentication: 'BEARER $session.token'
|
authentication: 'BEARER $session.token'
|
||||||
},
|
},
|
||||||
payload: {
|
payload: {
|
||||||
username: 'seich'
|
username: 'seich'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
invalidRequestConfig = {
|
invalidRequestConfig = {
|
||||||
request: `POST /session`,
|
request: `POST /session`,
|
||||||
endpoint: 'http://martianwabbit.com'
|
endpoint: 'http://martianwabbit.com'
|
||||||
};
|
};
|
||||||
|
|
||||||
cache = new RequestCache();
|
cache = new RequestCache();
|
||||||
cache.add('session', { token: 'abc123' });
|
cache.add('session', { token: 'abc123' });
|
||||||
cache.add('profile', { UserId: 14 });
|
cache.add('profile', { UserId: 14 });
|
||||||
|
|
||||||
request = new Request(validRequestConfig);
|
request = new Request(validRequestConfig);
|
||||||
requestWithoutDependencies = new Request({
|
requestWithoutDependencies = new Request({
|
||||||
endpoint: 'http://martianwabbit.com',
|
endpoint: 'http://martianwabbit.com',
|
||||||
request: 'GET /user',
|
request: 'GET /user',
|
||||||
alias: 'show'
|
alias: 'show'
|
||||||
});
|
});
|
||||||
|
|
||||||
requestPromiseNativeMock.fail = false;
|
requestPromiseNativeMock.fail = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load up the given request', () => {
|
it('should load up the given request', () => {
|
||||||
expect(request.VERB).toBe('POST');
|
expect(request.VERB).toBe('POST');
|
||||||
expect(request.ENDPOINT).toBe(validRequestConfig.endpoint);
|
expect(request.ENDPOINT).toBe(validRequestConfig.endpoint);
|
||||||
expect(request.HEADERS).toBeDefined();
|
expect(request.HEADERS).toBeDefined();
|
||||||
expect(request.PAYLOAD).toBeDefined();
|
expect(request.PAYLOAD).toBeDefined();
|
||||||
expect(request.PARAMS).toBeDefined();
|
expect(request.PARAMS).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if a given request is invalid', () => {
|
it('should throw if a given request is invalid', () => {
|
||||||
expect(() => new Request(invalidRequestConfig)).toThrow();
|
expect(() => new Request(invalidRequestConfig)).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should list all of its dependencies', () => {
|
it('should list all of its dependencies', () => {
|
||||||
expect(request.DEPENDENCIES.size).toBe(2);
|
expect(request.DEPENDENCIES.size).toBe(2);
|
||||||
expect(request.DEPENDENCIES).toContain('session');
|
expect(request.DEPENDENCIES).toContain('session');
|
||||||
expect(request.DEPENDENCIES).toContain('profile');
|
expect(request.DEPENDENCIES).toContain('profile');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should execute a request', async () => {
|
it('should execute a request', async () => {
|
||||||
await expect(request.exec(cache)).resolves.toMatchSnapshot();
|
await expect(request.exec(cache)).resolves.toMatchSnapshot();
|
||||||
await expect(
|
await expect(
|
||||||
requestWithoutDependencies.exec()
|
requestWithoutDependencies.exec()
|
||||||
).resolves.toMatchSnapshot();
|
).resolves.toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if the request fails', async () => {
|
it('should throw if the request fails', async () => {
|
||||||
requestPromiseNativeMock.fail = true;
|
requestPromiseNativeMock.fail = true;
|
||||||
await expect(requestWithoutDependencies.exec()).rejects.toThrow(Error);
|
await expect(requestWithoutDependencies.exec()).rejects.toThrow(Error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,89 +1,89 @@
|
||||||
const RequestCache = require('../requestCache');
|
const RequestCache = require('../requestCache');
|
||||||
|
|
||||||
describe('Request Cache', () => {
|
describe('Request Cache', () => {
|
||||||
let cache;
|
let cache;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cache = new RequestCache();
|
cache = new RequestCache();
|
||||||
|
|
||||||
cache.add('session', {
|
cache.add('session', {
|
||||||
hello: 'World'
|
hello: 'World'
|
||||||
});
|
});
|
||||||
|
|
||||||
cache.add('array', [
|
cache.add('array', [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Sergio'
|
name: 'Sergio'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: 'Angela'
|
name: 'Angela'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add keys to the cache', () => {
|
it('should add keys to the cache', () => {
|
||||||
expect(cache.$cache.session.hello).toBe('World');
|
expect(cache.$cache.session.hello).toBe('World');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('get', () => {
|
describe('get', () => {
|
||||||
it('should be able to find key values with a given path', () => {
|
it('should be able to find key values with a given path', () => {
|
||||||
expect(cache.get('session.hello')).toBe('World');
|
expect(cache.get('session.hello')).toBe('World');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when given an invalid path', () => {
|
it('should throw when given an invalid path', () => {
|
||||||
expect(() => cache.get('$session.world')).toThrow();
|
expect(() => cache.get('$session.world')).toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('parse', () => {
|
describe('parse', () => {
|
||||||
it("should transform variables in strings using it's cache", () => {
|
it("should transform variables in strings using it's cache", () => {
|
||||||
expect(cache.parse('Hello $session.hello')).toBe('Hello World');
|
expect(cache.parse('Hello $session.hello')).toBe('Hello World');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should go transform variables in all values when given an object', () => {
|
it('should go transform variables in all values when given an object', () => {
|
||||||
let parsed = cache.parse({
|
let parsed = cache.parse({
|
||||||
hello: 'hello $session.hello',
|
hello: 'hello $session.hello',
|
||||||
earth: '$session.hello'
|
earth: '$session.hello'
|
||||||
});
|
});
|
||||||
expect(parsed.hello).toBe('hello World');
|
expect(parsed.hello).toBe('hello World');
|
||||||
expect(parsed.earth).toBe('World');
|
expect(parsed.earth).toBe('World');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return every non-string value as-is', () => {
|
it('should return every non-string value as-is', () => {
|
||||||
let parsed = cache.parse({
|
let parsed = cache.parse({
|
||||||
number: 1,
|
number: 1,
|
||||||
nulled: null,
|
nulled: null,
|
||||||
truthy: false,
|
truthy: false,
|
||||||
hello: '$session.hello'
|
hello: '$session.hello'
|
||||||
});
|
});
|
||||||
expect(parsed.number).toBe(1);
|
expect(parsed.number).toBe(1);
|
||||||
expect(parsed.nulled).toBeNull();
|
expect(parsed.nulled).toBeNull();
|
||||||
expect(parsed.truthy).toBe(false);
|
expect(parsed.truthy).toBe(false);
|
||||||
expect(parsed.hello).toBe('World');
|
expect(parsed.hello).toBe('World');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse arrays as well', () => {
|
it('should parse arrays as well', () => {
|
||||||
let parsed = cache.parse({ hello: '$array.0.name' });
|
let parsed = cache.parse({ hello: '$array.0.name' });
|
||||||
expect(parsed.hello).toBe('Sergio');
|
expect(parsed.hello).toBe('Sergio');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an object when given an undefined value', () => {
|
it('should return an object when given an undefined value', () => {
|
||||||
expect(Object.keys(cache.parse(undefined)).length).toBe(0);
|
expect(Object.keys(cache.parse(undefined)).length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse any value other than undefined', () => {
|
it('should parse any value other than undefined', () => {
|
||||||
expect(cache.parse('Hello $session.hello')).toBe('Hello World');
|
expect(cache.parse('Hello $session.hello')).toBe('Hello World');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null when passed null', () => {
|
it('should return null when passed null', () => {
|
||||||
expect(cache.parse(null)).toBe(null);
|
expect(cache.parse(null)).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`shouldn't replace escaped variables`, () => {
|
it(`shouldn't replace escaped variables`, () => {
|
||||||
expect(cache.parse(`\\$session.hello is $session.hello`)).toBe(
|
expect(cache.parse(`\\$session.hello is $session.hello`)).toBe(
|
||||||
`$session.hello is World`
|
`$session.hello is World`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,76 +3,76 @@ const RequestList = require('../requestList');
|
||||||
const requestPromiseNativeMock = require('request-promise-native');
|
const requestPromiseNativeMock = require('request-promise-native');
|
||||||
|
|
||||||
describe('RequestList', () => {
|
describe('RequestList', () => {
|
||||||
const endpoint = 'http://martianwabbit.com';
|
const endpoint = 'http://martianwabbit.com';
|
||||||
|
|
||||||
let env = {
|
let env = {
|
||||||
environmental: true
|
environmental: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const doc = {
|
const doc = {
|
||||||
ENDPOINT: endpoint,
|
ENDPOINT: endpoint,
|
||||||
ENVIRONMENT: env,
|
ENVIRONMENT: env,
|
||||||
'GET /post': { alias: 'get-posts' },
|
'GET /post': { alias: 'get-posts' },
|
||||||
'POST /user': {
|
'POST /user': {
|
||||||
alias: 'user',
|
alias: 'user',
|
||||||
payload: {
|
payload: {
|
||||||
name: 'Sergio',
|
name: 'Sergio',
|
||||||
lastname: 'Diaz'
|
lastname: 'Diaz'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let requests;
|
let requests;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
requestPromiseNativeMock.fail = false;
|
requestPromiseNativeMock.fail = false;
|
||||||
|
|
||||||
let config = new Config(doc);
|
let config = new Config(doc);
|
||||||
requests = new RequestList(config);
|
requests = new RequestList(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow an empty request list', () => {
|
it('should allow an empty request list', () => {
|
||||||
requests = new RequestList();
|
requests = new RequestList();
|
||||||
expect(requests.list.length).toBe(0);
|
expect(requests.list.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load valid requests', () => {
|
it('should load valid requests', () => {
|
||||||
expect(requests.list.length).toBe(2);
|
expect(requests.list.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fetch dependencies', async () => {
|
it('should fetch dependencies', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
requests.fetchDependencies(['get-posts'])
|
requests.fetchDependencies(['get-posts'])
|
||||||
).resolves.toMatchSnapshot();
|
).resolves.toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should execute requests by alias.', async () => {
|
it('should execute requests by alias.', async () => {
|
||||||
await expect(requests.execByAlias('user')).resolves.toMatchSnapshot();
|
await expect(requests.execByAlias('user')).resolves.toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if the request fails', async () => {
|
it('should fail if the request fails', async () => {
|
||||||
requestPromiseNativeMock.fail = true;
|
requestPromiseNativeMock.fail = true;
|
||||||
await expect(requests.execByAlias('user')).rejects.toThrow();
|
await expect(requests.execByAlias('user')).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a cached result if available', async () => {
|
it('should return a cached result if available', async () => {
|
||||||
const obj = { test: true };
|
const obj = { test: true };
|
||||||
requests.cache.add('test', obj);
|
requests.cache.add('test', obj);
|
||||||
await expect(requests.execByAlias('test')).resolves.toBe(obj);
|
await expect(requests.execByAlias('test')).resolves.toBe(obj);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if the alias is not found', async () => {
|
it('should fail if the alias is not found', async () => {
|
||||||
await expect(requests.execByAlias('notAnAlias')).rejects.toThrow();
|
await expect(requests.execByAlias('notAnAlias')).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should fail if a given request doesn't have an alias`, () => {
|
it(`should fail if a given request doesn't have an alias`, () => {
|
||||||
let config = new Config({
|
let config = new Config({
|
||||||
'GET /hello': {
|
'GET /hello': {
|
||||||
headers: {
|
headers: {
|
||||||
hello: 1
|
hello: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => new RequestList(config, config)).toThrow();
|
expect(() => new RequestList(config, config)).toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ const RequestList = require('./requestList');
|
||||||
const Config = require('./config');
|
const Config = require('./config');
|
||||||
|
|
||||||
class Beau {
|
class Beau {
|
||||||
constructor(doc, env = {}) {
|
constructor(doc, env = {}) {
|
||||||
this.config = new Config(doc, env);
|
this.config = new Config(doc, env);
|
||||||
this.requests = new RequestList(this.config);
|
this.requests = new RequestList(this.config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Beau;
|
module.exports = Beau;
|
||||||
|
|
|
||||||
138
src/config.js
138
src/config.js
|
|
@ -3,96 +3,96 @@ const { requestRegex, UpperCaseKeys } = require('./shared');
|
||||||
const Plugins = require('./plugins');
|
const Plugins = require('./plugins');
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
constructor(doc, env = {}) {
|
constructor(doc, env = {}) {
|
||||||
this.defaultConfigValues = {
|
this.defaultConfigValues = {
|
||||||
VERSION: 1,
|
VERSION: 1,
|
||||||
ENDPOINT: '',
|
ENDPOINT: '',
|
||||||
PLUGINS: [],
|
PLUGINS: [],
|
||||||
DEFAULTS: {},
|
DEFAULTS: {},
|
||||||
ENVIRONMENT: {},
|
ENVIRONMENT: {},
|
||||||
HOSTS: [],
|
HOSTS: [],
|
||||||
COOKIEJAR: false
|
COOKIEJAR: false
|
||||||
};
|
};
|
||||||
|
|
||||||
this.configKeys = Object.keys(this.defaultConfigValues);
|
this.configKeys = Object.keys(this.defaultConfigValues);
|
||||||
this.doc = doc;
|
this.doc = doc;
|
||||||
|
|
||||||
let config = this.loadConfig(doc);
|
let config = this.loadConfig(doc);
|
||||||
this.configKeys.forEach(k => {
|
this.configKeys.forEach(k => {
|
||||||
this[k] = config[k] || this.defaultConfigValues[k];
|
this[k] = config[k] || this.defaultConfigValues[k];
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ENVIRONMENT = deepMerge(this.ENVIRONMENT, env);
|
this.ENVIRONMENT = deepMerge(this.ENVIRONMENT, env);
|
||||||
|
|
||||||
this.REQUESTS = [];
|
this.REQUESTS = [];
|
||||||
|
|
||||||
this.loadRequests(doc, {
|
this.loadRequests(doc, {
|
||||||
DEFAULTS: this.DEFAULTS,
|
DEFAULTS: this.DEFAULTS,
|
||||||
ENDPOINT: this.ENDPOINT
|
ENDPOINT: this.ENDPOINT
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loadHosts(this.HOSTS, config);
|
this.loadHosts(this.HOSTS, config);
|
||||||
|
|
||||||
this.PLUGINS = new Plugins(this.PLUGINS);
|
this.PLUGINS = new Plugins(this.PLUGINS);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadHosts(hosts, rootConfig) {
|
loadHosts(hosts, rootConfig) {
|
||||||
hosts.forEach(host => {
|
hosts.forEach(host => {
|
||||||
if (typeof host.host === 'undefined') {
|
if (typeof host.host === 'undefined') {
|
||||||
throw new Error(`Host doesn't indicate it's host name.`);
|
throw new Error(`Host doesn't indicate it's host name.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = deepMerge(
|
let config = deepMerge(
|
||||||
this.defaultConfigValues,
|
this.defaultConfigValues,
|
||||||
this.loadConfig(host)
|
this.loadConfig(host)
|
||||||
);
|
);
|
||||||
|
|
||||||
config.DEFAULTS = deepMerge(rootConfig.DEFAULTS, config.DEFAULTS);
|
config.DEFAULTS = deepMerge(rootConfig.DEFAULTS, config.DEFAULTS);
|
||||||
|
|
||||||
this.loadRequests(host, {
|
this.loadRequests(host, {
|
||||||
DEFAULTS: config.DEFAULTS,
|
DEFAULTS: config.DEFAULTS,
|
||||||
ENDPOINT: config.ENDPOINT,
|
ENDPOINT: config.ENDPOINT,
|
||||||
NAMESPACE: host.host
|
NAMESPACE: host.host
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadRequests(host, settings) {
|
loadRequests(host, settings) {
|
||||||
let requests = Object.keys(host)
|
let requests = Object.keys(host)
|
||||||
.filter(key => requestRegex.test(key))
|
.filter(key => requestRegex.test(key))
|
||||||
.map(key => {
|
.map(key => {
|
||||||
let requestDefinitionIsString = typeof host[key] === 'string';
|
let requestDefinitionIsString = typeof host[key] === 'string';
|
||||||
let originalRequest = requestDefinitionIsString
|
let originalRequest = requestDefinitionIsString
|
||||||
? { ALIAS: host[key] }
|
? { ALIAS: host[key] }
|
||||||
: host[key];
|
: host[key];
|
||||||
|
|
||||||
let request = UpperCaseKeys(originalRequest);
|
let request = UpperCaseKeys(originalRequest);
|
||||||
|
|
||||||
if (settings.NAMESPACE) {
|
if (settings.NAMESPACE) {
|
||||||
request.ALIAS = `${settings.NAMESPACE}:${request.ALIAS}`;
|
request.ALIAS = `${settings.NAMESPACE}:${request.ALIAS}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
request.REQUEST = key;
|
request.REQUEST = key;
|
||||||
request.COOKIEJAR = this.COOKIEJAR;
|
request.COOKIEJAR = this.COOKIEJAR;
|
||||||
request.ENDPOINT = settings.ENDPOINT;
|
request.ENDPOINT = settings.ENDPOINT;
|
||||||
|
|
||||||
let defaults = UpperCaseKeys(settings.DEFAULTS);
|
let defaults = UpperCaseKeys(settings.DEFAULTS);
|
||||||
|
|
||||||
return deepMerge(defaults, request);
|
return deepMerge(defaults, request);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.REQUESTS = this.REQUESTS.concat(requests);
|
this.REQUESTS = this.REQUESTS.concat(requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfig(host) {
|
loadConfig(host) {
|
||||||
let config = {};
|
let config = {};
|
||||||
|
|
||||||
Object.keys(host)
|
Object.keys(host)
|
||||||
.filter(k => this.configKeys.includes(k.toUpperCase()))
|
.filter(k => this.configKeys.includes(k.toUpperCase()))
|
||||||
.forEach(k => (config[k.toUpperCase()] = host[k]));
|
.forEach(k => (config[k.toUpperCase()] = host[k]));
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Config;
|
module.exports = Config;
|
||||||
|
|
|
||||||
130
src/plugins.js
130
src/plugins.js
|
|
@ -5,91 +5,91 @@ const { toKebabCase, dynamicValueRegex, replaceInObject } = require('./shared');
|
||||||
const isPlainObject = require('is-plain-object');
|
const isPlainObject = require('is-plain-object');
|
||||||
|
|
||||||
class Plugins {
|
class Plugins {
|
||||||
constructor(plugins = []) {
|
constructor(plugins = []) {
|
||||||
this.registry = {
|
this.registry = {
|
||||||
preRequestModifiers: [],
|
preRequestModifiers: [],
|
||||||
postRequestModifiers: [],
|
postRequestModifiers: [],
|
||||||
dynamicValues: []
|
dynamicValues: []
|
||||||
};
|
};
|
||||||
|
|
||||||
this.context = {};
|
this.context = {};
|
||||||
|
|
||||||
plugins.forEach(plugin => this.loadPlugin(plugin));
|
plugins.forEach(plugin => this.loadPlugin(plugin));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPlugin(plugin) {
|
loadPlugin(plugin) {
|
||||||
let name = plugin;
|
let name = plugin;
|
||||||
let settings = {};
|
let settings = {};
|
||||||
|
|
||||||
if (typeof plugin === 'object') {
|
if (typeof plugin === 'object') {
|
||||||
let keys = Object.keys(plugin);
|
let keys = Object.keys(plugin);
|
||||||
|
|
||||||
if (keys.length !== 1) {
|
if (keys.length !== 1) {
|
||||||
throw new Error(`Plugin items should contain only one key.`);
|
throw new Error(`Plugin items should contain only one key.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
name = keys[0];
|
name = keys[0];
|
||||||
settings = plugin[name];
|
settings = plugin[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin = requireg(`beau-${toKebabCase(name)}`);
|
plugin = requireg(`beau-${toKebabCase(name)}`);
|
||||||
new plugin(this, settings);
|
new plugin(this, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
executeModifier(modifier, obj, orig) {
|
executeModifier(modifier, obj, orig) {
|
||||||
let result = deepmerge({}, obj, { isMergeableObject: isPlainObject });
|
let result = deepmerge({}, obj, { isMergeableObject: isPlainObject });
|
||||||
|
|
||||||
this.registry[modifier].forEach(
|
this.registry[modifier].forEach(
|
||||||
modifier => (result = modifier(result, orig))
|
modifier => (result = modifier(result, orig))
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceDynamicValues(obj) {
|
replaceDynamicValues(obj) {
|
||||||
return replaceInObject(obj, val => {
|
return replaceInObject(obj, val => {
|
||||||
let valIsEmpty = val.trim().length === 0;
|
let valIsEmpty = val.trim().length === 0;
|
||||||
|
|
||||||
if (valIsEmpty) {
|
if (valIsEmpty) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let onlyHasDynamic =
|
let onlyHasDynamic =
|
||||||
val.replace(dynamicValueRegex, '').trim() === '';
|
val.replace(dynamicValueRegex, '').trim() === '';
|
||||||
|
|
||||||
if (onlyHasDynamic) {
|
if (onlyHasDynamic) {
|
||||||
let call;
|
let call;
|
||||||
val.replace(dynamicValueRegex, (match, c) => {
|
val.replace(dynamicValueRegex, (match, c) => {
|
||||||
call = c;
|
call = c;
|
||||||
});
|
});
|
||||||
|
|
||||||
return vm.runInContext(call, this.context);
|
return vm.runInContext(call, this.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return val.replace(dynamicValueRegex, (match, call) => {
|
return val.replace(dynamicValueRegex, (match, call) => {
|
||||||
return vm.runInContext(call, this.context);
|
return vm.runInContext(call, this.context);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`DynamicValue: ` + e);
|
throw new Error(`DynamicValue: ` + e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addPreRequestModifier(modifier) {
|
addPreRequestModifier(modifier) {
|
||||||
this.registry.preRequestModifiers.push(modifier);
|
this.registry.preRequestModifiers.push(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
addPostRequestModifier(modifier) {
|
addPostRequestModifier(modifier) {
|
||||||
this.registry.postRequestModifiers.push(modifier);
|
this.registry.postRequestModifiers.push(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
defineDynamicValue(name, fn) {
|
defineDynamicValue(name, fn) {
|
||||||
this.registry.dynamicValues.push({ name, fn });
|
this.registry.dynamicValues.push({ name, fn });
|
||||||
this.context[name] = fn;
|
this.context[name] = fn;
|
||||||
|
|
||||||
vm.createContext(this.context);
|
vm.createContext(this.context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Plugins;
|
module.exports = Plugins;
|
||||||
|
|
|
||||||
232
src/request.js
232
src/request.js
|
|
@ -4,149 +4,149 @@ const RequestCache = require('./requestCache');
|
||||||
const Plugins = require('./plugins');
|
const Plugins = require('./plugins');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
httpVerbs,
|
httpVerbs,
|
||||||
requestRegex,
|
requestRegex,
|
||||||
replacementRegex,
|
replacementRegex,
|
||||||
UpperCaseKeys,
|
UpperCaseKeys,
|
||||||
removeOptionalKeys
|
removeOptionalKeys
|
||||||
} = require('./shared');
|
} = require('./shared');
|
||||||
|
|
||||||
class Request {
|
class Request {
|
||||||
constructor(req, plugins = new Plugins()) {
|
constructor(req, plugins = new Plugins()) {
|
||||||
this.originalRequest = req;
|
this.originalRequest = req;
|
||||||
this.plugins = plugins;
|
this.plugins = plugins;
|
||||||
|
|
||||||
this.loadCofiguration(
|
this.loadCofiguration(
|
||||||
[
|
[
|
||||||
'REQUEST',
|
'REQUEST',
|
||||||
'ENDPOINT',
|
'ENDPOINT',
|
||||||
'HEADERS',
|
'HEADERS',
|
||||||
'PAYLOAD',
|
'PAYLOAD',
|
||||||
'PARAMS',
|
'PARAMS',
|
||||||
'FORM',
|
'FORM',
|
||||||
'ALIAS',
|
'ALIAS',
|
||||||
'COOKIEJAR',
|
'COOKIEJAR',
|
||||||
'FORMDATA'
|
'FORMDATA'
|
||||||
],
|
],
|
||||||
req
|
req
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!this.ALIAS) {
|
if (!this.ALIAS) {
|
||||||
throw new Error(`${this.REQUEST} is missing an alias.`);
|
throw new Error(`${this.REQUEST} is missing an alias.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { VERB, PATH } = this.parseRequest(this.REQUEST);
|
const { VERB, PATH } = this.parseRequest(this.REQUEST);
|
||||||
|
|
||||||
this.VERB = VERB;
|
this.VERB = VERB;
|
||||||
this.PATH = PATH;
|
this.PATH = PATH;
|
||||||
|
|
||||||
this.DEPENDENCIES = this.findDependencies(req);
|
this.DEPENDENCIES = this.findDependencies(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCofiguration(keys, obj) {
|
loadCofiguration(keys, obj) {
|
||||||
obj = UpperCaseKeys(obj);
|
obj = UpperCaseKeys(obj);
|
||||||
keys.forEach(k => {
|
keys.forEach(k => {
|
||||||
this[k] = obj[k];
|
this[k] = obj[k];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
parseRequest(request) {
|
parseRequest(request) {
|
||||||
const parts = request.match(requestRegex);
|
const parts = request.match(requestRegex);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
VERB: parts[1],
|
VERB: parts[1],
|
||||||
PATH: parts[2]
|
PATH: parts[2]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
findDependencies(request, set = new Set()) {
|
findDependencies(request, set = new Set()) {
|
||||||
let type = typeof request;
|
let type = typeof request;
|
||||||
|
|
||||||
if (type === 'object') {
|
if (type === 'object') {
|
||||||
Object.keys(request)
|
Object.keys(request)
|
||||||
.filter(key => key !== 'ALIAS')
|
.filter(key => key !== 'ALIAS')
|
||||||
.forEach(key => {
|
.forEach(key => {
|
||||||
set = this.findDependencies(request[key], set);
|
set = this.findDependencies(request[key], set);
|
||||||
});
|
});
|
||||||
} else if (type === 'string') {
|
} else if (type === 'string') {
|
||||||
const matches = [];
|
const matches = [];
|
||||||
request.replace(
|
request.replace(
|
||||||
replacementRegex,
|
replacementRegex,
|
||||||
(match, g1) => !match.startsWith('\\') && matches.push(g1)
|
(match, g1) => !match.startsWith('\\') && matches.push(g1)
|
||||||
);
|
);
|
||||||
|
|
||||||
const deps = matches.map(m => m.split('.')[0]);
|
const deps = matches.map(m => m.split('.')[0]);
|
||||||
|
|
||||||
return new Set([...set, ...deps]);
|
return new Set([...set, ...deps]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
async exec(cache = new RequestCache()) {
|
async exec(cache = new RequestCache()) {
|
||||||
let settings = cache.parse({
|
let settings = cache.parse({
|
||||||
baseUrl: this.ENDPOINT,
|
baseUrl: this.ENDPOINT,
|
||||||
uri: this.PATH,
|
uri: this.PATH,
|
||||||
method: this.VERB,
|
method: this.VERB,
|
||||||
jar: this.COOKIEJAR,
|
jar: this.COOKIEJAR,
|
||||||
|
|
||||||
headers: this.HEADERS,
|
headers: this.HEADERS,
|
||||||
qs: this.PARAMS,
|
qs: this.PARAMS,
|
||||||
body: this.PAYLOAD,
|
body: this.PAYLOAD,
|
||||||
form: this.FORM,
|
form: this.FORM,
|
||||||
formData: this.FORMDATA,
|
formData: this.FORMDATA,
|
||||||
|
|
||||||
json: true,
|
json: true,
|
||||||
simple: false,
|
simple: false,
|
||||||
resolveWithFullResponse: true
|
resolveWithFullResponse: true
|
||||||
});
|
});
|
||||||
|
|
||||||
settings = removeOptionalKeys(settings, [
|
settings = removeOptionalKeys(settings, [
|
||||||
'headers',
|
'headers',
|
||||||
'qs',
|
'qs',
|
||||||
'body',
|
'body',
|
||||||
'form',
|
'form',
|
||||||
'formData'
|
'formData'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
settings = this.plugins.replaceDynamicValues(settings);
|
settings = this.plugins.replaceDynamicValues(settings);
|
||||||
|
|
||||||
settings = this.plugins.executeModifier(
|
settings = this.plugins.executeModifier(
|
||||||
'preRequestModifiers',
|
'preRequestModifiers',
|
||||||
settings,
|
settings,
|
||||||
this.originalRequest
|
this.originalRequest
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await request(settings);
|
const response = await request(settings);
|
||||||
|
|
||||||
let results = {
|
let results = {
|
||||||
request: {
|
request: {
|
||||||
headers: response.request.headers,
|
headers: response.request.headers,
|
||||||
body: response.request.body,
|
body: response.request.body,
|
||||||
endpoint: response.request.uri.href
|
endpoint: response.request.uri.href
|
||||||
},
|
},
|
||||||
response: {
|
response: {
|
||||||
status: response.statusCode,
|
status: response.statusCode,
|
||||||
headers: response.headers,
|
headers: response.headers,
|
||||||
body: response.body
|
body: response.body
|
||||||
},
|
},
|
||||||
body: response.body
|
body: response.body
|
||||||
};
|
};
|
||||||
|
|
||||||
results = this.plugins.executeModifier(
|
results = this.plugins.executeModifier(
|
||||||
'postRequestModifiers',
|
'postRequestModifiers',
|
||||||
results,
|
results,
|
||||||
this.originalRequest
|
this.originalRequest
|
||||||
);
|
);
|
||||||
|
|
||||||
cache.add(this.ALIAS, results);
|
cache.add(this.ALIAS, results);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
} catch ({ error }) {
|
} catch ({ error }) {
|
||||||
throw new Error(`Request Error: ` + error);
|
throw new Error(`Request Error: ` + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Request;
|
module.exports = Request;
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,46 @@
|
||||||
const { replacementRegex, replaceInObject } = require('./shared');
|
const { replacementRegex, replaceInObject } = require('./shared');
|
||||||
|
|
||||||
class RequestCache {
|
class RequestCache {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.$cache = {};
|
this.$cache = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
exists(key) {
|
exists(key) {
|
||||||
return typeof this.$cache[key] !== 'undefined';
|
return typeof this.$cache[key] !== 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
add(key, value) {
|
add(key, value) {
|
||||||
this.$cache[key] = value;
|
this.$cache[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get(path) {
|
get(path) {
|
||||||
let result = this.$cache;
|
let result = this.$cache;
|
||||||
path.split('.').forEach(part => {
|
path.split('.').forEach(part => {
|
||||||
if (result[part] === undefined) {
|
if (result[part] === undefined) {
|
||||||
throw new Error(`${path} not found in cache.`);
|
throw new Error(`${path} not found in cache.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = result[part];
|
result = result[part];
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(item) {
|
parse(item) {
|
||||||
if (item === null) {
|
if (item === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return replaceInObject(item, item => {
|
return replaceInObject(item, item => {
|
||||||
return item.replace(replacementRegex, (match, key) => {
|
return item.replace(replacementRegex, (match, key) => {
|
||||||
if (match.startsWith('\\')) {
|
if (match.startsWith('\\')) {
|
||||||
return match.replace('\\$', '$');
|
return match.replace('\\$', '$');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.get(key);
|
return this.get(key);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RequestCache;
|
module.exports = RequestCache;
|
||||||
|
|
|
||||||
|
|
@ -3,58 +3,58 @@ const RequestCache = require('./requestCache');
|
||||||
const httpVerbs = require('./shared').httpVerbs;
|
const httpVerbs = require('./shared').httpVerbs;
|
||||||
|
|
||||||
class RequestList {
|
class RequestList {
|
||||||
constructor(config = { REQUESTS: [] }) {
|
constructor(config = { REQUESTS: [] }) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.REQUESTS = config.REQUESTS;
|
this.REQUESTS = config.REQUESTS;
|
||||||
|
|
||||||
this.list = this.loadRequests();
|
this.list = this.loadRequests();
|
||||||
this.cache = new RequestCache();
|
this.cache = new RequestCache();
|
||||||
|
|
||||||
this.cache.add(`env`, this.config.ENVIRONMENT);
|
this.cache.add(`env`, this.config.ENVIRONMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execByAlias(alias) {
|
async execByAlias(alias) {
|
||||||
if (this.cache.exists(alias)) {
|
if (this.cache.exists(alias)) {
|
||||||
return this.cache.get(alias);
|
return this.cache.get(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
const request = this.list.find(r => r.ALIAS === alias);
|
const request = this.list.find(r => r.ALIAS === alias);
|
||||||
|
|
||||||
if (typeof request === 'undefined') {
|
if (typeof request === 'undefined') {
|
||||||
throw new Error(`${alias} not found among the requests.`);
|
throw new Error(`${alias} not found among the requests.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.fetchDependencies(Array.from(request.DEPENDENCIES));
|
await this.fetchDependencies(Array.from(request.DEPENDENCIES));
|
||||||
return await request.exec(this.cache);
|
return await request.exec(this.cache);
|
||||||
} catch (reason) {
|
} catch (reason) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Request: ${request.VERB} ${
|
`Request: ${request.VERB} ${
|
||||||
request.ENDPOINT
|
request.ENDPOINT
|
||||||
} FAILED. \n${reason}`
|
} FAILED. \n${reason}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchDependencies(dependencies) {
|
async fetchDependencies(dependencies) {
|
||||||
dependencies = dependencies.map(d => this.execByAlias(d));
|
dependencies = dependencies.map(d => this.execByAlias(d));
|
||||||
await Promise.all(dependencies);
|
await Promise.all(dependencies);
|
||||||
|
|
||||||
return this.cache;
|
return this.cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadRequests() {
|
loadRequests() {
|
||||||
let requests = [];
|
let requests = [];
|
||||||
this.REQUESTS.forEach(request => {
|
this.REQUESTS.forEach(request => {
|
||||||
try {
|
try {
|
||||||
requests.push(new Request(request, this.config.PLUGINS));
|
requests.push(new Request(request, this.config.PLUGINS));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`${request.request} was ignored: ${e}`);
|
throw new Error(`${request.request} was ignored: ${e}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return requests;
|
return requests;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RequestList;
|
module.exports = RequestList;
|
||||||
|
|
|
||||||
122
src/schema.js
122
src/schema.js
|
|
@ -2,78 +2,78 @@ const Joi = require('joi');
|
||||||
const { requestRegex } = require('./shared.js');
|
const { requestRegex } = require('./shared.js');
|
||||||
|
|
||||||
const pluginSchema = [
|
const pluginSchema = [
|
||||||
Joi.string(),
|
Joi.string(),
|
||||||
Joi.object()
|
Joi.object()
|
||||||
.keys(null)
|
.keys(null)
|
||||||
.max(1)
|
.max(1)
|
||||||
];
|
];
|
||||||
|
|
||||||
const requestSchema = [
|
const requestSchema = [
|
||||||
Joi.object()
|
Joi.object()
|
||||||
.keys({
|
.keys({
|
||||||
HEADERS: Joi.object().keys(null),
|
HEADERS: Joi.object().keys(null),
|
||||||
PAYLOAD: [Joi.object().keys(null), Joi.string()],
|
PAYLOAD: [Joi.object().keys(null), Joi.string()],
|
||||||
PARAMS: Joi.object().keys(null),
|
PARAMS: Joi.object().keys(null),
|
||||||
FORM: Joi.object().keys(null),
|
FORM: Joi.object().keys(null),
|
||||||
ALIAS: Joi.string().required(),
|
ALIAS: Joi.string().required(),
|
||||||
FORMDATA: Joi.object().keys(null)
|
FORMDATA: Joi.object().keys(null)
|
||||||
})
|
})
|
||||||
.without('FORM', ['PAYLOAD', 'FORMDATA'])
|
.without('FORM', ['PAYLOAD', 'FORMDATA'])
|
||||||
.without('PAYLOAD', ['FORM', 'FORMDATA'])
|
.without('PAYLOAD', ['FORM', 'FORMDATA'])
|
||||||
.without('FORMDATA', ['FORM', 'PAYLOAD'])
|
.without('FORMDATA', ['FORM', 'PAYLOAD'])
|
||||||
.rename(/headers/i, 'HEADERS', { override: true })
|
.rename(/headers/i, 'HEADERS', { override: true })
|
||||||
.rename(/payload/i, 'PAYLOAD', { override: true })
|
.rename(/payload/i, 'PAYLOAD', { override: true })
|
||||||
.rename(/params/i, 'PARAMS', { override: true })
|
.rename(/params/i, 'PARAMS', { override: true })
|
||||||
.rename(/form/i, 'FORM', { override: true })
|
.rename(/form/i, 'FORM', { override: true })
|
||||||
.rename(/alias/i, 'ALIAS', { override: true }),
|
.rename(/alias/i, 'ALIAS', { override: true }),
|
||||||
|
|
||||||
Joi.string()
|
Joi.string()
|
||||||
];
|
];
|
||||||
|
|
||||||
const hostSchema = Joi.object()
|
const hostSchema = Joi.object()
|
||||||
.keys({
|
.keys({
|
||||||
HOST: Joi.string().required(),
|
HOST: Joi.string().required(),
|
||||||
ENDPOINT: Joi.string(),
|
ENDPOINT: Joi.string(),
|
||||||
DEFAULTS: Joi.object().keys(null)
|
DEFAULTS: Joi.object().keys(null)
|
||||||
})
|
})
|
||||||
.pattern(requestRegex, requestSchema)
|
.pattern(requestRegex, requestSchema)
|
||||||
.rename(/host/i, 'HOST', { override: true })
|
.rename(/host/i, 'HOST', { override: true })
|
||||||
.rename(/defaults/i, 'DEFAULTS', { override: true })
|
.rename(/defaults/i, 'DEFAULTS', { override: true })
|
||||||
.rename(/endpoint/i, 'ENDPOINT', { override: true });
|
.rename(/endpoint/i, 'ENDPOINT', { override: true });
|
||||||
|
|
||||||
const schema = Joi.object()
|
const schema = Joi.object()
|
||||||
.keys({
|
.keys({
|
||||||
VERSION: Joi.number().integer(),
|
VERSION: Joi.number().integer(),
|
||||||
ENDPOINT: Joi.string().uri(),
|
ENDPOINT: Joi.string().uri(),
|
||||||
PLUGINS: Joi.array().items(pluginSchema),
|
PLUGINS: Joi.array().items(pluginSchema),
|
||||||
DEFAULTS: Joi.object(),
|
DEFAULTS: Joi.object(),
|
||||||
ENVIRONMENT: Joi.object(),
|
ENVIRONMENT: Joi.object(),
|
||||||
HOSTS: Joi.array().items(hostSchema),
|
HOSTS: Joi.array().items(hostSchema),
|
||||||
COOKIEJAR: Joi.boolean()
|
COOKIEJAR: Joi.boolean()
|
||||||
})
|
})
|
||||||
.pattern(requestRegex, requestSchema)
|
.pattern(requestRegex, requestSchema)
|
||||||
.rename(/version/i, 'VERSION', { override: true })
|
.rename(/version/i, 'VERSION', { override: true })
|
||||||
.rename(/endpoint/i, 'ENDPOINT', { override: true })
|
.rename(/endpoint/i, 'ENDPOINT', { override: true })
|
||||||
.rename(/hosts/i, 'HOSTS', { override: true })
|
.rename(/hosts/i, 'HOSTS', { override: true })
|
||||||
.rename(/plugins/i, 'PLUGINS', { override: true })
|
.rename(/plugins/i, 'PLUGINS', { override: true })
|
||||||
.rename(/defaults/i, 'DEFAULTS', { override: true })
|
.rename(/defaults/i, 'DEFAULTS', { override: true })
|
||||||
.rename(/environment/i, 'ENVIRONMENT', { override: true })
|
.rename(/environment/i, 'ENVIRONMENT', { override: true })
|
||||||
.rename(/cookiejar/i, 'COOKIEJAR', { override: true });
|
.rename(/cookiejar/i, 'COOKIEJAR', { override: true });
|
||||||
|
|
||||||
const validate = async function(config) {
|
const validate = async function(config) {
|
||||||
try {
|
try {
|
||||||
let results = await Joi.validate(config, schema, {
|
let results = await Joi.validate(config, schema, {
|
||||||
allowUnknown: true
|
allowUnknown: true
|
||||||
});
|
});
|
||||||
return { valid: true };
|
return { valid: true };
|
||||||
} catch ({ name, details }) {
|
} catch ({ name, details }) {
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
message: `${name}: \n ${details
|
message: `${name}: \n ${details
|
||||||
.map(d => d.message + ' @ ' + d.path)
|
.map(d => d.message + ' @ ' + d.path)
|
||||||
.join(' \n ')}`
|
.join(' \n ')}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { schema, validate };
|
module.exports = { schema, validate };
|
||||||
|
|
|
||||||
100
src/shared.js
100
src/shared.js
|
|
@ -1,13 +1,13 @@
|
||||||
const httpVerbs = [
|
const httpVerbs = [
|
||||||
'GET',
|
'GET',
|
||||||
'HEAD',
|
'HEAD',
|
||||||
'POST',
|
'POST',
|
||||||
'PUT',
|
'PUT',
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'CONNECT',
|
'CONNECT',
|
||||||
'OPTIONS',
|
'OPTIONS',
|
||||||
'TRACE',
|
'TRACE',
|
||||||
'PATCH'
|
'PATCH'
|
||||||
];
|
];
|
||||||
|
|
||||||
const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i');
|
const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i');
|
||||||
|
|
@ -15,65 +15,65 @@ const replacementRegex = /(?:\\?)\$([a-zA-Z\.\d\-\_\/\\\:]+)/g;
|
||||||
const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])+?\))\]/g;
|
const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])+?\))\]/g;
|
||||||
|
|
||||||
const UpperCaseKeys = function(obj) {
|
const UpperCaseKeys = function(obj) {
|
||||||
let result = {};
|
let result = {};
|
||||||
Object.keys(obj).forEach(k => (result[k.toUpperCase()] = obj[k]));
|
Object.keys(obj).forEach(k => (result[k.toUpperCase()] = obj[k]));
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeOptionalKeys = function(obj, optionalValues) {
|
const removeOptionalKeys = function(obj, optionalValues) {
|
||||||
let result = {};
|
let result = {};
|
||||||
|
|
||||||
Object.keys(obj).forEach(key => {
|
Object.keys(obj).forEach(key => {
|
||||||
if (
|
if (
|
||||||
optionalValues.includes(key) &&
|
optionalValues.includes(key) &&
|
||||||
(Object.keys(obj[key]).length === 0 &&
|
(Object.keys(obj[key]).length === 0 &&
|
||||||
obj[key].constructor === Object)
|
obj[key].constructor === Object)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result[key] = obj[key];
|
result[key] = obj[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toKebabCase = function(str) {
|
const toKebabCase = function(str) {
|
||||||
return str
|
return str
|
||||||
.trim()
|
.trim()
|
||||||
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
||||||
.replace(/\s+/g, '-')
|
.replace(/\s+/g, '-')
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
const replaceInObject = function(obj, fn) {
|
const replaceInObject = function(obj, fn) {
|
||||||
if (obj === null) {
|
if (obj === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let type = typeof obj;
|
let type = typeof obj;
|
||||||
|
|
||||||
if (type === 'undefined') {
|
if (type === 'undefined') {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'string') {
|
if (type === 'string') {
|
||||||
return fn(obj);
|
return fn(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'object') {
|
if (type === 'object') {
|
||||||
Object.keys(obj).forEach(k => (obj[k] = replaceInObject(obj[k], fn)));
|
Object.keys(obj).forEach(k => (obj[k] = replaceInObject(obj[k], fn)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
requestRegex,
|
requestRegex,
|
||||||
replacementRegex,
|
replacementRegex,
|
||||||
dynamicValueRegex,
|
dynamicValueRegex,
|
||||||
UpperCaseKeys,
|
UpperCaseKeys,
|
||||||
removeOptionalKeys,
|
removeOptionalKeys,
|
||||||
toKebabCase,
|
toKebabCase,
|
||||||
replaceInObject
|
replaceInObject
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue