mirror of https://github.com/Seich/Beau.git
commit
dc7d6f977d
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
<h1 align="center">Beau</h1>
|
||||
<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?
|
||||
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
|
||||
|
||||
version: 1
|
||||
host: https://example.com/api/
|
||||
endpoint: https://example.com/api/
|
||||
|
||||
POST /session:
|
||||
ALIAS: session
|
||||
|
|
|
|||
|
|
@ -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 [],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
@ -48,7 +48,7 @@ Array [
|
|||
},
|
||||
Object {
|
||||
"alias": "show",
|
||||
"host": "http://martianwabbit.com",
|
||||
"endpoint": "http://martianwabbit.com",
|
||||
"request": "GET /user",
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,23 +1,44 @@
|
|||
const Beau = require('../beau');
|
||||
const yaml = require('js-yaml');
|
||||
const Beau = require('../beau');
|
||||
|
||||
describe(`Beau's config Loader.`, () => {
|
||||
it('Should only load valid configuration keys', () => {
|
||||
let host = 'http://martianwabbit.com';
|
||||
let version = 1;
|
||||
let cache = false;
|
||||
let shouldntBeAdded = true;
|
||||
const doc = yaml.safeLoad(`
|
||||
version: 1
|
||||
endpoint: http://martianwabbit.com
|
||||
cache: false
|
||||
shouldntBeAdded: true
|
||||
`);
|
||||
|
||||
let beau = new Beau({
|
||||
version,
|
||||
host,
|
||||
cache,
|
||||
shouldntBeAdded
|
||||
});
|
||||
const beau = new Beau(doc);
|
||||
|
||||
expect(beau.config.HOST).toBe(host);
|
||||
expect(beau.config.CACHE).toBe(cache);
|
||||
expect(beau.config.VERSION).toBe(version);
|
||||
expect(beau.config.ENDPOINT).toBe(doc.endpoint);
|
||||
expect(beau.config.CACHE).toBe(doc.cache);
|
||||
expect(beau.config.VERSION).toBe(doc.version);
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ describe('Request', () => {
|
|||
beforeEach(() => {
|
||||
req = {
|
||||
request: 'POST /user',
|
||||
host: 'http://martianwabbit.com',
|
||||
endpoint: 'http://martianwabbit.com',
|
||||
alias: 'update',
|
||||
params: {
|
||||
userId: '$profile.UserId'
|
||||
|
|
@ -31,7 +31,7 @@ describe('Request', () => {
|
|||
|
||||
request = new Request(req);
|
||||
requestWithoutDependencies = new Request({
|
||||
host: 'http://martianwabbit.com',
|
||||
endpoint: 'http://martianwabbit.com',
|
||||
request: 'GET /user',
|
||||
alias: 'show'
|
||||
});
|
||||
|
|
@ -41,7 +41,7 @@ describe('Request', () => {
|
|||
|
||||
test('It should load up the given request', () => {
|
||||
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.PAYLOAD).toBeDefined();
|
||||
expect(request.PARAMS).toBeDefined();
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ const RequestList = require('../requestList');
|
|||
const requestPromiseNativeMock = require('request-promise-native');
|
||||
|
||||
describe('RequestList', () => {
|
||||
const host = 'http://martianwabbit.com';
|
||||
const endpoint = 'http://martianwabbit.com';
|
||||
const doc = {
|
||||
'POST /session': null,
|
||||
'Not a Request': null,
|
||||
'GET /post': 'get-posts',
|
||||
'GET /post': { alias: 'get-posts' },
|
||||
'POST /user': {
|
||||
alias: 'user',
|
||||
payload: {
|
||||
|
|
@ -20,7 +20,7 @@ describe('RequestList', () => {
|
|||
beforeEach(() => {
|
||||
requestPromiseNativeMock.fail = false;
|
||||
requests = new RequestList(doc, {
|
||||
HOST: host,
|
||||
ENDPOINT: endpoint,
|
||||
PLUGINS: [
|
||||
{
|
||||
'beau-jwt': {
|
||||
|
|
@ -40,7 +40,7 @@ describe('RequestList', () => {
|
|||
|
||||
expect(requests.list.length).toBe(3);
|
||||
expect(request.VERB).toBe('POST');
|
||||
expect(request.ENDPOINT).toBe(host + '/session');
|
||||
expect(request.ENDPOINT).toBe(endpoint + '/session');
|
||||
});
|
||||
|
||||
it('should fetch dependencies', () => {
|
||||
|
|
|
|||
32
beau.js
32
beau.js
|
|
@ -1,17 +1,43 @@
|
|||
const deepMerge = require('deepmerge');
|
||||
|
||||
const RequestList = require('./requestList');
|
||||
const requestRegex = require('./shared').requestRegex;
|
||||
|
||||
class Beau {
|
||||
constructor(doc) {
|
||||
this.defaults = {
|
||||
VERSION: 1,
|
||||
CACHE: false,
|
||||
HOST: '',
|
||||
PLUGINS: []
|
||||
ENDPOINT: '',
|
||||
PLUGINS: [],
|
||||
DEFAULTS: []
|
||||
};
|
||||
|
||||
this.configKeys = Object.keys(this.defaults);
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
VERSION: 1
|
||||
HOST: https://api.github.com
|
||||
ENDPOINT: https://api.github.com
|
||||
|
||||
auth: &auth
|
||||
HEADERS:
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
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/:
|
||||
alias: posts
|
||||
documentation:
|
||||
title: Fetch Posts
|
||||
description: Fetches all posts available.
|
||||
headers:
|
||||
hello: false
|
||||
|
||||
POST /posts/:
|
||||
alias: new-post
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
host: http://localhost:10080
|
||||
endpoint: http://localhost:10080
|
||||
|
||||
plugins:
|
||||
- beau-jwt:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
VERSION: '1'
|
||||
HOST: https://slack.com/api
|
||||
ENDPOINT: https://slack.com/api
|
||||
|
||||
auth: &auth
|
||||
token: xoxp-139455775026-139455775090-147751461120-f224ed6ffee029869a0f138d0859e7d6
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -7,12 +7,14 @@
|
|||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"watch": "jest --watch"
|
||||
"watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"cli-color": "^1.1.0",
|
||||
"clui": "^0.3.1",
|
||||
"commander": "^2.12.2",
|
||||
"deepmerge": "^2.0.1",
|
||||
"js-yaml": "^3.7.0",
|
||||
"jsome": "^2.3.26",
|
||||
"request": "^2.83.0",
|
||||
|
|
@ -29,5 +31,8 @@
|
|||
},
|
||||
"bin": {
|
||||
"beau": "./bin/beau"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
request.js
10
request.js
|
|
@ -14,15 +14,15 @@ class Request {
|
|||
REQUEST,
|
||||
ALIAS,
|
||||
PAYLOAD,
|
||||
HOST,
|
||||
ENDPOINT,
|
||||
PARAMS,
|
||||
HEADERS,
|
||||
DOCUMENTATION
|
||||
} = config;
|
||||
const { verb, endpoint } = this.parseRequest(REQUEST);
|
||||
const { verb, path } = this.parseRequest(REQUEST);
|
||||
|
||||
this.VERB = verb;
|
||||
this.ENDPOINT = HOST + endpoint;
|
||||
this.ENDPOINT = ENDPOINT + path;
|
||||
|
||||
this.HEADERS = HEADERS;
|
||||
this.PAYLOAD = PAYLOAD;
|
||||
|
|
@ -39,11 +39,11 @@ class Request {
|
|||
}
|
||||
|
||||
parseRequest(request) {
|
||||
let parts = request.match(requestRegex);
|
||||
const parts = request.match(requestRegex);
|
||||
|
||||
return {
|
||||
verb: parts[1],
|
||||
endpoint: parts[2]
|
||||
path: parts[2]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,17 +51,8 @@ class RequestList {
|
|||
});
|
||||
|
||||
return requests.map(request => {
|
||||
const type = typeof doc[request];
|
||||
|
||||
if (type === 'string') {
|
||||
doc[request] = {
|
||||
ALIAS: doc[request]
|
||||
};
|
||||
}
|
||||
|
||||
doc[request] = doc[request] || {};
|
||||
|
||||
doc[request].HOST = this.config.HOST;
|
||||
doc[request].ENDPOINT = this.config.ENDPOINT;
|
||||
doc[request].request = request;
|
||||
|
||||
return new Request(doc[request]);
|
||||
|
|
|
|||
Loading…
Reference in New Issue