From a39a7c8334aff7e2add61646be6c4c310e3a87e3 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 18 May 2017 12:18:57 +0100 Subject: [PATCH 1/3] Update to more recent mock-request Just copy-and-paste the updated version from js-sdk in here. --- test/mock-request.js | 183 +++++++++++++++++++++++++++++-------------- 1 file changed, 125 insertions(+), 58 deletions(-) diff --git a/test/mock-request.js b/test/mock-request.js index 8510ad54..e4a929a6 100644 --- a/test/mock-request.js +++ b/test/mock-request.js @@ -1,6 +1,6 @@ "use strict"; -var q = require("q"); -var expect = require('expect'); +const q = require("q"); +import expect from 'expect'; /** * Construct a mock HTTP backend, heavily inspired by Angular.js. @@ -9,23 +9,25 @@ var expect = require('expect'); function HttpBackend() { this.requests = []; this.expectedRequests = []; - var self = this; + const self = this; // the request function dependency that the SDK needs. this.requestFn = function(opts, callback) { - var realReq = new Request(opts.method, opts.uri, opts.body, opts.qs); - realReq.callback = callback; - console.log("HTTP backend received request: %s %s", opts.method, opts.uri); - self.requests.push(realReq); + const req = new Request(opts, callback); + console.log("HTTP backend received request: %s", req); + self.requests.push(req); - var abort = function() { - var idx = self.requests.indexOf(realReq); + const abort = function() { + const idx = self.requests.indexOf(req); if (idx >= 0) { - console.log("Aborting HTTP request: %s %s", opts.method, opts.uri); + console.log("Aborting HTTP request: %s %s", opts.method, + opts.uri); self.requests.splice(idx, 1); + req.callback("aborted"); } - } + }; + return { - abort: abort + abort: abort, }; }; } @@ -34,43 +36,48 @@ 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. - * @return {Promise} resolved when there is nothing left to flush. + * @param {integer=} waitTime The time (in ms) to wait for a request to happen. + * default: 5 + * + * @return {Promise} resolves when there is nothing left to flush, with the + * number of requests flushed */ - flush: function(path, numToFlush) { - var defer = q.defer(); - var self = this; - var flushed = 0; - var triedWaiting = false; + flush: function(path, numToFlush, waitTime) { + const defer = q.defer(); + const self = this; + let flushed = 0; + let triedWaiting = false; + if (waitTime === undefined) { + waitTime = 5; + } console.log( - "HTTP backend flushing... (path=%s numToFlush=%s)", path, numToFlush + "HTTP backend flushing... (path=%s numToFlush=%s waitTime=%s)", + path, numToFlush, waitTime, ); - var tryFlush = function() { + const tryFlush = function() { // if there's more real requests and more expected requests, flush 'em. console.log( - " trying to flush queue => reqs=%s expected=%s [%s]", - self.requests.length, self.expectedRequests.length, path + " trying to flush queue => reqs=[%s] expected=[%s]", + self.requests, self.expectedRequests.map((er) => er.path), ); if (self._takeFromQueue(path)) { // try again on the next tick. - console.log(" flushed. Trying for more. [%s]", path); flushed += 1; if (numToFlush && flushed === numToFlush) { - console.log(" [%s] Flushed assigned amount: %s", path, numToFlush); - defer.resolve(); - } - else { + console.log(" Flushed assigned amount: %s", numToFlush); + defer.resolve(flushed); + } else { + console.log(" flushed. Trying for more."); setTimeout(tryFlush, 0); } - } - else if (flushed === 0 && !triedWaiting) { + } else if (flushed === 0 && !triedWaiting) { // we may not have made the request yet, wait a generous amount of // time before giving up. - setTimeout(tryFlush, 5); + setTimeout(tryFlush, waitTime); triedWaiting = true; - } - else { - console.log(" no more flushes. [%s]", path); - defer.resolve(); + } else { + console.log(" no more flushes."); + defer.resolve(flushed); } }; @@ -85,14 +92,19 @@ HttpBackend.prototype = { * @return {boolean} true if something was resolved. */ _takeFromQueue: function(path) { - var req = null; - var i, j; - var matchingReq, expectedReq, testResponse = null; + 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 (path && path !== expectedReq.path) { + continue; + } if (expectedReq.method === req.method && req.path.indexOf(expectedReq.path) !== -1) { if (!expectedReq.data || (JSON.stringify(expectedReq.data) === @@ -114,12 +126,12 @@ HttpBackend.prototype = { } testResponse = matchingReq.response; console.log(" responding to %s", matchingReq.path); - var body = testResponse.body; + 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 + testResponse.err, testResponse.response, body, ); matchingReq = null; } @@ -134,10 +146,10 @@ HttpBackend.prototype = { * Makes sure that the SDK hasn't sent any more requests to the backend. */ verifyNoOutstandingRequests: function() { - var firstOutstandingReq = this.requests[0] || {}; + const firstOutstandingReq = this.requests[0] || {}; expect(this.requests.length).toEqual(0, "Expected no more HTTP requests but received request to " + - firstOutstandingReq.path + firstOutstandingReq.path, ); }, @@ -145,12 +157,9 @@ HttpBackend.prototype = { * Makes sure that the test doesn't have any unresolved requests. */ verifyNoOutstandingExpectation: function() { - var firstOutstandingExpectation = this.expectedRequests[0] || {}; - expect(this.expectedRequests.length).toEqual( - 0, - "Expected to see HTTP request for " - + firstOutstandingExpectation.method - + " " + firstOutstandingExpectation.path + const firstOutstandingExpectation = this.expectedRequests[0] || {}; + expect(this.expectedRequests.length).toEqual(0, + "Expected to see HTTP request for " + firstOutstandingExpectation.path, ); }, @@ -162,22 +171,32 @@ HttpBackend.prototype = { * @return {Request} An expected request. */ when: function(method, path, data) { - var pendingReq = new Request(method, path, data); + const pendingReq = new ExpectedRequest(method, path, data); this.expectedRequests.push(pendingReq); return pendingReq; - } + }, }; -function Request(method, path, data, queryParams) { +/** + * Represents the expectation of a request. + * + *

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.queryParams = queryParams; - this.callback = null; this.response = null; this.checks = []; } -Request.prototype = { + +ExpectedRequest.prototype = { /** * Execute a check when this request has been satisfied. * @param {Function} fn The function to execute. @@ -198,10 +217,10 @@ Request.prototype = { this.response = { response: { statusCode: code, - headers: {} + headers: {}, }, body: data, - err: null + err: null, }; }, @@ -214,14 +233,62 @@ Request.prototype = { this.response = { response: { statusCode: code, - headers: {} + headers: {}, }, body: null, - err: err + 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. */ From f60773ae1fdc5494d39988396f51a7b389206050 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 18 May 2017 13:37:23 +0100 Subject: [PATCH 2/3] mock-request: improve logging attempt to make the logging a bit more comprehensible --- test/mock-request.js | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/test/mock-request.js b/test/mock-request.js index e4a929a6..0ebabb03 100644 --- a/test/mock-request.js +++ b/test/mock-request.js @@ -13,7 +13,7 @@ function HttpBackend() { // the request function dependency that the SDK needs. this.requestFn = function(opts, callback) { const req = new Request(opts, callback); - console.log("HTTP backend received request: %s", req); + console.log("HTTP backend received request: " + req); self.requests.push(req); const abort = function() { @@ -51,20 +51,23 @@ HttpBackend.prototype = { waitTime = 5; } console.log( - "HTTP backend flushing... (path=%s numToFlush=%s waitTime=%s)", - path, numToFlush, waitTime, + "HTTP backend flushing... (path=" + path + + " numToFlush=" + numToFlush + + " waitTime=" + waitTime + + ")", ); const tryFlush = function() { // if there's more real requests and more expected requests, flush 'em. console.log( - " trying to flush queue => reqs=[%s] expected=[%s]", - self.requests, self.expectedRequests.map((er) => er.path), + " trying to flush queue => reqs=[" + self.requests + + "] expected=[" + self.expectedRequests + + "]", ); if (self._takeFromQueue(path)) { // try again on the next tick. flushed += 1; if (numToFlush && flushed === numToFlush) { - console.log(" Flushed assigned amount: %s", numToFlush); + console.log(" Flushed assigned amount:", numToFlush); defer.resolve(flushed); } else { console.log(" flushed. Trying for more."); @@ -73,10 +76,20 @@ HttpBackend.prototype = { } else if (flushed === 0 && !triedWaiting) { // we may not have made the request yet, wait a generous amount of // time before giving up. + console.log( + " nothing to flush yet; waiting " + waitTime + + "ms for requests.") setTimeout(tryFlush, waitTime); triedWaiting = true; } else { - console.log(" no more flushes."); + if (flushed === 0) { + console.log(" nothing to flush; giving up"); + } else { + console.log( + " no more flushes after flushing", flushed, + "requests", + ); + } defer.resolve(flushed); } }; @@ -197,6 +210,10 @@ function ExpectedRequest(method, path, data) { } 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. From f16086bbea481b1d6bb97644ea805d74e7a473f1 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 18 May 2017 13:39:33 +0100 Subject: [PATCH 3/3] Attempt to deflakify joining test give the client a bit longer to get started. --- test/app-tests/joining.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/test/app-tests/joining.js b/test/app-tests/joining.js index 76d90ce8..7aaaaec8 100644 --- a/test/app-tests/joining.js +++ b/test/app-tests/joining.js @@ -74,7 +74,6 @@ describe('joining a room', function () { httpBackend.when('GET', '/pushrules').respond(200, {}); httpBackend.when('POST', '/filter').respond(200, { filter_id: 'fid' }); - httpBackend.when('GET', '/sync').respond(200, {}); // note that we deliberately do *not* set an expectation for a // presence update - setting one makes the first httpBackend.flush @@ -86,7 +85,11 @@ describe('joining a room', function () { localStorage.setItem("mx_access_token", ACCESS_TOKEN ); localStorage.setItem("mx_user_id", USER_ID); - var mc = ; + var mc = ( + {throw new Error("unimplemented");}} + /> + ); matrixChat = ReactDOM.render(mc, parentDiv); // switch to the Directory @@ -94,10 +97,24 @@ describe('joining a room', function () { var roomView; - // wait for /sync to happen - return q.delay(1).then(() => { - return httpBackend.flush(); - }).then(() => { + // wait for /sync to happen. This may take some time, as the client + // has to initialise indexeddb. + console.log("waiting for /sync"); + let syncDone = false; + httpBackend.when('GET', '/sync') + .check((r) => {syncDone = true;}) + .respond(200, {}); + function awaitSync(attempts) { + if (syncDone) { + return q(); + } + if (!attempts) { + throw new Error("Gave up waiting for /sync") + } + return httpBackend.flush().then(() => awaitSync(attempts-1)); + } + + return awaitSync(10).then(() => { // wait for the directory requests httpBackend.when('POST', '/publicRooms').respond(200, {chunk: []}); httpBackend.when('GET', '/thirdparty/protocols').respond(200, {});