OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 cr.define('settings_people_page_quick_unlock', function() { | |
6 var element = null; | |
7 var quickUnlockPrivateApi = null; | |
8 var QuickUnlockMode = chrome.quickUnlockPrivate.QuickUnlockMode; | |
9 | |
10 /** | |
11 * Returns if the elmeent is visible. | |
12 * @param {!Element} element | |
13 */ | |
14 function isVisible(element) { | |
15 while (element) { | |
16 if (element.offsetWidth <= 0 || element.offsetHeight <= 0 || | |
17 element.hidden) { | |
18 return false; | |
19 } | |
20 | |
21 element = element.parentElement; | |
22 } | |
stevenjb
2016/10/13 21:36:45
Is just testing element.offsetWidth/Height not suf
jdufault
2016/10/13 23:41:24
Nope :(
| |
23 | |
24 return true; | |
25 } | |
26 | |
27 /** | |
28 * Returns true if the given |element| has class |className|. | |
29 * @param {!Element} element | |
30 * @param {string} className | |
31 */ | |
32 function assertHasClass(element, className) { | |
33 assertTrue(element.classList.contains(className)); | |
34 } | |
35 | |
36 /** | |
37 * Returns the result of running |selector| on element. | |
38 * @param {string} selector | |
39 * @return {Element} | |
40 */ | |
41 function getFromElement(selector) { | |
42 var childElement = element.$$(selector); | |
43 assertTrue(!!childElement); | |
44 return childElement; | |
45 } | |
46 | |
47 /** | |
48 * Sets the active quick unlock modes and raises a mode change event. | |
49 * @param {!Array<chrome.quickUnlockPrivate.QuickUnlockMode>} modes | |
50 */ | |
51 function setActiveModes(modes) { | |
52 quickUnlockPrivateApi.activeModes = modes; | |
53 quickUnlockPrivateApi.onActiveModesChanged.callListeners(modes); | |
54 } | |
55 | |
56 function registerAuthenticateTests() { | |
57 suite('authenticate', function() { | |
58 var passwordElement = null; | |
59 | |
60 setup(function() { | |
61 PolymerTest.clearBody(); | |
62 | |
63 quickUnlockPrivateApi = new settings.FakeQuickUnlockPrivate(); | |
64 | |
65 element = document.createElement('settings-password-prompt-dialog'); | |
66 element.quickUnlockPrivate_ = quickUnlockPrivateApi; | |
67 document.body.appendChild(element); | |
68 | |
69 passwordElement = getFromElement('#passwordInput'); | |
70 }); | |
71 | |
72 test('PasswordCheckDoesNotChangeActiveMode', function() { | |
73 // No active modes. | |
74 quickUnlockPrivateApi.activeModes = []; | |
75 passwordElement.value = 'foo'; | |
76 element.submitPassword_(); | |
77 assertDeepEquals([], quickUnlockPrivateApi.activeModes); | |
78 assertDeepEquals([], quickUnlockPrivateApi.credentials); | |
79 | |
80 // PIN is active. | |
81 quickUnlockPrivateApi.activeModes = [QuickUnlockMode.PIN]; | |
82 passwordElement.value = 'foo'; | |
83 element.submitPassword_(); | |
84 assertDeepEquals([QuickUnlockMode.PIN], | |
85 quickUnlockPrivateApi.activeModes); | |
86 assertDeepEquals([''], quickUnlockPrivateApi.credentials); | |
87 }); | |
88 | |
89 // A bad password does not provide an authenticated setModes object. | |
90 test('InvalidPasswordDoesNotProvideAuthentication', function() { | |
91 quickUnlockPrivateApi.accountPassword = 'bar'; | |
92 | |
93 passwordElement.value = 'foo'; | |
94 element.submitPassword_(); | |
95 | |
96 assertFalse(!!element.setModes); | |
97 }); | |
98 | |
99 // A valid password provides an authenticated setModes object. | |
100 test('ValidPasswordProvidesAuthentication', function() { | |
101 quickUnlockPrivateApi.accountPassword = 'foo'; | |
102 | |
103 passwordElement.value = 'foo'; | |
104 element.submitPassword_(); | |
105 | |
106 assertTrue(!!element.setModes); | |
107 }); | |
108 | |
109 // The setModes objects times out after a delay. | |
110 test('AuthenticationTimesOut', function(done) { | |
111 quickUnlockPrivateApi.accountPassword = 'foo'; | |
112 | |
113 element.passwordActiveDurationMs_ = 0; | |
114 passwordElement.value = 'foo'; | |
115 element.submitPassword_(); | |
116 | |
117 assertFalse(!!element.password_); | |
118 assertTrue(!!element.setModes); | |
119 | |
120 // Two setTimeout calls with the same delay are guaranteed to execute in | |
121 // the same order that they were submitted in, so using | |
122 // element.autosubmitDelayMs_ is safe. | |
123 setTimeout(function() { | |
124 assertFalse(!!element.password_); | |
125 assertFalse(!!element.setModes); | |
126 done(); | |
127 }, element.passwordActiveDurationMs_); | |
128 }); | |
129 }); | |
130 } | |
131 | |
132 function registerLockScreenTests() { | |
133 suite('lock-screen', function() { | |
134 /** @const */ var ENABLE_LOCK_SCREEN_PREF = 'settings.enable_screen_lock'; | |
135 | |
136 var fakeSettings = null; | |
137 var passwordRadioButton = null; | |
138 var pinPasswordRadioButton = null; | |
139 var noneRadioButton = null; | |
140 var configureButton = null; | |
141 | |
142 /** | |
143 * Asserts that only the given radio button is active and all of the | |
144 * others are inactive. | |
145 * @param {Element} radioButton | |
146 */ | |
147 function assertRadioButtonActive(radioButton) { | |
148 function doAssert(element, name) { | |
149 if (radioButton == element) | |
150 assertTrue(element.active, 'Expected ' + name + ' to be active'); | |
151 else | |
152 assertFalse(element.active, 'Expected ' + name + ' to be inactive'); | |
153 } | |
154 | |
155 doAssert(passwordRadioButton, 'passwordButton'); | |
156 doAssert(pinPasswordRadioButton, 'pinPasswordButton'); | |
157 } | |
158 | |
159 /** | |
160 * Returns the lock screen pref value. | |
161 * @return {boolean} | |
162 */ | |
163 function getLockScreenPref() { | |
164 var result; | |
165 fakeSettings.getPref(ENABLE_LOCK_SCREEN_PREF, function(value) { | |
166 result = value; | |
167 }); | |
168 assertNotEquals(undefined, result); | |
169 return result.value; | |
170 } | |
171 | |
172 /** | |
173 * Changes the lock screen pref value using the settings API; this is like | |
174 * the pref got changed from an unkown source such as another tab. | |
175 * @param {boolean} value | |
176 */ | |
177 function setLockScreenPref(value) { | |
178 fakeSettings.setPref(ENABLE_LOCK_SCREEN_PREF, value, '', assertTrue); | |
179 } | |
180 | |
181 suiteSetup(function() { | |
182 var urls = [ | |
183 'chrome://md-settings/i18n_setup.html', | |
184 'chrome://md-settings/prefs/prefs.html', | |
185 ]; | |
186 return Promise.all(urls.map(PolymerTest.importHtml)); | |
187 }); | |
188 | |
189 setup(function(done) { | |
190 PolymerTest.clearBody(); | |
191 | |
192 CrSettingsPrefs.deferInitialization = true; | |
193 | |
194 // Build pref fakes. | |
195 var fakePrefs = [{ | |
196 key: ENABLE_LOCK_SCREEN_PREF, | |
197 type: chrome.settingsPrivate.PrefType.BOOLEAN, | |
198 value: true | |
199 }]; | |
200 fakeSettings = new settings.FakeSettingsPrivate(fakePrefs); | |
201 setLockScreenPref(true); | |
202 var prefElement = document.createElement('settings-prefs'); | |
203 prefElement.initialize(fakeSettings); | |
204 document.body.appendChild(prefElement); | |
205 | |
206 // Wait for prefElement to finish initializing; it takes some time for | |
207 // the prefs element to get allocated. | |
208 prefElement.addEventListener('prefs-changed', function prefsReady() { | |
209 prefElement.removeEventListener('prefs-changed', prefsReady); | |
210 | |
211 quickUnlockPrivateApi = new settings.FakeQuickUnlockPrivate(); | |
212 | |
213 // Create choose-method element. | |
214 element = document.createElement('settings-lock-screen'); | |
215 element.settingsPrivate_ = fakeSettings; | |
216 element.quickUnlockPrivate_ = quickUnlockPrivateApi; | |
217 element.prefs = prefElement.prefs; | |
218 | |
219 document.body.appendChild(element); | |
220 Polymer.dom.flush(); | |
221 | |
222 element.setModes_ = | |
223 quickUnlockPrivateApi.setModes.bind(quickUnlockPrivateApi, ''); | |
224 | |
225 passwordRadioButton = | |
226 getFromElement('paper-radio-button[name="password"]'); | |
227 pinPasswordRadioButton = | |
228 getFromElement('paper-radio-button[name="pin+password"]'); | |
229 //configureButton = getFromElement('#foobar');//paper-button'); | |
stevenjb
2016/10/13 21:36:45
??
jdufault
2016/10/13 23:41:24
Done.
| |
230 configureButton = getFromElement('paper-button'); | |
231 | |
232 // Wait for the element to finish initializing. | |
233 //element.addEventListener('ready', function() { done(); }); | |
234 //done(); | |
stevenjb
2016/10/13 21:36:45
??
jdufault
2016/10/13 23:41:24
Done.
| |
235 setTimeout(function() { done(); }, 500); | |
236 }); | |
237 }); | |
238 | |
239 // Showing the choose method screen does not make any destructive pref or | |
240 // quickUnlockPrivate calls. | |
241 test('ShowingScreenDoesNotModifyPrefs', function() { | |
242 assertTrue(getLockScreenPref()); | |
243 assertRadioButtonActive(passwordRadioButton); | |
244 assertDeepEquals([], quickUnlockPrivateApi.activeModes); | |
245 }); | |
246 | |
247 // The various radio buttons update internal state and do not modify | |
248 // prefs. | |
249 test('TappingButtonsChangesUnderlyingState', function() { | |
250 function togglePin() { | |
251 assertRadioButtonActive(passwordRadioButton); | |
252 | |
253 // Tap pin+password button. | |
254 MockInteractions.tap(pinPasswordRadioButton); | |
255 assertRadioButtonActive(pinPasswordRadioButton); | |
256 assertTrue(isVisible(configureButton)); | |
257 assertDeepEquals([], quickUnlockPrivateApi.activeModes); | |
258 | |
259 // Enable quick unlock so that we verify tapping password disables it. | |
260 setActiveModes([QuickUnlockMode.PIN]); | |
261 | |
262 // Tap password button and verify quick unlock is disabled. | |
263 MockInteractions.tap(passwordRadioButton); | |
264 assertRadioButtonActive(passwordRadioButton); | |
265 assertFalse(isVisible(configureButton)); | |
266 assertDeepEquals([], quickUnlockPrivateApi.activeModes); | |
267 } | |
268 | |
269 // Verify toggling PIN on/off does not disable screen lock. | |
270 setLockScreenPref(true); | |
271 togglePin(); | |
272 assertTrue(getLockScreenPref()); | |
273 | |
274 // Verify toggling PIN on/off does not enable screen lock. | |
275 setLockScreenPref(false); | |
276 togglePin(); | |
277 assertFalse(getLockScreenPref()); | |
278 }); | |
279 | |
280 // If quick unlock is changed by another settings page the radio button | |
281 // will update to show quick unlock is active. | |
282 test('EnablingQuickUnlockChangesButtonState', function() { | |
283 setActiveModes([QuickUnlockMode.PIN]); | |
284 assertRadioButtonActive(pinPasswordRadioButton); | |
285 assertTrue(isVisible(configureButton)); | |
286 | |
287 setActiveModes([]); | |
288 assertRadioButtonActive(passwordRadioButton); | |
289 assertDeepEquals([], quickUnlockPrivateApi.activeModes); | |
290 }); | |
291 | |
292 // Tapping the PIN configure button opens up the setup PIN dialog. | |
293 test('TappingConfigureOpensSetupPin', function() { | |
294 assertRadioButtonActive(passwordRadioButton); | |
295 | |
296 MockInteractions.tap(pinPasswordRadioButton); | |
297 assertTrue(isVisible(configureButton)); | |
298 assertRadioButtonActive(pinPasswordRadioButton) | |
299 | |
300 MockInteractions.tap(configureButton); | |
301 var setupPinDialog = getFromElement('#setupPin'); | |
302 assertTrue(setupPinDialog.$.dialog.open); | |
303 }); | |
304 }); | |
305 } | |
306 | |
307 function registerSetupPinDialogTests() { | |
308 suite('setup-pin-dialog', function() { | |
309 var titleDiv = null; | |
310 var problemDiv = null; | |
311 var pinKeyboard = null; | |
312 var backButton = null; | |
313 var continueButton = null; | |
314 | |
315 suiteSetup(function() { | |
316 var urls = ['chrome://md-settings/i18n_setup.html']; | |
317 return Promise.all(urls.map(PolymerTest.importHtml)); | |
318 }); | |
319 | |
320 setup(function() { | |
321 PolymerTest.clearBody(); | |
322 | |
323 quickUnlockPrivateApi = new settings.FakeQuickUnlockPrivate(); | |
324 | |
325 // Create setup-pin element. | |
326 element = document.createElement('settings-setup-pin-dialog'); | |
327 element.setModes = | |
328 quickUnlockPrivateApi.setModes.bind(quickUnlockPrivateApi, ''); | |
329 | |
330 document.body.appendChild(element); | |
331 Polymer.dom.flush(); | |
332 | |
333 element.open(); | |
334 | |
335 titleDiv = getFromElement('div[class="title"]'); | |
336 problemDiv = getFromElement('#problemDiv'); | |
337 pinKeyboard = getFromElement('pin-keyboard'); | |
338 backButton = getFromElement('paper-button[class="cancel-button"]'); | |
339 continueButton = getFromElement('paper-button[class="action-button"]'); | |
340 | |
341 assertTrue(isVisible(backButton)); | |
342 assertTrue(isVisible(continueButton)); | |
343 }); | |
344 | |
345 // The continue button and title change text between the setup and confirm | |
346 // steps. | |
347 test('TextChangesBetweenSetupAndConfirmStep', function() { | |
348 var initialContinue = continueButton.textContent; | |
349 var initialTitle = titleDiv.textContent; | |
350 | |
351 pinKeyboard.value = '1111'; | |
352 MockInteractions.tap(continueButton); | |
353 | |
354 assertNotEquals(initialContinue, continueButton.textContent); | |
355 assertNotEquals(initialTitle, titleDiv.textContent); | |
356 }); | |
357 | |
358 // The continue button is disabled unless the user has entered a >= 4 | |
359 // digit PIN. | |
360 test('CanOnlyContinueAfterEnteringAtLeastFourDigitPin', function() { | |
361 pinKeyboard.value = '111'; | |
362 assertTrue(continueButton.disabled); | |
363 | |
364 pinKeyboard.value = '1111'; | |
365 assertFalse(continueButton.disabled); | |
366 | |
367 pinKeyboard.value = '111'; | |
368 assertTrue(continueButton.disabled); | |
369 | |
370 pinKeyboard.value = ''; | |
371 assertTrue(continueButton.disabled); | |
372 | |
373 pinKeyboard.value = '1111111'; | |
374 assertFalse(continueButton.disabled); | |
375 }); | |
376 | |
377 // Problem messages are hidden if the PIN is cleared. | |
378 test('NoProblemShownWithEmptyPin', function() { | |
379 pinKeyboard.value = '11'; | |
380 assertTrue(isVisible(problemDiv)); | |
381 | |
382 pinKeyboard.value = ''; | |
383 assertFalse(isVisible(problemDiv)); | |
384 }); | |
385 | |
386 // If the PIN is too short an error problem is shown. | |
387 test('ErrorShownForShortPins', function() { | |
388 assertFalse(isVisible(problemDiv)); | |
389 | |
390 pinKeyboard.value = '11'; | |
391 | |
392 assertTrue(isVisible(problemDiv)); | |
393 assertHasClass(problemDiv, 'error'); | |
394 assertTrue(continueButton.disabled); | |
395 }); | |
396 | |
397 // If the PIN is weak a warning problem is shown. | |
398 test('WarningShownForWeakPins', function() { | |
399 assertFalse(isVisible(problemDiv)); | |
400 | |
401 pinKeyboard.value = '1111'; | |
402 | |
403 assertTrue(isVisible(problemDiv)); | |
404 assertHasClass(problemDiv, 'warning'); | |
405 }); | |
406 | |
407 // If the confirm PIN does not match the initial PIN an error is shown and | |
408 // the submit button is disabled. | |
409 test('ErrorShownForMismatchedPins', function() { | |
410 pinKeyboard.value = '1118'; | |
411 MockInteractions.tap(continueButton); | |
412 pinKeyboard.value = '1119'; | |
413 | |
414 assertTrue(isVisible(problemDiv)); | |
415 assertHasClass(problemDiv, 'error'); | |
416 assertTrue(continueButton.disabled); | |
417 }); | |
418 | |
419 // Hitting cancel at the setup step dismisses the dialog. | |
420 test('HittingBackButtonResetsState', function() { | |
421 MockInteractions.tap(backButton); | |
422 assertFalse(element.$.dialog.open); | |
423 }); | |
424 | |
425 // Hitting cancel at the confirm step dismisses the dialog. | |
426 test('HittingBackButtonResetsState', function() { | |
427 pinKeyboard.value = '1111'; | |
428 MockInteractions.tap(continueButton); | |
429 MockInteractions.tap(backButton); | |
430 assertFalse(element.$.dialog.open); | |
431 }); | |
432 | |
433 // User has to re-enter PIN for confirm step. | |
434 test('PinKeyboardIsResetForConfirmStep', function() { | |
435 pinKeyboard.value = '1111'; | |
436 MockInteractions.tap(continueButton); | |
437 assertEquals('', pinKeyboard.value); | |
438 }); | |
439 | |
440 // Completing the flow results in a call to the quick unlock private API. | |
441 test('SubmittingPinCallsQuickUnlockApi', function() { | |
442 // Entering the same (even weak) pin twice calls the quick unlock API | |
443 // and sets up a PIN. | |
444 pinKeyboard.value = '1111'; | |
445 MockInteractions.tap(continueButton); | |
446 pinKeyboard.value = '1111'; | |
447 MockInteractions.tap(continueButton); | |
448 | |
449 assertDeepEquals(['PIN'], quickUnlockPrivateApi.activeModes); | |
450 assertDeepEquals(['1111'], quickUnlockPrivateApi.credentials); | |
451 }); | |
452 }); | |
453 } | |
454 | |
455 return { | |
456 registerAuthenticateTests: registerAuthenticateTests, | |
457 registerLockScreenTests: registerLockScreenTests, | |
458 registerSetupPinDialogTests: registerSetupPinDialogTests | |
459 }; | |
460 }); | |
OLD | NEW |