blob: 22ac6152ee48a9b51d069a8efa3cc29a8d8d1e4b [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(robliao,vadimt): Determine the granularity of testing to perform.
/**
* Test fixture for background.js.
* @constructor
* @extends {testing.Test}
*/
function GoogleNowBackgroundUnitTest () {
testing.Test.call(this);
}
GoogleNowBackgroundUnitTest.prototype = {
__proto__: testing.Test.prototype,
/** @override */
extraLibraries: [
'common_test_util.js',
'background_test_util.js',
'background.js'
]
};
var TEST_NAME = 'GoogleNowBackgroundUnitTest';
/**
* Tasks Conflict Test
*/
TEST_F(TEST_NAME, 'AreTasksConflicting', function() {
function testTaskPair(newTaskName, scheduledTaskName, expected) {
assertTrue(areTasksConflicting(newTaskName, scheduledTaskName) == expected,
'(' + newTaskName + ', ' + scheduledTaskName + ')');
}
testTaskPair(UPDATE_CARDS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
testTaskPair(UPDATE_CARDS_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
testTaskPair(UPDATE_CARDS_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
testTaskPair(UPDATE_CARDS_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
testTaskPair(DISMISS_CARD_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
testTaskPair(DISMISS_CARD_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
testTaskPair(DISMISS_CARD_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
testTaskPair(DISMISS_CARD_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
testTaskPair(RETRY_DISMISS_TASK_NAME, UPDATE_CARDS_TASK_NAME, true);
testTaskPair(RETRY_DISMISS_TASK_NAME, DISMISS_CARD_TASK_NAME, true);
testTaskPair(RETRY_DISMISS_TASK_NAME, RETRY_DISMISS_TASK_NAME, true);
testTaskPair(RETRY_DISMISS_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
testTaskPair(STATE_CHANGED_TASK_NAME, UPDATE_CARDS_TASK_NAME, false);
testTaskPair(STATE_CHANGED_TASK_NAME, DISMISS_CARD_TASK_NAME, false);
testTaskPair(STATE_CHANGED_TASK_NAME, RETRY_DISMISS_TASK_NAME, false);
testTaskPair(STATE_CHANGED_TASK_NAME, STATE_CHANGED_TASK_NAME, false);
});
/**
* Server Request Tests
*/
TEST_F(TEST_NAME, 'AuthServerRequestSuccess', function() {
expectServerRequests(this, 200, '{}');
var callbackCalled = false;
requestFromServer('GET', 'test/target').then(function(request) {
callbackCalled = true;
assertTrue(request.status === 200);
assertTrue(request.responseText === '{}');
});
assertTrue(callbackCalled);
});
TEST_F(TEST_NAME, 'AuthServerRequestForbidden', function() {
this.makeAndRegisterMockApis(['authenticationManager.removeToken']);
this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING);
expectServerRequests(this, 403, '');
var thenCalled = false;
var catchCalled = false;
requestFromServer('GET', 'test/target').then(function(request) {
thenCalled = true;
}).catch(function(request) {
// The promise is rejected on HTTP failures.
catchCalled = true;
assertTrue(request.status === 403);
});
assertFalse(thenCalled);
assertTrue(catchCalled);
});
TEST_F(TEST_NAME, 'AuthServerRequestNoAuth', function() {
this.makeAndRegisterMockApis(['authenticationManager.removeToken']);
this.mockApis.expects(once()).authenticationManager_removeToken(ANYTHING);
expectServerRequests(this, 401, '');
var thenCalled = false;
var catchCalled = false;
requestFromServer('GET', 'test/target').then(function(request) {
thenCalled = true;
}).catch(function(request) {
// The promise is rejected on HTTP failures.
catchCalled = true;
assertTrue(request.status === 401);
});
assertFalse(thenCalled);
assertTrue(catchCalled);
});
function expectServerRequests(fixture, httpStatus, responseText) {
fixture.makeAndRegisterMockApis([
'authenticationManager.getAuthToken',
'buildServerRequest'
]);
function XMLHttpRequest() {}
XMLHttpRequest.prototype = {
addEventListener: function(type, listener, wantsUntrusted) {},
setRequestHeader: function(header, value) {},
send: function() {}
}
fixture.mockApis.expects(once()).authenticationManager_getAuthToken()
.will(returnValue(Promise.resolve('token')));
var mockXMLHttpRequest = mock(XMLHttpRequest);
var mockXMLHttpRequestProxy = mockXMLHttpRequest.proxy();
fixture.mockApis.expects(once())
.buildServerRequest(ANYTHING, ANYTHING, ANYTHING)
.will(returnValue(mockXMLHttpRequestProxy));
mockXMLHttpRequest.expects(once())
.setRequestHeader('Authorization', 'Bearer token');
var loadEndSavedArgs = new SaveMockArguments();
mockXMLHttpRequest.expects(once())
.addEventListener(
loadEndSavedArgs.match(eq('loadend')),
loadEndSavedArgs.match(ANYTHING),
loadEndSavedArgs.match(eq(false)));
mockXMLHttpRequestProxy.status = httpStatus;
mockXMLHttpRequestProxy.response = responseText;
mockXMLHttpRequestProxy.responseText = responseText;
mockXMLHttpRequest.expects(once()).send()
.will(invokeCallback(loadEndSavedArgs, 1, mockXMLHttpRequestProxy));
}
TEST_F(TEST_NAME, 'AuthServerRequestNoToken', function() {
this.makeAndRegisterMockApis([
'authenticationManager.getAuthToken',
'buildServerRequest'
]);
this.mockApis.expects(once()).authenticationManager_getAuthToken()
.will(returnValue(Promise.reject()));
this.mockApis.expects(never()).buildServerRequest()
var thenCalled = false;
var catchCalled = false;
requestFromServer('GET', 'test/target').then(function(request) {
thenCalled = true;
}).catch(function() {
catchCalled = true;
});
assertFalse(thenCalled);
assertTrue(catchCalled);
})
/**
* requestNotificationGroupsFromServer Tests
*/
TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerEmpty', function() {
this.makeAndRegisterMockGlobals([
'shouldShowExplanatoryCard',
'recordEvent',
'requestFromServer'
]);
this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
.will(returnValue(false));
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
var requestFromServerArgs = new SaveMockArguments();
this.mockGlobals.expects(once()).requestFromServer(
requestFromServerArgs.match(eq('GET')),
requestFromServerArgs.match(ANYTHING))
.will(returnValue(
Promise.resolve({status: 200, responseText: "{}"})));
var thenCalled = false;
var catchCalled = false;
requestNotificationGroupsFromServer([]).then(function() {
thenCalled = true;
}).catch(function() {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
var pathAndQuery = requestFromServerArgs.arguments[1];
var query = pathAndQuery.split('?')[1];
assertTrue(query.search('timeZoneOffsetMs') >= 0);
assertTrue(query.search('uiLocale') >= 0);
assertFalse(query.search('cardExplanation') >= 0);
});
TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerWithGroups', function() {
this.makeAndRegisterMockGlobals([
'shouldShowExplanatoryCard',
'recordEvent',
'requestFromServer'
]);
this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
.will(returnValue(false));
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
var requestFromServerArgs = new SaveMockArguments();
this.mockGlobals.expects(once()).requestFromServer(
requestFromServerArgs.match(eq('GET')),
requestFromServerArgs.match(ANYTHING))
.will(returnValue(
Promise.resolve({status: 200, responseText: "{}"})));
var thenCalled = false;
var catchCalled = false;
requestNotificationGroupsFromServer(['A', 'B', 'C']).then(function() {
thenCalled = true;
}).catch(function() {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
var pathAndQuery = requestFromServerArgs.arguments[1];
var query = pathAndQuery.split('?')[1];
assertTrue(query.search('timeZoneOffsetMs') >= 0);
assertTrue(query.search('uiLocale') >= 0);
assertFalse(query.search('cardExplanation') >= 0);
assertTrue(query.search('requestTypes=A') >= 0);
assertTrue(query.search('requestTypes=B') >= 0);
assertTrue(query.search('requestTypes=C') >= 0);
});
TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerExplanatory', function() {
this.makeAndRegisterMockGlobals([
'shouldShowExplanatoryCard',
'recordEvent',
'requestFromServer'
]);
this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
.will(returnValue(true));
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
var requestFromServerArgs = new SaveMockArguments();
this.mockGlobals.expects(once()).requestFromServer(
requestFromServerArgs.match(eq('GET')),
requestFromServerArgs.match(ANYTHING))
.will(returnValue(
Promise.resolve({status: 200, responseText: "{}"})));
var thenCalled = false;
var catchCalled = false;
requestNotificationGroupsFromServer([]).then(function() {
thenCalled = true;
}).catch(function() {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
var pathAndQuery = requestFromServerArgs.arguments[1];
var query = pathAndQuery.split('?')[1];
assertTrue(query.search('timeZoneOffsetMs') >= 0);
assertTrue(query.search('uiLocale') >= 0);
assertTrue(query.search('cardExplanation=true') >= 0);
});
TEST_F(TEST_NAME, 'RequestNotificationGroupsFromServerFailure', function() {
this.makeAndRegisterMockGlobals([
'shouldShowExplanatoryCard',
'recordEvent',
'requestFromServer'
]);
this.mockGlobals.expects(once()).shouldShowExplanatoryCard()
.will(returnValue(false));
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
var requestFromServerArgs = new SaveMockArguments();
this.mockGlobals.expects(once()).requestFromServer(
requestFromServerArgs.match(eq('GET')),
requestFromServerArgs.match(ANYTHING))
.will(returnValue(
Promise.reject({status: 401})));
var thenCalled = false;
var catchCalled = false;
requestNotificationGroupsFromServer([]).then(function() {
thenCalled = true;
}).catch(function() {
catchCalled = true;
});
assertFalse(thenCalled);
assertTrue(catchCalled);
});
/**
* requestAndUpdateOptIn Tests
*/
TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedIn', function() {
this.makeAndRegisterMockApis([
'chrome.storage.local.set',
'requestFromServer'
]);
this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
.will(returnValue(Promise.resolve({
status: 200,
responseText: '{"value": true}'})));
this.mockApis.expects(once())
.chrome_storage_local_set(eqJSON({googleNowEnabled: true}));
var thenCalled = false;
var catchCalled = false;
requestAndUpdateOptedIn().then(function(optedIn) {
thenCalled = true;
assertTrue(optedIn);
}).catch(function() {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
});
TEST_F(TEST_NAME, 'RequestAndUpdateOptInOptedOut', function() {
this.makeAndRegisterMockApis([
'chrome.storage.local.set',
'requestFromServer'
]);
this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
.will(returnValue(Promise.resolve({
status: 200,
responseText: '{"value": false}'})));
this.mockApis.expects(once())
.chrome_storage_local_set(eqJSON({googleNowEnabled: false}));
var thenCalled = false;
var catchCalled = false;
requestAndUpdateOptedIn().then(function(optedIn) {
thenCalled = true;
assertFalse(optedIn);
}).catch(function() {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
});
TEST_F(TEST_NAME, 'RequestAndUpdateOptInFailure', function() {
this.makeAndRegisterMockApis([
'chrome.storage.local.set',
'requestFromServer'
]);
this.mockApis.expects(once()).requestFromServer('GET', 'settings/optin')
.will(returnValue(Promise.reject({status: 404})));
this.mockApis.expects(never()).chrome_storage_local_set();
var thenCalled = false;
var catchCalled = false;
requestAndUpdateOptedIn().then(function() {
thenCalled = true;
}).catch(function() {
catchCalled = true;
});
assertFalse(thenCalled);
assertTrue(catchCalled);
});
/**
* pollOptedInNoImmediateRecheck Tests
*/
TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedIn', function() {
this.makeAndRegisterMockApis([
'requestAndUpdateOptedIn',
'instrumented.metricsPrivate.getVariationParams',
'optInPollAttempts.start'
]);
this.mockApis.expects(once()).requestAndUpdateOptedIn()
.will(returnValue(Promise.resolve(true)));
this.mockApis.expects(never())
.instrumented_metricsPrivate_getVariationParams();
this.mockApis.expects(never()).optInPollAttempts_start();
pollOptedInNoImmediateRecheck();
});
TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckOptedOut', function() {
this.makeAndRegisterMockApis([
'requestAndUpdateOptedIn',
'instrumented.metricsPrivate.getVariationParams',
'optInPollAttempts.start'
]);
this.mockApis.expects(once()).requestAndUpdateOptedIn()
.will(returnValue(Promise.resolve(false)));
var getVariationParamsSavedArgs = new SaveMockArguments();
this.mockApis.expects(once())
.instrumented_metricsPrivate_getVariationParams(
getVariationParamsSavedArgs.match(eq('GoogleNow')),
getVariationParamsSavedArgs.match(ANYTHING))
.will(invokeCallback(getVariationParamsSavedArgs, 1, {}));
this.mockApis.expects(once())
.optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS);
pollOptedInNoImmediateRecheck();
});
TEST_F(TEST_NAME, 'pollOptedInNoImmediateRecheckFailure', function() {
this.makeAndRegisterMockApis([
'requestAndUpdateOptedIn',
'instrumented.metricsPrivate.getVariationParams',
'optInPollAttempts.start'
]);
this.mockApis.expects(once()).requestAndUpdateOptedIn()
.will(returnValue(Promise.reject()));
var getVariationParamsSavedArgs = new SaveMockArguments();
this.mockApis.expects(once())
.instrumented_metricsPrivate_getVariationParams(
getVariationParamsSavedArgs.match(eq('GoogleNow')),
getVariationParamsSavedArgs.match(ANYTHING))
.will(invokeCallback(getVariationParamsSavedArgs, 1, {}));
this.mockApis.expects(once())
.optInPollAttempts_start(DEFAULT_OPTIN_CHECK_PERIOD_SECONDS);
pollOptedInNoImmediateRecheck();
});
/**
* getGroupsToRequest Tests
*/
TEST_F(TEST_NAME, 'GetGroupsToRequestNone', function() {
this.makeAndRegisterMockApis([
'fillFromChromeLocalStorage',
'Date.now'
]);
this.mockApis.expects(once())
.fillFromChromeLocalStorage(eqJSON({notificationGroups: {}}))
.will(returnValue(Promise.resolve({notificationGroups: {}})));
this.mockApis.expects(once()).Date_now().will(returnValue(20));
getGroupsToRequest().then(function(groupsToRequest) {
assertTrue(JSON.stringify(groupsToRequest) === '[]');
});
});
TEST_F(TEST_NAME, 'GetGroupsToRequestWithGroups', function() {
this.makeAndRegisterMockApis([
'fillFromChromeLocalStorage',
'Date.now'
]);
this.mockApis.expects(once())
.fillFromChromeLocalStorage(eqJSON({notificationGroups: {}}))
.will(returnValue(Promise.resolve({notificationGroups: {
TIME18: {nextPollTime: 18},
TIME19: {nextPollTime: 19},
TIME20: {nextPollTime: 20},
TIME21: {nextPollTime: 21},
TIME22: {nextPollTime: 22},
TIMEUNDEF: {}
}})));
this.mockApis.expects(once()).Date_now().will(returnValue(20));
getGroupsToRequest().then(function(groupsToRequest) {
assertTrue(groupsToRequest.length == 3);
assertTrue(groupsToRequest.indexOf('TIME18') >= 0);
assertTrue(groupsToRequest.indexOf('TIME19') >= 0);
assertTrue(groupsToRequest.indexOf('TIME20') >= 0);
});
});
/**
* combineGroup Tests
*/
TEST_F(TEST_NAME, 'CombineGroup', function() {
// Tests combineGroup function. Verifies that both notifications with and
// without show time are handled correctly and that cards are correctly
// added to existing cards with same ID or start a new combined card.
// Setup and expectations.
var combinedCards = {
'EXISTING CARD': [1]
};
var receivedNotificationNoShowTime = {
chromeNotificationId: 'EXISTING CARD',
trigger: {hideTimeSec: 1}
};
var receivedNotificationWithShowTime = {
chromeNotificationId: 'NEW CARD',
trigger: {showTimeSec: 2, hideTimeSec: 3}
}
var storedGroup = {
cardsTimestamp: 10000,
cards: [
receivedNotificationNoShowTime,
receivedNotificationWithShowTime
]
};
// Invoking the tested function.
combineGroup(combinedCards, storedGroup);
// Check the output value.
var expectedCombinedCards = {
'EXISTING CARD': [
1,
{
receivedNotification: receivedNotificationNoShowTime,
hideTime: 11000
}
],
'NEW CARD': [
{
receivedNotification: receivedNotificationWithShowTime,
showTime: 12000,
hideTime: 13000
}
]
};
assertEquals(
JSON.stringify(expectedCombinedCards),
JSON.stringify(combinedCards));
});
/**
* Mocks global functions and APIs that initialize() depends upon.
* @param {Test} fixture Test fixture.
*/
function mockInitializeDependencies(fixture) {
fixture.makeAndRegisterMockGlobals([
'pollOptedInNoImmediateRecheck',
'recordEvent',
'removeAllCards',
'setBackgroundEnable',
'startPollingCards',
'stopPollingCards'
]);
fixture.makeAndRegisterMockApis([
'authenticationManager.isSignedIn',
'chrome.storage.local.remove',
'fillFromChromeLocalStorage',
'instrumented.metricsPrivate.getVariationParams',
'instrumented.notifications.getAll',
'instrumented.notifications.getPermissionLevel',
'instrumented.webstorePrivate.getBrowserLogin',
'optInPollAttempts.isRunning',
'optInPollAttempts.stop',
'tasks.add',
'updateCardsAttempts.isRunning',
'updateCardsAttempts.stop'
]);
}
/**
* Sets up the test to expect the state machine calls and send
* the specified state machine state. Currently used to test initialize().
* Note that this CAN NOT be used if any of the methods below are called
* outside of this context with the same argument matchers.
* expects() calls cannot be chained with the same argument matchers.
* @param {object} fixture Test fixture.
* @param {string} testIdentityToken getAuthToken callback token.
* @param {object} testExperimentVariationParams Response of
* metricsPrivate.getVariationParams.
* @param {string} testExperimentVariationParams Response of
* notifications.getPermissionLevel.
* @param {boolean} testGoogleNowEnabled True if the user is opted in to Google
* Now.
*/
function expectStateMachineCalls(
fixture,
testIdentityToken,
testExperimentVariationParams,
testNotificationPermissionLevel,
testGoogleNowEnabled) {
fixture.mockApis.expects(once()).
authenticationManager_isSignedIn().
will(returnValue(new Promise(function(resolve) {
resolve(!!testIdentityToken);
})));
var getVariationParamsSavedArgs = new SaveMockArguments();
fixture.mockApis.expects(once()).
instrumented_metricsPrivate_getVariationParams(
getVariationParamsSavedArgs.match(ANYTHING),
getVariationParamsSavedArgs.match(ANYTHING)).
will(invokeCallback(
getVariationParamsSavedArgs, 1, testExperimentVariationParams));
var notificationGetPermissionLevelSavedArgs = new SaveMockArguments();
fixture.mockApis.expects(once()).
instrumented_notifications_getPermissionLevel(
notificationGetPermissionLevelSavedArgs.match(ANYTHING)).
will(invokeCallback(
notificationGetPermissionLevelSavedArgs,
0,
testNotificationPermissionLevel))
expectChromeLocalStorageGet(
fixture,
{googleNowEnabled: false},
{googleNowEnabled: testGoogleNowEnabled});
var updateCardsAttemptsIsRunningSavedArgs = new SaveMockArguments();
fixture.mockApis.expects(once()).
updateCardsAttempts_isRunning(
updateCardsAttemptsIsRunningSavedArgs.match(ANYTHING)).
will(
invokeCallback(
updateCardsAttemptsIsRunningSavedArgs, 0, undefined));
var optInPollAttemptsIsRunningSavedArgs = new SaveMockArguments();
fixture.mockApis.expects(once()).
optInPollAttempts_isRunning(
optInPollAttemptsIsRunningSavedArgs.match(ANYTHING)).
will(
invokeCallback(
optInPollAttemptsIsRunningSavedArgs, 0, undefined));
}
/**
* Sets up the test to expect the initialization calls that
* initialize() invokes.
* Note that this CAN NOT be used if any of the methods below are called
* outside of this context with the same argument matchers.
* expects() calls cannot be chained with the same argument matchers.
*/
function expectInitialization(fixture) {
var tasksAddSavedArgs = new SaveMockArguments();
fixture.mockApis.expects(once()).
tasks_add(
tasksAddSavedArgs.match(ANYTHING),
tasksAddSavedArgs.match(ANYTHING)).
will(invokeCallback(tasksAddSavedArgs, 1, function() {}));
// The ordering here between stubs and expects is important.
// We only care about the EXTENSION_START event. The other events are covered
// by the NoCards tests below. Reversing the calls will cause all recordEvent
// calls to be unexpected.
fixture.mockGlobals.stubs().recordEvent(ANYTHING);
fixture.mockGlobals.
expects(once()).recordEvent(GoogleNowEvent.EXTENSION_START);
}
TEST_F(TEST_NAME,'Initialize_SignedOut', function() {
// Tests the case when getAuthToken fails most likely because the user is
// not signed in. In this case, the function should quietly exit after
// finding out that getAuthToken fails.
// Setup and expectations.
var testIdentityToken = undefined;
var testExperimentVariationParams = {};
var testNotificationPermissionLevel = 'denied';
var testGoogleNowEnabled = undefined;
mockInitializeDependencies(this);
expectInitialization(this);
expectStateMachineCalls(
this,
testIdentityToken,
testExperimentVariationParams,
testNotificationPermissionLevel,
testGoogleNowEnabled);
this.mockGlobals.expects(once()).setBackgroundEnable(false);
this.mockGlobals.expects(never()).startPollingCards();
this.mockGlobals.expects(once()).stopPollingCards();
this.mockGlobals.expects(once()).removeAllCards();
this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
this.mockApis.expects(once()).optInPollAttempts_stop();
// Invoking the tested function.
initialize();
});
TEST_F(TEST_NAME,'Initialize_NotificationDisabled', function() {
// Tests the case when Google Now is disabled in the notifications center.
// Setup and expectations.
var testIdentityToken = 'some identity token';
var testExperimentVariationParams = {};
var testNotificationPermissionLevel = 'denied';
var testGoogleNowEnabled = undefined;
mockInitializeDependencies(this);
expectInitialization(this);
expectStateMachineCalls(
this,
testIdentityToken,
testExperimentVariationParams,
testNotificationPermissionLevel,
testGoogleNowEnabled);
this.mockGlobals.expects(once()).setBackgroundEnable(false);
this.mockGlobals.expects(never()).startPollingCards();
this.mockGlobals.expects(once()).stopPollingCards();
this.mockGlobals.expects(once()).removeAllCards();
this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
this.mockApis.expects(once()).optInPollAttempts_stop();
// Invoking the tested function.
initialize();
});
TEST_F(TEST_NAME, 'Initialize_NoBackground', function() {
// Tests when the no background variation is received.
// Setup and expectations.
var testIdentityToken = 'some identity token';
var testExperimentVariationParams = {canEnableBackground: 'false'};
var testNotificationPermissionLevel = 'granted';
var testGoogleNowEnabled = true;
mockInitializeDependencies(this);
expectInitialization(this);
expectStateMachineCalls(
this,
testIdentityToken,
testExperimentVariationParams,
testNotificationPermissionLevel,
testGoogleNowEnabled);
this.mockGlobals.expects(once()).setBackgroundEnable(false);
this.mockGlobals.expects(once()).startPollingCards();
this.mockGlobals.expects(never()).stopPollingCards();
this.mockGlobals.expects(never()).removeAllCards();
this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
this.mockApis.expects(once()).optInPollAttempts_stop();
// Invoking the tested function.
initialize();
});
TEST_F(TEST_NAME, 'Initialize_GoogleNowDisabled', function() {
// Tests when the user has Google Now disabled.
// Setup and expectations.
var testIdentityToken = 'some identity token';
var testExperimentVariationParams = {};
var testNotificationPermissionLevel = 'granted';
var testGoogleNowEnabled = false;
mockInitializeDependencies(this);
expectInitialization(this);
expectStateMachineCalls(
this,
testIdentityToken,
testExperimentVariationParams,
testNotificationPermissionLevel,
testGoogleNowEnabled);
this.mockGlobals.expects(once()).setBackgroundEnable(false);
this.mockGlobals.expects(never()).startPollingCards();
this.mockGlobals.expects(once()).stopPollingCards();
this.mockGlobals.expects(once()).removeAllCards();
this.mockGlobals.expects(once()).pollOptedInNoImmediateRecheck();
this.mockApis.expects(never()).optInPollAttempts_stop();
// Invoking the tested function.
initialize();
});
TEST_F(TEST_NAME, 'Initialize_RunGoogleNow', function() {
// Tests if Google Now will invoke startPollingCards when all
// of the required state is fulfilled.
// Setup and expectations.
var testIdentityToken = 'some identity token';
var testExperimentVariationParams = {};
var testNotificationPermissionLevel = 'granted';
var testGoogleNowEnabled = true;
mockInitializeDependencies(this);
expectInitialization(this);
expectStateMachineCalls(
this,
testIdentityToken,
testExperimentVariationParams,
testNotificationPermissionLevel,
testGoogleNowEnabled);
this.mockGlobals.expects(once()).setBackgroundEnable(true);
this.mockGlobals.expects(once()).startPollingCards();
this.mockGlobals.expects(never()).stopPollingCards();
this.mockGlobals.expects(never()).removeAllCards();
this.mockGlobals.expects(never()).pollOptedInNoImmediateRecheck();
this.mockApis.expects(once()).optInPollAttempts_stop();
// Invoking the tested function.
initialize();
});
/**
* No Cards Event Recording Tests
*/
TEST_F(TEST_NAME, 'NoCardsSignedOut', function() {
var signedIn = false;
var notificationEnabled = false;
var googleNowEnabled = false;
this.makeAndRegisterMockGlobals([
'recordEvent',
'removeAllCards',
'setBackgroundEnable',
'setShouldPollCards',
'setShouldPollOptInStatus']);
this.mockGlobals.stubs().removeAllCards();
this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.STOPPED);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.SIGNED_OUT);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.NOTIFICATION_DISABLED);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.GOOGLE_NOW_DISABLED);
updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
});
TEST_F(TEST_NAME, 'NoCardsNotificationsDisabled', function() {
var signedIn = true;
var notificationEnabled = false;
var googleNowEnabled = false;
this.makeAndRegisterMockGlobals([
'recordEvent',
'removeAllCards',
'setBackgroundEnable',
'setShouldPollCards',
'setShouldPollOptInStatus']);
this.mockGlobals.stubs().removeAllCards();
this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.STOPPED);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.SIGNED_OUT);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.NOTIFICATION_DISABLED);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.GOOGLE_NOW_DISABLED);
updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
});
TEST_F(TEST_NAME, 'NoCardsGoogleNowDisabled', function() {
var signedIn = true;
var notificationEnabled = true;
var googleNowEnabled = false;
this.makeAndRegisterMockGlobals([
'recordEvent',
'removeAllCards',
'setBackgroundEnable',
'setShouldPollCards',
'setShouldPollOptInStatus']);
this.mockGlobals.stubs().removeAllCards();
this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.STOPPED);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.SIGNED_OUT);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.NOTIFICATION_DISABLED);
this.mockGlobals.expects(once()).recordEvent(
GoogleNowEvent.GOOGLE_NOW_DISABLED);
updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
});
TEST_F(TEST_NAME, 'NoCardsEverythingEnabled', function() {
var signedIn = true;
var notificationEnabled = true;
var googleNowEnabled = true;
this.makeAndRegisterMockGlobals([
'recordEvent',
'removeAllCards',
'setBackgroundEnable',
'setShouldPollCards',
'setShouldPollOptInStatus']);
this.mockGlobals.stubs().removeAllCards();
this.mockGlobals.stubs().setBackgroundEnable(ANYTHING);
this.mockGlobals.stubs().setShouldPollCards(ANYTHING);
this.mockGlobals.stubs().setShouldPollOptInStatus(ANYTHING);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.STOPPED);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.SIGNED_OUT);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.NOTIFICATION_DISABLED);
this.mockGlobals.expects(never()).recordEvent(
GoogleNowEvent.GOOGLE_NOW_DISABLED);
updateRunningState(signedIn, true, notificationEnabled, googleNowEnabled);
});
/**
* Mocks global functions and APIs that onNotificationClicked() depends upon.
* @param {Test} fixture Test fixture.
*/
function mockOnNotificationClickedDependencies(fixture) {
fixture.makeAndRegisterMockApis([
'chrome.windows.create',
'chrome.windows.update',
'fillFromChromeLocalStorage',
'instrumented.tabs.create']);
}
TEST_F(TEST_NAME, 'OnNotificationClicked_NoData', function() {
// Tests the case when there is no data associated with notification id.
// In this case, the function should do nothing.
// Setup and expectations.
var testNotificationId = 'TEST_ID';
var testNotificationDataRequest = {notificationsData: {}};
var testNotificationData = {notificationsData: {}};
mockOnNotificationClickedDependencies(this);
this.makeMockLocalFunctions(['selector']);
expectChromeLocalStorageGet(
this, testNotificationDataRequest, testNotificationData);
// Invoking the tested function.
onNotificationClicked(
testNotificationId, this.mockLocalFunctions.functions().selector);
});
TEST_F(TEST_NAME, 'OnNotificationClicked_ActionUrlsUndefined', function() {
// Tests the case when the data associated with notification id is
// 'undefined'.
// In this case, the function should do nothing.
// Setup and expectations.
var testActionUrls = undefined;
var testNotificationId = 'TEST_ID';
var testNotificationDataRequest = {notificationsData: {}};
var testNotificationData = {
notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
};
mockOnNotificationClickedDependencies(this);
this.makeMockLocalFunctions(['selector']);
expectChromeLocalStorageGet(
this, testNotificationDataRequest, testNotificationData);
this.mockLocalFunctions.expects(once())
.selector(eqJSON(
testNotificationData.notificationsData[testNotificationId]))
.will(returnValue(undefined));
// Invoking the tested function.
onNotificationClicked(
testNotificationId, this.mockLocalFunctions.functions().selector);
});
TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateSuccess', function() {
// Tests the selected URL is OK and crome.tabs.create suceeds.
// Setup and expectations.
var testActionUrls = {testField: 'TEST VALUE'};
var testNotificationId = 'TEST_ID';
var testNotificationDataRequest = {notificationsData: {}};
var testNotificationData = {
notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
};
var testActionUrl = 'http://testurl.com';
var testCreatedTab = {windowId: 239};
mockOnNotificationClickedDependencies(this);
this.makeMockLocalFunctions(['selector']);
expectChromeLocalStorageGet(
this, testNotificationDataRequest, testNotificationData);
this.mockLocalFunctions.expects(once())
.selector(eqJSON(
testNotificationData.notificationsData[testNotificationId]))
.will(returnValue(testActionUrl));
var chromeTabsCreateSavedArgs = new SaveMockArguments();
this.mockApis.expects(once()).
instrumented_tabs_create(
chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
chromeTabsCreateSavedArgs.match(ANYTHING)).
will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
this.mockApis.expects(once()).chrome_windows_update(
testCreatedTab.windowId,
eqJSON({focused: true}));
// Invoking the tested function.
onNotificationClicked(
testNotificationId, this.mockLocalFunctions.functions().selector);
});
TEST_F(TEST_NAME, 'OnNotificationClicked_TabCreateFail', function() {
// Tests the selected URL is OK and crome.tabs.create fails.
// In this case, the function should invoke chrome.windows.create as a
// second attempt.
// Setup and expectations.
var testActionUrls = {testField: 'TEST VALUE'};
var testNotificationId = 'TEST_ID';
var testNotificationDataRequest = {notificationsData: {}};
var testNotificationData = {
notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
};
var testActionUrl = 'http://testurl.com';
var testCreatedTab = undefined; // chrome.tabs.create fails
mockOnNotificationClickedDependencies(this);
this.makeMockLocalFunctions(['selector']);
expectChromeLocalStorageGet(
this, testNotificationDataRequest, testNotificationData);
this.mockLocalFunctions.expects(once())
.selector(eqJSON(
testNotificationData.notificationsData[testNotificationId]))
.will(returnValue(testActionUrl));
var chromeTabsCreateSavedArgs = new SaveMockArguments();
this.mockApis.expects(once()).
instrumented_tabs_create(
chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
chromeTabsCreateSavedArgs.match(ANYTHING)).
will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
this.mockApis.expects(once()).chrome_windows_create(
eqJSON({url: testActionUrl, focused: true}));
// Invoking the tested function.
onNotificationClicked(
testNotificationId, this.mockLocalFunctions.functions().selector);
});
TEST_F(TEST_NAME, 'ShowNotificationGroups', function() {
// Tests showNotificationGroups function. Checks that the function properly
// deletes the card that didn't get an update, updates existing card and
// creates a new card that previously didn't exist.
// Setup and expectations.
var existingNotifications = {
'SHOULD BE DELETED': 'SOMETHING',
'SHOULD BE KEPT': 'SOMETHING'
};
var keptCard = {
chromeNotificationId: 'SHOULD BE KEPT',
trigger: {showTimeSec: 0, hideTimeSec: 0}
};
var keptNotification = {
receivedNotification: keptCard,
showTime: 0,
hideTime: 0
};
var newCard = {
chromeNotificationId: 'NEW CARD',
trigger: {showTimeSec: 0, hideTimeSec: 0}
};
var newNotification = {
receivedNotification: newCard,
showTime: 0,
hideTime: 0
};
var notificationGroups = {
'TEST GROUP 1': {cards: [keptCard], cardsTimestamp: 0},
'TEST GROUP 2': {cards: [newCard], cardsTimestamp: 0}
};
var fakeOnCardShownFunction = 'FAKE ON CARD SHOWN FUNCTION';
var expectedUpdatedNotifications = {
'SHOULD BE KEPT': 'KEPT CARD NOTIFICATION DATA',
'NEW CARD': 'NEW CARD NOTIFICATION DATA'
};
this.makeAndRegisterMockApis([
'cardSet.update',
'chrome.storage.local.set',
'instrumented.notifications.getAll'
]);
this.makeMockLocalFunctions([
'onSuccess'
]);
var notificationsGetAllSavedArgs = new SaveMockArguments();
this.mockApis.expects(once()).
instrumented_notifications_getAll(
notificationsGetAllSavedArgs.match(ANYTHING)).
will(invokeCallback(
notificationsGetAllSavedArgs, 0, existingNotifications));
this.mockApis.expects(once()).
cardSet_update(
'SHOULD BE KEPT',
eqJSON([keptNotification]),
eqJSON(notificationGroups),
fakeOnCardShownFunction).
will(returnValue('KEPT CARD NOTIFICATION DATA'));
this.mockApis.expects(once()).
cardSet_update(
'NEW CARD',
eqJSON([newNotification]),
eqJSON(notificationGroups),
fakeOnCardShownFunction).
will(returnValue('NEW CARD NOTIFICATION DATA'));
this.mockApis.expects(once()).
cardSet_update(
'SHOULD BE DELETED',
[],
eqJSON(notificationGroups),
fakeOnCardShownFunction).
will(returnValue(undefined));
this.mockApis.expects(once()).
chrome_storage_local_set(
eqJSON({notificationsData: expectedUpdatedNotifications}));
this.mockLocalFunctions.expects(once()).
onSuccess(undefined);
// Invoking the tested function.
showNotificationGroups(notificationGroups, fakeOnCardShownFunction)
.then(this.mockLocalFunctions.functions().onSuccess);
});
TEST_F(TEST_NAME, 'ProcessServerResponse', function() {
// Tests processServerResponse function.
// Setup and expectations.
Date.now = function() { return 3000000; };
// GROUP1 was requested and contains cards c4 and c5. For c5, there is a
// non-expired dismissal, so it will be ignored.
// GROUP2 was not requested, but is contained in server response to
// indicate that the group still exists. Stored group GROUP2 won't change.
// GROUP3 is stored, but is not present in server's response, which means
// it doesn't exist anymore. This group will be deleted.
// GROUP4 doesn't contain cards, but it was requested. This is treated as
// if it had an empty array of cards. Cards in the stored group will be
// replaced with an empty array.
// GROUP5 doesn't have next poll time, and it will be stored without next
// poll time.
var serverResponse = {
groups: {
GROUP1: {requested: true, nextPollSeconds: 46},
GROUP2: {requested: false},
GROUP4: {requested: true, nextPollSeconds: 45},
GROUP5: {requested: true}
},
notifications: [
{notificationId: 'c4', groupName: 'GROUP1'},
{notificationId: 'c5', groupName: 'GROUP1'}
]
};
var recentDismissals = {
c4: 1800000, // expired dismissal
c5: 1800001 // non-expired dismissal
};
var storedGroups = {
GROUP2: {
cards: [{notificationId: 'c2'}],
cardsTimestamp: 239,
nextPollTime: 10000
},
GROUP3: {
cards: [{notificationId: 'c3'}],
cardsTimestamp: 240,
nextPollTime: 10001
},
GROUP4: {
cards: [{notificationId: 'c6'}],
cardsTimestamp: 241,
nextPollTime: 10002
}
};
var expectedUpdatedGroups = {
GROUP1: {
cards: [{notificationId: 'c4', groupName: 'GROUP1'}],
cardsTimestamp: 3000000,
nextPollTime: 3046000
},
GROUP2: {
cards: [{notificationId: 'c2'}],
cardsTimestamp: 239,
nextPollTime: 10000
},
GROUP4: {
cards: [],
cardsTimestamp: 3000000,
nextPollTime: 3045000
},
GROUP5: {
cards: [],
cardsTimestamp: 3000000
}
};
var expectedUpdatedRecentDismissals = {
c5: 1800001
};
this.makeAndRegisterMockGlobals([
'scheduleNextCardsPoll'
]);
this.makeAndRegisterMockApis([
'fillFromChromeLocalStorage',
]);
expectChromeLocalStorageGet(
this,
{
notificationGroups: {},
recentDismissals: {}
},
{
notificationGroups: storedGroups,
recentDismissals: recentDismissals
});
this.mockGlobals.expects(once())
.scheduleNextCardsPoll(eqJSON(expectedUpdatedGroups));
// Invoking the tested function.
processServerResponse(serverResponse);
});
TEST_F(TEST_NAME, 'ProcessServerResponseGoogleNowDisabled', function() {
// Tests processServerResponse function for the case when the response
// indicates that Google Now is disabled.
// Setup and expectations.
var serverResponse = {
googleNowDisabled: true,
groups: {}
};
this.makeAndRegisterMockGlobals([
'scheduleNextCardsPoll'
]);
this.makeAndRegisterMockApis([
'chrome.storage.local.set',
'fillFromChromeLocalStorage'
]);
this.mockApis.expects(once()).
chrome_storage_local_set(eqJSON({googleNowEnabled: false}));
this.mockGlobals.expects(never()).scheduleNextCardsPoll();
// Invoking the tested function.
processServerResponse(serverResponse);
});