blob: 2c14a8f9ad018d017a90a57d2a64b29082e4063b [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// clang-format off
import 'chrome://settings/settings.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import type {CrInputElement, CrTextareaElement} from 'chrome://settings/lazy_load.js';
import {AutofillAddressOptInChange, AutofillManagerImpl, CountryDetailManagerProxyImpl} from 'chrome://settings/lazy_load.js';
import {assertEquals, assertFalse, assertGT, assertTrue} from 'chrome://webui-test/chai_assert.js';
import type {MetricsTracker} from 'chrome://webui-test/metrics_test_support.js';
import {fakeMetricsPrivate} from 'chrome://webui-test/metrics_test_support.js';
import type {CrLinkRowElement} from 'chrome://settings/settings.js';
import {loadTimeData, OpenWindowProxyImpl} from 'chrome://settings/settings.js';
import {eventToPromise, whenAttributeIs, isVisible} from 'chrome://webui-test/test_util.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {TestOpenWindowProxy} from 'chrome://webui-test/test_open_window_proxy.js';
import {AutofillManagerExpectations, createAddressEntry, createEmptyAddressEntry, STUB_USER_ACCOUNT_INFO, TestAutofillManager} from './autofill_fake_data.js';
import {createAutofillSection, initiateRemoving, initiateEditing, createAddressDialog, createRemoveAddressDialog, expectEvent, openAddressDialog, getAddressFieldValue} from './autofill_section_test_utils.js';
import {TestCountryDetailManagerProxy} from './test_country_detail_manager_proxy.js';
// clang-format on
const FieldType = chrome.autofillPrivate.FieldType;
const ADDRESS_COMPONENTS_US = {
components: [
{
row: [
{
field: FieldType.NAME_FULL,
fieldName: 'Name',
isLongField: true,
isRequired: false,
},
],
},
{
row: [
{
field: FieldType.ADDRESS_HOME_CITY,
fieldName: 'City',
isLongField: false,
isRequired: true,
},
{
field: FieldType.ADDRESS_HOME_STATE,
fieldName: 'State',
isLongField: false,
isRequired: true,
},
{
field: FieldType.ADDRESS_HOME_ZIP,
fieldName: 'ZIP code',
isLongField: false,
isRequired: true,
},
],
},
],
languageCode: 'en',
};
const ADDRESS_COMPONENTS_GB = {
components: [
{
row: [
{
field: FieldType.NAME_FULL,
fieldName: 'Name',
isLongField: true,
isRequired: false,
},
],
},
{
row: [
{
field: FieldType.ADDRESS_HOME_CITY,
fieldName: 'Post town',
isLongField: false,
isRequired: true,
},
],
},
{
row: [
{
field: FieldType.ADDRESS_HOME_ZIP,
fieldName: 'Postal code',
isLongField: false,
isRequired: true,
},
],
},
{
row: [
{
field: FieldType.ADDRESS_HOME_STATE,
fieldName: 'County',
isLongField: false,
isRequired: true,
},
],
},
],
languageCode: 'en',
};
const ADDRESS_COMPONENTS_IL = {
components: [
{
row: [
{
field: FieldType.NAME_FULL,
fieldName: 'Name',
isLongField: true,
isRequired: false,
},
],
},
{
row: [
{
field: FieldType.ADDRESS_HOME_CITY,
fieldName: 'City',
isLongField: false,
isRequired: true,
},
{
field: FieldType.ADDRESS_HOME_ZIP,
fieldName: 'Postal code',
isLongField: false,
isRequired: true,
},
],
},
],
languageCode: 'iw',
};
suite('AutofillSectionUiTest', function() {
test('AutofillExtensionIndicator', function() {
// Initializing with fake prefs
const section = document.createElement('settings-autofill-section');
section.prefs = {autofill: {profile_enabled: {}}};
document.body.appendChild(section);
assertFalse(
!!section.shadowRoot!.querySelector('#autofillExtensionIndicator'));
section.set('prefs.autofill.profile_enabled.extensionId', 'test-id');
flush();
assertTrue(
!!section.shadowRoot!.querySelector('#autofillExtensionIndicator'));
document.body.removeChild(section);
});
test('verifyAddressDeleteRecordTypeNotice', async () => {
const address = createAddressEntry();
const accountAddress = createAddressEntry();
accountAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT;
const autofillManager = new TestAutofillManager();
autofillManager.data.addresses = [address, accountAddress];
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isSyncEnabledForAutofillProfiles: true,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
{
const dialog = await initiateRemoving(section, 0);
const expectedMessage =
loadTimeData.getString('removeSyncAddressConfirmationDescription');
assertEquals(
dialog.$.description.textContent.trim(), expectedMessage,
'Sync-on message should be visible');
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
await flushTasks();
const changeListener =
autofillManager.lastCallback.setPersonalDataManagerListener;
assertTrue(
!!changeListener,
'PersonalDataChangedListener should be set in the section element');
// Imitate disabling sync.
changeListener(autofillManager.data.addresses, [], [], [], {
...STUB_USER_ACCOUNT_INFO,
});
{
const dialog = await initiateRemoving(section, 0);
const expectedMessage =
loadTimeData.getString('removeLocalAddressConfirmationDescription');
assertEquals(
dialog.$.description.textContent.trim(), expectedMessage,
'Sync-off message should be visible');
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
await flushTasks();
// Imitate disabling sync.
changeListener(autofillManager.data.addresses, [], [], [], undefined);
{
const dialog = await initiateRemoving(section, 0);
const expectedMessage =
loadTimeData.getString('removeLocalAddressConfirmationDescription');
assertEquals(
dialog.$.description.textContent.trim(), expectedMessage,
'Sync-off message should be visible when account info is missing');
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
await flushTasks();
changeListener(autofillManager.data.addresses, [], [], [], {
...STUB_USER_ACCOUNT_INFO,
isSyncEnabledForAutofillProfiles: true,
});
{
const dialog = await initiateRemoving(section, 1);
const expectedMessage = loadTimeData.getStringF(
'deleteAccountAddressRecordTypeNotice', STUB_USER_ACCOUNT_INFO.email);
assertEquals(
dialog.$.description.textContent.trim(), expectedMessage,
'Account address message should be visible');
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
document.body.removeChild(section);
});
test('verifyAddressDeleteHomeAddressNotice', async () => {
const homeAddress = createAddressEntry();
homeAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_HOME;
const autofillManager = new TestAutofillManager();
autofillManager.data.addresses = [homeAddress];
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isSyncEnabledForAutofillProfiles: true,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
{
const dialog = await initiateRemoving(section, 0);
const homeUrl = loadTimeData.getString('googleAccountHomeAddressUrl')
.replace(/&/g, '&');
const expectedMessage = loadTimeData.getStringF(
'deleteHomeAddressNotice', homeUrl, STUB_USER_ACCOUNT_INFO.email);
assertEquals(
dialog.$.description.innerHTML, expectedMessage,
`Home address delete confirmation view description is incorrect.`);
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
document.body.removeChild(section);
});
test('verifyAddressDeleteWorkAddressNotice', async () => {
const workAddress = createAddressEntry();
workAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_WORK;
const autofillManager = new TestAutofillManager();
autofillManager.data.addresses = [workAddress];
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isSyncEnabledForAutofillProfiles: true,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
{
const dialog = await initiateRemoving(section, 0);
const workUrl = loadTimeData.getString('googleAccountWorkAddressUrl')
.replace(/&/g, '&');
const expectedMessage = loadTimeData.getStringF(
'deleteWorkAddressNotice', workUrl, STUB_USER_ACCOUNT_INFO.email);
assertEquals(
dialog.$.description.innerHTML, expectedMessage,
`Work address delete confirmation view description is incorrect.`);
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
document.body.removeChild(section);
});
test('verifyAddressDeleteNameEmailAddressNotice', async () => {
const nameEmailAddress = createAddressEntry();
nameEmailAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_NAME_EMAIL;
const autofillManager = new TestAutofillManager();
autofillManager.data.addresses = [nameEmailAddress];
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isSyncEnabledForAutofillProfiles: true,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
{
const dialog = await initiateRemoving(section, 0);
const nameEmailUrl =
loadTimeData.getString('googleAccountNameEmailAddressEditUrl')
.replace(/&/g, '&');
const expectedDescription = loadTimeData.getStringF(
'deleteNameEmailAddressNotice', nameEmailUrl,
STUB_USER_ACCOUNT_INFO.email);
assertEquals(
dialog.$.description.innerHTML, expectedDescription,
`Name email delete confirmation view description is incorrect.`);
const title = dialog.shadowRoot!.querySelector<HTMLElement>('#title');
assertTrue(!!title);
assertEquals(
title.innerHTML,
loadTimeData.getString('removeNameEmailAddressConfirmationTitle'),
`Name email delete confirmation view title is incorrect.`);
const removeButton =
dialog.shadowRoot!.querySelector<HTMLElement>('#remove');
assertTrue(!!removeButton);
assertEquals(
removeButton.innerText,
loadTimeData.getString('removeAddressFromChrome'),
`Name email delete confirmation remove button label is incorrect.`);
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
document.body.removeChild(section);
});
test('verifyAddressEditRecordTypeNotice', async () => {
const email = '[email protected]';
const address = createAddressEntry();
const accountAddress = createAddressEntry();
accountAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT;
const section = await createAutofillSection([address, accountAddress], {}, {
...STUB_USER_ACCOUNT_INFO,
email,
});
{
const dialog = await initiateEditing(section, 0);
assertFalse(
isVisible(dialog.$.accountRecordTypeNotice),
'account notice should be invisible for non-account address');
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
await flushTasks();
{
const dialog = await initiateEditing(section, 1);
assertTrue(
isVisible(dialog.$.accountRecordTypeNotice),
'account notice should be visible for account address');
assertEquals(
dialog.$.accountRecordTypeNotice.innerText,
section.i18n('editAccountAddressRecordTypeNotice', email));
dialog.$.dialog.close();
// Make sure closing clean-ups are finished.
await eventToPromise('close', dialog.$.dialog);
}
document.body.removeChild(section);
});
});
suite('AutofillSectionAddressTests', function() {
let countryDetailManager: TestCountryDetailManagerProxy;
let metricsTracker: MetricsTracker;
setup(function() {
document.body.innerHTML = window.trustedTypes!.emptyHTML;
metricsTracker = fakeMetricsPrivate();
countryDetailManager = new TestCountryDetailManagerProxy();
CountryDetailManagerProxyImpl.setInstance(countryDetailManager);
countryDetailManager.setGetCountryListRepsonse([
{name: 'United States', countryCode: 'US'}, // Default country.
{name: 'Israel', countryCode: 'IL'},
{name: 'United Kingdom', countryCode: 'GB'},
]);
countryDetailManager.setGetAddressFormatRepsonse(ADDRESS_COMPONENTS_US);
});
test('verifyAutofillAddressToggleMetric', async function() {
const section =
await createAutofillSection([], {profile_enabled: {value: true}});
const button = section.$.autofillProfileToggle;
assertTrue(!!button);
// The address profile toggle is on by default.
assertTrue(button.checked);
assertEquals(metricsTracker.count('Autofill.Address.IsEnabled.Change'), 0);
// Test that toggling the button off records the correct metric.
button.click();
assertEquals(metricsTracker.count('Autofill.Address.IsEnabled.Change'), 1);
assertEquals(
metricsTracker.count(
'Autofill.Address.IsEnabled.Change',
AutofillAddressOptInChange.OPT_OUT),
1);
// Test that toggling the button on records the correct metric.
button.click();
assertEquals(metricsTracker.count('Autofill.Address.IsEnabled.Change'), 2);
assertEquals(
metricsTracker.count(
'Autofill.Address.IsEnabled.Change',
AutofillAddressOptInChange.OPT_IN),
1);
});
test('verifyNoAddresses', async function() {
const section =
await createAutofillSection([], {profile_enabled: {value: true}});
const addressList = section.$.addressList;
assertTrue(!!addressList);
// 1 for the template element.
assertEquals(1, addressList.children.length);
assertFalse(section.$.noAddressesLabel.hidden);
assertFalse(section.$.addAddress.disabled);
assertFalse(section.$.autofillProfileToggle.disabled);
});
test('verifyAddressCount', async function() {
const addresses = [
createAddressEntry(),
createAddressEntry(),
createAddressEntry(),
createAddressEntry(),
createAddressEntry(),
];
const section = await createAutofillSection(
addresses, {profile_enabled: {value: true}});
const addressList = section.$.addressList;
assertTrue(!!addressList);
assertEquals(
addresses.length, addressList.querySelectorAll('.list-item').length);
assertTrue(section.$.noAddressesLabel.hidden);
assertFalse(section.$.autofillProfileToggle.disabled);
assertFalse(section.$.addAddress.disabled);
});
test('verifyAddressDisabled', async function() {
const section =
await createAutofillSection([], {profile_enabled: {value: false}});
assertFalse(section.$.autofillProfileToggle.disabled);
assertTrue(section.$.addAddress.hidden);
});
test('verifyAddressFields', async function() {
const address = createAddressEntry();
const section = await createAutofillSection([address], {});
const addressList = section.$.addressList;
const row = addressList.children[0];
assertTrue(!!row);
const addressSummary =
address.metadata!.summaryLabel + address.metadata!.summarySublabel;
let actualSummary = '';
// Eliminate white space between nodes!
const addressPieces = row.querySelector('#addressSummary')!.children;
for (const addressPiece of addressPieces) {
actualSummary += addressPiece.textContent.trim();
}
assertEquals(addressSummary, actualSummary);
});
test('verifyAddressLocalIndication', async () => {
const autofillManager = new TestAutofillManager();
autofillManager.data.addresses = [createAddressEntry()];
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isSyncEnabledForAutofillProfiles: true,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
const addressList = section.$.addressList;
const getIcon = () => addressList.children[0]!.querySelector<HTMLElement>(
'#address-row-icon');
const iconName1 = getIcon()!.getAttribute('icon');
assertFalse(
!!iconName1 && iconName1.includes('cloud-off'),
'Sync for addresses is enabled, the local indicator should be off.');
const changeListener =
autofillManager.lastCallback.setPersonalDataManagerListener!;
changeListener(autofillManager.data.addresses, [], [], [], undefined);
const iconName2 = getIcon()!.getAttribute('icon');
assertFalse(
!!iconName2 && iconName2.includes('cloud-off'),
'The local indicator should not be shown to logged-out users');
changeListener(
autofillManager.data.addresses, [], [], [], STUB_USER_ACCOUNT_INFO);
assertTrue(
isVisible(getIcon()),
'Sync is disabled but the feature is on, the icon should be visible.');
document.body.removeChild(section);
});
test('verifyNoAddressLocalIndicationForAccountNameEmail', async () => {
const nameEmailAddress = createAddressEntry();
nameEmailAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_NAME_EMAIL;
const autofillManager = new TestAutofillManager();
autofillManager.data.addresses = [nameEmailAddress];
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
const addressList = section.$.addressList;
const getIcon = () => addressList.children[0]!.querySelector<HTMLElement>(
'#address-row-icon');
const iconName = getIcon()!.getAttribute('icon');
assertFalse(
!!iconName && iconName.includes('cloud-off'),
'Local indicator should not be shown on account name email profile');
document.body.removeChild(section);
});
test('verifyAddressRowButtonTriggersDropdown', async function() {
const address = createAddressEntry();
const section = await createAutofillSection([address], {});
const addressList = section.$.addressList;
const row = addressList.children[0];
assertTrue(!!row);
const menuButton = row.querySelector<HTMLElement>('.address-menu');
assertTrue(!!menuButton);
menuButton.click();
flush();
assertTrue(!!section.shadowRoot!.querySelector('#menuEditAddress'));
});
test('verifyAccountHomeAddressEdit', async function() {
const openWindowProxy = new TestOpenWindowProxy();
OpenWindowProxyImpl.setInstance(openWindowProxy);
const homeAddress = createAddressEntry();
homeAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_HOME;
const section = await createAutofillSection([homeAddress], {});
const addressList = section.$.addressList;
const row = addressList.children[0];
assertTrue(!!row);
const menuButton = row.querySelector<HTMLElement>('.address-menu');
assertTrue(!!menuButton);
menuButton.click();
flush();
const editButton =
section.shadowRoot!.querySelector<HTMLElement>('#menuEditAddress');
assertTrue(!!editButton);
editButton.click();
const url = await openWindowProxy.whenCalled('openUrl');
assertEquals(url, loadTimeData.getString('googleAccountHomeAddressUrl'));
});
test('verifyAccountWorkAddressEdit', async function() {
const openWindowProxy = new TestOpenWindowProxy();
OpenWindowProxyImpl.setInstance(openWindowProxy);
const workAddress = createAddressEntry();
workAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_WORK;
const section = await createAutofillSection([workAddress], {});
const addressList = section.$.addressList;
const row = addressList.children[0];
assertTrue(!!row);
const menuButton = row.querySelector<HTMLElement>('.address-menu');
assertTrue(!!menuButton);
menuButton.click();
flush();
const editButton =
section.shadowRoot!.querySelector<HTMLElement>('#menuEditAddress');
assertTrue(!!editButton);
editButton.click();
const url = await openWindowProxy.whenCalled('openUrl');
assertEquals(url, loadTimeData.getString('googleAccountWorkAddressUrl'));
});
test('verifyAccountNameEmailAddressEdit', async function() {
const openWindowProxy = new TestOpenWindowProxy();
OpenWindowProxyImpl.setInstance(openWindowProxy);
const nameEmailAddress = createAddressEntry();
nameEmailAddress.metadata!.recordType =
chrome.autofillPrivate.AddressRecordType.ACCOUNT_NAME_EMAIL;
const section = await createAutofillSection([nameEmailAddress], {});
const addressList = section.$.addressList;
const row = addressList.children[0];
assertTrue(!!row);
const menuButton = row.querySelector<HTMLElement>('.address-menu');
assertTrue(!!menuButton);
menuButton.click();
flush();
const editButton =
section.shadowRoot!.querySelector<HTMLElement>('#menuEditAddress');
assertTrue(!!editButton);
editButton.click();
const url = await openWindowProxy.whenCalled('openUrl');
assertEquals(
url, loadTimeData.getString('googleAccountNameEmailAddressEditUrl'));
});
test('verifyAddAddressDialog', function() {
const address = createEmptyAddressEntry();
return createAddressDialog(address).then(function(dialog) {
const title = dialog.shadowRoot!.querySelector('[slot=title]')!;
assertEquals(
loadTimeData.getString('addAddressTitle'), title.textContent);
// A country is preselected.
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
assertTrue(!!countrySelect.value);
});
});
test('verifyEditAddressDialog', function() {
return createAddressDialog(createAddressEntry()).then(function(dialog) {
const title = dialog.shadowRoot!.querySelector('[slot=title]')!;
assertEquals(
loadTimeData.getString('editAddressTitle'), title.textContent);
// Should be possible to save when editing because fields are
// populated.
assertFalse(dialog.$.saveButton.disabled);
});
});
// The first editable element should be focused by default.
test('verifyFirstFieldFocused', async function() {
const dialog = await createAddressDialog(createEmptyAddressEntry());
const currentFocus = dialog.shadowRoot!.activeElement;
const editableElements =
dialog.$.dialog.querySelectorAll('cr-input, select');
assertEquals(editableElements[0], currentFocus);
});
test('verifyRemoveAddressDialogConfirmed', async function() {
const autofillManager = new TestAutofillManager();
const removeAddressDialog =
await createRemoveAddressDialog(autofillManager);
// Wait for the dialog to open.
await whenAttributeIs(removeAddressDialog.$.dialog, 'open', '');
removeAddressDialog.$.remove.click();
// Wait for the dialog to close.
await eventToPromise('close', removeAddressDialog);
assertTrue(removeAddressDialog.wasConfirmed());
assertEquals(
1,
metricsTracker.count('Autofill.ProfileDeleted.Settings.Account', true));
assertEquals(
0,
metricsTracker.count(
'Autofill.ProfileDeleted.Settings.Account', false));
assertEquals(
1,
metricsTracker.count('Autofill.ProfileDeleted.Settings.Total', true));
assertEquals(
0,
metricsTracker.count('Autofill.ProfileDeleted.Settings.Total', false));
assertEquals(
1, metricsTracker.count('Autofill.ProfileDeleted.Any.Account', true));
assertEquals(
0, metricsTracker.count('Autofill.ProfileDeleted.Any.Account', false));
assertEquals(
1, metricsTracker.count('Autofill.ProfileDeleted.Any.Total', true));
assertEquals(
0, metricsTracker.count('Autofill.ProfileDeleted.Any.Total', false));
const expected = new AutofillManagerExpectations();
expected.requestedAddresses = 1;
expected.listeningAddresses = 1;
expected.removeAddress = 1;
autofillManager.assertExpectations(expected);
});
test('verifyRemoveAddressDialogCanceled', async function() {
const autofillManager = new TestAutofillManager();
const removeAddressDialog =
await createRemoveAddressDialog(autofillManager);
// Wait for the dialog to open.
await whenAttributeIs(removeAddressDialog.$.dialog, 'open', '');
removeAddressDialog.$.cancel.click();
// Wait for the dialog to close.
await eventToPromise('close', removeAddressDialog);
assertFalse(removeAddressDialog.wasConfirmed());
assertEquals(
0,
metricsTracker.count('Autofill.ProfileDeleted.Settings.Account', true));
assertEquals(
1,
metricsTracker.count(
'Autofill.ProfileDeleted.Settings.Account', false));
assertEquals(
0,
metricsTracker.count('Autofill.ProfileDeleted.Settings.Total', true));
assertEquals(
1,
metricsTracker.count('Autofill.ProfileDeleted.Settings.Total', false));
assertEquals(
0, metricsTracker.count('Autofill.ProfileDeleted.Any.Account', true));
assertEquals(
1, metricsTracker.count('Autofill.ProfileDeleted.Any.Account', false));
assertEquals(
0, metricsTracker.count('Autofill.ProfileDeleted.Any.Total', true));
assertEquals(
1, metricsTracker.count('Autofill.ProfileDeleted.Any.Total', false));
const expected = new AutofillManagerExpectations();
expected.requestedAddresses = 1;
expected.listeningAddresses = 1;
expected.removeAddress = 0;
autofillManager.assertExpectations(expected);
});
test('verifyCountryIsSaved', function() {
const address = createEmptyAddressEntry();
return createAddressDialog(address).then(function(dialog) {
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
// The country should be pre-selected.
assertEquals('US', countrySelect.value);
countrySelect.value = 'GB';
countrySelect.dispatchEvent(new CustomEvent('change'));
flush();
assertEquals('GB', countrySelect.value);
});
});
test('verifyLanguageCodeIsSaved', function() {
const address = createEmptyAddressEntry();
// TODO(crbug.com/403312087): Don't nest promise callbacks (here and
// everywhere else in this file). Use async/await instead. Check this
// comment for more info: crrev.com/c/6348920/comment/25b26a8a_d69cf940/
return createAddressDialog(address).then(function(dialog) {
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
// The first country is pre-selected.
assertEquals('US', countrySelect.value);
assertEquals('en', address.languageCode);
countrySelect.value = 'IL';
countryDetailManager.setGetAddressFormatRepsonse(ADDRESS_COMPONENTS_IL);
countrySelect.dispatchEvent(new CustomEvent('change'));
flush();
return eventToPromise('on-update-address-wrapper', dialog)
.then(function() {
assertEquals('IL', countrySelect.value);
assertEquals('iw', address.languageCode);
});
});
});
test('verifyPhoneAndEmailAreSaved', async () => {
const address = createEmptyAddressEntry();
const dialog = await createAddressDialog(address);
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertGT(rows.length, 0, 'dialog should contain address rows');
const lastRow = rows[rows.length - 1]!;
const phoneInput =
lastRow.querySelector<CrInputElement>('cr-input:nth-of-type(1)');
const emailInput =
lastRow.querySelector<CrInputElement>('cr-input:nth-of-type(2)');
assertTrue(!!phoneInput, 'phone element should be the first cr-input');
assertTrue(!!emailInput, 'email element should be the second cr-input');
assertEquals(undefined, phoneInput.value);
assertFalse(
!!getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER));
assertEquals(undefined, emailInput.value);
assertFalse(!!getAddressFieldValue(address, FieldType.EMAIL_ADDRESS));
const phoneNumber = '(555) 555-5555';
const emailAddress = '[email protected]';
phoneInput.value = phoneNumber;
emailInput.value = emailAddress;
await Promise.all([phoneInput.updateComplete, emailInput.updateComplete]);
await expectEvent(dialog, 'save-address', function() {
dialog.$.saveButton.click();
});
assertEquals(phoneNumber, phoneInput.value);
assertEquals(
phoneNumber,
getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER));
assertEquals(emailAddress, emailInput.value);
assertEquals(
emailAddress, getAddressFieldValue(address, FieldType.EMAIL_ADDRESS));
});
test('verifyPhoneAndEmailAreRemoved', function() {
const address = createEmptyAddressEntry();
const phoneNumber = '(555) 555-5555';
const emailAddress = '[email protected]';
address.fields.push({
type: FieldType.ADDRESS_HOME_COUNTRY,
value: 'US',
}); // Set to allow save to be active.
address.fields.push({
type: FieldType.PHONE_HOME_WHOLE_NUMBER,
value: phoneNumber,
});
address.fields.push({type: FieldType.EMAIL_ADDRESS, value: emailAddress});
return createAddressDialog(address).then(async function(dialog) {
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertGT(rows.length, 0, 'dialog should contain address rows');
const lastRow = rows[rows.length - 1]!;
const phoneInput =
lastRow.querySelector<CrInputElement>('cr-input:nth-of-type(1)');
const emailInput =
lastRow.querySelector<CrInputElement>('cr-input:nth-of-type(2)');
assertTrue(!!phoneInput, 'phone element should be the first cr-input');
assertTrue(!!emailInput, 'email element should be the second cr-input');
assertEquals(
phoneNumber, phoneInput.value,
'The input should have the corresponding address field value.');
assertEquals(
emailAddress, emailInput.value,
'The input should have the corresponding address field value.');
phoneInput.value = '';
emailInput.value = '';
await flushTasks();
return expectEvent(dialog, 'save-address', function() {
dialog.$.saveButton.click();
}).then(function() {
assertFalse(
!!getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER),
'The phone field should be empty.');
assertFalse(
!!getAddressFieldValue(address, FieldType.EMAIL_ADDRESS),
'The email field should be empty.');
});
});
});
// Test will set a value of 'foo' in each text field and verify that the
// save button is enabled, then it will clear the field and verify that the
// save button is disabled. Test passes after all elements have been tested.
test('verifySaveIsNotClickableIfAllInputFieldsAreEmpty', async function() {
const dialog = await createAddressDialog(createEmptyAddressEntry());
const saveButton = dialog.$.saveButton;
const testElements =
dialog.$.dialog.querySelectorAll<CrTextareaElement|CrInputElement>(
'cr-textarea, cr-input');
// The country can be preselected. Clear it to ensure the form is empty.
await expectEvent(dialog, 'on-update-can-save', function() {
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
countrySelect.value = '';
countrySelect.dispatchEvent(new CustomEvent('change'));
});
assertEquals(
6, testElements.length,
'There should be 6 elements: The 4 fields from ' +
'`ADDRESS_COMPONENTS_US` + phone + email that are added ' +
'separately.');
assertTrue(saveButton.disabled);
for (const element of testElements) {
await expectEvent(dialog, 'on-update-can-save', function() {
element.value = 'foo';
});
assertFalse(saveButton.disabled);
await expectEvent(dialog, 'on-update-can-save', function() {
element.value = '';
});
assertTrue(saveButton.disabled);
}
});
// Setting the country should allow the address to be saved.
test('verifySaveIsNotClickableIfCountryNotSet', async function() {
function simulateCountryChange(countryCode: string) {
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
countrySelect.value = countryCode;
countrySelect.dispatchEvent(new CustomEvent('change'));
}
const dialog = await createAddressDialog(createEmptyAddressEntry());
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
// A country code is preselected.
assertFalse(dialog.$.saveButton.disabled);
assertEquals(countrySelect.value, 'US');
await expectEvent(
dialog, 'on-update-can-save', simulateCountryChange.bind(null, 'GB'));
assertFalse(dialog.$.saveButton.disabled);
await expectEvent(
dialog, 'on-update-can-save', simulateCountryChange.bind(null, ''));
assertTrue(dialog.$.saveButton.disabled);
});
// Test will timeout if save-address event is not fired.
test('verifyDefaultCountryIsAppliedWhenSaving', function() {
const address = createEmptyAddressEntry();
address.fields.push({type: FieldType.NAME_FULL, value: 'Name'});
return createAddressDialog(address).then(function(dialog) {
return expectEvent(dialog, 'save-address', function() {
// Verify |countryCode| is not set.
assertEquals(
undefined,
getAddressFieldValue(
address, FieldType.ADDRESS_HOME_COUNTRY));
dialog.$.saveButton.click();
}).then(function(_event) {
// 'US' is the default country for these tests.
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
assertEquals('US', countrySelect.value);
});
});
});
test(
'verifyNoSaveAddressEventWhenEditDialogCancelButtonIsClicked',
function(done) {
createAddressDialog(createAddressEntry()).then(function(dialog) {
eventToPromise('save-address', dialog).then(function() {
// Fail the test because the save event should not be fired when
// the cancel is clicked.
assertTrue(true);
});
eventToPromise('cancel', dialog).then(function() {
// Test is |done| in a timeout in order to ensure that
// 'save-address' is NOT fired after this test.
assertEquals(
1,
metricsTracker.count('Autofill.Settings.EditAddress', false));
window.setTimeout(done, 100);
});
dialog.$.cancelButton.click();
});
});
test('verifyNoCancelEventWhenEditDialogSaveButtonIsClicked', function(done) {
createAddressDialog(createAddressEntry()).then(function(dialog) {
eventToPromise('cancel', dialog).then(function() {
// Fail the test because the cancel event should not be fired when
// the save is clicked.
assertTrue(false);
});
eventToPromise('save-address', dialog).then(function() {
// Test is |done| in a timeout in order to ensure that
// 'save-address' is NOT fired after this test.
assertEquals(
1, metricsTracker.count('Autofill.Settings.EditAddress', true));
window.setTimeout(done, 100);
});
dialog.$.saveButton.click();
});
});
test('verifySyncRecordTypeNoticeForNewAddress', async () => {
const section = await createAutofillSection([], {}, {
...STUB_USER_ACCOUNT_INFO,
email: '[email protected]',
isSyncEnabledForAutofillProfiles: true,
isEligibleForAddressAccountStorage: false,
});
const dialog = await openAddressDialog(section);
assertTrue(
!isVisible(dialog.$.accountRecordTypeNotice),
'account notice should be invisible for non-account address');
document.body.removeChild(section);
});
test('verifyAccountRecordTypeNoticeForNewAddress', async () => {
const email = '[email protected]';
const section = await createAutofillSection([], {}, {
...STUB_USER_ACCOUNT_INFO,
email,
isSyncEnabledForAutofillProfiles: true,
isEligibleForAddressAccountStorage: true,
});
const dialog = await openAddressDialog(section);
assertTrue(
isVisible(dialog.$.accountRecordTypeNotice),
'account notice should be visible as the user is eligible');
assertEquals(
dialog.$.accountRecordTypeNotice.innerText,
section.i18n('newAccountAddressRecordTypeNotice', email));
document.body.removeChild(section);
});
// TODO(crbug.com/40943238): Remove when toggle becomes available on the Sync
// page for non-syncing users.
test('verifyAutofillSyncToggleAvailability', async () => {
const autofillManager = new TestAutofillManager();
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isAutofillSyncToggleAvailable: false,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
assertFalse(
isVisible(section.$.autofillSyncToggle),
'The toggle should not be visible because of ' +
'accountInfo.isAutofillSyncToggleAvailable == false');
const changeListener =
autofillManager.lastCallback.setPersonalDataManagerListener;
assertTrue(
!!changeListener,
'PersonalDataChangedListener should be set in the section element');
// Imitate native code `PersonalDataChangedListener` triggering.
changeListener([], [], [], [], {
...STUB_USER_ACCOUNT_INFO,
isAutofillSyncToggleAvailable: true,
isAutofillSyncToggleEnabled: false,
});
await flushTasks();
assertTrue(
isVisible(section.$.autofillSyncToggle),
'The toggle should be visible because of ' +
'accountInfo.isAutofillSyncToggleAvailable == true');
assertFalse(
section.$.autofillSyncToggle.checked,
'The toggle should not be checked because of ' +
'accountInfo.isAutofillSyncToggleEnabled == false');
// Imitate native code `PersonalDataChangedListener` triggering.
changeListener([], [], [], [], {
...STUB_USER_ACCOUNT_INFO,
isAutofillSyncToggleAvailable: true,
isAutofillSyncToggleEnabled: true,
});
await flushTasks();
assertTrue(
isVisible(section.$.autofillSyncToggle),
'The toggle should be visible because of ' +
'accountInfo.isAutofillSyncToggleAvailable == true');
assertTrue(
section.$.autofillSyncToggle.checked,
'The toggle should be checked because of ' +
'accountInfo.isAutofillSyncToggleEnabled == true');
});
// TODO(crbug.com/40943238): Remove as part of the cleanup work for the ticket.
test('verifyAutofillSyncToggleChanges', async () => {
const autofillManager = new TestAutofillManager();
autofillManager.data.accountInfo = {
...STUB_USER_ACCOUNT_INFO,
isAutofillSyncToggleAvailable: true,
isAutofillSyncToggleEnabled: false,
};
AutofillManagerImpl.setInstance(autofillManager);
const section = document.createElement('settings-autofill-section');
document.body.appendChild(section);
await autofillManager.whenCalled('getAddressList');
await flushTasks();
const changeListener =
autofillManager.lastCallback.setPersonalDataManagerListener;
assertTrue(
!!changeListener,
'PersonalDataChangedListener should be set in the section element');
assertFalse(
section.$.autofillSyncToggle.checked,
'The toggle should not be checked because of initial ' +
'accountInfo.isAutofillSyncToggleEnabled == false');
section.$.autofillSyncToggle.click();
await section.$.autofillSyncToggle.updateComplete;
assertTrue(
section.$.autofillSyncToggle.checked,
'The toggle should be checked after the click.');
assertEquals(
autofillManager.getCallCount('setAutofillSyncToggleEnabled'), 1);
section.$.autofillSyncToggle.click();
await section.$.autofillSyncToggle.updateComplete;
assertFalse(
section.$.autofillSyncToggle.checked,
'The toggle should not be checked after another click.');
assertEquals(
autofillManager.getCallCount('setAutofillSyncToggleEnabled'), 2);
// Imitate native code `PersonalDataChangedListener` triggering. Notice
// that it was unchecked after the second click, but the listener was
// given `true`, the following assert checks it an covers the case when
// the toggle was not updated in the native code for some reason.
changeListener([], [], [], [], {
...STUB_USER_ACCOUNT_INFO,
isAutofillSyncToggleAvailable: true,
isAutofillSyncToggleEnabled: true,
});
await flushTasks();
assertTrue(
section.$.autofillSyncToggle.checked,
'The toggle should be checked because of ' +
'accountInfo.isAutofillSyncToggleEnabled == true');
});
});
suite('AutofillSectionAddressLocaleTests', function() {
let countryDetailManager: TestCountryDetailManagerProxy;
setup(function() {
document.body.innerHTML = window.trustedTypes!.emptyHTML;
countryDetailManager = new TestCountryDetailManagerProxy();
CountryDetailManagerProxyImpl.setInstance(countryDetailManager);
countryDetailManager.setGetCountryListRepsonse([
{name: 'United States', countryCode: 'US'}, // Default country.
{name: 'Israel', countryCode: 'IL'},
{name: 'United Kingdom', countryCode: 'GB'},
]);
countryDetailManager.setGetAddressFormatRepsonse(ADDRESS_COMPONENTS_US);
});
// US address has 3 fields on the same line.
test('verifyEditingUSAddress', function() {
const address = createEmptyAddressEntry();
address.fields = [
{type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'},
{type: FieldType.NAME_FULL, value: 'Name'},
{type: FieldType.ADDRESS_HOME_CITY, value: 'City'},
{type: FieldType.ADDRESS_HOME_STATE, value: 'State'},
{type: FieldType.ADDRESS_HOME_ZIP, value: 'ZIP code'},
{type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'},
{type: FieldType.EMAIL_ADDRESS, value: 'Email'},
];
return createAddressDialog(address).then(function(dialog) {
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertEquals(
4, rows.length,
'There should be 4 rows: Country, Name, City + State + Zip, ' +
'Phone + Email');
let index = 0;
// Country
let row = rows[index]!;
const countrySelect = row.querySelector('select');
assertTrue(!!countrySelect);
assertEquals(
'United States',
countrySelect.selectedOptions[0]!.textContent.trim());
index++;
// Name
row = rows[index]!;
let cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.NAME_FULL), cols[0]!.value);
index++;
// City, State, ZIP code
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(3, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY),
cols[0]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_STATE),
cols[1]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP),
cols[2]!.value);
index++;
// Phone, Email
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER),
cols[0]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.EMAIL_ADDRESS),
cols[1]!.value);
});
});
// GB address has 1 field per line for all lines that change.
test('verifyEditingGBAddress', function() {
const address = createEmptyAddressEntry();
address.fields = [
{type: FieldType.ADDRESS_HOME_COUNTRY, value: 'GB'},
{type: FieldType.NAME_FULL, value: 'Name'},
{type: FieldType.ADDRESS_HOME_CITY, value: 'Post town'},
{type: FieldType.ADDRESS_HOME_ZIP, value: 'Postal code'},
{type: FieldType.ADDRESS_HOME_STATE, value: 'County'},
{type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'},
{type: FieldType.EMAIL_ADDRESS, value: 'Email'},
];
countryDetailManager.setGetAddressFormatRepsonse(ADDRESS_COMPONENTS_GB);
return createAddressDialog(address).then(function(dialog) {
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertEquals(
6, rows.length,
'There should be 6 rows: Country, Name, City, Zip, State, ' +
'Phone + Email');
let index = 0;
// Country
let row = rows[index]!;
const countrySelect = row.querySelector('select');
assertTrue(!!countrySelect);
assertEquals(
'United Kingdom',
countrySelect.selectedOptions[0]!.textContent.trim());
index++;
// Name
row = rows[index]!;
let cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.NAME_FULL), cols[0]!.value);
index++;
// Post Town
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY),
cols[0]!.value);
index++;
// Postal code
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP),
cols[0]!.value);
index++;
// County
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_STATE),
cols[0]!.value);
index++;
// Phone, Email
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER),
cols[0]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.EMAIL_ADDRESS),
cols[1]!.value);
});
});
// IL address has 2 fields on the same line and is an RTL locale.
// RTL locale shouldn't affect this test.
test('verifyEditingILAddress', function() {
const address = createEmptyAddressEntry();
address.fields = [
{type: FieldType.ADDRESS_HOME_COUNTRY, value: 'IL'},
{type: FieldType.NAME_FULL, value: 'Name'},
{type: FieldType.ADDRESS_HOME_CITY, value: 'City'},
{type: FieldType.ADDRESS_HOME_ZIP, value: 'Postal code'},
{type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'},
{type: FieldType.EMAIL_ADDRESS, value: 'Email'},
];
countryDetailManager.setGetAddressFormatRepsonse(ADDRESS_COMPONENTS_IL);
return createAddressDialog(address).then(function(dialog) {
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertEquals(
4, rows.length,
'There should be 4 rows: Country, Name, City + Zip, Phone + Email');
let index = 0;
// Country
let row = rows[index]!;
const countrySelect = row.querySelector('select');
assertTrue(!!countrySelect);
assertEquals(
'Israel', countrySelect.selectedOptions[0]!.textContent.trim());
index++;
// Name
row = rows[index]!;
let cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.NAME_FULL)!, cols[0]!.value);
index++;
// City, Postal code
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY),
cols[0]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP),
cols[1]!.value);
index++;
// Phone, Email
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER),
cols[0]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.EMAIL_ADDRESS),
cols[1]!.value);
});
});
// Testing address edit dialog in an RTL layout by setting the document
// direction to 'rtl'. The phone number input should have direction=ltr and
// text-align=end.
test('verifyEditingILAddressWithRtlLayout', function() {
document.documentElement.dir = 'rtl';
const address = createEmptyAddressEntry();
address.fields = [
{type: FieldType.ADDRESS_HOME_COUNTRY, value: 'IL'},
{type: FieldType.NAME_FULL, value: 'Name'},
{type: FieldType.ADDRESS_HOME_CITY, value: 'City'},
{type: FieldType.ADDRESS_HOME_ZIP, value: 'Postal code'},
{type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'},
{type: FieldType.EMAIL_ADDRESS, value: 'Email'},
];
countryDetailManager.setGetAddressFormatRepsonse(ADDRESS_COMPONENTS_IL);
return createAddressDialog(address).then(function(dialog) {
const rows = dialog.$.dialog.querySelectorAll('.address-row');
// There should be 4 rows: Country, Name, City + Zip, Phone + Email
assertEquals(4, rows.length);
let index = 0;
// Country
let row = rows[index]!;
const countrySelect = row.querySelector('select');
assertTrue(!!countrySelect);
assertEquals(
'Israel', countrySelect.selectedOptions[0]!.textContent.trim());
index++;
// Name
row = rows[index]!;
let cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(1, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.NAME_FULL)!, cols[0]!.value);
index++;
// City, Postal code
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY),
cols[0]!.value);
assertEquals(
getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP),
cols[1]!.value);
index++;
// Phone, Email
row = rows[index]!;
cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(
getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER),
cols[0]!.value);
assertTrue(cols[0]!.classList.contains('phone-number-input'));
const phoneInput = (cols[0]! as CrInputElement).inputElement;
assertEquals(
'ltr',
(phoneInput.computedStyleMap().get('direction') as CSSUnitValue)
.value);
assertEquals(
'end',
(phoneInput.computedStyleMap().get('text-align') as CSSUnitValue)
.value);
assertEquals(
getAddressFieldValue(address, FieldType.EMAIL_ADDRESS),
cols[1]!.value);
});
});
// US has an extra field 'State'. Validate that this field is
// persisted when switching to IL then back to US.
test('verifyAddressPersistanceWhenSwitchingCountries', function() {
const address = createEmptyAddressEntry();
address.fields.push({type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'});
return createAddressDialog(address).then(function(dialog) {
const city = 'Los Angeles';
const state = 'CA';
const zip = '90291';
const countrySelect = dialog.$.country;
assertTrue(!!countrySelect);
return expectEvent(
dialog, 'on-update-address-wrapper',
function() {
// US:
const rows =
dialog.$.dialog.querySelectorAll('.address-row');
assertEquals(
4, rows.length,
'There should be 4 rows: Country, Name, City + State ' +
'+ Zip, Phone + Email');
// City, State, ZIP code
const row = rows[2]!;
const cols =
row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(3, cols.length);
cols[0]!.value = city;
cols[1]!.value = state;
cols[2]!.value = zip;
countryDetailManager.setGetAddressFormatRepsonse(
ADDRESS_COMPONENTS_IL);
countrySelect.value = 'IL';
countrySelect.dispatchEvent(new CustomEvent('change'));
})
.then(function() {
return expectEvent(dialog, 'on-update-address-wrapper', function() {
// IL:
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertEquals(
4, rows.length,
'There should be 4 rows: Country, Name, City + Zip, ' +
'Phone + Email');
// City, Postal code
const row = rows[2]!;
const cols =
row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(2, cols.length);
assertEquals(city, cols[0]!.value);
assertEquals(zip, cols[1]!.value);
countryDetailManager.setGetAddressFormatRepsonse(
ADDRESS_COMPONENTS_US);
countrySelect.value = 'US';
countrySelect.dispatchEvent(new CustomEvent('change'));
});
})
.then(function() {
// US:
const rows = dialog.$.dialog.querySelectorAll('.address-row');
assertEquals(
4, rows.length,
'There should be 4 rows: Country, Name, City + State + Zip, ' +
'Phone + Email');
// City, State, ZIP code
const row = rows[2]!;
const cols = row.querySelectorAll<CrTextareaElement|CrInputElement>(
'.address-column');
assertEquals(3, cols.length);
assertEquals(city, cols[0]!.value);
assertEquals(state, cols[1]!.value);
assertEquals(zip, cols[2]!.value);
});
});
});
});
suite('PlusAddressesTest', function() {
const fakeUrl = 'https://foo.bar';
let metrics: MetricsTracker;
let openWindowProxy: TestOpenWindowProxy;
setup(function() {
metrics = fakeMetricsPrivate();
openWindowProxy = new TestOpenWindowProxy();
OpenWindowProxyImpl.setInstance(openWindowProxy);
loadTimeData.overrideValues({
// Required to show the plus address management entry.
plusAddressEnabled: true,
plusAddressManagementUrl: fakeUrl,
});
});
test('verifyPlusAddressManagementEntryExistence', async function() {
const autofillSection = await createAutofillSection([], {});
const plusAddressButton =
autofillSection.shadowRoot!.querySelector<CrLinkRowElement>(
'#plusAddressSettingsButton');
assertTrue(!!plusAddressButton);
autofillSection.remove();
});
test(
'verifyPlusAddressManagementEntryExistenceWhenNotEnabled',
async function() {
loadTimeData.overrideValues({
plusAddressEnabled: false,
});
const autofillSection = await createAutofillSection([], {});
const plusAddressButton =
autofillSection.shadowRoot!.querySelector<CrLinkRowElement>(
'#plusAddressSettingsButton');
assertFalse(!!plusAddressButton);
autofillSection.remove();
});
test(
'verifyClickingPlusAddressManagementEntryOpensWebsite', async function() {
const autofillSection = await createAutofillSection([], {});
const plusAddressButton =
autofillSection.shadowRoot!.querySelector<CrLinkRowElement>(
'#plusAddressSettingsButton');
assertTrue(!!plusAddressButton);
// Validate that, when present, the button results in opening the URL
// passed in via the `loadTimeData` override.
plusAddressButton.click();
const url = await openWindowProxy.whenCalled('openUrl');
assertEquals(url, fakeUrl);
assertEquals(
1, metrics.count('Settings.ManageOptionOnSettingsSelected'));
autofillSection.remove();
});
});