Chromium Code Reviews| Index: chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js |
| diff --git a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..68aa394481c74f9f3a0d7f7ff0c18dca63a0ceea |
| --- /dev/null |
| +++ b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js |
| @@ -0,0 +1,482 @@ |
| +// Copyright 2016 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. |
| + |
| +cr.define('settings_people_page_quick_unlock', function() { |
| + var element = null; |
| + var quickUnlockPrivateApi = null; |
| + var QuickUnlockMode = chrome.quickUnlockPrivate.QuickUnlockMode; |
| + |
| + /** |
| + * Verifies element is visible. |
| + * @param {!Element} element |
| + */ |
| + function assertVisible(element) { |
|
tommycli
2016/07/18 20:47:24
I assume it's not practical to test the .hidden pr
jdufault
2016/07/19 00:11:08
Right, the hidden property might have been set in
|
| + assertTrue(element.offsetWidth > 0); |
| + } |
| + |
| + /** |
| + * Verifies element is not visible. |
| + * @param {!Element} element |
| + */ |
| + function assertNotVisible(element) { |
| + assertTrue(element.offsetWidth <= 0 && element.offsetHeight <= 0); |
| + } |
| + |
| + /** |
| + * Returns true if the given |element| has class |className|. |
| + * @param {!Element} element |
| + * @param {string} className |
| + */ |
| + function assertHasClass(element, className) { |
| + assertTrue(element.classList.contains(className)); |
| + } |
| + |
| + /** |
| + * Returns the result of running |selector| on element. |
| + * @param {string} selector |
| + * @return {Element} |
| + */ |
| + function getFromElement(selector) { |
| + var childElement = element.$$(selector); |
| + assertTrue(!!childElement); |
| + return childElement; |
| + } |
| + |
| + /** |
| + * Sets the active quick unlock modes and raises a mode change event. |
| + * @param {!Array<chrome.quickUnlockPrivate.QuickUnlockMode>} modes |
| + */ |
| + function setActiveModes(modes) { |
| + quickUnlockPrivateApi.activeModes = modes; |
| + quickUnlockPrivateApi.onActiveModesChanged.callListeners(modes); |
| + } |
| + |
| + function registerAuthenticateTests() { |
| + suite('authenticate', function() { |
| + var passwordElement = null; |
| + |
| + setup(function() { |
| + PolymerTest.clearBody(); |
| + |
| + quickUnlockPrivateApi = new settings.FakeQuickUnlockPrivate(); |
| + |
| + element = document.createElement('settings-quick-unlock-authenticate'); |
| + element.quickUnlockPrivate_ = quickUnlockPrivateApi; |
| + document.body.appendChild(element); |
| + |
| + passwordElement = getFromElement('#password-input'); |
| + }); |
| + |
| + // Checking the password does not change the active set of quick unlock |
| + // modes. |
|
tommycli
2016/07/18 20:47:24
I think the test name explains it well enough so t
jdufault
2016/07/19 00:11:08
Done.
|
| + test('PasswordCheckDoesNotChangeActiveMode', function() { |
| + // No active modes. |
| + quickUnlockPrivateApi.activeModes = []; |
| + passwordElement.value = 'foo'; |
| + element.checkPasswordNow_(); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + assertDeepEquals([], quickUnlockPrivateApi.credentials); |
| + |
| + // PIN is active. |
| + quickUnlockPrivateApi.activeModes = [QuickUnlockMode.PIN]; |
| + passwordElement.value = 'foo'; |
| + element.checkPasswordNow_(); |
| + assertDeepEquals([QuickUnlockMode.PIN], |
| + quickUnlockPrivateApi.activeModes); |
| + assertDeepEquals([''], quickUnlockPrivateApi.credentials); |
| + }); |
| + |
| + // A bad password does not provide an authenticated setModes object. |
| + test('InvalidPasswordDoesNotProvideAuthentication', function() { |
| + quickUnlockPrivateApi.accountPassword = 'bar'; |
| + |
| + passwordElement.value = 'foo'; |
| + element.checkPasswordNow_(); |
| + |
| + assertTrue(!element.setModes); |
|
tommycli
2016/07/18 20:47:24
For symmetry with the below, can this be assertFal
jdufault
2016/07/19 00:11:08
Done.
|
| + }); |
| + |
| + // A valid password provides an authenticated setModes object. |
| + test('ValidPasswordProvidesAuthentication', function() { |
| + quickUnlockPrivateApi.accountPassword = 'foo'; |
| + |
| + passwordElement.value = 'foo'; |
| + element.checkPasswordNow_(); |
| + |
| + assertTrue(!!element.setModes); |
| + }); |
| + |
| + // The password automatically submits after a delay. |
| + test('PasswordAutoSubmitsAfterDelay', function(done) { |
| + quickUnlockPrivateApi.accountPassword = 'foo'; |
| + |
| + element.autosubmitDelayMs_ = 0; |
| + passwordElement.value = 'foo'; |
| + element.startDelayedPasswordCheck_(); |
| + |
| + setTimeout(function() { |
| + assertFalse(!!element.password_); |
| + assertTrue(!!element.setModes); |
| + done(); |
| + }, 1050); |
|
jdufault
2016/07/15 22:59:36
Change to 50
tommycli
2016/07/18 20:47:24
Hmm... I'm worried this test might be flaky... but
jdufault
2016/07/19 00:11:08
So long as the 50 is >= all of the other setTimeou
tommycli
2016/07/19 21:27:12
Can we make this not a numeric literal, but autosu
jdufault
2016/10/06 19:15:41
Done.
|
| + }); |
| + |
| + // The setModes objects times out after a delay. |
| + test('AuthenticationTimesOut', function(done) { |
| + quickUnlockPrivateApi.accountPassword = 'foo'; |
| + |
| + element.passwordActiveDurationMs_ = 0; |
| + passwordElement.value = 'foo'; |
| + element.checkPasswordNow_(); |
| + |
| + assertFalse(!!element.password_); |
| + assertTrue(!!element.setModes); |
| + |
| + setTimeout(function() { |
| + assertFalse(!!element.password_); |
| + assertFalse(!!element.setModes); |
| + done(); |
| + }, 50); |
| + }); |
| + }); |
| + } |
| + |
| + function registerChooseMethodTests() { |
| + suite('choose-method', function() { |
| + /** @const */ var ENABLE_LOCK_SCREEN_PREF = 'settings.enable_screen_lock'; |
| + |
| + var fakeSettings = null; |
| + var passwordRadioButton = null; |
| + var pinPasswordRadioButton = null; |
| + var noneRadioButton = null; |
| + var configureButton = null; |
| + |
| + /** |
| + * Asserts that only the given radio button is active and all of the |
| + * others are inactive. |
| + * @param {Element} radioButton |
| + */ |
| + function assertRadioButtonActive(radioButton) { |
| + function doAssert(element, name) { |
| + if (radioButton == element) |
| + assertTrue(element.active, 'Expected ' + name + ' to be active'); |
| + else |
| + assertFalse(element.active, 'Expected ' + name + ' to be inactive'); |
| + } |
| + |
| + doAssert(passwordRadioButton, 'passwordButton'); |
| + doAssert(pinPasswordRadioButton, 'pinPasswordButton'); |
| + doAssert(noneRadioButton, 'noneButton'); |
| + } |
| + |
| + /** |
| + * Returns the lock screen pref value. |
| + * @return {boolean} |
| + */ |
| + function getLockScreenPref() { |
| + return element.getPref(ENABLE_LOCK_SCREEN_PREF).value; |
| + } |
| + |
| + /** |
| + * Changes the lock screen pref value using the settings API; this is like |
| + * the pref got changed from an unkown source such as another tab. |
| + * @param {boolean} value |
| + */ |
| + function setLockScreenPrefOnSettings(value) { |
| + fakeSettings.setPref(ENABLE_LOCK_SCREEN_PREF, value, '', assertTrue); |
| + } |
| + |
| + setup(function(done) { |
| + PolymerTest.clearBody(); |
| + |
| + CrSettingsPrefs.deferInitialization = true; |
| + |
| + // Build pref fakes. |
| + var fakePrefs = [{ |
| + key: ENABLE_LOCK_SCREEN_PREF, |
| + type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| + value: true |
| + }]; |
| + fakeSettings = new settings.FakeSettingsPrivate(fakePrefs); |
| + setLockScreenPrefOnSettings(true); |
| + var prefElement = document.createElement('settings-prefs'); |
| + prefElement.initializeForTesting(fakeSettings); |
| + document.body.appendChild(prefElement); |
| + |
| + // Wait for prefElement to finish initializing; it takes some time for |
| + // the prefs element to get allocated. |
| + prefElement.addEventListener('prefs-changed', function prefsReady() { |
| + prefElement.removeEventListener('prefs-changed', prefsReady); |
| + |
| + quickUnlockPrivateApi = new settings.FakeQuickUnlockPrivate(); |
| + |
| + // Create choose-method element. |
| + element = document.createElement( |
| + 'settings-quick-unlock-choose-method'); |
| + element.settingsPrivate_ = fakeSettings; |
| + element.quickUnlockPrivate_ = quickUnlockPrivateApi; |
| + element.prefs = prefElement.prefs; |
| + element.currentRoute = { |
| + url: '/quickUnlock/chooseMethod', |
| + page: 'basic', |
| + section: 'people', |
| + subpage: ['quick-unlock-choose-method'], |
| + }; |
| + element.setModes = |
| + quickUnlockPrivateApi.setModes.bind(quickUnlockPrivateApi, ''); |
| + |
| + // Previous test may have disabled the pref. |
| + element.setPrefValue(ENABLE_LOCK_SCREEN_PREF, true); |
| + |
| + document.body.appendChild(element); |
| + Polymer.dom.flush(); |
| + |
| + passwordRadioButton = |
| + getFromElement('paper-radio-button[name="password"]'); |
| + pinPasswordRadioButton = |
| + getFromElement('paper-radio-button[name="pin+password"]'); |
| + noneRadioButton = getFromElement('paper-radio-button[name="none"]'); |
| + configureButton = getFromElement('paper-button'); |
| + |
| + // Give the element some time to initialize. |
| + setTimeout(done); |
|
tommycli
2016/07/18 20:47:24
This seems like it could be flaky. In other UI tes
jdufault
2016/07/19 00:11:08
Changed to async, I was having troubles getting We
tommycli
2016/07/19 21:27:12
See here: https://cs.chromium.org/chromium/src/chr
jdufault
2016/10/06 19:15:41
The element will now fire a 'ready' event when it
|
| + }); |
| + }); |
| + |
| + // Showing the choose method screen does not make any destructive pref or |
| + // quickUnlockPrivate calls. |
| + test('ShowingScreenDoesNotModifyPrefs', function() { |
| + assertTrue(getLockScreenPref()); |
| + assertRadioButtonActive(passwordRadioButton); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + }); |
| + |
| + // The various radio buttons update the pref and quick unlock state. |
| + test('TappingButtonsChangesUnderlyingState', function() { |
| + assertTrue(getLockScreenPref()); |
| + assertRadioButtonActive(passwordRadioButton); |
| + |
| + function tapNone() { |
| + MockInteractions.tap(noneRadioButton); |
| + assertRadioButtonActive(noneRadioButton); |
| + assertNotVisible(configureButton); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + assertFalse(getLockScreenPref()); |
| + } |
| + |
| + // Disable pref. |
| + tapNone(); |
| + |
| + // Tap pin+password button, verify pref is enabled. |
| + MockInteractions.tap(pinPasswordRadioButton); |
| + assertRadioButtonActive(pinPasswordRadioButton); |
| + assertVisible(configureButton); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + assertTrue(getLockScreenPref()); |
| + |
| + // Enable quick unlock so that we verify tapping none disables it. |
| + setActiveModes([QuickUnlockMode.PIN]); |
| + tapNone(); |
| + |
| + // Tap password button, verify pref is enabled. |
| + MockInteractions.tap(passwordRadioButton); |
| + assertRadioButtonActive(passwordRadioButton); |
| + assertNotVisible(configureButton); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + assertTrue(getLockScreenPref()); |
| + }); |
| + |
| + // If quick unlock is changed by another settings page the radio button |
| + // will update to show quick unlock is active. |
| + test('EnablingQuickUnlockChangesButtonState', function() { |
| + assertTrue(getLockScreenPref()); |
| + assertRadioButtonActive(passwordRadioButton); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + |
| + setActiveModes([QuickUnlockMode.PIN]); |
| + assertRadioButtonActive(pinPasswordRadioButton); |
| + assertVisible(configureButton); |
| + }); |
| + |
| + // If prefs are changed by another source the radio button will update. |
| + test('PrefChangeUpdatesButtonState', function() { |
| + assertTrue(getLockScreenPref()); |
| + assertRadioButtonActive(passwordRadioButton); |
| + |
| + setLockScreenPrefOnSettings(false); |
| + assertRadioButtonActive(noneRadioButton); |
| + |
| + setLockScreenPrefOnSettings(true); |
| + assertRadioButtonActive(passwordRadioButton); |
| + }), |
| + |
| + // Tapping the PIN configure button changes the route to the setup pin |
| + // page. |
| + test('TappingConfigureOpensSetupPin', function() { |
| + assertTrue(getLockScreenPref()); |
| + assertRadioButtonActive(passwordRadioButton); |
| + |
| + MockInteractions.tap(pinPasswordRadioButton); |
| + assertVisible(configureButton); |
| + assertRadioButtonActive(pinPasswordRadioButton) |
| + |
| + MockInteractions.tap(configureButton); |
| + assertDeepEquals('quick-unlock-setup-pin', |
|
tommycli
2016/07/18 20:47:24
does assertEquals(settings.Route.QUICK_UNLOCK_SETU
jdufault
2016/07/19 00:11:08
settings.Route is undefined
tommycli
2016/07/19 21:27:12
Try importing /route.html in the quick_unlock_conf
|
| + element.currentRoute.subpage.slice(-1)[0]); |
| + }); |
| + }); |
| + } |
| + |
| + function registerSetupPinTests() { |
| + suite('setup-pin', function() { |
| + var titleDiv = null; |
| + var problemDiv = null; |
| + var pinKeyboard = null; |
| + var backButton = null; |
| + var continueButton = null; |
| + |
| + setup(function() { |
| + PolymerTest.clearBody(); |
| + |
| + quickUnlockPrivateApi = new settings.FakeQuickUnlockPrivate(); |
| + |
| + // Create choose-method element. |
| + element = document.createElement('settings-quick-unlock-setup-pin'); |
| + element.quickUnlockPrivate_ = quickUnlockPrivateApi; |
| + element.currentRoute = { |
| + url: '/quickUnlock/setupPin', |
| + page: 'basic', |
| + section: 'people', |
| + subpage: ['quick-unlock-choose-method', 'quick-unlock-setup-pin'], |
| + }; |
| + element.setModes = |
| + quickUnlockPrivateApi.setModes.bind(quickUnlockPrivateApi, ''); |
| + |
| + document.body.appendChild(element); |
| + Polymer.dom.flush(); |
| + |
| + titleDiv = getFromElement('#title-div'); |
| + problemDiv = getFromElement('#problem-div'); |
| + pinKeyboard = getFromElement('pin-keyboard'); |
| + backButton = getFromElement('paper-button[class="cancel-button"]'); |
| + continueButton = getFromElement('paper-button[class="action-button"]'); |
| + }); |
| + |
| + // The back button is only displayed during the confirm PIN step. |
| + test('BackOnlyShownWhenConfirmingPin', function() { |
| + assertNotVisible(backButton); |
| + assertVisible(continueButton); |
| + |
| + pinKeyboard.value = '1111'; |
| + MockInteractions.tap(continueButton); |
| + |
| + assertVisible(backButton); |
| + }); |
| + |
| + // The continue button is disabled unless the user has entered a >= 4 |
| + // digit PIN. |
| + test('CanOnlyContinueAfterEnteringAtLeastFourDigitPin', function() { |
| + pinKeyboard.value = '111'; |
| + assertTrue(continueButton.disabled); |
| + |
| + pinKeyboard.value = '1111'; |
| + assertFalse(continueButton.disabled); |
| + |
| + pinKeyboard.value = '111'; |
| + assertTrue(continueButton.disabled); |
| + |
| + pinKeyboard.value = ''; |
| + assertTrue(continueButton.disabled); |
| + |
| + pinKeyboard.value = '1111111'; |
| + assertFalse(continueButton.disabled); |
| + }); |
| + |
| + // Problem messages are hidden if the PIN is cleared. |
| + test('NoProblemShownWithEmptyPin', function() { |
| + pinKeyboard.value = '11'; |
| + assertVisible(problemDiv); |
| + |
| + pinKeyboard.value = ''; |
| + assertNotVisible(problemDiv); |
| + }); |
| + |
| + // If the PIN is too short an error problem is shown. |
| + test('ErrorShownForShortPins', function() { |
| + assertVisible(titleDiv); |
| + assertNotVisible(problemDiv); |
| + |
| + pinKeyboard.value = '11'; |
| + |
| + assertNotVisible(titleDiv); |
| + assertVisible(problemDiv); |
| + assertHasClass(problemDiv, 'error'); |
| + assertTrue(continueButton.disabled); |
| + }); |
| + |
| + // If the PIN is weak a warning problem is shown. |
| + test('WarningShownForWeakPins', function() { |
| + assertVisible(titleDiv); |
| + assertNotVisible(problemDiv); |
| + |
| + pinKeyboard.value = '1111'; |
| + |
| + assertNotVisible(titleDiv); |
| + assertVisible(problemDiv); |
| + assertHasClass(problemDiv, 'warning'); |
| + }); |
| + |
| + // If the confirm PIN does not match the initial PIN an error is shown and |
| + // the submit button is disabled. |
| + test('ErrorShownForMismatchedPins', function() { |
| + pinKeyboard.value = '1118'; |
| + MockInteractions.tap(continueButton); |
| + pinKeyboard.value = '1119'; |
| + |
| + assertVisible(problemDiv); |
| + assertHasClass(problemDiv, 'error'); |
| + assertTrue(continueButton.disabled); |
| + }); |
| + |
| + // Hitting back on the confirm PIN step properly resets the flow. |
| + test('HittingBackButtonResetsState', function() { |
| + // Submit initial PIN. |
| + pinKeyboard.value = '1111'; |
| + MockInteractions.tap(continueButton); |
| + assertVisible(backButton); |
| + assertEquals('', pinKeyboard.value); |
| + |
| + // Prepare confirm pin but go back instead. |
| + pinKeyboard.value = '1111'; |
| + MockInteractions.tap(backButton); |
| + assertNotVisible(backButton); |
| + assertEquals('', pinKeyboard.value); |
| + |
| + // Submit initial PIN; verify we did not call quick unlock private API. |
| + pinKeyboard.value = '1111'; |
| + MockInteractions.tap(continueButton); |
| + assertDeepEquals([], quickUnlockPrivateApi.activeModes); |
| + }); |
| + |
| + // Completing the flow results in a call to the quick unlock private API. |
| + test('SubmittingPinCallsQuickUnlockApi', function() { |
| + // Entering the same (even weak) pin twice calls the quick unlock API |
| + // and sets up a PIN. |
| + pinKeyboard.value = '1111'; |
| + MockInteractions.tap(continueButton); |
| + pinKeyboard.value = '1111'; |
| + MockInteractions.tap(continueButton); |
| + |
| + assertDeepEquals(['PIN'], quickUnlockPrivateApi.activeModes); |
| + assertDeepEquals(['1111'], quickUnlockPrivateApi.credentials); |
| + }); |
| + }); |
| + } |
| + |
| + return { |
| + registerAuthenticateTests: registerAuthenticateTests, |
| + registerChooseMethodTests: registerChooseMethodTests, |
| + registerSetupPinTests: registerSetupPinTests |
| + }; |
| +}); |