Merge pull request #1 from Seich/defaults

Added Defaults.
This commit is contained in:
Sergio Díaz 2017-12-27 16:47:14 -06:00 committed by GitHub
commit dc7d6f977d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 2229 additions and 358 deletions

View File

@ -4,7 +4,11 @@
<h1 align="center">Beau</h1> <h1 align="center">Beau</h1>
<p align="center">Testing JSON APIs made easy.</p> <p align="center">Testing JSON APIs made easy.</p>
<p align="center">
<a href="https://codeclimate.com/github/Seich/Beau/maintainability"><img src="https://api.codeclimate.com/v1/badges/bc2de4d71893d6a2d18b/maintainability" /></a>
<a href="https://codeclimate.com/github/Seich/Beau/test_coverage"><img src="https://api.codeclimate.com/v1/badges/bc2de4d71893d6a2d18b/test_coverage" /></a>
<a href="https://circleci.com/gh/Seich/Beau/tree/master"><img src="https://circleci.com/gh/Seich/Beau/tree/master.svg?style=svg" alt="CircleCI"></a>
</p>
## What is Beau? ## What is Beau?
Beau, is a CLI that executes HTTP requests based on a YAML configuration file. This makes testing easy, it allows you to share test requests with others as part of your repo. Beau, is a CLI that executes HTTP requests based on a YAML configuration file. This makes testing easy, it allows you to share test requests with others as part of your repo.
@ -33,7 +37,7 @@ Beau, is a CLI that executes HTTP requests based on a YAML configuration file. T
## Example Configuration File ## Example Configuration File
version: 1 version: 1
host: https://example.com/api/ endpoint: https://example.com/api/
POST /session: POST /session:
ALIAS: session ALIAS: session

View File

