voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
1,433 lines (1,353 loc) • 70.3 kB
JavaScript
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Tests for ifchandler.js
*/
goog.provide('fireauth.iframeclient.IfcHandlerTest');
goog.require('fireauth.AuthError');
goog.require('fireauth.AuthEvent');
goog.require('fireauth.EmailAuthProvider');
goog.require('fireauth.FacebookAuthProvider');
goog.require('fireauth.FederatedProvider');
goog.require('fireauth.GoogleAuthProvider');
goog.require('fireauth.InvalidOriginError');
goog.require('fireauth.OAuthProvider');
goog.require('fireauth.RpcHandler');
goog.require('fireauth.TwitterAuthProvider');
goog.require('fireauth.authenum.Error');
goog.require('fireauth.constants');
goog.require('fireauth.iframeclient.IfcHandler');
goog.require('fireauth.iframeclient.IframeUrlBuilder');
goog.require('fireauth.iframeclient.IframeWrapper');
goog.require('fireauth.iframeclient.OAuthUrlBuilder');
goog.require('fireauth.util');
goog.require('goog.Promise');
goog.require('goog.Uri');
goog.require('goog.testing.AsyncTestCase');
goog.require('goog.testing.MockClock');
goog.require('goog.testing.MockControl');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.mockmatchers');
goog.require('goog.testing.recordFunction');
goog.setTestOnly('fireauth.iframeclient.IfcHandlerTest');
var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall();
var stubs = new goog.testing.PropertyReplacer();
var ifcHandler;
var authDomain = 'subdomain.firebaseapp.com';
var apiKey = 'apiKey1';
var appName = 'appName1';
var authEvent;
var eventsMap = {};
var version = '3.0.0';
var clock;
var mockControl;
var ignoreArgument;
function setUp() {
eventsMap = {};
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype,
'open_',
function() {
return goog.Promise.resolve();
});
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype, 'onReady',
goog.testing.recordFunction(goog.Promise.resolve));
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype,
'registerEvent',
function(eventName, handler) {
eventsMap[eventName] = handler;
});
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype,
'sendMessage',
function(message) {
assertEquals('webStorageSupport', message['type']);
var response = [{'status': 'ACK', 'webStorageSupport': true}];
return goog.Promise.resolve(response);
});
ignoreArgument = goog.testing.mockmatchers.ignoreArgument;
mockControl = new goog.testing.MockControl();
mockControl.$resetAll();
}
function tearDown() {
stubs.reset();
ifcHandler = null;
goog.dispose(clock);
try {
mockControl.$verifyAll();
} finally {
mockControl.$tearDown();
}
}
/**
* Simulates the current Auth language/frameworks on the specified App instance.
* @param {string} appName The expected App instance identifier.
* @param {?string} languageCode The default Auth language.
* @param {?Array<string>} frameworks The list of frameworks on the Auth
* instance.
*/
function simulateAuthService(appName, languageCode, frameworks) {
stubs.replace(
firebase,
'app',
function(name) {
assertEquals(appName, name);
return {
auth: function() {
return {
getLanguageCode: function() {
return languageCode;
},
getFramework: function() {
return frameworks || [];
}
};
}
};
});
}
/**
* Asserts that two errors are equivalent. Plain assertObjectEquals cannot be
* used as Internet Explorer adds the stack trace as a property of the object.
* @param {!fireauth.AuthError} expected
* @param {!fireauth.AuthError} actual
*/
function assertErrorEquals(expected, actual) {
assertObjectEquals(expected.toPlainObject(), actual.toPlainObject());
}
function testIframeUrlBuilder() {
var builder = new fireauth.iframeclient.IframeUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'MY_APP');
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP',
builder.setVersion(null).toString());
// Set version parameter.
builder.setVersion('3.4.0');
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP&v=3.4.0',
builder.toString());
// Modify version parameter.
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP&v=3.4.1',
builder.setVersion('3.4.1').toString());
// Remove version parameter.
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP',
builder.setVersion(null).toString());
// Set eid parameter.
builder.setEndpointId('p');
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP&eid=p',
builder.toString());
// Modify eid parameter.
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP&eid=s',
builder.setEndpointId('s').toString());
// Remove eid parameter.
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP',
builder.setEndpointId(null).toString());
// Set fw parameter.
builder.setFrameworks(['f1', 'f2']);
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP&fw=' + encodeURIComponent('f1,f2'),
builder.toString());
// Modify fw parameter.
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP&fw=f3',
builder.setFrameworks(['f3']).toString());
// Remove fw parameter.
assertEquals(
'https://example.firebaseapp.com/__/auth/iframe?apiKey=API_KEY&appName' +
'=MY_APP',
builder.setFrameworks(null).toString());
}
/**
* Asserts IframeUrlBuilder.prototype.toString handles emulator URLs.
*/
function testIframeUrlBuilder_withEmulator() {
var builder = new fireauth.iframeclient.IframeUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'MY_APP', {
url: 'http://emulator.test.domain:1234'
});
assertEquals(
'http://emulator.test.domain:1234/emulator/auth/iframe?' +
'apiKey=API_KEY&appName=MY_APP',
builder.setVersion(null).toString());
}
function testOAuthUrlBuilder() {
var redirectUrl = 'http://www.example.com/redirect?a=b#c';
var redirectUrl2 = 'http://www.example.com/redirect2?d=e#f';
var provider = new fireauth.GoogleAuthProvider();
var additionalParams = {
// This entry should be ignored.
'apiKey': 'OTHER_KEY',
'apn': 'com.example.android',
'sessionId': 'SESSION_ID1'
};
var additionalParams2 = {
'ibi': 'com.example.ios',
'sessionId': 'SESSION_ID2'
};
provider.addScope('scope1');
provider.addScope('scope2');
var customParams = {
'hd': 'example.com',
'login_hint': 'user@example.com',
'state': 'bla'
};
var filteredCustomParams = {
'hd': 'example.com',
'login_hint': 'user@example.com'
};
provider.setCustomParameters(customParams);
var builder = new fireauth.iframeclient.OAuthUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'APP_NAME', 'signInWithPopup',
provider);
var partialUrl = 'https://example.firebaseapp.com/__/auth/handler?apiKey=A' +
'PI_KEY&appName=APP_NAME&authType=signInWithPopup&providerId=google.co' +
'm&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(filteredCustomParams)) +
'&scopes=' + encodeURIComponent('profile,scope1,scope2');
assertEquals(partialUrl, builder.toString());
// Add redirect URL.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl),
builder.setRedirectUrl(redirectUrl).toString());
// Modify redirect URL.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2),
builder.setRedirectUrl(redirectUrl2).toString());
// Add eventId.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID1',
builder.setEventId('EVENT_ID1').toString());
// Modify eventId.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2',
builder.setEventId('EVENT_ID2').toString());
// Add version.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.0',
builder.setVersion('3.4.0').toString());
// Modify version.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1',
builder.setVersion('3.4.1').toString());
// Add additional parameters.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1&apn=' +
encodeURIComponent('com.example.android') + '&sessionId=SESSION_ID1',
builder.setAdditionalParameters(additionalParams).toString());
// Modify additional parameters.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1&ibi=' +
encodeURIComponent('com.example.ios') + '&sessionId=SESSION_ID2',
builder.setAdditionalParameters(additionalParams2).toString());
// Add tenantId.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1&ibi=' +
encodeURIComponent('com.example.ios') +
'&sessionId=SESSION_ID2&tid=TENANT_ID1',
builder.setTenantId('TENANT_ID1').toString());
// Modify tenantId.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1&ibi=' +
encodeURIComponent('com.example.ios') +
'&sessionId=SESSION_ID2&tid=TENANT_ID2',
builder.setTenantId('TENANT_ID2').toString());
// Delete tenantId.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1&ibi=' +
encodeURIComponent('com.example.ios') + '&sessionId=SESSION_ID2',
builder.setTenantId(null).toString());
// Delete additional parameters.
assertEquals(
partialUrl + '&redirectUrl=' + encodeURIComponent(redirectUrl2) +
'&eventId=EVENT_ID2&v=3.4.1',
builder.setAdditionalParameters(null).toString());
// Delete redirect URL.
assertEquals(
partialUrl + '&eventId=EVENT_ID2&v=3.4.1',
builder.setRedirectUrl(null).toString());
// Delete eventId.
assertEquals(
partialUrl + '&v=3.4.1',
builder.setEventId(null).toString());
// Delete version.
assertEquals(partialUrl, builder.setVersion(null).toString());
// Set eid parameter.
builder.setEndpointId('p');
assertEquals(
partialUrl + '&eid=p',
builder.toString());
// Modify eid parameter.
assertEquals(
partialUrl + '&eid=s',
builder.setEndpointId('s').toString());
// Remove eid parameter.
assertEquals(
partialUrl,
builder.setEndpointId(null).toString());
// Simulate frameworks logged.
var frameworks = ['firebaseui', 'angularfire'];
simulateAuthService('APP_NAME', null, frameworks);
assertEquals(
partialUrl + '&fw=' + encodeURIComponent(frameworks.join(',')),
builder.toString());
// Remove frameworks.
simulateAuthService('APP_NAME', null, []);
assertEquals(partialUrl, builder.toString());
}
function testOAuthUrlBuilder_localization() {
var expectedUrl;
var provider = new fireauth.GoogleAuthProvider();
provider.addScope('scope1');
provider.addScope('scope2');
// Custom parameters with no language field as provided by the developer.
var customParams = {
'hd': 'example.com',
'login_hint': 'user@example.com',
'state': 'bla'
};
// Custom parameters with a language field as provided by the developer.
var customParamsWithLang = {
'hd': 'example.com',
'login_hint': 'user@example.com',
'state': 'bla',
'hl': 'de'
};
// Expected filtered custom parameters with the default language added.
var expectedCustomParams = {
'hd': 'example.com',
'login_hint': 'user@example.com',
// Default language set.
'hl': 'fr'
};
// Expected filtered custom parameters with no language added.
var expectedCustomParamsWithoutLang = {
'hd': 'example.com',
'login_hint': 'user@example.com'
};
// Expected filtered custom parameters with non-default language added.
var expectedCustomParamsWithLang = {
'hd': 'example.com',
'login_hint': 'user@example.com',
// Default language overridden.
'hl': 'de'
};
// OAuth URL builder.
var builder = new fireauth.iframeclient.OAuthUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'APP_NAME', 'signInWithPopup',
provider);
// Simulate Auth language set.
simulateAuthService('APP_NAME', 'fr');
// Pass custom parameters with no language field.
provider.setCustomParameters(customParams);
// Expected URL should include the default language.
expectedUrl = 'https://example.firebaseapp.com/__/auth/handler?apiKey=A' +
'PI_KEY&appName=APP_NAME&authType=signInWithPopup&providerId=google.co' +
'm&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(expectedCustomParams)) +
'&scopes=' + encodeURIComponent('profile,scope1,scope2');
assertEquals(expectedUrl, builder.toString());
// Modify custom parameters to include a language parameter.
provider.setCustomParameters(customParamsWithLang);
// Expected URL should include the non-default language.
expectedUrl = 'https://example.firebaseapp.com/__/auth/handler?apiKey=A' +
'PI_KEY&appName=APP_NAME&authType=signInWithPopup&providerId=google.co' +
'm&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(
expectedCustomParamsWithLang)) +
'&scopes=' + encodeURIComponent('profile,scope1,scope2');
assertEquals(expectedUrl, builder.toString());
// Simulate no default language.
simulateAuthService('APP_NAME', null);
// Set custom parameters without a language field.
provider.setCustomParameters(customParams);
expectedUrl = 'https://example.firebaseapp.com/__/auth/handler?apiKey=A' +
'PI_KEY&appName=APP_NAME&authType=signInWithPopup&providerId=google.co' +
'm&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(
expectedCustomParamsWithoutLang)) +
'&scopes=' + encodeURIComponent('profile,scope1,scope2');
assertEquals(expectedUrl, builder.toString());
}
function testOAuthUrlBuilder_genericIdp() {
var provider = new fireauth.OAuthProvider('idp.com');
provider.addScope('thescope');
var customParams = {
'hl': 'es'
};
provider.setCustomParameters(customParams);
var builder = new fireauth.iframeclient.OAuthUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'APP_NAME', 'signInWithPopup',
provider);
var url = 'https://example.firebaseapp.com/__/auth/handler?' +
'apiKey=API_KEY&appName=APP_NAME&authType=signInWithPopup&' +
'providerId=idp.com&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(customParams)) +
'&scopes=thescope';
assertEquals(url, builder.toString());
}
function testOAuthUrlBuilder_twitter() {
var provider = new fireauth.TwitterAuthProvider();
var customParams = {
'lang': 'es'
};
provider.setCustomParameters(customParams);
var builder = new fireauth.iframeclient.OAuthUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'APP_NAME', 'signInWithPopup',
provider);
var url = 'https://example.firebaseapp.com/__/auth/handler?' +
'apiKey=API_KEY&appName=APP_NAME&authType=signInWithPopup&' +
'providerId=twitter.com&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(customParams));
assertEquals(url, builder.toString());
}
function testOAuthUrlBuilder_notOAuthProviderInstance() {
// instanceof doesn't always work due to renaming when compiling. Make sure
// that adding OAuth2 scopes works even if the provider class isn't an
// instance of OAuthProvider.
var provider = new fireauth.FederatedProvider('example.com');
provider.getScopes = function() {
return ['scope1'];
};
var customParams = {
'lang': 'es'
};
provider.setCustomParameters(customParams);
var builder = new fireauth.iframeclient.OAuthUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'APP_NAME', 'signInWithPopup',
provider);
var url = 'https://example.firebaseapp.com/__/auth/handler?' +
'apiKey=API_KEY&appName=APP_NAME&authType=signInWithPopup&' +
'providerId=example.com&customParameters=' +
encodeURIComponent(fireauth.util.stringifyJSON(customParams)) +
'&scopes=scope1';
assertEquals(url, builder.toString());
}
/**
* Tests OAuth URL Builder with an emulator config
*/
function testOAuthUrlBuilder_withEmulatorConfig() {
var provider = new fireauth.GoogleAuthProvider();
var emulatorConfig = {
url: "http://emulator.host:1234"
};
var builder = new fireauth.iframeclient.OAuthUrlBuilder(
'example.firebaseapp.com', 'API_KEY', 'APP_NAME', 'signInWithPopup',
provider, emulatorConfig);
var url = 'http://emulator.host:1234/emulator/auth/handler?' +
'apiKey=API_KEY&appName=APP_NAME&authType=signInWithPopup&' +
'providerId=google.com&scopes=profile';
assertEquals(url, builder.toString());
}
/**
* Tests initialization of Auth iframe and its event listeners.
*/
function testIfcHandler() {
asyncTestCase.waitForSignals(6);
// The expected iframe URL.
var expectedUrl = fireauth.iframeclient.IfcHandler.getAuthIframeUrl(
authDomain, apiKey, appName, version);
var authEvent = new fireauth.AuthEvent(
'unknown', '1234', 'http://www.example.com/#oauthResponse', 'SESSION_ID');
var resp = {
'authEvent': authEvent.toPlainObject()
};
var invalid = undefined;
var handler1 = goog.testing.recordFunction(function() {return true;});
var handler2 = goog.testing.recordFunction(function() {return true;});
var handler3 = goog.testing.recordFunction(function() {return false;});
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Should not have volatile storage.
assertFalse(ifcHandler.hasVolatileStorage());
// Should unload on redirect.
assertTrue(ifcHandler.unloadsOnRedirect());
// Confirm expected iframe URL.
assertEquals(ifcHandler.getIframeUrl(), expectedUrl);
// Should not be initialized in constructor.
assertEquals(
0, fireauth.iframeclient.IframeWrapper.prototype.onReady.getCallCount());
ifcHandler.initialize().then(function() {
// Test Auth event listeners.
// Add both handlers.
ifcHandler.addAuthEventListener(handler1);
ifcHandler.addAuthEventListener(handler2);
ifcHandler.addAuthEventListener(handler3);
eventsMap[fireauth.iframeclient.IfcHandler.ReceiverEvent.AUTH_EVENT](resp)
.then(function(resolvedResp) {
assertObjectEquals({'status': 'ACK'}, resolvedResp);
asyncTestCase.signal();
});
// All should be called.
assertEquals(1, handler1.getCallCount());
assertObjectEquals(
authEvent, handler1.getLastCall().getArgument(0));
assertEquals(1, handler2.getCallCount());
assertObjectEquals(
authEvent, handler2.getLastCall().getArgument(0));
assertEquals(1, handler3.getCallCount());
assertObjectEquals(
authEvent, handler3.getLastCall().getArgument(0));
// Remove handler2.
ifcHandler.removeAuthEventListener(handler2);
eventsMap[fireauth.iframeclient.IfcHandler.ReceiverEvent.AUTH_EVENT](resp)
.then(function(resolvedResp) {
assertObjectEquals({'status': 'ACK'}, resolvedResp);
asyncTestCase.signal();
});
// Only handler1 and handler3 should be called.
assertEquals(2, handler1.getCallCount());
assertObjectEquals(
authEvent, handler1.getLastCall().getArgument(0));
assertEquals(2, handler3.getCallCount());
assertObjectEquals(
authEvent, handler3.getLastCall().getArgument(0));
assertEquals(1, handler2.getCallCount());
// Remove handler1.
ifcHandler.removeAuthEventListener(handler1);
eventsMap[fireauth.iframeclient.IfcHandler.ReceiverEvent.AUTH_EVENT](resp)
.then(function(resolvedResp) {
// No handler for event so error returned.
assertObjectEquals({'status': 'ERROR'}, resolvedResp);
asyncTestCase.signal();
});
// Only handler3 called.
assertEquals(2, handler1.getCallCount());
assertEquals(1, handler2.getCallCount());
assertEquals(3, handler3.getCallCount());
assertObjectEquals(
authEvent, handler3.getLastCall().getArgument(0));
// Remove handler3.
ifcHandler.removeAuthEventListener(handler3);
eventsMap[fireauth.iframeclient.IfcHandler.ReceiverEvent.AUTH_EVENT](resp)
.then(function(resolvedResp) {
// No handler for event so error returned.
assertObjectEquals({'status': 'ERROR'}, resolvedResp);
asyncTestCase.signal();
});
// No handler called again.
assertEquals(2, handler1.getCallCount());
assertEquals(1, handler2.getCallCount());
assertEquals(3, handler3.getCallCount());
// Test when error occurs.
ifcHandler.addAuthEventListener(handler1);
eventsMap[fireauth.iframeclient.IfcHandler.ReceiverEvent.AUTH_EVENT](
invalid).then(function(resolvedResp) {
assertObjectEquals({'status': 'ERROR'}, resolvedResp);
asyncTestCase.signal();
});
// Test isWebStorageSupported.
ifcHandler.isWebStorageSupported().then(function(status) {
assertTrue(status);
asyncTestCase.signal();
});
});
}
/**
* Asserts getIframeUrl handles emulator URLs.
*/
function testIfcHandler_withEmulator() {
var emulatorConfig = {
url: 'http://emulator.test.domain:1234'
};
// The expected iframe URL.
var expectedUrl = fireauth.iframeclient.IfcHandler.getAuthIframeUrl(
authDomain, apiKey, appName, version, undefined, undefined,
emulatorConfig);
// Initialize the ifcHandler.
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version, undefined, emulatorConfig);
// Confirm expected iframe URL.
assertEquals(ifcHandler.getIframeUrl(), expectedUrl);
}
function testIfcHandler_shouldNotBeInitializedEarly() {
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Can run in background.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return true;
});
// Iframe can sync web storage.
stubs.replace(
fireauth.util,
'iframeCanSyncWebStorage',
function() {
return true;
});
assertFalse(ifcHandler.shouldBeInitializedEarly());
// Iframe cannot sync web storage.
stubs.replace(
fireauth.util,
'iframeCanSyncWebStorage',
function() {
return false;
});
assertFalse(ifcHandler.shouldBeInitializedEarly());
// Cannot run in background.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return false;
});
// Iframe can sync web storage.
stubs.replace(
fireauth.util,
'iframeCanSyncWebStorage',
function() {
return true;
});
assertFalse(ifcHandler.shouldBeInitializedEarly());
}
function testIfcHandler_shouldBeInitializedEarly() {
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Cannot run in background.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return false;
});
// Iframe cannot sync web storage.
stubs.replace(
fireauth.util,
'iframeCanSyncWebStorage',
function() {
return false;
});
assertTrue(ifcHandler.shouldBeInitializedEarly());
}
function testIfcHandler_initializeAndWait_success() {
// Confirm expected endpoint config and frameworks passed to underlying RPC
// handler.
var provider = new fireauth.GoogleAuthProvider();
var expectedFrameworks = [fireauth.util.Framework.FIREBASEUI];
var expectedClientVersion = fireauth.util.getClientVersion(
fireauth.util.ClientImplementation.JSCORE,
version,
expectedFrameworks);
var endpoint = fireauth.constants.Endpoint.STAGING;
var endpointConfig = {
'firebaseEndpoint': endpoint.firebaseAuthEndpoint,
'secureTokenEndpoint': endpoint.secureTokenEndpoint
};
// Simulate expected frameworks on the Auth instance corresponding to appName.
simulateAuthService(appName, null, expectedFrameworks);
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
stubs.replace(
fireauth.constants,
'getEndpointConfig',
function(opt_id) {
assertEquals(endpoint.id, opt_id);
return endpointConfig;
});
var getAuthIframeUrl = mockControl.createMethodMock(
fireauth.iframeclient.IfcHandler, 'getAuthIframeUrl');
var rpcHandler = mockControl.createStrictMock(fireauth.RpcHandler);
var rpcHandlerConstructor = mockControl.createConstructorMock(
fireauth, 'RpcHandler');
var iframeWrapper = mockControl.createStrictMock(
fireauth.iframeclient.IframeWrapper);
var iframeWrapperConstructor = mockControl.createConstructorMock(
fireauth.iframeclient, 'IframeWrapper');
// Iframe initialized with expected endpoint ID.
getAuthIframeUrl(authDomain, apiKey, appName, ignoreArgument,
fireauth.constants.Endpoint.STAGING.id, expectedFrameworks, ignoreArgument)
.$returns('https://url');
// Confirm iframe URL returned by getAuthIframeUrl used to initialize the
// IframeWrapper.
iframeWrapperConstructor('https://url').$returns(iframeWrapper);
iframeWrapper.registerEvent('authEvent', ignoreArgument);
iframeWrapper.onReady().$returns(goog.Promise.resolve());
// Should be initialized with expected endpoint config and client version.
rpcHandlerConstructor(apiKey, endpointConfig, expectedClientVersion)
.$returns(rpcHandler);
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
rpcHandler.getAuthorizedDomains().$returns(goog.Promise.resolve([domain]));
mockControl.$replayAll();
asyncTestCase.waitForSignals(1);
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version,
fireauth.constants.Endpoint.STAGING.id);
ifcHandler.initializeAndWait().then(function() {
return ifcHandler.processRedirect('linkViaRedirect', provider, '1234');
}).then(function() {
assertEquals(1, fireauth.util.goTo.getCallCount());
asyncTestCase.signal();
});
}
function testIfcHandler_initializeAndWait_error() {
asyncTestCase.waitForSignals(1);
var expectedError = new fireauth.AuthError(
fireauth.authenum.Error.NETWORK_REQUEST_FAILED);
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype,
'onReady',
function() {
return goog.Promise.reject(new Error('Network Error'));
});
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Should throw network error.
ifcHandler.initializeAndWait().thenCatch(function(error) {
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_blocked() {
asyncTestCase.waitForSignals(1);
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
var expectedError =
new fireauth.AuthError(fireauth.authenum.Error.POPUP_BLOCKED);
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Should throw popup blocked error.
ifcHandler.processPopup(
null, 'linkViaPopup', provider, onInit, onError, '1234', false)
.thenCatch(function(error) {
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_invalidOrigin() {
asyncTestCase.waitForSignals(1);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
// Assume origin is an invalid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
return goog.Promise.resolve([]);
});
var expectedError =
new fireauth.InvalidOriginError(fireauth.util.getCurrentUrl());
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Should throw invalid origin error.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.thenCatch(function(error) {
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_invalidProvider() {
asyncTestCase.waitForSignals(1);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
var expectedError =
new fireauth.AuthError(fireauth.authenum.Error.INVALID_OAUTH_PROVIDER);
// Non OAuth provider should throw invalid provider error.
var provider = new fireauth.EmailAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Should throw invalid provider error.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.thenCatch(function(error) {
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_initializeAndWaitError() {
asyncTestCase.waitForSignals(1);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
// Simulate error embedding the iframe.
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype,
'onReady',
function() {
return goog.Promise.reject(new Error('Network Error'));
});
var expectedError =
new fireauth.AuthError(fireauth.authenum.Error.NETWORK_REQUEST_FAILED);
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Should throw network error.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.thenCatch(function(error) {
// Should be initialized.
assertEquals(1, onInit.getCallCount());
// Should channel error.
assertEquals(1, onError.getCallCount());
assertEquals(error, onError.getLastCall().getArgument(0));
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_notAlreadyRedirected_success() {
asyncTestCase.waitForSignals(1);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
var provider = new fireauth.GoogleAuthProvider();
var expectedUrl = fireauth.iframeclient.IfcHandler.getOAuthHelperWidgetUrl(
authDomain,
apiKey,
appName,
'linkViaPopup',
provider,
null,
'1234',
version,
undefined,
// Check expected endpoint ID appended.
fireauth.constants.Endpoint.STAGING.id);
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version,
fireauth.constants.Endpoint.STAGING.id);
// Should succeed.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.then(function() {
// On init should be called as the iframe is initialized.
assertEquals(1, onInit.getCallCount());
// No error.
assertEquals(0, onError.getCallCount());
// Popup redirected.
assertEquals(
expectedUrl,
fireauth.util.goTo.getLastCall().getArgument(0));
assertEquals(
popupWin,
fireauth.util.goTo.getLastCall().getArgument(1));
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_notAlreadyRedirected_tenantId_success() {
asyncTestCase.waitForSignals(1);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
var tenantId = '123456789012';
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
var provider = new fireauth.GoogleAuthProvider();
var expectedUrl = fireauth.iframeclient.IfcHandler.getOAuthHelperWidgetUrl(
authDomain,
apiKey,
appName,
'linkViaPopup',
provider,
null,
'1234',
version,
undefined,
// Check expected endpoint ID appended.
fireauth.constants.Endpoint.STAGING.id,
tenantId);
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version,
fireauth.constants.Endpoint.STAGING.id);
// Should succeed.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false,
tenantId).then(function() {
// On init should be called as the iframe is initialized.
assertEquals(1, onInit.getCallCount());
// No error.
assertEquals(0, onError.getCallCount());
// Popup redirected.
assertEquals(
expectedUrl,
fireauth.util.goTo.getLastCall().getArgument(0));
assertEquals(
popupWin,
fireauth.util.goTo.getLastCall().getArgument(1));
asyncTestCase.signal();
});
}
/** Asserts processRedirect can handle emulator URLs. */
function testIfcHandler_processPopup_success_withEmulator() {
var emulatorConfig = {
url: 'http:/emulator.test.domain:1234'
};
asyncTestCase.waitForSignals(1);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function () {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
stubs.replace(
fireauth.RpcHandler.prototype,
'updateEmulatorConfig',
goog.testing.recordFunction());
var provider = new fireauth.GoogleAuthProvider();
var expectedUrl = fireauth.iframeclient.IfcHandler.getOAuthHelperWidgetUrl(
authDomain,
apiKey,
appName,
'linkViaPopup',
provider,
null,
'1234',
version,
undefined,
// Check expected endpoint ID appended.
fireauth.constants.Endpoint.STAGING.id,
undefined,
emulatorConfig);
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version,
fireauth.constants.Endpoint.STAGING.id, emulatorConfig);
// Should succeed.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.then(function () {
// On init should be called as the iframe is initialized.
assertEquals(1, onInit.getCallCount());
// No error.
assertEquals(0, onError.getCallCount());
// Popup redirected.
assertEquals(
expectedUrl,
fireauth.util.goTo.getLastCall().getArgument(0));
// Emulator config set on RpcHandler.
assertObjectEquals(
emulatorConfig,
fireauth.RpcHandler.prototype.updateEmulatorConfig.getLastCall()
.getArgument(0));
assertEquals(
popupWin,
fireauth.util.goTo.getLastCall().getArgument(1));
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_redirected_iframeCanRunInBG_success() {
asyncTestCase.waitForSignals(1);
// Simulate that the app can run in the background but is running in an
// iframe. This typically triggers processPopup call with
// opt_alreadyRedirected set to true. This is due to the fact that sandboxed
// iframes may not be able to redirect a popup window that they opened.
// In this case, simulate the origin is whitelisted. This should succeed with
// no additional redirect call.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return true;
});
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
var popupWin = {
close: goog.testing.recordFunction()
};
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Call with alreadyRedirected true.
// Should succeed.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', true)
.then(function() {
// On init should be called as the iframe is initialized.
assertEquals(1, onInit.getCallCount());
// No error.
assertEquals(0, onError.getCallCount());
// No additional redirect.
assertEquals(0, fireauth.util.goTo.getCallCount(0));
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_redirected_iframeCanRunInBG_error() {
asyncTestCase.waitForSignals(1);
// Simulate that the app can run in the background but is running in an
// iframe. This typically triggers processPopup call with
// opt_alreadyRedirected set to true. This is due to the fact that sandboxed
// iframes may not be able to redirect a popup window that they opened.
// In this case, simulate the origin is not whitelisted. This should throw the
// expected error.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return true;
});
// Assume origin is an invalid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
return goog.Promise.resolve([]);
});
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
var popupWin = {
close: goog.testing.recordFunction()
};
var provider = new fireauth.GoogleAuthProvider();
var expectedError =
new fireauth.InvalidOriginError(fireauth.util.getCurrentUrl());
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Call with alreadyRedirected true.
// Should succeed.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', true)
.thenCatch(function(error) {
assertErrorEquals(expectedError, error);
// On init should not be called.
assertEquals(0, onInit.getCallCount());
// No on error call.
assertEquals(0, onError.getCallCount());
// No redirect.
assertEquals(0, fireauth.util.goTo.getCallCount(0));
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_alreadyRedirected_success() {
asyncTestCase.waitForSignals(1);
// Simulate that the app cannot run in the background. This typically triggers
// processPopup call with opt_alreadyRedirected set to true.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return false;
});
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
var popupWin = {
close: goog.testing.recordFunction()
};
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Call with alreadyRedirected true.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', true)
.then(function() {
// On initialization called.
assertEquals(1, onInit.getCallCount());
// No error.
assertEquals(0, onError.getCallCount());
// As popup already redirected, no redirect triggered.
/** @suppress {missingRequire} */
assertEquals(0, fireauth.util.goTo.getCallCount());
asyncTestCase.signal();
});
}
function testIfcHandler_processPopup_alreadyRedirect_initializeAndWaitError() {
asyncTestCase.waitForSignals(1);
// Simulate that the app cannot run in the background. This typically triggers
// processPopup call with opt_alreadyRedirected set to true.
stubs.replace(
fireauth.util,
'runsInBackground',
function() {
return false;
});
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
stubs.replace(
fireauth.iframeclient.IframeWrapper.prototype,
'onReady',
function() {
return goog.Promise.reject(new Error('Network Error'));
});
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
var popupWin = {
close: goog.testing.recordFunction()
};
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Call with alreadyRedirected true.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', true)
.then(function() {
// On initialization called.
assertEquals(1, onInit.getCallCount());
// No popup redirect.
/** @suppress {missingRequire} */
assertEquals(0, fireauth.util.goTo.getCallCount());
// onError should be called in the background if an error occurs
// during embed of iframe.
ifcHandler.initializeAndWait().thenCatch(function(error) {
assertEquals(1, onError.getCallCount());
assertObjectEquals(error, onError.getLastCall().getArgument(0));
asyncTestCase.signal();
});
});
}
function testIfcHandler_processPopup_networkError_then_success() {
asyncTestCase.waitForSignals(1);
var expectedError =
new fireauth.AuthError(fireauth.authenum.Error.NETWORK_REQUEST_FAILED);
var popupWin = {
close: goog.testing.recordFunction()
};
var onInit = goog.testing.recordFunction();
var onError = goog.testing.recordFunction();
stubs.replace(
fireauth.util,
'goTo',
goog.testing.recordFunction());
var calls = 0;
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
calls++;
// Simulate network error on first call.
if (calls == 1) {
return goog.Promise.reject(expectedError);
}
// Simulate valid origin on next call.
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();
return goog.Promise.resolve([domain]);
});
var provider = new fireauth.GoogleAuthProvider();
var expectedUrl = fireauth.iframeclient.IfcHandler.getOAuthHelperWidgetUrl(
authDomain,
apiKey,
appName,
'linkViaPopup',
provider,
null,
'1234',
version);
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// First call fails with origin check network error.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.thenCatch(function(error) {
assertErrorEquals(expectedError, error);
// Second call should succeed and confirm origin check not cached.
ifcHandler.processPopup(
popupWin, 'linkViaPopup', provider, onInit, onError, '1234', false)
.then(function() {
// Success on retrial. Invalid origin not cached.
assertEquals(1, onInit.getCallCount());
assertEquals(0, onError.getCallCount());
assertEquals(
expectedUrl,
fireauth.util.goTo.getLastCall().getArgument(0));
assertEquals(
popupWin,
fireauth.util.goTo.getLastCall().getArgument(1));
asyncTestCase.signal();
});
});
}
function testIfcHandler_startPopupTimeout_webStorageNotSupported() {
stubs.replace(
fireauth.iframeclient.IfcHandler.prototype,
'isWebStorageSupported',
function() {
return goog.Promise.resolve(false);
});
asyncTestCase.waitForSignals(1);
var expectedError =
new fireauth.AuthError(fireauth.authenum.Error.WEB_STORAGE_UNSUPPORTED);
var popupWin = {
close: goog.testing.recordFunction()
};
// On error should be triggered with web storage not supported error.
var onError = function(error) {
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
};
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
ifcHandler.startPopupTimeout(popupWin, onError, 1000);
}
function testIfcHandler_startPopupTimeout_popupClosedByUser() {
clock = new goog.testing.MockClock(true);
asyncTestCase.waitForSignals(1);
var expectedError =
new fireauth.AuthError(fireauth.authenum.Error.POPUP_CLOSED_BY_USER);
var popupWin = {
close: goog.testing.recordFunction()
};
var onError = goog.testing.recordFunction();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// onError should be called with the expected popup closed by user error.
ifcHandler.startPopupTimeout(popupWin, onError, 2000).then(function() {
assertEquals(1, onError.getCallCount());
assertObjectEquals(expectedError, onError.getLastCall().getArgument(0));
asyncTestCase.signal();
});
// Exceed timeout after close to trigger popup closed by user.
popupWin.closed = true;
clock.tick(4000);
}
function testIfcHandler_processRedirect_invalidOrigin() {
asyncTestCase.waitForSignals(1);
// Assume origin is an invalid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
return goog.Promise.resolve([]);
});
var expectedError =
new fireauth.InvalidOriginError(fireauth.util.getCurrentUrl());
var provider = new fireauth.GoogleAuthProvider();
ifcHandler = new fireauth.iframeclient.IfcHandler(
authDomain, apiKey, appName, version);
// Invalid origin error should be thrown.
ifcHandler.processRedirect('linkViaRedirect', provider, '1234')
.thenCatch(function(error) {
assertErrorEquals(expectedError, error);
asyncTestCase.signal();
});
}
function testIfcHandler_processRedirect_invalidProvider() {
asyncTestCase.waitForSignals(1);
// Assume origin is a valid one.
stubs.replace(
fireauth.RpcHandler.prototype,
'getAuthorizedDomains',
function() {
var uri = goog.Uri.parse(fireauth.util.getCurrentUrl());
var domain = uri.getDomain();