How to use _inspectOnFailure method in frisby

Best JavaScript code snippet using frisby

icedfrisby.js

Source:icedfrisby.js Github

copy

Full Screen

1'use strict'2/*3 * IcedFrisby.js4 * 2015 Robert Herhold (maintainer) & other wonderful contrubuters5 * 2011-2014 Vance Lucas, Brightbit, LLC6 *7 * IcedFrisby is a library designed to easily test REST API endpoints and their8 * responses with node.js and Mocha. It is based on the original Frisby project.9 *10 * IcedFrisby is distributed under the MIT and BSD licenses11 * https://opensource.org/licenses/MIT12 * https://opensource.org/licenses/bsd-license13 */14const https = require('https')15const { Stream } = require('stream')16const util = require('util')17const _ = require('lodash')18const chai = require('chai')19const chalk = require('chalk')20const qs = require('qs')21const request = require('request')22const { errorFromList } = require('verror')23const { sleep } = require('wait-promise')24const pkg = require('../package.json')25const pm = require('./pathMatch')26/**27 * @param {object} headerName - header name28 * @param {object} headers- http headers29 * @return {boolean}30 * @desc verifies proper headers31 */32function _hasHeader(headername, headers) {33 const headerNames = Object.keys(headers || {})34 const lowerNames = headerNames.map(function (name) {35 return name.toLowerCase()36 })37 const lowerName = headername.toLowerCase()38 for (let i = 0; i < lowerNames.length; i++) {39 if (lowerNames[i] === lowerName) return headerNames[i]40 }41 return false42}43/**44 * Parse body as JSON, ensuring not to re-parse when body is already an object45 * (thanks @dcaylor).46 * @param {object} body - json object47 * @return {object}48 * @desc parse response body as json49 */50function _jsonParse(body) {51 let json = ''52 try {53 json = typeof body === 'object' ? body : JSON.parse(body)54 } catch (e) {55 throw new Error(56 'Error parsing JSON string: ' + e.message + '\n\tGiven: ' + body57 )58 }59 return json60}61/**62 * @param {string} app - Node.js app. (e.g. Express, Koa)63 * @param {string} basePath - base path to append to the server address64 * @return {Object}65 */66function startApp(app, basePath) {67 // coerce basePath to a string68 basePath = basePath ? basePath + '' : ''69 let server70 if (!app.listening) {71 server = app.listen()72 } else {73 server = app74 }75 const protocol = app instanceof https.Server ? 'https' : 'http'76 const port = server.address().port77 return {78 server,79 uri: `${protocol}://127.0.0.1:${port}${basePath}`,80 }81}82/**83 * IcedFrisby object, uses create() to initialize84 */85module.exports = class Frisby {86 static get version() {87 return pkg.version88 }89 /**90 * @constructor91 * @param {string} message - message to print for it()92 * @return {object}93 */94 constructor(message) {95 // Optional exception handler96 this._exceptionHandler = false97 Object.assign(this, {98 _message: message,99 _hooks: {100 before: [],101 after: [],102 finally: [],103 },104 _inspects: [],105 _expects: [],106 _failures: [],107 _attempts: {108 count: 0,109 maxRetries: 0,110 backoffMillis: 1000,111 },112 _runner: null,113 _requestArgs: null,114 _outgoing: null,115 _waitsMillis: 0,116 _response: {117 error: null,118 status: null,119 headers: [],120 body: null,121 time: 0,122 },123 _inspectOnFailure: true,124 _requestTimeoutId: undefined,125 _requestDidTimeOut: false,126 })127 // Spec storage128 this.current = {129 isNot: false, // test negation130 // For an app provided to a single test.131 app: null,132 // Custom vars added to test HTTP Request (like headers)133 request: {134 headers: {},135 json: false,136 baseUri: '',137 },138 }139 this.currentRequestFinished = false140 this._timeout = 5000141 this._only = false142 this._skip = false143 this._skipWhen = undefined144 return this145 }146 /**147 * specify global defaults for IcedFrisby test run148 * @param {object} obj - setup object149 * @return {object}150 * @desc global setup function151 */152 static globalSetup() {153 throw Error('globalSetup() has been removed.')154 }155 /**156 * Main Frisby method used to start new spec tests157 */158 static create(msg) {159 // Use `this` instead of `Frisby` so this does the right thing when160 // composed with mixins.161 return new this(msg)162 }163 only() {164 this._only = true165 return this166 }167 skip() {168 this._skip = true169 return this170 }171 skipIf(condition) {172 if (condition) {173 this._skip = true174 }175 return this176 }177 get _shouldSkip() {178 return this._skip || (this._skipWhen && this._skipWhen())179 }180 skipWhen(predicate) {181 if (typeof predicate !== 'function') {182 throw Error('Expected predicate to be a function')183 }184 this._skipWhen = predicate185 return this186 }187 /**188 * Set the baseUri, replacing any baseUri from global setup189 * @param baseUri The new base URI190 */191 baseUri(baseUri) {192 this.current.request.baseUri = baseUri193 return this194 }195 /**196 * @param {string} app - Node.js app. (e.g. Express, Koa)197 * @param {string} basePath - base path to append to the server address198 * @return {object}199 * @desc Setup the request to use a passed in Node http.Server app200 */201 useApp(app, basePath) {202 if (!app) {203 throw new Error('No app provided')204 }205 this.current.useApp = { app, basePath }206 // The app's baseUri won't be known until the app is started. Its uri207 // will be prepended then.208 this.current.request.baseUri = null209 return this210 }211 /**212 * @param {number} ms - timeout value in milliseconds213 * @return {object}214 * @desc Timeout getter and setter215 */216 timeout(ms) {217 if (!ms) {218 return this._timeout219 }220 this._timeout = ms221 return this222 }223 /**224 * @param {number} count - retry n times225 * @param {number} backoffMillis - backoff time for each retry226 * @return {object}227 * @desc retry the request (good for flaky,slow tests)228 */229 retry(count, backoffMillis) {230 this._attempts.maxRetries = count231 if (typeof backoffMillis !== 'undefined') {232 this._attempts.backoffMillis = backoffMillis233 }234 return this235 }236 /**237 * @param {number} ms - n time in milliseconds238 * @return {object}239 * @desc time to wait before attempting to the test240 */241 waits(ms) {242 this._waitsMillis = ms243 return this244 }245 /**246 * @param {string} header - header key247 * @param {string} content - header value content248 * @return {object}249 * @desc Add HTTP header by key and value250 */251 addHeader(header, content) {252 this.current.request.headers[(header + '').toLowerCase()] = content + ''253 return this254 }255 /**256 * @param {object} headers - header object {k:v, k:v}257 * @return {object}258 * @desc Add group of HTTP headers together259 */260 addHeaders(headers) {261 Object.keys(headers).forEach(key => {262 this.addHeader(key, headers[key])263 })264 return this265 }266 /**267 * @param {string} key - header key to remove268 * @return {object}269 * @desc Remove HTTP header from outgoing request by key270 */271 removeHeader(key) {272 delete this.current.request.headers[(key + '').toLowerCase()]273 return this274 }275 /**276 * @param {string} user - username277 * @param {string} pass - password278 * @param {boolean} digest - set digest279 * @return {object}280 * @desc Setup HTTP basic auth281 */282 auth(user, pass, digest) {283 this.current.request.auth = {284 sendImmediately: !digest,285 user,286 pass,287 }288 return this289 }290 /**291 * @param {object} options object292 *293 * @desc Set configuration options on this object.294 * inspectOnFailure: This is a really neat option that will help you figure out what is happening with your requests. Dumps request/response information to the logs.295 * timeout: Sets the maximum time we'll wait for a response before failing the request296 * retry: Number of times we'll try this request before returning a failure. If timeout is set, each retry uses the timeout.297 * request: Options for the request module. An object containing any of these: https://github.com/request/request#requestoptions-callback298 * json: Sets body to JSON representation of value and adds Content-type: application/json header. Additionally, parses the response body as JSON.299 */300 config(opts) {301 if ('inspectOnFailure' in opts) {302 this._inspectOnFailure = opts.inspectOnFailure303 }304 if ('timeout' in opts) {305 this._timeout = opts.timeout306 }307 if ('retry' in opts) {308 this._attempts.maxRetries = opts.retry309 }310 if ('request' in opts) {311 const request_options = _.cloneDeep(opts.request)312 for (const request_option in request_options) {313 if (request_option in request_options) {314 if (request_option == 'headers') {315 this.addHeaders(request_options[request_option]) //Deals with case sensitivity316 } else {317 this.current.request[request_option] =318 request_options[request_option]319 }320 }321 }322 }323 if ('json' in opts) {324 this.current.request.json = opts.json //opts.json will override opts.request.json, if provided325 }326 return this327 }328 /**329 * Set exception handler callback function.330 */331 exceptionHandler(fn) {332 if (_.isUndefined(fn)) {333 return this._exceptionHandler334 }335 this._exceptionHandler = fn336 return this337 }338 /**339 * @return {object}340 * @desc Reset Frisby global and setup options341 */342 reset() {343 throw Error(344 "reset() has been removed from IcedFrisby v2.0+ - there's no more globalSetup(), use config() instead"345 )346 }347 /**348 * @param {array} arguments - method [uri, data, params]349 * @param {string} uri - resource350 * @param {object} [data] - post data351 * @param {string} [param] - uri parameters352 * @return {object}353 * @desc _request object354 */355 _request() {356 const args = Array.from(arguments)357 const method = args.shift()358 const uri = typeof args[0] === 'string' && args.shift()359 const data = typeof args[0] === 'object' && args.shift()360 const params = typeof args[0] === 'object' && args.shift()361 this._requestArgs = { method, uri, data, params }362 // Store test runner function (request or provided mock).363 this._runner = params.mock || request364 return this365 }366 /**367 * Perform GET request against resource368 * @param {string} uri - resource369 * @param {object} [params] - uri parameters370 * @return {object}371 * @desc Perform an HTTP GET request372 * @example373 * .get('/resource', {key: value})374 */375 get(uri, params) {376 return this._request.apply(this, ['GET', uri, null, params])377 }378 /**379 * @param {string} uri - resource380 * @param {object} [data] - patch data381 * @param {string} [param] - uri parameters382 * @desc Perform HTTP PATCH request383 * @example384 * .patch('/resource', {key: value}, {key: value})385 */386 patch(uri, data, params) {387 return this._request.apply(this, ['PATCH', uri, data, params])388 }389 /**390 * @param {string} uri - resource391 * @param {object} [data] - post data392 * @param {string} [param] - uri parameters393 * @return {object}394 * @desc Perform HTTP POST request395 * @example396 * .post('/resource', {key: value}, {key: value})397 */398 post(uri, data, params) {399 return this._request.apply(this, ['POST', uri, data, params])400 }401 /**402 * @param {string} uri - resource403 * @param {object} [data] - put data404 * @param {string} [param] - uri parameters405 * @return {object}406 * @desc Perform HTTP PUT request407 * @example408 * .put('/resource', {key: value}, {key: value})409 */410 put(uri, data, params) {411 return this._request.apply(this, ['PUT', uri, data, params])412 }413 /**414 * @param {string} uri - resource415 * @param {object} [data] - delete data416 * @param {string} [param] - uri parameters417 * @return {object}418 * @desc Perform HTTP DELETE request419 * @example420 * .delete('/resource', {key: value}, {key: value})421 */422 delete(uri, data, params) {423 return this._request.apply(this, ['DELETE', uri, data, params])424 }425 /**426 * @param {string} uri - resource (/identifier)427 * @param {string} [params] - uri parameters428 * @return {object}429 * @desc Perform HTTP HEAD request430 * @example431 * .head('/resource', {key: value})432 */433 head(uri, params) {434 return this._request.apply(this, ['HEAD', uri, null, params])435 }436 /**437 * @param {string} uri - resource (/identifier)438 * @param {string} [params] - uri parameters439 * @return {object}440 * @desc Perform HTTP OPTIONS request441 * @example442 * .options('/resource', {key: value}, {key: value})443 */444 options(uri, params) {445 return this._request.apply(this, ['OPTIONS', uri, null, params])446 }447 _expect(fn) {448 this._expects.push(fn)449 return this450 }451 /**452 * @param {string} header - header key453 * @param {string} content - header value content454 * @return {object}455 * @desc Add HTTP header by key and value456 */457 not() {458 this.current.isNot = true459 return this460 }461 /**462 * @param {number} ms - Maximum response timeout in n milliseconds463 * @return {object}464 * @desc HTTP max response time expect helper465 */466 expectMaxResponseTime(ms) {467 return this._expect(() => {468 chai.expect(this._response.time).to.be.lessThan(ms)469 })470 }471 /**472 * @param {number} statusCode - HTTP status code473 * @return {object}474 * @desc HTTP status code expect helper475 */476 expectStatus(statusCode) {477 return this._expect(() => {478 chai.expect(this._response.status).to.equal(statusCode)479 })480 }481 /**482 * @param {string} header - header key483 * @param {string} content - header value content484 * @return {object}485 * @desc HTTP header expect helper486 */487 expectHeader(header, content, options = {}) {488 const self = this489 header = (header + '').toLowerCase()490 options = {491 allowMultipleHeaders: options.allowMultipleHeaders || false,492 }493 return this._expect(function () {494 if (495 !options.allowMultipleHeaders &&496 self._response.headers[header] instanceof Array497 ) {498 throw new Error(499 "Header '" +500 header +501 "' present more than once in HTTP response. Pass {allowMultipleHeaders: true} in options if this is expected."502 )503 }504 if (typeof self._response.headers[header] !== 'undefined') {505 let responseHeaders = [].concat(self._response.headers[header])506 if (content instanceof RegExp) {507 chai508 .expect(responseHeaders)509 .to.include.something.that.matches(content)510 } else if (typeof content === 'string') {511 responseHeaders = responseHeaders.map(thisHeader =>512 thisHeader.toLowerCase()513 )514 chai515 .expect(responseHeaders)516 .to.include.a.thing.that.equals(content.toLowerCase())517 } else {518 throw new Error(519 "Content '" + content + "' is neither a string or regex"520 )521 }522 } else {523 throw new Error("Header '" + header + "' not present in HTTP response")524 }525 })526 }527 /**528 * @param {string} header - header key529 * @param {string} content - header value content530 * @return {object}531 * @desc HTTP header expect helper (using 'contains' instead of 'equals')532 */533 expectHeaderContains(header, content, options = {}) {534 header = (header + '').toLowerCase()535 options = {536 allowMultipleHeaders: options.allowMultipleHeaders || false,537 }538 return this._expect(() => {539 if (540 !options.allowMultipleHeaders &&541 this._response.headers[header] instanceof Array542 ) {543 throw new Error(544 "Header '" +545 header +546 "' present more than once in HTTP response. Pass {allowMultipleHeaders: true} in options if this is expected."547 )548 }549 if (typeof this._response.headers[header] !== 'undefined') {550 const responseHeaders = []551 .concat(this._response.headers[header])552 .map(thisHeader => thisHeader.toLowerCase())553 chai554 .expect(responseHeaders)555 .to.include.something.that.satisfies(556 thisHeader =>557 thisHeader.toLowerCase().includes(content.toLowerCase()),558 content.toLowerCase() + ' not found in ' + responseHeaders559 )560 // Ugly workaround for https://github.com/chaijs/chai-things/issues/42 or something closely related561 // .include.something.that.contains(textVar) has the same problem, and all values562 // are checked, throwing failures when one doesn't match.563 // Hence the awful use of custom messaging... Sorry.564 } else {565 throw new Error("Header '" + header + "' not present in HTTP response")566 }567 })568 }569 /**570 * @param {string} header - header key571 * @param {string} pattern - header value content regular express572 * @return {object}573 * @desc Alias for expectHeader574 */575 expectHeaderToMatch(header, pattern) {576 return this.expectHeader(header, pattern)577 }578 /**579 * @param {string} header - header key580 * @return {object}581 * @desc Asserts that a header is not present in the response582 */583 expectNoHeader(header) {584 header = (header + '').toLowerCase()585 return this._expect(() => {586 chai.expect(this._response.headers).to.not.have.property(header)587 })588 }589 /**590 * @param {string} content - body content591 * @return {object}592 * @desc HTTP body expect helper593 */594 expectBodyContains(content) {595 return this._expect(() => {596 chai.expect(this._response.body).to.contain(content)597 })598 }599 /**600 * @param {array} arguments - joi tree, path, jsonTest601 * @return {object}602 * @desc Helper to check parse HTTP response body as JSON and check key types603 */604 expectJSONTypes(/* [tree], jsonTest */) {605 const args = Array.from(arguments)606 const path = typeof args[0] === 'string' && args.shift()607 const jsonTest = typeof args[0] === 'object' && args.shift()608 return this._expect(() => {609 pm.matchJSONTypes({610 jsonBody: _jsonParse(this._response.body),611 jsonTest: jsonTest,612 isNot: this.current.isNot,613 path: path,614 })615 })616 }617 /**618 * @param {array} jsonTest - [path, jsonTest]619 * @return {object}620 * @desc Helper to check JSON response body exactly matches a provided object621 */622 expectJSON(jsonTest) {623 const args = Array.from(arguments)624 const path = typeof args[0] === 'string' && args.shift()625 jsonTest = typeof args[0] === 'object' && args.shift()626 return this._expect(() => {627 pm.matchJSON({628 jsonBody: _jsonParse(this._response.body),629 jsonTest,630 isNot: this.current.isNot,631 path,632 })633 })634 }635 /**636 * @param {array} jsonTest - [path, jsonTest]637 * @return {object}638 * @desc Helper to check JSON response contains a provided object639 */640 expectContainsJSON(jsonTest) {641 const args = Array.from(arguments)642 const path = typeof args[0] === 'string' && args.shift()643 jsonTest = typeof args[0] === 'object' && args.shift()644 return this._expect(() => {645 pm.matchContainsJSON({646 jsonBody: _jsonParse(this._response.body),647 jsonTest,648 isNot: this.current.isNot,649 path,650 })651 })652 }653 /**654 * @param {array} expectedLength - [path, expectedLength]655 * @return {object}656 * @desc Helper to check response body as JSON and check array or object length657 */658 expectJSONLength(expectedLength) {659 const args = Array.from(arguments)660 const path = _.isString(args[0]) && args.shift() // optional 1st parameter661 expectedLength =662 (_.isNumber(args[0]) || _.isString(args[0])) && args.shift() // 1st or 2nd parameter663 let lengthSegments = null664 // if expectedLength is a string, we have to parse out the sign665 if (!_.isNumber(expectedLength)) {666 const sign = /\D+/.exec(expectedLength)667 lengthSegments = {668 count: parseInt(/\d+/.exec(expectedLength), 10),669 sign: sign ? sign[0].trim() : null, // extract the sign, e.g. <, <=, >, >= and trim out whitespace670 }671 } else {672 lengthSegments = {673 count: expectedLength,674 sign: null,675 }676 }677 return this._expect(() => {678 pm.matchJSONLength({679 jsonBody: _jsonParse(this._response.body),680 jsonTest: lengthSegments, // we aren't testing any JSON here, just use this to pass in the length segments681 isNot: this.current.isNot,682 path,683 })684 })685 }686 /**687 * @param {inspectCallback} cb - callback688 * @return {object}689 * @desc inspection of data after request is made but before test is completed690 */691 inspect(cb) {692 // This function uses both `self` and `this`. Are they different? Hmm.693 const self = this694 if (!cb) {695 return self696 }697 // Node invokes inspect() when printing formatting objects. Guess if that's698 // happening based on the arguments passed, and delgate back to inspect,699 // disabling custom inspection.700 // https://nodejs.org/api/util.html#util_custom_inspection_functions_on_objects701 if (typeof cb !== 'function') {702 return util.inspect(self, { customInspect: false })703 }704 this._inspects.push(function () {705 cb.call(706 this,707 self._response.error,708 self.currentRequestFinished.req,709 self.currentRequestFinished.res,710 self._response.body,711 self._response.headers712 )713 })714 return this715 }716 /**717 * @param {string} message - message to print before the inspection718 * @return {object}719 * @desc Debugging helper to inspect the HTTP request720 */721 inspectRequest(message) {722 this.inspect(function (err, req, res, body) {723 if (message) {724 console.log(message)725 }726 console.log(req)727 })728 return this729 }730 /**731 * @param {string} message - message to print before the inspection732 * @return {object}733 * @desc Debugging helper to inspect the HTTP response734 */735 inspectResponse(message) {736 this.inspect(function (err, req, res, body) {737 if (message) {738 console.log(message)739 }740 console.log(res)741 })742 return this743 }744 /**745 * @param {string} message - message to print before the inspection746 * @return {object}747 * @desc Debugging helper to inspect the HTTP headers748 */749 inspectHeaders(message) {750 this.inspect(function (err, req, res, body) {751 if (message) {752 console.log(message)753 }754 console.log(res.headers)755 })756 return this757 }758 /**759 * @param {string} message - message to print before the inspection760 * @return {object}761 * @desc Debugging helper to inspect the HTTP response body content762 */763 inspectBody(message) {764 this.inspect(function (err, req, res, body) {765 if (message) {766 console.log(message)767 }768 console.log(body)769 })770 return this771 }772 /**773 * @param {string} message - message to print before the inspection774 * @return {object}775 * @desc Debugging helper to inspect the JSON response body content776 */777 inspectJSON(message) {778 this.inspect(function (err, req, res, body) {779 if (message) {780 console.log(message)781 }782 console.log(util.inspect(_jsonParse(body), false, 10, true))783 })784 return this785 }786 /**787 * @param {string} message - message to print before the inspection788 * @return {object}789 * @desc Debugging helper to inspect the HTTP response code790 */791 inspectStatus(message) {792 this.inspect(function (err, req, res, body) {793 if (message) {794 console.log(message)795 }796 console.log(res.statusCode)797 })798 return this799 }800 _performInspections() {801 this._inspects.forEach(fn => fn())802 }803 /**804 * @param {afterCallback} cb - callback805 * @return {object}806 * @desc callback function to run before the request is made807 */808 before(cb) {809 if (!_.isFunction(cb)) {810 throw new Error(811 'Expected Function object in before(), but got ' + typeof cb812 )813 }814 this._hooks.before.push(cb)815 return this816 }817 /**818 * @param {afterCallback} cb - callback819 * @return {object}820 * @desc callback function to run after test is completed821 */822 after(cb) {823 if (!_.isFunction(cb)) {824 throw new Error(825 'Expected Function object in after(), but got ' + typeof cb826 )827 }828 if (cb.length > 4) {829 // assume it has a callback function argument830 this._hooks.after.push(done => {831 cb.call(832 this,833 this._response.error,834 this.currentRequestFinished.res,835 this._response.body,836 this._response.headers,837 done838 )839 })840 } else {841 this._hooks.after.push(() => {842 cb.call(843 this,844 this._response.error,845 this.currentRequestFinished.res,846 this._response.body,847 this._response.headers848 )849 })850 }851 return this852 }853 /**854 * @param {afterJSONCallback} cb - callback855 * @return {object}856 * @desc Callback function to run after test is completed,857 * helper to convert response body to JSON858 * @example859 * .afterJSON(function(json) {860 * // previous test JSON response861 * let id = json.id862 * frisby.create(msg)863 * .get('/item' + id)864 * .toss()865 * })866 */867 afterJSON(cb) {868 this._hooks.after.push(function () {869 const responseHeaders = _jsonParse(this._response.headers)870 const bodyJSON = _jsonParse(this._response.body)871 cb.call(this, bodyJSON, responseHeaders)872 })873 return this874 }875 /**876 * Register a hook to run after a test runs, regardless of whether it877 * succeeded or failed.878 * @param {finallyCallback} cb - callback879 * @return {object}880 */881 finally(cb) {882 if (!_.isFunction(cb)) {883 throw new Error(884 'Expected Function object in finally(), but got ' + typeof cb885 )886 }887 this._hooks.finally.push(cb)888 return this889 }890 async _runHooks(hooks) {891 return new Promise((resolve, reject) => {892 let invokationIndex = 0893 // naiive implementation of async callback support:894 const invokeNextHook = () => {895 if (invokationIndex === hooks.length) {896 resolve()897 } else {898 const nextHook = hooks[invokationIndex++]899 if (nextHook.length) {900 // assume it has a callback function argument901 try {902 nextHook.call(this, invokeNextHook)903 } catch (e) {904 if (false === this._exceptionHandler) {905 this._failures.push(e)906 //Fishbowler 25-6-2018: No unit tests for this line - currently unreachable.907 return reject(e)908 } else {909 this._exceptionHandler(e)910 setImmediate(invokeNextHook)911 }912 }913 } else {914 // assume sync915 try {916 nextHook.call(this)917 } catch (e) {918 if (false === this._exceptionHandler) {919 this._failures.push(e)920 return reject(e)921 } else {922 this._exceptionHandler(e)923 }924 }925 setImmediate(invokeNextHook)926 }927 }928 }929 invokeNextHook()930 })931 }932 get testInfo() {933 const { method, uri } = this._requestArgs934 return `${method.toUpperCase()} ${uri}`935 }936 async _makeRequest() {937 return new Promise((resolve, reject) => {938 this._attempts.count++939 this._requestDidTimeOut = false940 this.currentRequestFinished = false941 const { method, uri, params } = this._requestArgs942 let { data } = this._requestArgs943 const outgoing = {944 json: params.json || this.current.request.json || false,945 uri: (this.current.request.baseUri || '') + uri,946 body: params.body || undefined,947 method,948 timeout: this._timeout,949 ...this.current.request,950 ...params,951 ...{952 headers: {953 ...this.current.request.headers,954 ...params.headers,955 },956 },957 form: params.form,958 formData: params.form ? data : undefined,959 stream: data instanceof Stream ? data : undefined,960 }961 // Store outgoing request on current Frisby object for inspection in unit962 // tests.963 this._outgoing = outgoing964 // Explicit setting of 'body' param overrides data.965 if (params.body) {966 data = params.body967 }968 // Normalize case of Content-Type header to simplify the header969 // manipulation that follows.970 const contentTypeKey = _hasHeader('content-type', outgoing.headers)971 if (contentTypeKey !== 'content-type') {972 outgoing.headers['content-type'] = outgoing.headers[contentTypeKey]973 delete outgoing.headers[contentTypeKey]974 }975 // Ensure we have at least one 'content-type' header976 if (outgoing.headers['content-type'] === undefined) {977 outgoing.headers['content-type'] = 'application/x-www-form-urlencoded'978 }979 // If the content-type header contains 'json' but outgoing.json is false,980 // the user likely messed up. Warn them.981 if (982 !outgoing.json &&983 data &&984 outgoing.headers['content-type'].includes('json')985 ) {986 console.warn(987 chalk.yellow.bold(988 'WARNING - content-type is json but body type is not set'989 )990 )991 }992 // If the user has provided data, assume that it is query string and set993 // it to the `body` property of the options.994 if (data) {995 if (outgoing.json) {996 outgoing.body = data997 if (998 outgoing.headers['content-type'] &&999 !outgoing.headers['content-type'].includes('application/json')1000 ) {1001 outgoing.headers['content-type'] = 'application/json'1002 }1003 } else if (!outgoing.body) {1004 if (data instanceof Buffer) {1005 outgoing.body = data1006 } else if (!(data instanceof Stream)) {1007 outgoing.body = qs.stringify(data)1008 }1009 }1010 }1011 if (params.form === true) {1012 delete outgoing.headers['content-type']1013 }1014 const { _timeout: timeoutMillis } = this1015 const timeoutId = setTimeout(() => {1016 this._requestDidTimeOut = true1017 resolve()1018 }, timeoutMillis)1019 const requestStartTime = new Date().getTime()1020 const req = this._runner(outgoing, (err, res, body) => {1021 if (this._requestDidTimeOut) {1022 // Control has already returned to the caller and timeout has elapsed.1023 // Nothing left to do.1024 return1025 }1026 clearTimeout(timeoutId)1027 if (err) {1028 body =1029 '[IcedFrisby] Destination URL may be down or URL is invalid, ' + err1030 }1031 const requestDuration = new Date().getTime() - requestStartTime1032 this.currentRequestFinished = {1033 err: err,1034 res: res,1035 body: body,1036 req: outgoing,1037 }1038 let headers = {}1039 if (res) {1040 headers = _.mapKeys(res.headers, (value, key) => key.toLowerCase())1041 }1042 // Store relevant current response parts1043 this._response = {1044 error: err,1045 status: res ? res.statusCode : 599, // use 599 - network connect timeout error1046 headers: headers,1047 body: body ? body : '', //request already guarantees a body - this guarantees that developer mock functions are consistent1048 time: requestDuration,1049 }1050 resolve()1051 })1052 // Deal with a couple things that have to happen after the request fires.1053 if (params.form === true) {1054 const form = req.form()1055 for (const field in outgoing.formData) {1056 form.append(field, data[field])1057 }1058 }1059 if (1060 outgoing.stream &&1061 ['POST', 'PUT', 'PATCH'].includes(outgoing.method)1062 ) {1063 outgoing.stream.pipe(req)1064 }1065 })1066 }1067 // Return `true` if should stop processing expectations.1068 _noteExpectationFailed(e) {1069 if (false === this._exceptionHandler) {1070 this._failures.push(e)1071 return true1072 } else {1073 this._exceptionHandler.call(this, e)1074 return false1075 }1076 }1077 _invokeExpects() {1078 // REQUIRES count for EACH loop iteration (i.e. DO NOT OPTIMIZE THIS LOOP)1079 // Some 'expects' helpers add more tests when executed (recursive1080 // 'expectJSON' and 'expectJSONTypes', with nested JSON syntax etc.)1081 for (let i = 0; i < this._expects.length; i++) {1082 try {1083 this._expects[i].call(null)1084 } catch (e) {1085 const shouldStop = this._noteExpectationFailed(e)1086 if (shouldStop) {1087 break1088 }1089 }1090 }1091 }1092 async run() {1093 if (this._shouldSkip) {1094 return1095 }1096 // When an error occurs in a before() hook, stop executing before hooks and1097 // move on to finally() hooks. This mimics Mocha's behavior of before() and1098 // after() hooks. A dev-provided exception handler overrides this behavior.1099 let shouldProceedWithTest1100 try {1101 await this._runHooks(this._hooks.before)1102 shouldProceedWithTest = true1103 } catch (e) {1104 shouldProceedWithTest = false1105 }1106 if (shouldProceedWithTest && this._waitsMillis > 0) {1107 await sleep(this._waitsMillis)1108 }1109 // `shouldProceedWithTest` never changes, but using it as the loop1110 // condition saves a level of nesting. Otherwise this would read1111 // `if (shouldProceedWithTest) { while (true) { ... } }`.1112 while (shouldProceedWithTest) {1113 await this._makeRequest()1114 const canRetry =1115 this._attempts.count <= this._attempts.maxRetries &&1116 // Do not retry POST requests.1117 this._requestArgs.method.toUpperCase() !== 'POST'1118 if (1119 canRetry &&1120 (this._response.status >= 500 || this._requestDidTimeOut)1121 ) {1122 // Back off, then retry.1123 process.stdout.write('R')1124 await sleep(this._attempts.backoffMillis)1125 continue1126 }1127 if (this._response.error) {1128 this._noteExpectationFailed(this._response.error)1129 }1130 if (this._requestDidTimeOut) {1131 let message = `Request timed out after ${this._timeout} ms`1132 if (this._attempts.count > 1) {1133 message += ` (${this._attempts.count} attempts)`1134 }1135 this._noteExpectationFailed(new Error(message))1136 break1137 }1138 this._performInspections()1139 this._invokeExpects()1140 break1141 }1142 let didFail = this._failures.length > 01143 if (didFail && this._inspectOnFailure) {1144 console.log(`${this.testInfo} has FAILED with the following response:`)1145 this.inspectStatus()1146 this.inspectJSON()1147 }1148 // Don't run `after()` hooks on failure. If an `after()` hook fails, don't1149 // run any more of them.1150 if (!didFail && this._hooks.after) {1151 try {1152 await this._runHooks(this._hooks.after)1153 } catch (e) {1154 didFail = true1155 }1156 }1157 // Run the `finally()` hooks, regardless of sucess or failure.1158 try {1159 await this._runHooks(this._hooks.finally)1160 } catch (e) {1161 didFail = true1162 }1163 if (didFail) {1164 // Return null, the sole error, or a MultiError.1165 // https://github.com/joyent/node-verror#verrorerrorfromlisterrors1166 throw errorFromList(this._failures)1167 }1168 }1169 _mochaTimeout() {1170 // If one retry is allowed, the test needs:1171 // timeout interval for first request +1172 // retry backoff +1173 // timeout interval for second request1174 //1175 // We add a little extra time so frisby can handle the timeout.1176 const gracePeriodMillis = 251177 return (1178 this._timeout +1179 this._attempts.maxRetries *1180 (this._attempts.backoffMillis + this._timeout) +1181 gracePeriodMillis1182 )1183 }1184 /**1185 * Register the current Frisby test with Mocha.1186 */1187 toss() {1188 // Use `self` in order to preserve the Mocha context.1189 const self = this1190 let describeFn1191 if (this._shouldSkip) {1192 describeFn = describe.skip1193 } else if (this._only) {1194 describeFn = describe.only1195 } else {1196 describeFn = describe1197 }1198 describeFn(self._message, function () {1199 before(function () {1200 if (self.current.useApp) {1201 const { app, basePath } = self.current.useApp1202 const { server, uri } = startApp(app, basePath)1203 self.current.server = server1204 self._requestArgs.uri = uri + self._requestArgs.uri1205 }1206 })1207 after(function (done) {1208 if (self.current.server) {1209 self.current.server.close(() => {1210 done()1211 })1212 } else {1213 done()1214 }1215 })1216 it(`\n\t[ ${self.testInfo} ]`, async function () {1217 await self.run()1218 }).timeout(self._mochaTimeout())1219 })1220 }...

Full Screen

Full Screen

spec.js

Source:spec.js Github

copy

Full Screen

...300 inspectLog(...args) {301 console.log.call(null, ...args); // eslint-disable-line no-console302 return this;303 }304 _inspectOnFailure() {305 if (this._setupDefaults.request && this._setupDefaults.request.inspectOnFailure) {306 if (this._response) {307 let response = this._response;308 if (response.json) {309 this.inspectLog('\nFAILURE Status:', response.status, '\nJSON:', JSON.stringify(response.json, null, 4));310 } else {311 this.inspectLog('\nFAILURE Status:', response.status, '\nBody:', response.body);312 }313 }314 }315 }316 /**317 * Expectations (wrappers around Jasmine methods)318 * ==========================================================================319 */320 /**321 * Add expectation for current test (expects)322 */323 expect(expectName) {324 let expectArgs = Array.prototype.slice.call(arguments).slice(1);325 return this.then(this._getExpectRunner(expectName, expectArgs, true));326 }327 /**328 * Add negative expectation for current test (expects.not)329 */330 expectNot(expectName) {331 let expectArgs = Array.prototype.slice.call(arguments).slice(1);332 return this.then(this._getExpectRunner(expectName, expectArgs, false));333 }334 /**335 * Private methods (not meant to be part of the public API, and NOT to be336 * relied upon by consuming code - these names may change!)337 * ==========================================================================338 */339 /**340 * Used internally for expect and expectNot to return expectation function and then run it341 */342 _getExpectRunner(expectName, expectArgs, expectPass) {343 let expectHandler;344 if (_.isFunction(expectName)) {345 expectHandler = expectName;346 } else {347 expectHandler = expectHandlers[expectName];348 if (typeof expectHandler === 'undefined') {349 throw new Error("Expectation '" + expectName + "' is not defined.");350 }351 }352 return response => {353 let didFail = false;354 try {355 expectHandler.apply(this, [response].concat(expectArgs));356 } catch(e) {357 didFail = true;358 // Re-throw error if pass is expected; else bury it359 if (expectPass === true) {360 this._inspectOnFailure();361 throw e;362 }363 }364 if (!expectPass && !didFail) {365 this._inspectOnFailure();366 let fnArgs = expectArgs.map(a => a.toString()).join(', ');367 throw new Error(`expectNot('${expectName}', ${fnArgs}) passed and was supposed to fail`);368 }369 };370 }371 /**372 * Ensure fetch() has been called already373 */374 _ensureHasFetched() {375 if (typeof this._fetch === 'undefined') {376 throw new Error('Frisby spec not started. You must call fetch() first to begin a Frisby test.');377 }378 }379 /**...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2var inspect = require('util').inspect;3var _inspectOnFailure = frisby._inspectOnFailure;4frisby._inspectOnFailure = function(err) {5 console.log(inspect(err, { depth: null }));6 return _inspectOnFailure(err);7}8var frisby = require('frisby');9var inspect = require('util').inspect;10var _inspectOnFailure = frisby._inspectOnFailure;11frisby._inspectOnFailure = function(err) {12 console.log(inspect(err, { depth: null }));13 return _inspectOnFailure(err);14}15var frisby = require('frisby');16var inspect = require('util').inspect;17var _inspectOnFailure = frisby._inspectOnFailure;18frisby._inspectOnFailure = function(err) {19 console.log(inspect(err, { depth: null }));20 return _inspectOnFailure(err);21}22var frisby = require('frisby');23var inspect = require('util').inspect;24var _inspectOnFailure = frisby._inspectOnFailure;25frisby._inspectOnFailure = function(err) {26 console.log(inspect(err, { depth: null }));27 return _inspectOnFailure(err);28}29var frisby = require('frisby');30var inspect = require('util').inspect;31var _inspectOnFailure = frisby._inspectOnFailure;32frisby._inspectOnFailure = function(err) {33 console.log(inspect(err, { depth: null }));34 return _inspectOnFailure(err);35}36var frisby = require('frisby');

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2var fs = require('fs');3frisby.globalSetup({4 request: {5 headers: {6 }7 }8});9var test = function() {10 return frisby.create('Test')11 .expectStatus(200)12 .expectHeaderContains('content-type', 'application/json')13 .inspectOnFailure()14 .after(function(err, res, body) {15 console.log('I am done');16 })17 .toss();18};19test();20var frisby = require('frisby');21var fs = require('fs');22frisby.globalSetup({23 request: {24 headers: {25 }26 }27});28var test = function() {29 return frisby.create('Test')30 .expectStatus(200)31 .expectHeaderContains('content-type', 'application/json')32 .inspectOnFailure()33 .after(function(err, res, body) {34 console.log('I am done');35 })36 .toss();37};38test();39var frisby = require('frisby');40var fs = require('fs');41frisby.globalSetup({42 request: {43 headers: {44 }45 }46});47var test = function() {48 return frisby.create('Test')49 .expectStatus(200)50 .expectHeaderContains('content-type', 'application/json')51 .inspectOnFailure()52 .after(function(err, res, body) {53 console.log('I am done');54 })55 .toss();56};57test();58test();

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2var inspect = require('util').inspect;3var _inspectOnFailure = frisby._inspectOnFailure;4frisby._inspectOnFailure = function (response, body) {5 console.log(inspect(response, {colors: true, depth: 5}));6 _inspectOnFailure(response, body);7};8var frisby = require('frisby');9var inspect = require('util').inspect;10var _inspectOnFailure = frisby._inspectOnFailure;11frisby._inspectOnFailure = function (response, body) {12 console.log(inspect(response, {colors: true, depth: 5}));13 _inspectOnFailure(response, body);14};15var frisby = require('frisby');16var inspect = require('util').inspect;17var _inspectOnFailure = frisby._inspectOnFailure;18frisby._inspectOnFailure = function (response, body) {19 console.log(inspect(response, {colors: true, depth: 5}));20 _inspectOnFailure(response, body);21};22var frisby = require('frisby');23var inspect = require('util').inspect;24var _inspectOnFailure = frisby._inspectOnFailure;25frisby._inspectOnFailure = function (response, body) {26 console.log(inspect(response, {colors: true, depth: 5}));27 _inspectOnFailure(response, body);28};29var frisby = require('frisby');30var inspect = require('util').inspect;31var _inspectOnFailure = frisby._inspectOnFailure;32frisby._inspectOnFailure = function (response, body) {33 console.log(inspect(response, {colors: true, depth: 5}));34 _inspectOnFailure(response, body);35};36var frisby = require('frisby');37var inspect = require('util').inspect;38var _inspectOnFailure = frisby._inspectOnFailure;39frisby._inspectOnFailure = function (response, body)

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2frisby.create('Frisby test')3 .expectStatus(200)4 .expectHeaderContains('content-type', 'application/json')5 .expectJSON({6 })7 .inspectOnFailure()8 .toss();9describe("Jasmine test", function() {10 it("Jasmine test", function() {11 frisby.create('Frisby test')12 .expectStatus(200)13 .expectHeaderContains('content-type', 'application/json')14 .expectJSON({15 })16 .inspectOnFailure()17 .toss();18 });19});20describe("Mocha test", function() {21 it("Mocha test", function(done) {22 frisby.create('Frisby test')23 .expectStatus(200)24 .expectHeaderContains('content-type', 'application/json')25 .expectJSON({26 })27 .inspectOnFailure()28 .toss();29 });30});31describe("Jasmine-node test", function() {32 it("Jasmine-node test", function(done) {33 frisby.create('Frisby test')34 .expectStatus(200)35 .expectHeaderContains('content-type', 'application/json')36 .expectJSON({37 })38 .inspectOnFailure()39 .toss();40 });41});42describe("Jasmine-node test", function() {43 it("Jasmine-node test", function(done) {44 frisby.create('Frisby test')45 .expectStatus(200)46 .expectHeaderContains('content-type', 'application/json')47 .expectJSON({48 })49 .inspectOnFailure()50 .toss();51 });52});

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2var _inspectOnFailure = frisby._inspectOnFailure;3var _inspect = frisby._inspect;4frisby._inspectOnFailure = function (message, body, spec) {5 _inspectOnFailure(message, body, spec);6 _inspect(body, 'Response Body');7};8frisby._inspect = function (obj, label) {9 console.log(label + ':');10 console.log(obj);11};12frisby.create('Test case')13 .expectStatus(200)14 .after(function (err, res, body) {15 console.log('After method');16 })17 .toss();18{ args: {},19 { Accept: 'application/json',20 'User-Agent': 'Frisby.js' },

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2var _inspectOnFailure = frisby._inspectOnFailure;3frisby._inspectOnFailure = function (err, res, body) {4 console.log(body);5};6var frisby = require('frisby');7frisby.create('Get some Google search results')8 .expectStatus(200)9 .expectHeaderContains('content-type', 'text/html')10 .expectBodyContains('I\'m Feeling Lucky')11 .toss();

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2var _inspectOnFailure = frisby._inspectOnFailure;3frisby._inspectOnFailure = function (err) {4 _inspectOnFailure.call(this, err);5};6var frisby = require('frisby');7var _inspectOnFailure = frisby._inspectOnFailure;8frisby._inspectOnFailure = function (err) {9 _inspectOnFailure.call(this, err);10};

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2frisby.create('Get a list of countries')3 .expectStatus(200)4 .expectHeaderContains('content-type', 'application/json')5 .expectJSONTypes('RestResponse.result.*', {6 })7 .inspectOnFailure()8 .toss();

Full Screen

Using AI Code Generation

copy

Full Screen

1var frisby = require('frisby');2 request: {3 headers: {4 }5 }6});7frisby.create('Test for /api/v1/health')8 .expectStatus(200)9 .inspectOnFailure()10 .toss();11frisby.create('Test for /api/v1/health')12 .expectStatus(200)13 .inspectOnFailure()14 .toss();15frisby.create('Test for /api/v1/health')16 .expectStatus(200)17 .inspectOnFailure()18 .toss();19frisby.create('Test for /api/v1/health')20 .expectStatus(200)21 .inspectOnFailure()22 .toss();23frisby.create('Test for /api/v1/health')24 .expectStatus(200)25 .inspectOnFailure()26 .toss();27frisby.create('Test for /api/v1/health')28 .expectStatus(200)29 .inspectOnFailure()30 .toss();31frisby.create('Test for /api/v1/health')32 .expectStatus(200)33 .inspectOnFailure()34 .toss();35frisby.create('Test for /api/v1/health')36 .expectStatus(200)37 .inspectOnFailure()38 .toss();39frisby.create('Test for /api/v1/health')40 .expectStatus(200)41 .inspectOnFailure()

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run frisby automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful