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 |
+ }; |
+}); |