blob: 2348a123ad5f8b9152a0ae53c9e47d6264019d5c [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://os-settings/chromeos/lazy_load.js';
import {FingerprintBrowserProxyImpl, FingerprintResultType, FingerprintSetupStep} from 'chrome://os-settings/chromeos/lazy_load.js';
import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
import {webUIListenerCallback} from 'chrome://resources/ash/common/cr.m.js';
import {getDeepActiveElement} from 'chrome://resources/ash/common/util.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js';
import {isVisible} from 'chrome://webui-test/test_util.js';
/** @implements {FingerprintBrowserProxy} */
class TestFingerprintBrowserProxy extends TestBrowserProxy {
constructor() {
super([
'getFingerprintsList',
'getNumFingerprints',
'startEnroll',
'cancelCurrentEnroll',
'getEnrollmentLabel',
'removeEnrollment',
'changeEnrollmentLabel',
]);
/** @private {!Array<string>} */
this.fingerprintsList_ = [];
}
/** @param {!Array<string>} fingerprints */
setFingerprints(fingerprints) {
this.fingerprintsList_ = fingerprints.slice();
}
/**
* @param {FingerprintResultType} result
* @param {boolean} complete
* @param {number} percent
*/
scanReceived(result, complete, percent) {
if (complete) {
this.fingerprintsList_.push('New Label');
}
webUIListenerCallback(
'on-fingerprint-scan-received',
{result: result, isComplete: complete, percentComplete: percent});
}
/** @override */
getFingerprintsList() {
this.methodCalled('getFingerprintsList');
/** @type {FingerprintInfo} */
const fingerprintInfo = {
fingerprintsList: this.fingerprintsList_.slice(),
isMaxed: this.fingerprintsList_.length >= 3,
};
return Promise.resolve(fingerprintInfo);
}
/** @override */
getNumFingerprints() {
this.methodCalled('getNumFingerprints');
return Promise.resolve(fingerprintsList_.length);
}
/** @override */
startEnroll() {
this.methodCalled('startEnroll');
}
/** @override */
cancelCurrentEnroll() {
this.methodCalled('cancelCurrentEnroll');
}
/** @override */
getEnrollmentLabel(index) {
this.methodCalled('getEnrollmentLabel');
return Promise.resolve(this.fingerprintsList_[index]);
}
/** @override */
removeEnrollment(index) {
this.fingerprintsList_.splice(index, 1);
this.methodCalled('removeEnrollment', index);
return Promise.resolve(true);
}
/** @override */
changeEnrollmentLabel(index, newLabel) {
this.fingerprintsList_[index] = newLabel;
this.methodCalled('changeEnrollmentLabel', index, newLabel);
return Promise.resolve(true);
}
}
suite('settings-fingerprint-list-subpage', function() {
/** @type {?SettingsFingerprintListElement} */
let fingerprintList = null;
/** @type {?SettingsSetupFingerprintDialogElement} */
let dialog = null;
/** @type {?HTMLButtonElement} */
let addAnotherButton = null;
/** @type {?settings.TestFingerprintBrowserProxy} */
let browserProxy = null;
/**
* @param {number} index
* @param {string=} opt_label
*/
function createFakeEvent(index, opt_label) {
return {model: {index: index, item: opt_label || ''}};
}
function openDialog() {
fingerprintList.shadowRoot.querySelector('.action-button').click();
flush();
dialog = fingerprintList.shadowRoot.querySelector(
'settings-setup-fingerprint-dialog');
addAnotherButton = dialog.shadowRoot.querySelector('#addAnotherButton');
}
setup(async function() {
browserProxy = new TestFingerprintBrowserProxy();
FingerprintBrowserProxyImpl.setInstanceForTesting(browserProxy);
PolymerTest.clearBody();
fingerprintList =
document.createElement('settings-fingerprint-list-subpage');
document.body.appendChild(fingerprintList);
flush();
await browserProxy.whenCalled('getFingerprintsList');
assertEquals(0, fingerprintList.fingerprints_.length);
browserProxy.resetResolver('getFingerprintsList');
});
test('EnrollingFingerprintLottieAnimation', async function() {
loadTimeData.overrideValues({fingerprintUnlockEnabled: true});
openDialog();
await browserProxy.whenCalled('startEnroll');
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
assertFalse(
dialog.shadowRoot.querySelector('#scannerLocationLottie').hidden);
});
// Verify running through the enroll session workflow
// (settings-setup-fingerprint-dialog) works as expected.
test('EnrollingFingerprint', async function() {
loadTimeData.overrideValues({fingerprintUnlockEnabled: true});
openDialog();
await browserProxy.whenCalled('startEnroll');
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertEquals(0, dialog.percentComplete_);
assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
assertFalse(
dialog.shadowRoot.querySelector('#scannerLocationLottie').hidden);
assertTrue(dialog.shadowRoot.querySelector('#arc').hidden);
// Message should be shown for LOCATE_SCANNER step.
assertEquals(
'visible',
window.getComputedStyle(dialog.shadowRoot.querySelector('#messageDiv'))
.visibility);
// First tap on the sensor to start fingerprint enrollment.
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 20 /* percent */);
assertEquals(20, dialog.percentComplete_);
assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.step_);
assertTrue(
dialog.shadowRoot.querySelector('#scannerLocationLottie').hidden);
assertFalse(dialog.shadowRoot.querySelector('#arc').hidden);
// Verify that by sending a scan problem, the div that contains the
// problem message should be visible.
browserProxy.scanReceived(
FingerprintResultType.TOO_FAST, false, 20 /* percent */);
assertEquals(20, dialog.percentComplete_);
assertEquals(
'visible',
window.getComputedStyle(dialog.shadowRoot.querySelector('#messageDiv'))
.visibility);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 50 /* percent */);
assertEquals(
'hidden',
window.getComputedStyle(dialog.shadowRoot.querySelector('#messageDiv'))
.visibility);
assertEquals(50, dialog.percentComplete_);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 70 /* percent */);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, true, 100 /* percent */);
assertEquals(FingerprintSetupStep.READY, dialog.step_);
// Message should be shown for READY step.
assertEquals(
'visible',
window.getComputedStyle(dialog.shadowRoot.querySelector('#messageDiv'))
.visibility);
// Verify that by tapping the continue button we should exit the dialog
// and the fingerprint list should have one fingerprint registered.
dialog.shadowRoot.querySelector('#closeButton').click();
await flushTasks();
await browserProxy.whenCalled('getFingerprintsList');
assertEquals(1, fingerprintList.fingerprints_.length);
});
// Verify enrolling a fingerprint, then enrolling another without closing the
// dialog works as intended.
test('EnrollingAnotherFingerprint', async function() {
loadTimeData.overrideValues({fingerprintUnlockEnabled: true});
openDialog();
await browserProxy.whenCalled('startEnroll');
browserProxy.resetResolver('startEnroll');
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertEquals(0, dialog.percentComplete_);
assertFalse(isVisible(addAnotherButton));
assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
// First tap on the sensor to start fingerprint enrollment.
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 20 /* percent */);
assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.step_);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, true, 100 /* percent */);
assertEquals(FingerprintSetupStep.READY, dialog.step_);
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertTrue(isVisible(addAnotherButton));
addAnotherButton.click();
// Once the first fingerprint is enrolled, verify that enrolling the
// second fingerprint without closing the dialog works as expected.
await Promise.all([
browserProxy.whenCalled('startEnroll'),
browserProxy.whenCalled('getFingerprintsList'),
]);
browserProxy.resetResolver('getFingerprintsList');
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertFalse(isVisible(addAnotherButton));
assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.step_);
assertTrue(
dialog.shadowRoot.querySelector('#scannerLocationLottie').hidden);
assertFalse(dialog.shadowRoot.querySelector('#arc').hidden);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, true, 100 /* percent */);
// Verify that by tapping the continue button we should exit the
// dialog and the fingerprint list should have two fingerprints
// registered.
dialog.shadowRoot.querySelector('#closeButton').click();
await browserProxy.whenCalled('getFingerprintsList');
assertEquals(2, fingerprintList.fingerprints_.length);
});
// Verify after third fingerprint is enrolled, add another button in the
// setup dialog is hidden.
test('EnrollingThirdFingerprint', async function() {
browserProxy.setFingerprints(['1', '2']);
fingerprintList.updateFingerprintsList_();
openDialog();
await browserProxy.whenCalled('startEnroll');
browserProxy.resetResolver('startEnroll');
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertEquals(0, dialog.percentComplete_);
assertFalse(isVisible(addAnotherButton));
assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
// First tap on the sensor to start fingerprint enrollment.
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 20 /* percent */);
assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.step_);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, true, 100 /* percent */);
assertEquals(FingerprintSetupStep.READY, dialog.step_);
await browserProxy.whenCalled('getFingerprintsList');
browserProxy.resetResolver('getFingerprintsList');
// Add another is hidden after third fingerprint is enrolled.
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertFalse(isVisible(addAnotherButton));
assertEquals(3, fingerprintList.fingerprints_.length);
});
test('CancelEnrollingFingerprint', async function() {
openDialog();
await browserProxy.whenCalled('startEnroll');
assertTrue(dialog.shadowRoot.querySelector('#dialog').open);
assertEquals(0, dialog.percentComplete_);
assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
// First tap on the sensor to start fingerprint enrollment.
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 20 /* percent */);
assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.step_);
browserProxy.scanReceived(
FingerprintResultType.SUCCESS, false, 30 /* percent */);
assertEquals(30, dialog.percentComplete_);
assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.step_);
// Verify that by tapping the exit button we should exit the dialog
// and the fingerprint list should have zero fingerprints registered.
dialog.shadowRoot.querySelector('#closeButton').click();
await browserProxy.whenCalled('cancelCurrentEnroll');
assertEquals(0, fingerprintList.fingerprints_.length);
});
test('RemoveFingerprint', async function() {
browserProxy.setFingerprints(['Label 1', 'Label 2']);
fingerprintList.updateFingerprintsList_();
await browserProxy.whenCalled('getFingerprintsList');
browserProxy.resetResolver('getFingerprintsList');
assertEquals(2, fingerprintList.fingerprints_.length);
fingerprintList.onFingerprintDeleteTapped_(createFakeEvent(0));
await Promise.all([
browserProxy.whenCalled('removeEnrollment'),
browserProxy.whenCalled('getFingerprintsList'),
]);
assertEquals(1, fingerprintList.fingerprints_.length);
});
test('Deep link to add fingerprint', async () => {
const settingId = '1111';
browserProxy.setFingerprints(['Label 1', 'Label 2']);
fingerprintList.updateFingerprintsList_();
await browserProxy.whenCalled('getFingerprintsList');
const params = new URLSearchParams();
params.append('settingId', settingId);
Router.getInstance().navigateTo(routes.FINGERPRINT, params);
flush();
const deepLinkElement =
fingerprintList.shadowRoot.querySelector('#addFingerprint');
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
'Add button should be focused for settingId=' + settingId);
});
test('Deep link to remove fingerprint', async () => {
const settingId = '1112';
browserProxy.setFingerprints(['Label 1', 'Label 2']);
fingerprintList.updateFingerprintsList_();
await browserProxy.whenCalled('getFingerprintsList');
const params = new URLSearchParams();
params.append('settingId', settingId);
Router.getInstance().navigateTo(routes.FINGERPRINT, params);
flush();
const deepLinkElement =
fingerprintList.root.querySelectorAll('cr-icon-button')[0];
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
'Trash can button should be focused for settingId=' + settingId);
});
test('ChangeFingerprintLabel', async function() {
browserProxy.setFingerprints(['Label 1']);
fingerprintList.updateFingerprintsList_();
await browserProxy.whenCalled('getFingerprintsList');
assertEquals(1, fingerprintList.fingerprints_.length);
assertEquals('Label 1', fingerprintList.fingerprints_[0]);
// Verify that by sending a fingerprint input change event, the new
// label gets changed as expected.
fingerprintList.onFingerprintLabelChanged_(
createFakeEvent(0, 'New Label 1'));
await Promise.all([
browserProxy.whenCalled('changeEnrollmentLabel'),
browserProxy.whenCalled('getFingerprintsList'),
]);
assertEquals('New Label 1', fingerprintList.fingerprints_[0]);
});
test('AddingNewFingerprint', async function() {
browserProxy.setFingerprints(['1', '2', '3']);
fingerprintList.updateFingerprintsList_();
// Verify that new fingerprints cannot be added when there are already three
// registered fingerprints.
await browserProxy.whenCalled('getFingerprintsList');
browserProxy.resetResolver('getFingerprintsList');
assertEquals(3, fingerprintList.fingerprints_.length);
assertTrue(
fingerprintList.shadowRoot.querySelector('.action-button').disabled);
fingerprintList.onFingerprintDeleteTapped_(createFakeEvent(0));
await Promise.all([
browserProxy.whenCalled('removeEnrollment'),
browserProxy.whenCalled('getFingerprintsList'),
]);
assertEquals(2, fingerprintList.fingerprints_.length);
assertFalse(
fingerprintList.shadowRoot.querySelector('.action-button').disabled);
});
});