diff --git a/bin/cli/base.js b/bin/cli/base.js index 83a6796..e1e7f68 100644 --- a/bin/cli/base.js +++ b/bin/cli/base.js @@ -1,5 +1,6 @@ const yaml = require('js-yaml'); const fs = require('fs'); +const path = require('path'); const dotenv = require('dotenv'); const { Command, flags } = require('@oclif/command'); @@ -22,6 +23,12 @@ class Base extends Command { const envParams = { params: Object.assign(env, params) }; + const configFileDir = path.dirname( + path.resolve(process.cwd(), configFile) + ); + + process.chdir(configFileDir); + return new Beau(config, envParams); } } diff --git a/src/__mocks__/requireg.js b/src/__mocks__/requireg.js index 69fc692..405760b 100644 --- a/src/__mocks__/requireg.js +++ b/src/__mocks__/requireg.js @@ -2,13 +2,13 @@ function requireg(name) { return require(name); } -requireg.std_resolving = false; +requireg.resolving = true; requireg.resolve = function(name) { - if (requireg.std_resolving) { + if (requireg.resolving) { return ''; } else { - throw new Error(`Failed to resolve.`); + return undefined; } }; diff --git a/src/__tests__/beau.spec.js b/src/__tests__/beau.spec.js index e1b4b00..9f7bbcf 100644 --- a/src/__tests__/beau.spec.js +++ b/src/__tests__/beau.spec.js @@ -1,6 +1,9 @@ const yaml = require('js-yaml'); const Beau = require('../beau'); +const requireg = require('requireg'); +requireg.resolving = false; + describe(`Beau's config Loader.`, () => { it('should create a request list', () => { const doc = yaml.safeLoad(` diff --git a/src/__tests__/config.spec.js b/src/__tests__/config.spec.js index cd437f6..bde9f49 100644 --- a/src/__tests__/config.spec.js +++ b/src/__tests__/config.spec.js @@ -1,22 +1,25 @@ const yaml = require('js-yaml'); const Config = require('../config'); +const requireg = require('requireg'); +requireg.resolving = false; + describe('Config', () => { - it('should load valid config keys', () => { - const doc = yaml.safeLoad(` + it('should load valid config keys', () => { + const doc = yaml.safeLoad(` version: 1 endpoint: http://martianwabbit.com shouldntBeAdded: true `); - const config = new Config(doc); - expect(config.ENDPOINT).toBe(doc.endpoint); - expect(config.VERSION).toBe(doc.version); - expect(config.shouldntBeAdded).toBeUndefined(); - }); + const config = new Config(doc); + expect(config.ENDPOINT).toBe(doc.endpoint); + expect(config.VERSION).toBe(doc.version); + expect(config.shouldntBeAdded).toBeUndefined(); + }); - it('should load requests', () => { - const doc = yaml.safeLoad(` + it('should load requests', () => { + const doc = yaml.safeLoad(` endpoint: http://example.com GET /profile: get-profile @@ -28,12 +31,12 @@ describe('Config', () => { hello: world `); - const config = new Config(doc); - expect(Object.keys(config.REQUESTS).length).toBe(4); - }); + const config = new Config(doc); + expect(Object.keys(config.REQUESTS).length).toBe(4); + }); - it('should set up defaults for all requests', () => { - const doc = yaml.safeLoad(` + it('should set up defaults for all requests', () => { + const doc = yaml.safeLoad(` version: 1 endpoint: 'http://jsonplaceholder.typicode.com' @@ -48,16 +51,16 @@ describe('Config', () => { hello: world `); - const config = new Config(doc); + const config = new Config(doc); - expect(config).toMatchSnapshot(); - Object.values(config.REQUESTS).forEach(r => { - expect(r.HEADERS.authentication).toMatch('hello'); - }); + expect(config).toMatchSnapshot(); + Object.values(config.REQUESTS).forEach(r => { + expect(r.HEADERS.authentication).toMatch('hello'); }); + }); - it('should load multiple hosts', () => { - const doc = yaml.safeLoad(` + it('should load multiple hosts', () => { + const doc = yaml.safeLoad(` endpoint: http://example.org defaults: @@ -95,13 +98,13 @@ describe('Config', () => { 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', () => { - const doc = yaml.safeLoad(` + it('should namespace all aliases within an host', () => { + const doc = yaml.safeLoad(` hosts: - host: test1 endpoint: http://example.com @@ -111,14 +114,14 @@ describe('Config', () => { GET /posts: posts `); - let config = new Config(doc); + let config = new Config(doc); - expect(config.REQUESTS[0].ALIAS).toBe('test1:posts'); - expect(config.REQUESTS[1].ALIAS).toBe('test2:posts'); - }); + expect(config.REQUESTS[0].ALIAS).toBe('test1:posts'); + expect(config.REQUESTS[1].ALIAS).toBe('test2:posts'); + }); - it(`should throw if host doesn't have a host key`, () => { - const doc = yaml.safeLoad(` + it(`should throw if host doesn't have a host key`, () => { + const doc = yaml.safeLoad(` hosts: - endpoint: http://example.com GET /posts: posts @@ -128,11 +131,11 @@ describe('Config', () => { GET /posts: posts `); - expect(() => new Config(doc)).toThrow(); - }); + expect(() => new Config(doc)).toThrow(); + }); - it(`should merge host settings with global settings`, () => { - const doc = yaml.safeLoad(` + it(`should merge host settings with global settings`, () => { + const doc = yaml.safeLoad(` defaults: headers: hello: 1 @@ -150,7 +153,7 @@ describe('Config', () => { GET /posts: posts `); - let config = new Config(doc); - expect(config.REQUESTS[0].HEADERS.hello).toBe(1); - }); + let config = new Config(doc); + expect(config.REQUESTS[0].HEADERS.hello).toBe(1); + }); }); diff --git a/src/__tests__/plugins.spec.js b/src/__tests__/plugins.spec.js index f70fb3f..313b0c0 100644 --- a/src/__tests__/plugins.spec.js +++ b/src/__tests__/plugins.spec.js @@ -1,31 +1,15 @@ const yaml = require('js-yaml'); -const Config = require('../config'); const Plugins = require('../plugins'); const Request = require('../request'); const RequestCache = require('../requestCache'); const requireg = require('requireg'); describe(`Beau's plugin system`, () => { - let config; let request; let plugins; - let doc; beforeEach(() => { - doc = yaml.safeLoad(` - version: 1 - endpoint: 'http://example.com' - - plugins: - - Modifiers: - data: hi - - DynamicValues - - GET /posts/$[add(1, 1)]: get-post - `); - - config = new Config(doc); - plugins = config.PLUGINS; + plugins = new Plugins([{ Modifiers: [Object] }, 'DynamicValues'], []); }); it('should load all plugins', () => { @@ -34,19 +18,24 @@ describe(`Beau's plugin system`, () => { expect(plugins.registry.dynamicValues.length).toBe(1); }); - it(`should load autoload plugins`, () => { - requireg.std_resolving = true; - config = new Config(doc); - expect(config.PLUGINS.registry.dynamicValues.length).toBe(2); - requireg.std_resolving = false; - }); - it(`should throw if given an invalid configuration`, () => { expect(() => new Plugins([{ test1: true, test2: true }])).toThrow(); }); it(`shouldn't do anything when given an empty array.`, () => { - expect(new Plugins()).toMatchSnapshot(); + expect(new Plugins([], [])).toMatchSnapshot(); + }); + + it(`should warn if the plugin is not available.`, () => { + const spy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + requireg.resolving = false; + + new Plugins(['not-a-Package']); + expect(spy).toHaveBeenCalled(); + + requireg.resolving = true; + spy.mockReset(); + spy.mockRestore(); }); describe(`Request Modifiers`, () => { diff --git a/src/plugins.js b/src/plugins.js index 264569d..071f549 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -14,32 +14,51 @@ class Plugins { this.context = {}; - plugins.forEach(plugin => this.loadPlugin(plugin)); - autoload.forEach(plugin => { - try { - requireg.resolve(plugin); - this.loadPlugin(plugin); - } catch (e) {} - }); + this.loadPlugins(autoload.concat(plugins)); } - loadPlugin(plugin) { - let name = plugin; - let settings = {}; + normalizePlugins(plugins) { + let results = {}; - if (typeof plugin === 'object') { - let keys = Object.keys(plugin); + plugins.forEach(plugin => { + let name = plugin; + let settings = undefined; - if (keys.length !== 1) { - throw new Error(`Plugin items should contain only one key.`); + if (typeof plugin === 'object') { + let keys = Object.keys(plugin); + + if (keys.length !== 1) { + throw new Error( + `Plugin items should contain only one key.` + ); + } + + name = keys[0]; + settings = plugin[name]; } - name = keys[0]; - settings = plugin[name]; - } + results[name] = settings; + }); - plugin = requireg(`beau-${toKebabCase(name)}`); - new plugin(this, settings); + return results; + } + + loadPlugins(plugins) { + plugins = this.normalizePlugins(plugins); + Object.keys(plugins).forEach(name => { + const module = `beau-${toKebabCase(name)}`; + + if (typeof requireg.resolve(module) !== 'undefined') { + const plugin = requireg(module); + new plugin(this, plugins[name]); + } else { + if (name === 'std') return; + + console.warn( + `Plugin ${name} couldn't be found. It is available globally?` + ); + } + }); } executeModifier(modifier, obj, orig) { diff --git a/src/shared.js b/src/shared.js index 1d1f86d..558d421 100644 --- a/src/shared.js +++ b/src/shared.js @@ -12,7 +12,7 @@ const httpVerbs = [ const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i'); const replacementRegex = /(?:\\?)\$([a-zA-Z\.\d\-\_\/\\\:]+)/g; -const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])+?\))\]/g; +const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])*?\))\]/g; const UpperCaseKeys = function(obj) { let result = {};