| // 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, SettingsFingerprintListSubpageElement, SettingsSetupFingerprintDialogElement} from 'chrome://os-settings/chromeos/lazy_load.js'; |
| import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js'; |
| import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; |
| import {getDeepActiveElement} from 'chrome://resources/js/util_ts.js'; |
| import {DomRepeatEvent, flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; |
| import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; |
| import {isVisible} from 'chrome://webui-test/test_util.js'; |
| |
| import {TestFingerprintBrowserProxy} from './test_fingerprint_browser_proxy.js'; |
| |
| suite('<settings-fingerprint-list-subpage>', () => { |
| let fingerprintList: SettingsFingerprintListSubpageElement; |
| let dialog: SettingsSetupFingerprintDialogElement; |
| let addAnotherButton: HTMLButtonElement; |
| let browserProxy: TestFingerprintBrowserProxy; |
| |
| function createFakeEvent(index: number, label?: string) { |
| return {model: {index: index, item: label || ''}} as DomRepeatEvent<string>; |
| } |
| |
| function openDialog() { |
| const actionButton = |
| fingerprintList.shadowRoot!.querySelector<HTMLButtonElement>( |
| '.action-button'); |
| assertTrue(!!actionButton); |
| actionButton.click(); |
| flush(); |
| const dialogElement = fingerprintList.shadowRoot!.querySelector( |
| 'settings-setup-fingerprint-dialog'); |
| assertTrue(!!dialogElement); |
| dialog = dialogElement; |
| const button = dialog.shadowRoot!.querySelector<HTMLButtonElement>( |
| '#addAnotherButton'); |
| assertTrue(!!button); |
| addAnotherButton = button; |
| } |
| |
| setup(async () => { |
| browserProxy = new TestFingerprintBrowserProxy(); |
| FingerprintBrowserProxyImpl.setInstanceForTesting(browserProxy); |
| |
| fingerprintList = |
| document.createElement('settings-fingerprint-list-subpage'); |
| document.body.appendChild(fingerprintList); |
| flush(); |
| await browserProxy.whenCalled('getFingerprintsList'); |
| assertEquals(0, fingerprintList.get('fingerprints_').length); |
| browserProxy.resetResolver('getFingerprintsList'); |
| }); |
| |
| test('EnrollingFingerprintLottieAnimation', async () => { |
| loadTimeData.overrideValues({fingerprintUnlockEnabled: true}); |
| openDialog(); |
| await browserProxy.whenCalled('startEnroll'); |
| const dialogButton = |
| dialog.shadowRoot!.querySelector<CrDialogElement>('#dialog'); |
| assertTrue(!!dialogButton); |
| assertTrue(dialogButton.open); |
| assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.get('step_')); |
| const element = |
| dialog.shadowRoot!.querySelector<HTMLElement>('#scannerLocationLottie'); |
| assertTrue(!!element); |
| assertFalse(element.hidden); |
| }); |
| |
| // Verify running through the enroll session workflow |
| // (settings-setup-fingerprint-dialog) works as expected. |
| test('EnrollingFingerprint', async () => { |
| loadTimeData.overrideValues({fingerprintUnlockEnabled: true}); |
| openDialog(); |
| await browserProxy.whenCalled('startEnroll'); |
| const dialogButton = |
| dialog.shadowRoot!.querySelector<CrDialogElement>('#dialog'); |
| assertTrue(!!dialogButton); |
| assertTrue(dialogButton.open); |
| assertEquals(0, dialog.get('percentComplete_')); |
| assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.get('step_')); |
| const element = |
| dialog.shadowRoot!.querySelector<HTMLElement>('#scannerLocationLottie'); |
| assertTrue(!!element); |
| assertFalse(element.hidden); |
| const arcElement = dialog.shadowRoot!.querySelector<HTMLElement>('#arc'); |
| assertTrue(!!arcElement); |
| assertTrue(arcElement.hidden); |
| // Message should be shown for LOCATE_SCANNER step. |
| const message = dialog.shadowRoot!.querySelector('#messageDiv'); |
| assertTrue(!!message); |
| assertEquals('visible', window.getComputedStyle(message).visibility); |
| |
| // First tap on the sensor to start fingerprint enrollment. |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 20 /* percent */); |
| assertEquals(20, dialog.get('percentComplete_')); |
| assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.get('step_')); |
| assertTrue(element.hidden); |
| assertFalse(arcElement.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.get('percentComplete_')); |
| assertEquals('visible', window.getComputedStyle(message).visibility); |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 50 /* percent */); |
| assertEquals('hidden', window.getComputedStyle(message).visibility); |
| assertEquals(50, dialog.get('percentComplete_')); |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 70 /* percent */); |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, true, 100 /* percent */); |
| assertEquals(FingerprintSetupStep.READY, dialog.get('step_')); |
| // Message should be shown for READY step. |
| assertEquals('visible', window.getComputedStyle(message).visibility); |
| |
| // Verify that by tapping the continue button we should exit the dialog |
| // and the fingerprint list should have one fingerprint registered. |
| const closeButton = |
| dialog.shadowRoot!.querySelector<HTMLButtonElement>('#closeButton'); |
| assertTrue(!!closeButton); |
| closeButton.click(); |
| await flushTasks(); |
| await browserProxy.whenCalled('getFingerprintsList'); |
| assertEquals(1, fingerprintList.get('fingerprints_').length); |
| }); |
| |
| // Verify enrolling a fingerprint, then enrolling another without closing the |
| // dialog works as intended. |
| test('EnrollingAnotherFingerprint', async () => { |
| loadTimeData.overrideValues({fingerprintUnlockEnabled: true}); |
| openDialog(); |
| await browserProxy.whenCalled('startEnroll'); |
| browserProxy.resetResolver('startEnroll'); |
| |
| const dialogButton = |
| dialog.shadowRoot!.querySelector<CrDialogElement>('#dialog'); |
| assertTrue(!!dialogButton); |
| assertTrue(dialogButton.open); |
| assertEquals(0, dialog.get('percentComplete_')); |
| assertFalse(isVisible(addAnotherButton)); |
| assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.get('step_')); |
| |
| // First tap on the sensor to start fingerprint enrollment. |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 20 /* percent */); |
| assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.get('step_')); |
| |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, true, 100 /* percent */); |
| assertEquals(FingerprintSetupStep.READY, dialog.get('step_')); |
| |
| assertTrue(dialogButton.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(dialogButton.open); |
| assertFalse(isVisible(addAnotherButton)); |
| assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.get('step_')); |
| const element = |
| dialog.shadowRoot!.querySelector<HTMLElement>('#scannerLocationLottie'); |
| assertTrue(!!element); |
| assertTrue(element.hidden); |
| const arcElement = dialog.shadowRoot!.querySelector<HTMLElement>('#arc'); |
| assertTrue(!!arcElement); |
| assertFalse(arcElement.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. |
| const closeButton = |
| dialog.shadowRoot!.querySelector<HTMLButtonElement>('#closeButton'); |
| assertTrue(!!closeButton); |
| closeButton.click(); |
| await browserProxy.whenCalled('getFingerprintsList'); |
| assertEquals(2, fingerprintList.get('fingerprints_').length); |
| }); |
| |
| // Verify after third fingerprint is enrolled, add another button in the |
| // setup dialog is hidden. |
| test('EnrollingThirdFingerprint', async () => { |
| browserProxy.setFingerprints(['1', '2']); |
| fingerprintList['updateFingerprintsList_'](); |
| |
| openDialog(); |
| await browserProxy.whenCalled('startEnroll'); |
| browserProxy.resetResolver('startEnroll'); |
| |
| const dialogButton = |
| dialog.shadowRoot!.querySelector<CrDialogElement>('#dialog'); |
| assertTrue(!!dialogButton); |
| assertTrue(dialogButton.open); |
| assertEquals(0, dialog.get('percentComplete_')); |
| assertFalse(isVisible(addAnotherButton)); |
| assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.get('step_')); |
| |
| // First tap on the sensor to start fingerprint enrollment. |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 20 /* percent */); |
| assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.get('step_')); |
| |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, true, 100 /* percent */); |
| assertEquals(FingerprintSetupStep.READY, dialog.get('step_')); |
| await browserProxy.whenCalled('getFingerprintsList'); |
| browserProxy.resetResolver('getFingerprintsList'); |
| |
| // Add another is hidden after third fingerprint is enrolled. |
| assertTrue(dialogButton.open); |
| assertFalse(isVisible(addAnotherButton)); |
| assertEquals(3, fingerprintList.get('fingerprints_').length); |
| }); |
| |
| test('CancelEnrollingFingerprint', async () => { |
| openDialog(); |
| await browserProxy.whenCalled('startEnroll'); |
| const dialogButton = |
| dialog.shadowRoot!.querySelector<CrDialogElement>('#dialog'); |
| assertTrue(!!dialogButton); |
| assertTrue(dialogButton.open); |
| assertEquals(0, dialog.get('percentComplete_')); |
| assertEquals(FingerprintSetupStep.LOCATE_SCANNER, dialog.get('step_')); |
| // First tap on the sensor to start fingerprint enrollment. |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 20 /* percent */); |
| assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.get('step_')); |
| |
| browserProxy.scanReceived( |
| FingerprintResultType.SUCCESS, false, 30 /* percent */); |
| assertEquals(30, dialog.get('percentComplete_')); |
| assertEquals(FingerprintSetupStep.MOVE_FINGER, dialog.get('step_')); |
| |
| // Verify that by tapping the exit button we should exit the dialog |
| // and the fingerprint list should have zero fingerprints registered. |
| const closeButton = |
| dialog.shadowRoot!.querySelector<HTMLButtonElement>('#closeButton'); |
| assertTrue(!!closeButton); |
| closeButton.click(); |
| await browserProxy.whenCalled('cancelCurrentEnroll'); |
| assertEquals(0, fingerprintList.get('fingerprints_').length); |
| }); |
| |
| test('RemoveFingerprint', async () => { |
| browserProxy.setFingerprints(['Label 1', 'Label 2']); |
| fingerprintList['updateFingerprintsList_'](); |
| |
| await browserProxy.whenCalled('getFingerprintsList'); |
| browserProxy.resetResolver('getFingerprintsList'); |
| assertEquals(2, fingerprintList.get('fingerprints_').length); |
| fingerprintList['onFingerprintDeleteTapped_'](createFakeEvent(0)); |
| |
| await Promise.all([ |
| browserProxy.whenCalled('removeEnrollment'), |
| browserProxy.whenCalled('getFingerprintsList'), |
| ]); |
| assertEquals(1, fingerprintList.get('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<HTMLElement>( |
| '#addFingerprint'); |
| assertTrue(!!deepLinkElement); |
| 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]; |
| assertTrue(!!deepLinkElement); |
| await waitAfterNextRender(deepLinkElement); |
| assertEquals( |
| deepLinkElement, getDeepActiveElement(), |
| 'Trash can button should be focused for settingId=' + settingId); |
| }); |
| |
| test('ChangeFingerprintLabel', async () => { |
| browserProxy.setFingerprints(['Label 1']); |
| fingerprintList['updateFingerprintsList_'](); |
| |
| await browserProxy.whenCalled('getFingerprintsList'); |
| assertEquals(1, fingerprintList.get('fingerprints_').length); |
| assertEquals('Label 1', fingerprintList.get('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.get('fingerprints_')[0]); |
| }); |
| |
| test('AddingNewFingerprint', async () => { |
| 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.get('fingerprints_').length); |
| const actionButton = |
| fingerprintList.shadowRoot!.querySelector<HTMLButtonElement>( |
| '.action-button'); |
| assertTrue(!!actionButton); |
| assertTrue(actionButton.disabled); |
| fingerprintList['onFingerprintDeleteTapped_'](createFakeEvent(0)); |
| |
| await Promise.all([ |
| browserProxy.whenCalled('removeEnrollment'), |
| browserProxy.whenCalled('getFingerprintsList'), |
| ]); |
| assertEquals(2, fingerprintList.get('fingerprints_').length); |
| assertFalse(actionButton.disabled); |
| }); |
| }); |