Merge pull request #4489 from vector-im/rav/use_external_mock_request
Use external mock-requestpull/4326/merge
						commit
						5312c9ad4c
					
				|  | @ -121,6 +121,7 @@ | |||
|     "karma-mocha": "^0.2.2", | ||||
|     "karma-phantomjs-launcher": "^1.0.0", | ||||
|     "karma-webpack": "^1.7.0", | ||||
|     "matrix-mock-request": "^0.1.3", | ||||
|     "minimist": "^1.2.0", | ||||
|     "mkdirp": "^0.5.1", | ||||
|     "mocha": "^2.4.5", | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ var expect = require('expect'); | |||
| var q = require('q'); | ||||
| 
 | ||||
| var test_utils = require('../test-utils'); | ||||
| var MockHttpBackend = require('../mock-request'); | ||||
| var MockHttpBackend = require('matrix-mock-request'); | ||||
| 
 | ||||
| var HS_URL='http://localhost'; | ||||
| var IS_URL='http://localhost'; | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ import {VIEWS} from 'matrix-react-sdk/lib/components/structures/MatrixChat'; | |||
| import dis from 'matrix-react-sdk/lib/dispatcher'; | ||||
| 
 | ||||
| import * as test_utils from '../test-utils'; | ||||
| import MockHttpBackend from '../mock-request'; | ||||
| import MockHttpBackend from 'matrix-mock-request'; | ||||
| import {parseQs, parseQsFromFragment} from '../../src/vector/url_utils'; | ||||
| 
 | ||||
| var DEFAULT_HS_URL='http://my_server'; | ||||
|  |  | |||
|  | @ -1,336 +0,0 @@ | |||
| "use strict"; | ||||
| const q = require("q"); | ||||
| import expect from 'expect'; | ||||
| 
 | ||||
