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