@ -0,0 +1,96 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Beau's config Loader. should set up defaults for all requests 1`] = `
Beau {
"config": Object {
"CACHE": false,
"DEFAULTS": Object {
"headers": Object {
"authentication": "hello",
},
},
"ENDPOINT": "http://jsonplaceholder.typicode.com",
"PLUGINS": Array [],
"VERSION": 1,
},
"configKeys": Array [
"VERSION",
"CACHE",
"ENDPOINT",
"PLUGINS",
"DEFAULTS",
],
"defaults": Object {
"CACHE": false,
"DEFAULTS": Object {
"headers": Object {
"authentication": "hello",
},
},
"ENDPOINT": "http://jsonplaceholder.typicode.com",
"PLUGINS": Array [],
"VERSION": 1,
},
"requests": RequestList {
"cache": RequestCache {
"$cache": Object {},
},
"config": Object {
"CACHE": false,
"DEFAULTS": Object {
"headers": Object {
"authentication": "hello",
},
},
"ENDPOINT": "http://jsonplaceholder.typicode.com",
"PLUGINS": Array [],
"VERSION": 1,
},
"list": Array [
Request {
"ALIAS": "get-post",
"DEPENDENCIES": Set {},
"DOCUMENTATION": undefined,
"ENDPOINT": "http://jsonplaceholder.typicode.com/posts/1",
"HEADERS": Object {
"authentication": "hello",
},
"PARAMS": undefined,
"PAYLOAD": undefined,
"VERB": "GET",
"originalRequest": Object {
"ALIAS": "get-post",
"ENDPOINT": "http://jsonplaceholder.typicode.com",
"headers": Object {
"authentication": "hello",
},
"request": "GET /posts/1",
},
},
Request {
"ALIAS": "user",
"DEPENDENCIES": Set {},
"DOCUMENTATION": undefined,
"ENDPOINT": "http://jsonplaceholder.typicode.com/user",
"HEADERS": Object {
"authentication": "hello",
"hello": "world",
},
"PARAMS": undefined,
"PAYLOAD": undefined,
"VERB": "GET",
"originalRequest": Object {
"ENDPOINT": "http://jsonplaceholder.typicode.com",
"alias": "user",
"headers": Object {
"authentication": "hello",
"hello": "world",
},
"request": "GET /user",
},
},
],
"modifiers": Array [],
},
}
`;

View File

@ -48,7 +48,7 @@ Array [
}, },
Object { Object {
"alias": "show", "alias": "show",
"host": "http://martianwabbit.com", "endpoint": "http://martianwabbit.com",
"request": "GET /user", "request": "GET /user",
}, },
], ],

View File

@ -1,23 +1,44 @@
const Beau = require('../beau');
const yaml = require('js-yaml'); const yaml = require('js-yaml');
const Beau = require('../beau');
describe(`Beau's config Loader.`, () => { describe(`Beau's config Loader.`, () => {
it('Should only load valid configuration keys', () => { it('Should only load valid configuration keys', () => {
let host = 'http://martianwabbit.com'; const doc = yaml.safeLoad(`
let version = 1; version: 1
let cache = false; endpoint: http://martianwabbit.com
let shouldntBeAdded = true; cache: false
shouldntBeAdded: true
`);
let beau = new Beau({ const beau = new Beau(doc);
version,
host,
cache,
shouldntBeAdded
});
expect(beau.config.HOST).toBe(host); expect(beau.config.ENDPOINT).toBe(doc.endpoint);
expect(beau.config.CACHE).toBe(cache); expect(beau.config.CACHE).toBe(doc.cache);
expect(beau.config.VERSION).toBe(version); expect(beau.config.VERSION).toBe(doc.version);
expect(beau.config.shouldntBeAdded).toBeUndefined(); expect(beau.config.shouldntBeAdded).toBeUndefined();
}); });
it('should set up defaults for all requests', () => {
const doc = yaml.safeLoad(`
version: 1
endpoint: 'http://jsonplaceholder.typicode.com'
defaults:
headers:
authentication: hello
GET /posts/1: get-post
GET /user:
alias: user
headers:
hello: world
`);
const beau = new Beau(doc);
expect(beau).toMatchSnapshot();
beau.requests.list.forEach(r => {
expect(r.HEADERS.authentication).toMatch('hello');
});
});
}); });

View File

@ -12,7 +12,7 @@ describe('Request', () => {
beforeEach(() => { beforeEach(() => {
req = { req = {
request: 'POST /user', request: 'POST /user',
host: 'http://martianwabbit.com', endpoint: 'http://martianwabbit.com',
alias: 'update', alias: 'update',
params: { params: {
userId: '$profile.UserId' userId: '$profile.UserId'
@ -31,7 +31,7 @@ describe('Request', () => {
request = new Request(req); request = new Request(req);
requestWithoutDependencies = new Request({ requestWithoutDependencies = new Request({
host: 'http://martianwabbit.com', endpoint: 'http://martianwabbit.com',
request: 'GET /user', request: 'GET /user',
alias: 'show' alias: 'show'
}); });
@ -41,7 +41,7 @@ describe('Request', () => {
test('It should load up the given request', () => { test('It should load up the given request', () => {
expect(request.VERB).toBe('POST'); expect(request.VERB).toBe('POST');
expect(request.ENDPOINT).toBe(req.host + '/user'); expect(request.ENDPOINT).toBe(req.endpoint + '/user');
expect(request.HEADERS).toBeDefined(); expect(request.HEADERS).toBeDefined();
expect(request.PAYLOAD).toBeDefined(); expect(request.PAYLOAD).toBeDefined();
expect(request.PARAMS).toBeDefined(); expect(request.PARAMS).toBeDefined();

View File

@ -2,11 +2,11 @@ const RequestList = require('../requestList');
const requestPromiseNativeMock = require('request-promise-native'); const requestPromiseNativeMock = require('request-promise-native');
describe('RequestList', () => { describe('RequestList', () => {
const host = 'http://martianwabbit.com'; const endpoint = 'http://martianwabbit.com';
const doc = { const doc = {
'POST /session': null, 'POST /session': null,
'Not a Request': null, 'Not a Request': null,
'GET /post': 'get-posts', 'GET /post': { alias: 'get-posts' },
'POST /user': { 'POST /user': {
alias: 'user', alias: 'user',
payload: { payload: {
@ -20,7 +20,7 @@ describe('RequestList', () => {
beforeEach(() => { beforeEach(() => {
requestPromiseNativeMock.fail = false; requestPromiseNativeMock.fail = false;
requests = new RequestList(doc, { requests = new RequestList(doc, {
HOST: host, ENDPOINT: endpoint,
PLUGINS: [ PLUGINS: [
{ {
'beau-jwt': { 'beau-jwt': {
@ -40,7 +40,7 @@ describe('RequestList', () => {
expect(requests.list.length).toBe(3); expect(requests.list.length).toBe(3);
expect(request.VERB).toBe('POST'); expect(request.VERB).toBe('POST');
expect(request.ENDPOINT).toBe(host + '/session'); expect(request.ENDPOINT).toBe(endpoint + '/session');
}); });
it('should fetch dependencies', () => { it('should fetch dependencies', () => {

32
beau.js
View File

@ -1,17 +1,43 @@
const deepMerge = require('deepmerge');
const RequestList = require('./requestList'); const RequestList = require('./requestList');
const requestRegex = require('./shared').requestRegex;
class Beau { class Beau {
constructor(doc) { constructor(doc) {
this.defaults = { this.defaults = {
VERSION: 1, VERSION: 1,
CACHE: false, CACHE: false,
HOST: '', ENDPOINT: '',
PLUGINS: [] PLUGINS: [],
DEFAULTS: []
}; };
this.configKeys = Object.keys(this.defaults); this.configKeys = Object.keys(this.defaults);
this.config = this.loadConfig(doc); this.config = this.loadConfig(doc);
this.requests = new RequestList(doc, this.config); this.requests = this.getRequests(doc);
this.requests = new RequestList(this.requests, this.config);
}
getRequests(doc) {
let requests = Object.keys(doc).filter(key => {
return requestRegex.test(key);
});
let results = {};
requests.forEach(r => {
if (typeof doc[r] === 'string') {
results[r] = {
ALIAS: doc[r]
};
} else {
results[r] = doc[r];
}
results[r] = deepMerge(this.config.DEFAULTS, results[r]);
});
return results;
} }
loadConfig(doc) { loadConfig(doc) {

12
circle.yml Normal file
View File

@ -0,0 +1,12 @@
machine:
node:
version: 8.9.3
dependencies:
post:
- npm install -g codeclimate-test-reporter
test:
pre:
- npm run test:coverage
- codeclimate-test-reporter < ./coverage/lcov.info

View File

@ -1,5 +1,5 @@
VERSION: 1 VERSION: 1
HOST: https://api.github.com ENDPOINT: https://api.github.com
auth: &auth auth: &auth
HEADERS: HEADERS:

View File

@ -1,13 +1,16 @@
version: 1 version: 1
host: 'http://jsonplaceholder.typicode.com' endpoint: 'http://jsonplaceholder.typicode.com'
defaults:
headers:
hello: $posts.body.0.userId
GET /posts/1: get-post GET /posts/1: get-post
GET /posts/: GET /posts/:
alias: posts alias: posts
documentation: headers:
title: Fetch Posts hello: false
description: Fetches all posts available.
POST /posts/: POST /posts/:
alias: new-post alias: new-post

View File

@ -1,4 +1,4 @@
host: http://localhost:10080 endpoint: http://localhost:10080
plugins: plugins:
- beau-jwt: - beau-jwt:

View File

@ -1,5 +1,5 @@
VERSION: '1' VERSION: '1'
HOST: https://slack.com/api ENDPOINT: https://slack.com/api
auth: &auth auth: &auth
token: xoxp-139455775026-139455775090-147751461120-f224ed6ffee029869a0f138d0859e7d6 token: xoxp-139455775026-139455775090-147751461120-f224ed6ffee029869a0f138d0859e7d6

2321
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,14 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "jest", "test": "jest",
"watch": "jest --watch" "watch": "jest --watch",
"test:coverage": "jest --coverage"
}, },
"dependencies": { "dependencies": {
"cli-color": "^1.1.0", "cli-color": "^1.1.0",
"clui": "^0.3.1", "clui": "^0.3.1",
"commander": "^2.12.2", "commander": "^2.12.2",
"deepmerge": "^2.0.1",
"js-yaml": "^3.7.0", "js-yaml": "^3.7.0",
"jsome": "^2.3.26", "jsome": "^2.3.26",
"request": "^2.83.0", "request": "^2.83.0",
@ -29,5 +31,8 @@
}, },
"bin": { "bin": {
"beau": "./bin/beau" "beau": "./bin/beau"
},
"engines": {
"node": ">=8.9.3"
} }
} }

View File

@ -14,15 +14,15 @@ class Request {
REQUEST, REQUEST,
ALIAS, ALIAS,
PAYLOAD, PAYLOAD,
HOST, ENDPOINT,
PARAMS, PARAMS,
HEADERS, HEADERS,
DOCUMENTATION DOCUMENTATION
} = config; } = config;
const { verb, endpoint } = this.parseRequest(REQUEST); const { verb, path } = this.parseRequest(REQUEST);
this.VERB = verb; this.VERB = verb;
this.ENDPOINT = HOST + endpoint; this.ENDPOINT = ENDPOINT + path;
this.HEADERS = HEADERS; this.HEADERS = HEADERS;
this.PAYLOAD = PAYLOAD; this.PAYLOAD = PAYLOAD;
@ -39,11 +39,11 @@ class Request {
} }
parseRequest(request) { parseRequest(request) {
let parts = request.match(requestRegex); const parts = request.match(requestRegex);
return { return {
verb: parts[1], verb: parts[1],
endpoint: parts[2] path: parts[2]
}; };
} }

View File

@ -51,17 +51,8 @@ class RequestList {
}); });
return requests.map(request => { return requests.map(request => {
const type = typeof doc[request];
if (type === 'string') {
doc[request] = {
ALIAS: doc[request]
};
}
doc[request] = doc[request] || {}; doc[request] = doc[request] || {};
doc[request].ENDPOINT = this.config.ENDPOINT;
doc[request].HOST = this.config.HOST;
doc[request].request = request; doc[request].request = request;
return new Request(doc[request]); return new Request(doc[request]);

View File

@ -11,7 +11,7 @@ const httpVerbs = [
]; ];
const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i'); const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i');
const replacementRegex = /\$([a-zA-Z\.\d\-\_]*)/g; const replacementRegex = /\$([a-zA-Z\.\d\-\_\/\\]*)/g;
module.exports = { module.exports = {
httpVerbs, httpVerbs,