| /** | ||||
|  * Construct a mock HTTP backend, heavily inspired by Angular.js. | ||||
|  * @constructor | ||||
|  */ | ||||
| function HttpBackend() { | ||||
|     this.requests = []; | ||||
|     this.expectedRequests = []; | ||||
|     const self = this; | ||||
|     // the request function dependency that the SDK needs.
 | ||||
|     this.requestFn = function(opts, callback) { | ||||
|         const req = new Request(opts, callback); | ||||
|         console.log(`${Date.now()} HTTP backend received request: ${req}`); | ||||
|         self.requests.push(req); | ||||
| 
 | ||||
|         const abort = function() { | ||||
|             const idx = self.requests.indexOf(req); | ||||
|             if (idx >= 0) { | ||||
|                 console.log("Aborting HTTP request: %s %s", opts.method, | ||||
|                             opts.uri); | ||||
|                 self.requests.splice(idx, 1); | ||||
|                 req.callback("aborted"); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         return { | ||||
|             abort: abort, | ||||
|         }; | ||||
|     }; | ||||
| 
 | ||||
|     // very simplistic mapping from the whatwg fetch interface onto the request
 | ||||
|     // interface, so we can use the same mock backend for both.
 | ||||
|     this.fetchFn = function(input, init) { | ||||
|         init = init || {}; | ||||
|         const requestOpts = { | ||||
|             uri: input, | ||||
|             method: init.method || 'GET', | ||||
|             body: init.body, | ||||
|         }; | ||||
| 
 | ||||
|         return new Promise((resolve, reject) => { | ||||
|             function callback(err, response, body) { | ||||
|                 if (err) { | ||||
|                     reject(err); | ||||
|                 } | ||||
|                 resolve({ | ||||
|                     ok: response.statusCode >= 200 && response.statusCode < 300, | ||||
|                     json: () => body, | ||||
|                 }); | ||||
|             }; | ||||
| 
 | ||||
|             const req = new Request(requestOpts, callback); | ||||
|             console.log(`HTTP backend received request: ${req}`); | ||||
|             self.requests.push(req); | ||||
|         }); | ||||
|     }; | ||||
| } | ||||
| HttpBackend.prototype = { | ||||
|     /** | ||||
|      * Respond to all of the requests (flush the queue). | ||||
|      * @param {string} path The path to flush (optional) default: all. | ||||
|      * @param {integer} numToFlush The number of things to flush (optional), default: all. | ||||
|      * @param {integer=} waitTime  The time (in ms) to wait for a request to happen. | ||||
|      *    default: 100 | ||||
|      * | ||||
|      * @return {Promise} resolves when there is nothing left to flush, with the | ||||
|      *    number of requests flushed | ||||
|      */ | ||||
|     flush: function(path, numToFlush, waitTime) { | ||||
|         const defer = q.defer(); | ||||
|         const self = this; | ||||
|         let flushed = 0; | ||||
|         if (waitTime === undefined) { | ||||
|             waitTime = 100; | ||||
|         } | ||||
| 
 | ||||
|         function log(msg) { | ||||
|             console.log(`${Date.now()} flush[${path || ''}]: ${msg}`); | ||||
|         } | ||||
| 
 | ||||
|         log("HTTP backend flushing... (path=" + path | ||||
|             + " numToFlush=" + numToFlush | ||||
|             + " waitTime=" + waitTime | ||||
|             + ")", | ||||
|         ); | ||||
|         const endTime =  waitTime + Date.now(); | ||||
| 
 | ||||
|         const tryFlush = function() { | ||||
|             // if there's more real requests and more expected requests, flush 'em.
 | ||||
|             log(`  trying to flush => reqs=[${self.requests}] ` + | ||||
|                 `expected=[${self.expectedRequests}]`, | ||||
|             ); | ||||
|             if (self._takeFromQueue(path)) { | ||||
|                 // try again on the next tick.
 | ||||
|                 flushed += 1; | ||||
|                 if (numToFlush && flushed === numToFlush) { | ||||
|                     log(`Flushed assigned amount: ${numToFlush}`); | ||||
|                     defer.resolve(flushed); | ||||
|                 } else { | ||||
|                     log(`  flushed. Trying for more.`); | ||||
|                     setTimeout(tryFlush, 0); | ||||
|                 } | ||||
|             } else if (flushed === 0 && Date.now() < endTime) { | ||||
|                 // we may not have made the request yet, wait a generous amount of
 | ||||
|                 // time before giving up.
 | ||||
|                 log(`  nothing to flush yet; waiting for requests.`); | ||||
|                 setTimeout(tryFlush, 5); | ||||
|             } else { | ||||
|                 if (flushed === 0) { | ||||
|                     log("nothing to flush; giving up"); | ||||
|                 } else { | ||||
|                     log(`no more flushes after flushing ${flushed} requests`); | ||||
|                 } | ||||
|                 defer.resolve(flushed); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         setTimeout(tryFlush, 0); | ||||
| 
 | ||||
|         return defer.promise; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Attempts to resolve requests/expected requests. | ||||
|      * @param {string} path The path to flush (optional) default: all. | ||||
|      * @return {boolean} true if something was resolved. | ||||
|      */ | ||||
|     _takeFromQueue: function(path) { | ||||
|         let req = null; | ||||
|         let i; | ||||
|         let j; | ||||
|         let matchingReq = null; | ||||
|         let expectedReq = null; | ||||
|         let testResponse = null; | ||||
|         for (i = 0; i < this.requests.length; i++) { | ||||
|             req = this.requests[i]; | ||||
|             for (j = 0; j < this.expectedRequests.length; j++) { | ||||
|                 expectedReq = this.expectedRequests[j]; | ||||
|                 if (path && path !== expectedReq.path) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (expectedReq.method === req.method && | ||||
|                         req.path.indexOf(expectedReq.path) !== -1) { | ||||
|                     if (!expectedReq.data || (JSON.stringify(expectedReq.data) === | ||||
|                             JSON.stringify(req.data))) { | ||||
|                         matchingReq = expectedReq; | ||||
|                         this.expectedRequests.splice(j, 1); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (matchingReq) { | ||||
|                 // remove from request queue
 | ||||
|                 this.requests.splice(i, 1); | ||||
|                 i--; | ||||
| 
 | ||||
|                 for (j = 0; j < matchingReq.checks.length; j++) { | ||||
|                     matchingReq.checks[j](req); | ||||
|                 } | ||||
|                 testResponse = matchingReq.response; | ||||
|                 console.log(`${Date.now()}    responding to ${matchingReq.path}`); | ||||
|                 let body = testResponse.body; | ||||
|                 if (Object.prototype.toString.call(body) == "[object Function]") { | ||||
|                     body = body(req.path, req.data); | ||||
|                 } | ||||
|                 req.callback( | ||||
|                     testResponse.err, testResponse.response, body, | ||||
|                 ); | ||||
|                 matchingReq = null; | ||||
|             } | ||||
|         } | ||||
|         if (testResponse) {  // flushed something
 | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Makes sure that the SDK hasn't sent any more requests to the backend. | ||||
|      */ | ||||
|     verifyNoOutstandingRequests: function() { | ||||
|         const firstOutstandingReq = this.requests[0] || {}; | ||||
|         expect(this.requests.length).toEqual(0, | ||||
|             "Expected no more HTTP requests but received request to " + | ||||
|             firstOutstandingReq.path, | ||||
|         ); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Makes sure that the test doesn't have any unresolved requests. | ||||
|      */ | ||||
|     verifyNoOutstandingExpectation: function() { | ||||
|         const firstOutstandingExpectation = this.expectedRequests[0] || {}; | ||||
|         expect(this.expectedRequests.length).toEqual(0, | ||||
|             "Expected to see HTTP request for " + firstOutstandingExpectation.path, | ||||
|         ); | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Create an expected request. | ||||
|      * @param {string} method The HTTP method | ||||
|      * @param {string} path The path (which can be partial) | ||||
|      * @param {Object} data The expected data. | ||||
|      * @return {Request} An expected request. | ||||
|      */ | ||||
|     when: function(method, path, data) { | ||||
|         const pendingReq = new ExpectedRequest(method, path, data); | ||||
|         this.expectedRequests.push(pendingReq); | ||||
|         return pendingReq; | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Represents the expectation of a request. | ||||
|  * | ||||
|  * <p>Includes the conditions to be matched against, the checks to be made, | ||||
|  * and the response to be returned. | ||||
|  * | ||||
|  * @constructor | ||||
|  * @param {string} method | ||||
|  * @param {string} path | ||||
|  * @param {object?} data | ||||
|  */ | ||||
| function ExpectedRequest(method, path, data) { | ||||
|     this.method = method; | ||||
|     this.path = path; | ||||
|     this.data = data; | ||||
|     this.response = null; | ||||
|     this.checks = []; | ||||
| } | ||||
| 
 | ||||
| ExpectedRequest.prototype = { | ||||
|     toString: function() { | ||||
|         return this.method + " " + this.path | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Execute a check when this request has been satisfied. | ||||
|      * @param {Function} fn The function to execute. | ||||
|      * @return {Request} for chaining calls. | ||||
|      */ | ||||
|     check: function(fn) { | ||||
|         this.checks.push(fn); | ||||
|         return this; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Respond with the given data when this request is satisfied. | ||||
|      * @param {Number} code The HTTP status code. | ||||
|      * @param {Object|Function} data The HTTP JSON body. If this is a function, | ||||
|      * it will be invoked when the JSON body is required (which should be returned). | ||||
|      */ | ||||
|     respond: function(code, data) { | ||||
|         this.response = { | ||||
|             response: { | ||||
|                 statusCode: code, | ||||
|                 headers: {}, | ||||
|             }, | ||||
|             body: data, | ||||
|             err: null, | ||||
|         }; | ||||
|     }, | ||||
| 
 | ||||
|     /** | ||||
|      * Fail with an Error when this request is satisfied. | ||||
|      * @param {Number} code The HTTP status code. | ||||
|      * @param {Error} err The error to throw (e.g. Network Error) | ||||
|      */ | ||||
|     fail: function(code, err) { | ||||
|         this.response = { | ||||
|             response: { | ||||
|                 statusCode: code, | ||||
|                 headers: {}, | ||||
|             }, | ||||
|             body: null, | ||||
|             err: err, | ||||
|         }; | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Represents a request made by the app. | ||||
|  * | ||||
|  * @constructor | ||||
|  * @param {object} opts opts passed to request() | ||||
|  * @param {function} callback | ||||
|  */ | ||||
| function Request(opts, callback) { | ||||
|     this.opts = opts; | ||||
|     this.callback = callback; | ||||
| 
 | ||||
|     Object.defineProperty(this, 'method', { | ||||
|         get: function() { | ||||
|             return opts.method; | ||||
|         }, | ||||
|     }); | ||||
| 
 | ||||
|     Object.defineProperty(this, 'path', { | ||||
|         get: function() { | ||||
|             return opts.uri; | ||||
|         }, | ||||
|     }); | ||||
| 
 | ||||
|     Object.defineProperty(this, 'data', { | ||||
|         get: function() { | ||||
|             return opts.body; | ||||
|         }, | ||||
|     }); | ||||
| 
 | ||||
|     Object.defineProperty(this, 'queryParams', { | ||||
|         get: function() { | ||||
|             return opts.qs; | ||||
|         }, | ||||
|     }); | ||||
| 
 | ||||
|     Object.defineProperty(this, 'headers', { | ||||
|         get: function() { | ||||
|             return opts.headers || {}; | ||||
|         }, | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| Request.prototype = { | ||||
|     toString: function() { | ||||
|         return this.method + " " + this.path; | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * The HttpBackend class. | ||||
|  */ | ||||
| module.exports = HttpBackend; | ||||
		Loading…
	
		Reference in New Issue
	
	 Richard van der Hoff
						Richard van der Hoff