From 37d6c371db3d7442d6742e5ba79fd24b68d7ca92 Mon Sep 17 00:00:00 2001 From: vladikoff Date: Mon, 11 Aug 2014 14:37:50 -0700 Subject: [PATCH] fix(tests): Update service-mixin tests. Fixes #1400. --- app/scripts/views/mixins/service-mixin.js | 33 +++-- app/tests/spec/views/mixins/service-mixin.js | 141 ++++++++++++++++++- 2 files changed, 158 insertions(+), 16 deletions(-) diff --git a/app/scripts/views/mixins/service-mixin.js b/app/scripts/views/mixins/service-mixin.js index a3cd0e632d..ce9eb0c015 100644 --- a/app/scripts/views/mixins/service-mixin.js +++ b/app/scripts/views/mixins/service-mixin.js @@ -38,7 +38,7 @@ define([ return hasServiceView || this.isOAuthSameBrowser(); } - function notifyChannel(message, data) { + function _notifyChannel(message, data) { /*jshint validthis: true*/ var self = this; // Assume the receiver of the channel's notification will either @@ -48,7 +48,7 @@ define([ if (data && data.timeout) { self._expectResponseTimeout = self.setTimeout(function () { self.displayError(OAuthErrors.toError('TRY_AGAIN'), OAuthErrors); - }, EXPECT_CHANNEL_RESPONSE_TIMEOUT); + }, data.timeout); } return Channels.sendExpectResponse(message, data, { @@ -67,7 +67,7 @@ define([ * @param {Object} options * @returns {Object} */ - function decorateOAuthResult(result, options) { + function _decorateOAuthResult(result, options) { options = options || {}; // if specific to the WebChannel flow @@ -75,8 +75,8 @@ define([ // set closeWindow result.closeWindow = options.viewOptions && options.viewOptions.source === 'signin'; // if the source is "signin" then set a timeout for a successful WebChannel signin - if (options.viewOptions.source === 'signin') { - result.timeout = 3000; + if (options.viewOptions && options.viewOptions.source === 'signin') { + result.timeout = EXPECT_CHANNEL_RESPONSE_TIMEOUT; } } @@ -89,7 +89,7 @@ define([ * @param {Object} result * @returns {Object} */ - function formatOAuthResult(result) { + function _formatOAuthResult(result) { // get code and state from redirect params var redirectParams = result.redirect.split('?')[1]; result.state = Url.searchParam('state', redirectParams); @@ -118,6 +118,10 @@ define([ // to the 'client_id'. this.service = params.client_id || Session.service; + // assertion library to use to generate assertions + // can be substituted for testing + this.assertionLibrary = Assertion; + Session.set('service', this.service); // A hint that allows Session to determine whether the user // is in the OAuth flow. @@ -144,7 +148,7 @@ define([ }, finishOAuthFlowDifferentBrowser: function () { - return notifyChannel.call(this, 'oauth_complete', { + return _notifyChannel.call(this, 'oauth_complete', { redirect: this.serviceRedirectURI, error: RP_DIFFERENT_BROWSER_ERROR_CODE }); @@ -152,9 +156,8 @@ define([ finishOAuthFlow: buttonProgressIndicator(function (viewOptions) { var self = this; - return this._configLoader.fetch().then(function(config) { - return Assertion.generate(config.oauthUrl); + return self.assertionLibrary.generate(config.oauthUrl); }) .then(function(assertion) { self._oAuthParams.assertion = assertion; @@ -162,18 +165,18 @@ define([ }) .then(function(result) { - return formatOAuthResult(result); + return _formatOAuthResult(result); }) .then(function(result) { - return decorateOAuthResult(result, { + return _decorateOAuthResult(result, { context: self.window, viewOptions: viewOptions }); }) .then(function(result) { - return notifyChannel.call(self, 'oauth_complete', result); + return _notifyChannel.call(self, 'oauth_complete', result); }) .then(function() { Session.clear('oauth'); @@ -230,6 +233,10 @@ define([ isSync: function () { return Session.service === SYNC_SERVICE; - } + }, + // exported for testing purposes + _decorateOAuthResult: _decorateOAuthResult, + _formatOAuthResult: _formatOAuthResult, + _notifyChannel: _notifyChannel }; }); diff --git a/app/tests/spec/views/mixins/service-mixin.js b/app/tests/spec/views/mixins/service-mixin.js index b0ddebbfe5..630b9cb947 100644 --- a/app/tests/spec/views/mixins/service-mixin.js +++ b/app/tests/spec/views/mixins/service-mixin.js @@ -8,6 +8,7 @@ define([ 'chai', 'backbone', 'underscore', + 'lib/promise', '../../../mocks/oauth_servers', '../../../mocks/window', '../../../mocks/channel', @@ -15,16 +16,18 @@ define([ 'views/base', 'lib/session', 'stache!templates/test_template' -], function (Chai, Backbone, _, MockOAuthServers, WindowMock, ChannelMock, ServiceMixin, BaseView, Session, TestTemplate) { +], function (Chai, Backbone, _, p, MockOAuthServers, WindowMock, ChannelMock, ServiceMixin, BaseView, Session, TestTemplate) { var assert = Chai.assert; var CLIENT_ID = 'dcdb5ae7add825d2'; var STATE = '123'; + var CODE = 'code1'; var SCOPE = 'profile:email'; var CLIENT_NAME = '123Done'; var BASE_REDIRECT_URL = 'http://127.0.0.1:8080/api/oauth'; var DEFAULT_SEARCH_STRING = '?client_id=' + CLIENT_ID + '&state=' + STATE + '&scope=' + SCOPE; + var DEFAULT_REDIRECT_STRING = '?code=' + CODE + '&state=' + STATE; var OAuthView = BaseView.extend({ @@ -113,9 +116,141 @@ define([ }); }); + describe('_decorateOAuthResult', function () { + it('decorates nothing by default', function (done) { + view._decorateOAuthResult({}, {}) + .then(function (result) { + assert.notOk(result.closeWindow); + assert.notOk(result.timeout); + return done(); + }); + }); + + it('decorates WebChannel from Session with signin source', function (done) { + Session.set('oauth', { + webChannelId: 'id' + }); + + view._decorateOAuthResult({}, { + context: windowMock, + viewOptions: { + source: 'signin' + } + }).then(function (result) { + assert.isTrue(result.closeWindow); + assert.ok(result.timeout); + Session.clear('oauth'); + done(); + }); + }); + + it('decorates WebChannel from location param with signin source', function (done) { + windowMock.location.search = DEFAULT_SEARCH_STRING + '&webChannelId=id'; + + view._decorateOAuthResult({}, { + context: windowMock, + viewOptions: { + source: 'signin' + } + }).then(function (result) { + assert.isTrue(result.closeWindow); + assert.ok(result.timeout); + done(); + }); + }); + }); + + describe('_formatOAuthResult', function () { + it('formats the redirect params', function (done) { + view._formatOAuthResult({ + redirect: DEFAULT_REDIRECT_STRING + }).then(function (result) { + assert.equal(result.redirect, DEFAULT_REDIRECT_STRING); + assert.equal(result.code, CODE); + assert.equal(result.state, STATE); + done(); + }); + }); + }); + + describe('_notifyChannel', function () { + var mockChannel = { + init: function() {}, + send: function(msg, data, done) { done(); }, + teardown: function() {} + }; + + it('throws timeout errors', function (done) { + view.channel = mockChannel; + view.setTimeout = function(func) { func(); }; + + var displayedError = false; + view.displayError = function() { + displayedError = true; + done(); + }; + + view._notifyChannel({}, {timeout: 1}); + }); + + it('throws channel errors', function () { + view.channel = mockChannel; + view.channel.send = function (msg, data, done) { + done(new Error('Cannot send events')); + }; + + return view._notifyChannel({}) + .then(assert.fail, function() { assert.ok('Error thrown'); }); + }); + }); + describe('finishOAuthFlow', function () { - it('notifies the channel', function () { - // TODO - fill this in with #1141 + var mockAssertionLibrary = { + generate: function() { + return p('mockAssertion'); + } + }; + var mockConfigLoader = { + fetch: function() { + return p({oauthUrl: ''}); + } + }; + + it('notifies the channel', function (done) { + view.assertionLibrary = mockAssertionLibrary; + view._configLoader = mockConfigLoader; + view._oAuthParams = {}; + view._oAuthClient = { + getCode: function() { + return p({redirect: DEFAULT_REDIRECT_STRING}); + } + }; + + view.finishOAuthFlow() + .then(function () { + assert.equal(Session.oauth, null); + done(); + }); + }); + + it('throws errors', function () { + view.assertionLibrary = mockAssertionLibrary; + view._configLoader = mockConfigLoader; + view._oAuthParams = {}; + view._oAuthClient = { + getCode: function() { + return p({}); + } + }; + var displayedError = false; + view.displayError = function() { + displayedError = true; + }; + + return view.finishOAuthFlow() + .then(function () { + assert.isTrue(displayedError); + }); }); });