/** * requestSupport * @module requestSupport */ // @flow const _ = require('lodash'); const yaml = require('js-yaml'); const handlebars = require('handlebars'); const requestPromise = require('request-promise'); const { parseStepArg } = require('./utilities'); const { get, set, unset, log, log3, initializeWith } = require('./universe').namespaceFactory('_cukelib'); const requestCommon = (routeStr, options) => { // combine options const requestOptions = _.defaults({}, options, get('_request.defaultOptions')); // construct URL const url = handlebars.compile(`${requestOptions.host}/${routeStr.replace(/^\//, '')}`)(get()); requestOptions.url = url; delete requestOptions.host; // get cookie jar if (requestOptions.jar) { requestOptions.jar = get('_requestCookieJar') || set('_requestCookieJar', requestPromise.jar()); } // send request, log everything, capture response set('_requestOptions', requestOptions); log3('log3', 'requestOptions', requestOptions); const responsePromise = requestPromise(requestOptions); set('_requestResponsePromise', responsePromise); return responsePromise.then((result) => { log('response headers', result.headers); log('response body', result.body); unset('_requestResponsePromise'); set('_requestResponse', result); return responsePromise; }) .catch((err) => { log('err', err); return responsePromise; }); }; const parseYamlBody = (bodyStr) => { if (_.isPlainObject(bodyStr)) return bodyStr; if (!_.isString(bodyStr)) { throw new Error(`expected a string, but got ${bodyStr}`); } try { return yaml.safeLoad(bodyStr); } catch (err) { err.message += ' Error parsing:\n' + bodyStr; // eslint-disable-line prefer-template throw err; } }; module.exports = { /** * Initializes the "request" defaults. Should be called in a context which * contains the CucumberJS methods (`Given`, `Then`, `Before`, etc.) * * @example * requestSupport.initialize.call(this, options); * * @param {object} [options={}] merged with * Merged with [standard defaults](request_support.js.html#sunlight-1-line-67) * to set request defaultOptions * * @returns undefined */ initialize(options: Object = {}) { initializeWith.call(this, { _request: { defaultOptions: _.defaults({}, options, { host: 'http://localhost:3000', method: 'GET', simple: false, body: {}, resolveWithFullResponse: true, json: true, jar: true, }), }, }); }, /** * requestGET - Description * * @param {string} routeStr Description * @param {object} [options={}] Description * * @returns {type} Description */ requestGET(routeStr: string, options: Object = {}) { return requestCommon( routeStr, _.assign({ method: 'GET' }, options) ); }, requestPUT(routeStr: string, bodyStr: string|Object, options: Object = {}) { const done = (typeof bodyStr === 'function') ? bodyStr : null; const responsePromise = requestCommon( routeStr, _.assign({ method: 'PUT', body: done ? {} : parseYamlBody(parseStepArg(bodyStr)) }, options) ); if (done) { responsePromise.asCallback(done); return null; } return responsePromise; }, requestDELETE(routeStr: string, options: Object = {}) { return requestCommon( routeStr, _.assign({ method: 'DELETE' }, options) ); }, /** * Executes POST request to given `routeStr` * * `bodyStr` * - as a string will be interpreted as JSON and passed to the request. * - as an object with a `raw` property it is interpreted as a single tow cucumber table. * The table contents are merged, interpreted as JSON and passed to the request. * - as a plainObject it is passsed directly to the request. * - as a function it is assumed to be a `done` callback and an empty body is sent to the request * * @param {string} routeStr * @param {string|object|function} bodyStr * @param {object} [options={}] Overides to the request defaults. * * @returns {Promise|null} Response promise from `request` or `null` for callback style calls. */ requestPOST(routeStr: string, bodyStr: string|Object, options: Object = {}) { const done = (typeof bodyStr === 'function') ? bodyStr : null; const responsePromise = requestCommon( routeStr, _.assign({ method: 'POST', body: done ? {} : parseYamlBody(parseStepArg(bodyStr)) }, options) ); if (done) { responsePromise.asCallback(done); return null; } return responsePromise; }, };