// 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.
import 'chrome://os-settings/lazy_load.js';
import {CellularRoamingToggleButtonElement, NetworkProxySectionElement, PasspointRemoveDialogElement, SettingsInternetDetailPageElement} from 'chrome://os-settings/lazy_load.js';
import {CrDialogElement, CrLinkRowElement, InternetPageBrowserProxyImpl, LocalizedLinkElement, Router, routes, settingMojom, SettingsToggleButtonElement, setUserActionRecorderForTesting, userActionRecorderMojom} from 'chrome://os-settings/os_settings.js';
import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
import {PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {NetworkApnListElement} from 'chrome://resources/ash/common/network/network_apnlist.js';
import {NetworkChooseMobileElement} from 'chrome://resources/ash/common/network/network_choose_mobile.js';
import {NetworkConfigToggleElement} from 'chrome://resources/ash/common/network/network_config_toggle.js';
import {NetworkIpConfigElement} from 'chrome://resources/ash/common/network/network_ip_config.js';
import {NetworkNameserversElement} from 'chrome://resources/ash/common/network/network_nameservers.js';
import {NetworkPropertyListMojoElement} from 'chrome://resources/ash/common/network/network_property_list_mojo.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {getDeepActiveElement} from 'chrome://resources/js/util.js';
import {ActivationStateType, ApnAuthenticationType, ApnIpType, ApnSource, ApnState, DeviceStateProperties, GlobalPolicy, InhibitReason, ManagedOpenVPNProperties, ManagedProperties, MatchType, NetworkStateProperties, ProxyMode, SuppressionType, VpnType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ConnectionStateType, DeviceStateType, IPConfigType, NetworkType, OncSource, PolicySource, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {assertEquals, assertFalse, assertNotEquals, assertNull, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
import {FakePasspointService} from 'chrome://webui-test/chromeos/fake_passpoint_service_mojom.js';
import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';
import {FakeUserActionRecorder} from '../fake_user_action_recorder.js';
import {TestInternetPageBrowserProxy} from './test_internet_page_browser_proxy.js';
suite('<settings-internet-detail-subpage>', () => {
let internetDetailPage: SettingsInternetDetailPageElement;
let mojoApi: FakeNetworkConfig;
let passpointServiceApi: FakePasspointService;
let browserProxy: TestInternetPageBrowserProxy;
let userActionRecorder: userActionRecorderMojom.UserActionRecorderInterface;
const CELLULAR_SIM_LOCK_SETTING =
settingMojom.Setting.kCellularSimLock.toString();
const PREFS = {
'vpn_config_allowed': {
key: 'vpn_config_allowed',
type: chrome.settingsPrivate.PrefType.BOOLEAN,
value: true,
},
'cros': {
'signed': {
'data_roaming_enabled': {
key: 'data_roaming_enabled',
value: true,
controlledBy: chrome.settingsPrivate.ControlledBy.DEVICE_POLICY,
},
},
},
// Added use_shared_proxies and lacros_proxy_controlling_extension because
// triggering a change in PREFS without it will fail a "Pref is missing"
// assertion in the network-proxy-section
'settings': {
'use_shared_proxies': {
key: 'use_shared_proxies',
type: chrome.settingsPrivate.PrefType.BOOLEAN,
value: true,
},
},
'ash': {
'lacros_proxy_controlling_extension': {
key: 'ash.lacros_proxy_controlling_extension',
type: chrome.settingsPrivate.PrefType.DICTIONARY,
value: {},
},
},
};
suiteSetup(() => {
mojoApi = new FakeNetworkConfig();
MojoInterfaceProviderImpl.getInstance().setMojoServiceRemoteForTest(
mojoApi);
passpointServiceApi = new FakePasspointService();
MojoConnectivityProvider.getInstance().setPasspointServiceForTest(
passpointServiceApi);
});
function setNetworksForTest(networks: NetworkStateProperties[]): void {
mojoApi.resetForTest();
mojoApi.addNetworksForTest(networks);
}
function setSubscriptionForTest(subscription: PasspointSubscription): void {
passpointServiceApi.resetForTest();
passpointServiceApi.addSubscription(subscription);
}
function getAllowSharedProxy(): SettingsToggleButtonElement {
const allowShared =
internetDetailPage.shadowRoot!.querySelector('network-proxy-section')!
.shadowRoot!.querySelector<SettingsToggleButtonElement>(
'#allowShared');
assertTrue(!!allowShared);
return allowShared;
}
function getButton(buttonId: string): HTMLButtonElement {
const button =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
`#${buttonId}`);
assertTrue(!!button);
return button;
}
function getPasspointRemoveDialog(): PasspointRemoveDialogElement {
const dialog = internetDetailPage.shadowRoot!
.querySelector<PasspointRemoveDialogElement>(
'#passpointRemovalDialog');
assertTrue(!!dialog);
return dialog;
}
function getManagedProperties(
networkType: NetworkType, name: string,
source?: OncSource): ManagedProperties {
const result =
OncMojo.getDefaultManagedProperties(networkType, name + '_guid', name);
if (source) {
result.source = source;
}
return result;
}
function getHiddenToggle(): SettingsToggleButtonElement|null {
return internetDetailPage.shadowRoot!.querySelector('#hiddenToggle');
}
/**
* @param doNotProvidePrefs If provided, determine whether
* prefs should be provided for the element.
*/
function init(doNotProvidePrefs?: boolean): void {
internetDetailPage =
document.createElement('settings-internet-detail-subpage');
assertTrue(!!internetDetailPage);
if (!doNotProvidePrefs) {
internetDetailPage.prefs = PREFS;
}
document.body.appendChild(internetDetailPage);
}
function getDefaultDeviceStateProps(): DeviceStateProperties {
return {
ipv4Address: undefined,
ipv6Address: undefined,
imei: undefined,
macAddress: undefined,
scanning: false,
simLockStatus: undefined,
simInfos: undefined,
inhibitReason: InhibitReason.kNotInhibited,
simAbsent: false,
deviceState: DeviceStateType.kUninitialized,
type: NetworkType.kCellular,
managedNetworkAvailable: false,
serial: undefined,
isCarrierLocked: false,
isFlashing: false,
};
}
async function deepLinkToSimLockElement(isSimLocked: boolean): Promise<void> {
init();
const TEST_ICCID = '11111111111111111';
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simLockStatus: {
lockEnabled: true,
lockType: isSimLocked ? 'sim-pin' : '',
retriesLeft: 0,
},
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = false;
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
const params = new URLSearchParams();
params.append('guid', 'cellular_guid');
params.append('type', 'Cellular');
params.append('name', 'cellular');
params.append('settingId', CELLULAR_SIM_LOCK_SETTING);
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await flushTasks();
}
setup(async () => {
userActionRecorder = new FakeUserActionRecorder();
setUserActionRecorderForTesting(userActionRecorder);
loadTimeData.overrideValues({
internetAddConnection: 'internetAddConnection',
internetAddConnectionExpandA11yLabel:
'internetAddConnectionExpandA11yLabel',
internetAddConnectionNotAllowed: 'internetAddConnectionNotAllowed',
internetAddThirdPartyVPN: 'internetAddThirdPartyVPN',
internetAddVPN: 'internetAddVPN',
internetAddWiFi: 'internetAddWiFi',
internetDetailPageTitle: 'internetDetailPageTitle',
internetKnownNetworksPageTitle: 'internetKnownNetworksPageTitle',
showMeteredToggle: true,
});
mojoApi.resetForTest();
browserProxy = new TestInternetPageBrowserProxy();
InternetPageBrowserProxyImpl.setInstance(browserProxy);
await flushTasks();
});
teardown(() => {
internetDetailPage.close();
internetDetailPage.remove();
browserProxy.reset();
mojoApi.resetForTest();
passpointServiceApi.resetForTest();
Router.getInstance().resetRouteForTesting();
});
function getDefaultGlobalPolicy(): GlobalPolicy {
return {
allowApnModification: false,
allowOnlyPolicyWifiNetworksToConnect: false,
allowCellularSimLock: false,
allowCellularHotspot: false,
allowOnlyPolicyCellularNetworks: false,
allowOnlyPolicyNetworksToAutoconnect: false,
allowOnlyPolicyWifiNetworksToConnectIfAvailable: false,
dnsQueriesMonitored: false,
reportXdrEventsEnabled: false,
blockedHexSsids: [],
recommendedValuesAreEphemeral: false,
userCreatedNetworkConfigurationsAreEphemeral: false,
allowTextMessages: SuppressionType.kUnset,
};
}
suite('DetailsPageWiFi', () => {
test('LoadPage', () => {
init();
});
test('WiFi1', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi1'),
]);
internetDetailPage.init('wifi1_guid', 'WiFi', 'wifi1');
assertEquals('wifi1_guid', internetDetailPage.guid);
await flushTasks();
await mojoApi.whenCalled('getManagedProperties');
});
// Sanity test for the suite setup. Makes sure that re-opening the details
// page with a different network also succeeds.
test('WiFi2', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi2'),
]);
internetDetailPage.init('wifi2_guid', 'WiFi', 'wifi2');
assertEquals('wifi2_guid', internetDetailPage.guid);
await flushTasks();
await mojoApi.whenCalled('getManagedProperties');
});
test('Connect button disabled when WiFi is out of range', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork =
getManagedProperties(NetworkType.kWiFi, 'out_of_range_wifi');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
mojoApi.setWifiNetworkVisibleForTest('out_of_range_wifi_guid', false);
internetDetailPage.init(
'out_of_range_wifi_guid', 'WiFi', 'out_of_range_wifi');
await flushTasks();
const connectButton = getButton('connectDisconnect');
assertFalse(connectButton.hidden);
assertTrue(connectButton.disabled);
});
test(
'Connect button enabled on hidden network even when WiFi is out' +
' of range',
async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(
NetworkType.kWiFi, 'out_of_range_hidden_wifi');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.hiddenSsid =
OncMojo.createManagedBool(true);
mojoApi.setManagedPropertiesForTest(wifiNetwork);
mojoApi.setWifiNetworkVisibleForTest(
'out_of_range_hidden_wifi_guid', false);
internetDetailPage.init(
'out_of_range_hidden_wifi_guid', 'WiFi',
'out_of_range_hidden_wifi');
await flushTasks();
const connectButton = getButton('connectDisconnect');
assertFalse(connectButton.hidden);
assertFalse(connectButton.disabled);
});
test('WiFi in a portal portalState', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.connectionState = ConnectionStateType.kPortal;
wifiNetwork.portalState = PortalState.kPortal;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const networkStateText =
internetDetailPage.shadowRoot!.querySelector('#networkState');
assertTrue(!!networkStateText);
assertTrue(networkStateText.hasAttribute('warning'));
assertEquals(
internetDetailPage.i18n('networkListItemSignIn'),
networkStateText.textContent!.trim());
const signinButton = getButton('signinButton');
assertTrue(!!signinButton);
assertFalse(signinButton.hidden);
assertFalse(signinButton.disabled);
});
test('WiFi in a portal-suspected portalState', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.connectionState = ConnectionStateType.kPortal;
wifiNetwork.portalState = PortalState.kPortalSuspected;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const networkStateText =
internetDetailPage.shadowRoot!.querySelector('#networkState');
assertTrue(!!networkStateText);
assertTrue(networkStateText.hasAttribute('warning'));
assertEquals(
internetDetailPage.i18n('networkListItemSignIn'),
networkStateText.textContent!.trim());
const signinButton = getButton('signinButton');
assertTrue(!!signinButton);
assertFalse(signinButton.hidden);
assertFalse(signinButton.disabled);
});
test('WiFi in a no internet portalState', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.connectionState = ConnectionStateType.kPortal;
wifiNetwork.portalState = PortalState.kNoInternet;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const networkStateText =
internetDetailPage.shadowRoot!.querySelector('#networkState');
assertTrue(!!networkStateText);
assertTrue(networkStateText.hasAttribute('warning'));
assertEquals(
internetDetailPage.i18n('networkListItemConnectedNoConnectivity'),
networkStateText.textContent!.trim());
const signinButton = getButton('signinButton');
assertTrue(!!signinButton);
assertTrue(signinButton.hidden);
assertTrue(signinButton.disabled);
});
test('Hidden toggle enabled', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.hiddenSsid =
OncMojo.createManagedBool(true);
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const hiddenToggle = getHiddenToggle();
assertTrue(!!hiddenToggle);
assertTrue(hiddenToggle.checked);
});
test('Hidden toggle disabled', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.hiddenSsid =
OncMojo.createManagedBool(false);
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const hiddenToggle = getHiddenToggle();
assertTrue(!!hiddenToggle);
assertFalse(hiddenToggle.checked);
});
test('Hidden toggle hidden when not configured', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.connectable = false;
wifiNetwork.typeProperties.wifi!.hiddenSsid =
OncMojo.createManagedBool(false);
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const hiddenToggle = getHiddenToggle();
assertNull(hiddenToggle);
});
test('Hidden toggle hidden for non-WiFi networks', async () => {
init();
for (const networkType
of [NetworkType.kCellular, NetworkType.kEthernet,
NetworkType.kTether, NetworkType.kVPN]) {
mojoApi.setNetworkTypeEnabledState(networkType, true);
const networkTypeString = OncMojo.getNetworkTypeString(networkType);
const networkGuid = 'network_guid_' + networkTypeString;
const networkName = 'network_name_' + networkTypeString;
const network = getManagedProperties(networkType, networkName);
mojoApi.setManagedPropertiesForTest(network);
internetDetailPage.init(networkGuid, networkTypeString, networkName);
await flushTasks();
const hiddenToggle = getHiddenToggle();
assertNull(hiddenToggle);
}
});
test('Proxy Unshared', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
await flushTasks();
const proxySection =
internetDetailPage.shadowRoot!.querySelector('network-proxy-section');
assertTrue(!!proxySection);
const allowShared =
proxySection.shadowRoot!.querySelector<SettingsToggleButtonElement>(
'#allowShared');
assertTrue(!!allowShared);
assertTrue(allowShared.hidden);
});
test('Proxy Shared', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(
NetworkType.kWiFi, 'wifi_device', OncSource.kDevice);
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_device_guid', 'WiFi', 'wifi_device');
await flushTasks();
const allowShared = getAllowSharedProxy();
assertFalse(allowShared.hidden);
assertFalse(allowShared.disabled);
});
// When proxy settings are managed by a user policy but the configuration
// is from the shared (device) profile, they still respect the
// allowed_shared_proxies pref so #allowShared should be visible.
// TODO(stevenjb): Improve this: crbug.com/662529.
test('Proxy Shared User Managed', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(
NetworkType.kWiFi, 'wifi_device', OncSource.kDevice);
wifiNetwork.proxySettings = {
type: {
activeValue: 'Manual',
policySource: PolicySource.kUserPolicyEnforced,
policyValue: '',
},
manual: undefined,
excludeDomains: undefined,
pac: undefined,
};
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_device_guid', 'WiFi', 'wifi_device');
await flushTasks();
const allowShared = getAllowSharedProxy();
assertFalse(allowShared.hidden);
assertFalse(allowShared.disabled);
});
// When proxy settings are managed by a device policy they may respect the
// allowd_shared_proxies pref so #allowShared should be visible.
test('Proxy Shared Device Managed', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(
NetworkType.kWiFi, 'wifi_device', OncSource.kDevice);
wifiNetwork.proxySettings = {
type: {
activeValue: 'Manual',
policySource: PolicySource.kDevicePolicyEnforced,
policyValue: '',
},
manual: undefined,
excludeDomains: undefined,
pac: undefined,
};
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_device_guid', 'WiFi', 'wifi_device');
await flushTasks();
const allowShared = getAllowSharedProxy();
assertFalse(allowShared.hidden);
assertFalse(allowShared.disabled);
});
// Tests that when the route changes to one containing a deep link to
// the shared proxy toggle, toggle is focused.
test('Deep link to shared proxy toggle', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(
NetworkType.kWiFi, 'wifi_device', OncSource.kDevice);
mojoApi.setManagedPropertiesForTest(wifiNetwork);
const WIFI_PROXY_SETTING = settingMojom.Setting.kWifiProxy.toString();
const params = new URLSearchParams();
params.append('guid', 'wifi_device_guid');
params.append('type', 'WiFi');
params.append('name', 'wifi_device');
params.append('settingId', WIFI_PROXY_SETTING);
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await flushTasks();
const networkProxyElement =
internetDetailPage.shadowRoot!.querySelector('network-proxy-section');
assertTrue(!!networkProxyElement);
const allowShared =
networkProxyElement.shadowRoot!.querySelector('#allowShared');
assertTrue(!!allowShared);
const deepLinkElement =
allowShared.shadowRoot!.querySelector<HTMLElement>('#control');
assertTrue(!!deepLinkElement);
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
`Allow shared proxy toggle should be focused for settingId=${
WIFI_PROXY_SETTING}.`);
// Close the page to ensure the test is fully cleaned up and wait for
// os_route's popstate listener to fire. If we don't add this wait, this
// event can fire during the other tests which may interfere with its
// routing.
const popStatePromise = eventToPromise('popstate', window);
internetDetailPage.close();
await popStatePromise;
});
test('WiFi page disabled when blocked by policy', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_user_guid', 'WiFi', 'wifi_user');
internetDetailPage.globalPolicy = {
...getDefaultGlobalPolicy(),
allowOnlyPolicyWifiNetworksToConnect: true,
};
await flushTasks();
const connectDisconnectButton = getButton('connectDisconnect');
assertTrue(connectDisconnectButton.hidden);
assertTrue(connectDisconnectButton.disabled);
assertNull(internetDetailPage.shadowRoot!.querySelector('#infoFields'));
const configureButton = getButton('configureButton');
assertTrue(configureButton.hidden);
const advancedFields = getButton('advancedFields');
assertFalse(advancedFields.disabled);
assertFalse(advancedFields.hidden);
assertNull(internetDetailPage.shadowRoot!.querySelector('#deviceFields'));
assertNull(
internetDetailPage.shadowRoot!.querySelector('network-ip-config'));
assertNull(
internetDetailPage.shadowRoot!.querySelector('network-nameservers'));
assertNull(internetDetailPage.shadowRoot!.querySelector(
'network-proxy-section'));
});
test('WiFi Passpoint removal shows a dialog', async () => {
loadTimeData.overrideValues({
isPasspointSettingsEnabled: false,
});
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork =
getManagedProperties(NetworkType.kWiFi, 'wifi_passpoint');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.passpointId = 'a_passpoint_id';
wifiNetwork.typeProperties.wifi!.passpointMatchType = MatchType.kHome;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_passpoint_guid', 'WiFi', 'wifi_passpoint');
await flushTasks();
const forgetButton = getButton('forgetButton');
assertFalse(forgetButton.hidden);
assertFalse(forgetButton.disabled);
// Click the button and check the dialog is displayed.
forgetButton.click();
await waitAfterNextRender(forgetButton);
const removeDialog = getPasspointRemoveDialog();
let dialogElement =
removeDialog.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialogElement);
assertTrue(dialogElement.open);
// Check "Cancel" dismiss the dialog.
const cancelButton =
removeDialog.shadowRoot!.querySelector<HTMLButtonElement>(
'#cancelButton');
assertTrue(!!cancelButton);
cancelButton.click();
await flushTasks();
dialogElement =
removeDialog.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialogElement);
assertFalse(dialogElement.open);
// Check "Confirm" triggers network removal
forgetButton.click();
await flushTasks();
const confirmButton =
removeDialog.shadowRoot!.querySelector<HTMLButtonElement>(
'#confirmButton');
assertTrue(!!confirmButton);
confirmButton.click();
await flushTasks();
dialogElement =
removeDialog.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialogElement);
assertFalse(dialogElement.open);
await mojoApi.whenCalled('forgetNetwork');
});
test('WiFi Passpoint removal leads to subscription page', async () => {
loadTimeData.overrideValues({
isPasspointSettingsEnabled: true,
});
init();
const subId = 'a_passpoint_id';
setSubscriptionForTest({
id: subId,
friendlyName: 'My Passpoint provider',
domains: [],
provisioningSource: '',
expirationEpochMs: 0n,
trustedCa: null,
});
mojoApi.resetForTest();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork =
getManagedProperties(NetworkType.kWiFi, 'wifi_passpoint');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.passpointId = subId;
wifiNetwork.typeProperties.wifi!.passpointMatchType = MatchType.kHome;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_passpoint_guid', 'WiFi', 'wifi_passpoint');
await flushTasks();
const forgetButton = getButton('forgetButton');
assertFalse(forgetButton.hidden);
assertFalse(forgetButton.disabled);
// Click the button and check the dialog is displayed.
forgetButton.click();
await waitAfterNextRender(forgetButton);
const removeDialog = getPasspointRemoveDialog();
let dialogElement =
removeDialog.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialogElement);
assertTrue(dialogElement.open);
// Check "Confirm" leads to Passpoint subscription page.
forgetButton.click();
await flushTasks();
dialogElement =
removeDialog.shadowRoot!.querySelector<CrDialogElement>('#dialog');
assertTrue(!!dialogElement);
assertTrue(dialogElement.open);
const confirmButton =
removeDialog.shadowRoot!.querySelector<HTMLButtonElement>(
'#confirmButton');
assertTrue(!!confirmButton);
const showDetailPromise = eventToPromise('show-passpoint-detail', window);
confirmButton.click();
await flushTasks();
const showDetailEvent = await showDetailPromise;
assertEquals(subId, showDetailEvent.detail.id);
});
test(
'WiFi network removal without Passpoint does not show a dialog',
async () => {
loadTimeData.overrideValues({
isPasspointSettingsEnabled: false,
});
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_guid', 'WiFi', 'wifi');
await flushTasks();
const forgetButton = getButton('forgetButton');
assertFalse(forgetButton.hidden);
assertFalse(forgetButton.disabled);
// Click the button and check the dialog is displayed.
forgetButton.click();
await flushTasks();
assertNull(internetDetailPage.shadowRoot!.querySelector(
'#passpointRemovalDialog'));
});
[true, false].forEach(isPasspointSettingsEnabled => {
test('WiFi network with Passpoint shows provider row', async () => {
loadTimeData.overrideValues({
isPasspointSettingsEnabled,
});
init();
const subId = 'a_passpoint_id';
setSubscriptionForTest({
id: subId,
friendlyName: 'My Passpoint provider',
domains: [],
provisioningSource: '',
expirationEpochMs: 0n,
trustedCa: null,
});
mojoApi.resetForTest();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork =
getManagedProperties(NetworkType.kWiFi, 'wifi_passpoint');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.passpointId = subId;
wifiNetwork.typeProperties.wifi!.passpointMatchType = MatchType.kHome;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init(
'wifi_passpoint_guid', 'WiFi', 'wifi_passpoint');
await flushTasks();
const row =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
'#passpointProviderRow');
// The row is present only when Passpoint is enabled.
assertEquals(isPasspointSettingsEnabled, !!row);
if (isPasspointSettingsEnabled) {
const showDetailPromise =
eventToPromise('show-passpoint-detail', window);
assertTrue(!!row);
row.click();
const showDetailEvent = await showDetailPromise;
assertEquals(subId, showDetailEvent.detail.id);
}
});
});
test(
'WiFi network without Passpoint does not show provider row',
async () => {
loadTimeData.overrideValues({
isPasspointSettingsEnabled: true,
});
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_guid', 'WiFi', 'wifi');
await flushTasks();
assertNull(internetDetailPage.shadowRoot!.querySelector(
'#passpointProviderRow'));
});
test('WiFi network with Passpoint has no configure button', async () => {
loadTimeData.overrideValues({
isPasspointSettingsEnabled: true,
});
init();
const subId = 'a_passpoint_id';
setSubscriptionForTest({
id: subId,
friendlyName: 'My Passpoint provider',
domains: [],
provisioningSource: '',
expirationEpochMs: 0n,
trustedCa: null,
});
mojoApi.resetForTest();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifiNetwork =
getManagedProperties(NetworkType.kWiFi, 'wifi_passpoint');
wifiNetwork.source = OncSource.kUser;
wifiNetwork.connectable = true;
wifiNetwork.typeProperties.wifi!.passpointId = subId;
wifiNetwork.typeProperties.wifi!.passpointMatchType = MatchType.kHome;
mojoApi.setManagedPropertiesForTest(wifiNetwork);
internetDetailPage.init('wifi_passpoint_guid', 'WiFi', 'wifi_passpoint');
await flushTasks();
const configureButton = getButton('configureButton');
assertTrue(configureButton.hidden);
});
});
suite('DetailsPageVPN', () => {
/**
* @param doNotProvidePrefs If provided, determine whether
* prefs should be provided for the element.
*/
function initVpn(doNotProvidePrefs?: boolean): void {
init(doNotProvidePrefs);
mojoApi.setNetworkTypeEnabledState(NetworkType.kVPN, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kVPN, 'vpn1'),
]);
internetDetailPage.init('vpn1_guid', 'VPN', 'vpn1');
}
/**
* @param managedProperties
* Managed properties used to initialize the network.
*/
function initManagedVpn(managedProperties: ManagedProperties): void {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kVPN, true);
mojoApi.resetForTest();
mojoApi.addNetworksForTest([
OncMojo.managedPropertiesToNetworkState(managedProperties),
]);
mojoApi.setManagedPropertiesForTest(managedProperties);
internetDetailPage.init(
managedProperties.guid, 'VPN', managedProperties.name!.activeValue);
}
function getDefaultManagedOpenVpnProps(): ManagedOpenVPNProperties {
return {
auth: undefined,
authRetry: undefined,
authNoCache: undefined,
cipher: undefined,
clientCertPkcs11Id: undefined,
clientCertPattern: undefined,
clientCertProvisioningProfileId: undefined,
clientCertRef: undefined,
clientCertType: undefined,
compressionAlgorithm: undefined,
extraHosts: undefined,
ignoreDefaultRoute: undefined,
keyDirection: undefined,
nsCertType: undefined,
password: undefined,
port: undefined,
proto: undefined,
pushPeerInfo: undefined,
remoteCertEku: undefined,
remoteCertKu: undefined,
remoteCertTls: undefined,
renegSec: undefined,
saveCredentials: undefined,
serverCaPems: undefined,
serverCaRefs: undefined,
serverCertRef: undefined,
serverPollTimeout: undefined,
shaper: undefined,
staticChallenge: undefined,
tlsAuthContents: undefined,
tlsRemote: undefined,
tlsVersionMin: undefined,
userAuthenticationType: undefined,
username: undefined,
verb: undefined,
verifyHash: undefined,
verifyX509: undefined,
};
}
/**
* @param oncSource If
* provided, sets the source (user / device / policy) of the network.
*/
function initAdvancedVpn(oncSource: OncSource = 0): void {
const defaultManagedStringProps = {
activeValue: '',
policySource: PolicySource.kNone,
policyValue: undefined,
};
const vpn1 = OncMojo.getDefaultManagedProperties(
NetworkType.kVPN, 'vpn1_guid', 'vpn1');
vpn1.source = oncSource;
vpn1.typeProperties.vpn!.type = VpnType.kOpenVPN;
vpn1.typeProperties.vpn!.openVpn = {
...getDefaultManagedOpenVpnProps(),
auth: {
...defaultManagedStringProps,
activeValue: 'MD5',
},
cipher: {
...defaultManagedStringProps,
activeValue: 'AES-192-CBC',
},
compressionAlgorithm: {
...defaultManagedStringProps,
activeValue: 'LZO',
},
tlsAuthContents: {
...defaultManagedStringProps,
activeValue: 'FAKE_CREDENTIAL_VPaJDV9x',
},
keyDirection: {
...defaultManagedStringProps,
activeValue: '1',
},
};
initManagedVpn(vpn1);
}
function initVpnWithNoAdvancedProperties(): void {
const vpn1 = OncMojo.getDefaultManagedProperties(
NetworkType.kVPN, 'vpn1_guid', 'vpn1');
vpn1.source = OncSource.kUserPolicy;
vpn1.typeProperties.vpn!.type = VpnType.kOpenVPN;
// Try out all the values considered "empty" to make sure we do not
// register any of them as set.
vpn1.typeProperties.vpn!.openVpn = {
...getDefaultManagedOpenVpnProps(),
};
initManagedVpn(vpn1);
}
function initWireGuard(): void {
const wg1 = OncMojo.getDefaultManagedProperties(
NetworkType.kVPN, 'wg1_guid', 'wg1');
wg1.typeProperties.vpn!.type = VpnType.kWireGuard;
wg1.typeProperties.vpn!.wireguard = {
peers: {
activeValue: [{
publicKey: 'KFhwdv4+jKpSXMW6xEUVtOe4Mo8l/xOvGmshmjiHx1Y=',
endpoint: '192.168.66.66:32000',
allowedIps: '0.0.0.0/0',
presharedKey: '',
persistentKeepaliveInterval: 0,
}],
policySource: PolicySource.kNone,
policyValue: [],
},
ipAddresses: undefined,
privateKey: undefined,
publicKey: undefined,
};
wg1.staticIpConfig = {
ipAddress: {
activeValue: '10.10.0.1',
policySource: PolicySource.kNone,
policyValue: '',
},
gateway: undefined,
nameServers: undefined,
routingPrefix: undefined,
type: IPConfigType.kIPv4,
webProxyAutoDiscoveryUrl: undefined,
};
initManagedVpn(wg1);
}
test('VPN config allowed', async () => {
initVpn();
PREFS.vpn_config_allowed.value = true;
internetDetailPage.prefs = PREFS;
await flushTasks();
const disconnectButton = getButton('connectDisconnect');
assertFalse(disconnectButton.hasAttribute('enforced_'));
assertNull(disconnectButton.shadowRoot!.querySelector(
'cr-policy-pref-indicator'));
});
test('VPN config disallowed', async () => {
initVpn();
PREFS.vpn_config_allowed.value = false;
internetDetailPage.prefs = PREFS;
await flushTasks();
const disconnectButton = getButton('connectDisconnect');
assertTrue(disconnectButton.hasAttribute('enforced_'));
assertTrue(!!disconnectButton.shadowRoot!.querySelector(
'cr-policy-pref-indicator'));
});
test('Managed VPN with advanced fields', async () => {
initAdvancedVpn(OncSource.kUserPolicy);
await flushTasks();
assertTrue(
!!internetDetailPage.shadowRoot!.querySelector('#advancedFields'));
});
test('Unmanaged VPN with advanced fields', async () => {
initAdvancedVpn(OncSource.kUser);
await flushTasks();
assertNull(
internetDetailPage.shadowRoot!.querySelector('#advancedFields'));
});
// Regression test for issue fixed as part of https://crbug.com/1191626
// where page would throw an exception if prefs were undefined. Prefs are
// expected to be undefined if InternetDetailPage is loaded directly (e.g.,
// when the user clicks on the network in Quick Settings).
test('VPN without prefs', async () => {
initVpn(/*doNotProvidePrefs=*/ true);
await flushTasks();
});
test('OpenVPN does not show public key field', async () => {
initVpn();
await flushTasks();
assertNull(
internetDetailPage.shadowRoot!.querySelector('#wgPublicKeyField'));
});
test('WireGuard does show public key field', async () => {
initWireGuard();
await flushTasks();
assertTrue(
!!internetDetailPage.shadowRoot!.querySelector('#wgPublicKeyField'));
});
test('Advanced section hidden when properties are not set', async () => {
initVpnWithNoAdvancedProperties();
await flushTasks();
const expandButtons =
internetDetailPage.shadowRoot!.querySelectorAll<HTMLButtonElement>(
'cr-expand-button.settings-box');
expandButtons.forEach((button: HTMLButtonElement) => {
assertNotEquals('Advanced', button.textContent!.trim());
});
});
});
suite('DetailsPageCellular', () => {
async function expandConfigurableSection(): Promise<void> {
const configurableSections =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
'#configurableSections');
assertTrue(!!configurableSections);
configurableSections.click();
await flushTasks();
assertTrue(internetDetailPage.get('showConfigurableSections_'));
}
// Regression test for https://crbug.com/1182884.
test('Connect button enabled when not connectable', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = false;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const connectButton = getButton('connectDisconnect');
assertFalse(connectButton.hidden);
assertFalse(connectButton.disabled);
});
test('carrier locked subtext when carrier locked', async () => {
const TEST_ICCID = '11111111111111111';
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simLockStatus: {
lockEnabled: true,
lockType: 'network-pin',
retriesLeft: 0,
},
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = false;
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
cellularNetwork.typeProperties.cellular!.simLocked = true;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const carrierLockedText =
internetDetailPage.shadowRoot!.querySelector<LocalizedLinkElement>(
'#carrierLockedNoticeLink');
assertTrue(!!carrierLockedText);
assertEquals(
internetDetailPage.i18nAdvanced('networkCarrierLocked').toString(),
carrierLockedText.localizedString.toString());
// Verify network state
const networkStateText =
internetDetailPage.shadowRoot!.querySelector('#networkState');
assertTrue(!!networkStateText);
assertTrue(networkStateText.hasAttribute('warning'));
assertEquals(
internetDetailPage.i18n('networkMobileProviderLocked'),
networkStateText.textContent!.trim());
});
test(
'Connect button disabled when not connectable and locked', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = false;
cellularNetwork.typeProperties.cellular!.simLocked = true;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const connectButton = getButton('connectDisconnect');
assertFalse(connectButton.hidden);
assertTrue(connectButton.disabled);
});
test(
'Cellular view account button opens carrier account details',
async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const viewAccountButton =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
'#viewAccountButton');
assertTrue(!!viewAccountButton);
viewAccountButton.click();
await flushTasks();
await browserProxy.whenCalled('showCarrierAccountDetail');
});
test(
'Unactivated eSIM does not show activate or view account button',
async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.eid = 'eid';
cellularNetwork.connectionState = ConnectionStateType.kConnected;
cellularNetwork.typeProperties.cellular!.activationState =
ActivationStateType.kNotActivated;
cellularNetwork.typeProperties.cellular!.paymentPortal = {
url: 'url',
method: '',
postData: undefined,
};
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const activateButton =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
'#activateButton');
assertTrue(!!activateButton);
assertTrue(activateButton.hidden);
const viewAccountButton =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
'#viewAccountButton');
assertTrue(!!viewAccountButton);
assertTrue(viewAccountButton.hidden);
});
test('Cellular Scanning', async () => {
const TEST_ICCID = '11111111111111111';
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
scanning: true,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const spinner =
internetDetailPage.shadowRoot!.querySelector('paper-spinner-lite');
assertTrue(!!spinner);
assertFalse(spinner.hidden);
});
// Regression test for https://crbug.com/1201449.
test('Page closed while device is updating', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
mojoApi.setManagedPropertiesForTest(cellularNetwork);
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
scanning: true,
});
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
// Close the page as soon as getDeviceStateList() is invoked, before the
// callback returns.
mojoApi.beforeGetDeviceStateList = () => {
internetDetailPage.close();
};
mojoApi.onDeviceStateListChanged();
await flushTasks();
});
test('Deep link to disconnect button', async () => {
// Add listener for popstate event fired when the dialog closes and the
// router navigates backwards.
const popStatePromise = eventToPromise('popstate', window);
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = false;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
const DISCONNECT_CELLULAR_NETWORK_SETTING =
settingMojom.Setting.kDisconnectCellularNetwork.toString();
const params = new URLSearchParams();
params.append('guid', 'cellular_guid');
params.append('type', 'Cellular');
params.append('name', 'cellular');
params.append('settingId', DISCONNECT_CELLULAR_NETWORK_SETTING);
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await flushTasks();
const deepLinkElement =
getButton('connectDisconnect').shadowRoot!.querySelector('cr-button');
assertTrue(!!deepLinkElement);
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
`Disconnect network button should be focused for settingId=${
DISCONNECT_CELLULAR_NETWORK_SETTING}.`);
// Close the dialog and wait for os_route's popstate listener to fire. If
// we don't add this wait, this event can fire during the next test which
// will interfere with its routing.
internetDetailPage.close();
await popStatePromise;
});
test('Deep link to cellular roaming toggle button', async () => {
const TEST_ICCID = '11111111111111111';
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
cellularNetwork.connectable = false;
// Required for allowDataRoamingButton to be rendered.
cellularNetwork.typeProperties.cellular!.allowRoaming =
OncMojo.createManagedBool(false);
mojoApi.setManagedPropertiesForTest(cellularNetwork);
// Set SIM as active so that configurable sections are displayed.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
const CELLULAR_ROAMING_SETTING =
settingMojom.Setting.kCellularRoaming.toString();
const params = new URLSearchParams();
params.append('guid', 'cellular_guid');
params.append('type', 'Cellular');
params.append('name', 'cellular');
params.append('settingId', CELLULAR_ROAMING_SETTING);
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await flushTasks();
// Attempting to focus a <network-config-toggle> will result in the focus
// being pushed onto the internal <cr-toggle>.
const toggleBtn = internetDetailPage.shadowRoot!
.querySelector<CellularRoamingToggleButtonElement>(
'cellular-roaming-toggle-button');
assertTrue(!!toggleBtn);
const cellularRoamingToggle = toggleBtn.getCellularRoamingToggle();
assertTrue(!!cellularRoamingToggle);
const deepLinkElement =
cellularRoamingToggle.shadowRoot!.querySelector('cr-toggle');
assertTrue(!!deepLinkElement);
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
`Cellular roaming toggle button should be focused for settingId=${
CELLULAR_ROAMING_SETTING}.`);
});
test('Deep link to sim lock toggle', async () => {
await deepLinkToSimLockElement(/*isSimLocked=*/ false);
const simInfo = internetDetailPage.shadowRoot!.querySelector<HTMLElement>(
'#cellularSimInfoAdvanced');
assertTrue(!!simInfo);
// In this rare case, wait after next render twice due to focus behavior
// of the siminfo component.
await waitAfterNextRender(simInfo);
await waitAfterNextRender(simInfo);
assertEquals(
simInfo.shadowRoot!.querySelector('#simLockButton'),
getDeepActiveElement(),
`Sim lock toggle should be focused for settingId=${
CELLULAR_SIM_LOCK_SETTING}.`);
});
test('Deep link to sim unlock button', async () => {
await deepLinkToSimLockElement(/*isSimLocked=*/ true);
const simInfo = internetDetailPage.shadowRoot!.querySelector<HTMLElement>(
'#cellularSimInfoAdvanced');
assertTrue(!!simInfo);
// In this rare case, wait after next render twice due to focus behavior
// of the siminfo component.
await waitAfterNextRender(simInfo);
await waitAfterNextRender(simInfo);
assertEquals(
simInfo.shadowRoot!.querySelector('#unlockPinButton'),
getDeepActiveElement(),
`Sim unlock button should be focused for settingId=${
CELLULAR_SIM_LOCK_SETTING}.`);
});
test('Cellular page hides hidden toggle', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = false;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const hiddenToggle = getHiddenToggle();
assertNull(hiddenToggle);
});
test(
'Cellular network on active sim slot, show config sections',
async () => {
loadTimeData.overrideValues({isApnRevampEnabled: true});
init();
const TEST_ICCID = '11111111111111111';
await mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork = getManagedProperties(
NetworkType.kCellular, 'cellular', OncSource.kDevice);
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
// Required for allowDataRoamingButton to be rendered.
cellularNetwork.typeProperties.cellular!.allowRoaming =
OncMojo.createManagedBool(false);
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertTrue(internetDetailPage.get('showConfigurableSections_'));
// Check that an element from the primary account section exists.
const toggleBtn =
internetDetailPage.shadowRoot!
.querySelector<CellularRoamingToggleButtonElement>(
'cellular-roaming-toggle-button');
assertTrue(!!toggleBtn);
assertTrue(!!toggleBtn.getCellularRoamingToggle());
assertTrue(!!internetDetailPage.shadowRoot!.querySelector(
'#apnSubpageButton'));
});
test(
'Cellular network on non-active sim slot, hide config sections',
async () => {
loadTimeData.overrideValues({isApnRevampEnabled: true});
init();
const TEST_ICCID = '11111111111111111';
await mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork = getManagedProperties(
NetworkType.kCellular, 'cellular', OncSource.kDevice);
cellularNetwork.typeProperties.cellular!.iccid = '000';
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertFalse(internetDetailPage.get('showConfigurableSections_'));
// Check that an element from the primary account section exists.
assertNull(internetDetailPage.shadowRoot!.querySelector(
'#allowDataRoaming'));
// The section ConnectDisconnect button belongs to should still be
// showing.
assertTrue(!!internetDetailPage.shadowRoot!.querySelector(
'#connectDisconnect'));
assertNull(internetDetailPage.shadowRoot!.querySelector(
'#apnSubpageButton'));
});
test(
'Hide config section and Cellular Device object fields when' +
'sim becomes non-active',
async () => {
init();
const TEST_ICCID = '11111111111111111';
await mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork = getManagedProperties(
NetworkType.kCellular, 'cellular', OncSource.kDevice);
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
const isShowingCellularDeviceObjectFields = () => {
const deviceFields =
internetDetailPage.shadowRoot!
.querySelector<NetworkPropertyListMojoElement>(
'#deviceFields');
assertTrue(!!deviceFields);
return deviceFields.fields.includes('cellular.homeProvider.name');
};
// Set sim to non-active.
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: false,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertFalse(internetDetailPage.get('showConfigurableSections_'));
assertFalse(isShowingCellularDeviceObjectFields());
// Set sim to active.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertTrue(internetDetailPage.get('showConfigurableSections_'));
assertTrue(isShowingCellularDeviceObjectFields());
// Set sim to non-active again.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: false,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertFalse(internetDetailPage.get('showConfigurableSections_'));
assertFalse(isShowingCellularDeviceObjectFields());
});
test('Do not show MAC address', async () => {
const TEST_ICCID = '11111111111111111';
const TEST_MAC_ADDRESS = '01:23:45:67:89:AB';
const MISSING_MAC_ADDRESS = '00:00:00:00:00:00';
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.connectable = true;
cellularNetwork.typeProperties.cellular!.simLocked = false;
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
let deviceState = {
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
macAddress: TEST_MAC_ADDRESS,
};
mojoApi.setDeviceStateForTest(deviceState);
await flushTasks();
expandConfigurableSection();
let macAddress =
internetDetailPage.shadowRoot!.querySelector<HTMLElement>(
'#mac-address-container');
assertTrue(!!macAddress);
assertFalse(macAddress.hidden);
// Set MAC address to '00:00:00:00:00:00' missing address, this address
// is provided when device MAC address cannot be retrieved. If this is the
// case, the MAC address should not be displayed in UI.
deviceState = {
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
macAddress: MISSING_MAC_ADDRESS,
};
mojoApi.setDeviceStateForTest(deviceState);
await flushTasks();
expandConfigurableSection();
macAddress = internetDetailPage.shadowRoot!.querySelector<HTMLElement>(
'#mac-address-container');
assertTrue(!!macAddress);
assertTrue(macAddress.hidden);
});
// Syntactic sugar for running test twice with different values for the
// apnRevamp feature flag.
[true, false].forEach(isApnRevampEnabled => {
test(
`Page disabled when inhibited, ApnRevamp enabled is: ${
isApnRevampEnabled}`,
async () => {
loadTimeData.overrideValues({isApnRevampEnabled});
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork = getManagedProperties(
NetworkType.kCellular, 'cellular', OncSource.kDevice);
// Required for connectDisconnectButton to be rendered.
cellularNetwork.connectionState = ConnectionStateType.kConnected;
// Required for allowDataRoamingButton to be rendered.
cellularNetwork.typeProperties.cellular!.allowRoaming =
OncMojo.createManagedBool(false);
// Required for advancedFields to be rendered.
cellularNetwork.typeProperties.cellular!.networkTechnology = 'LTE';
// Required for infoFields to be rendered.
cellularNetwork.typeProperties.cellular!.servingOperator = {
name: 'name',
code: '',
country: '',
};
// Required for deviceFields to be rendered.
const TEST_ICCID = '11111111111111111';
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
// Required for networkChooseMobile to be rendered.
cellularNetwork.typeProperties.cellular!.supportNetworkScan = true;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
// Start uninhibited.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
// Required for configurable sections to be rendered.
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const connectDisconnectButton = getButton('connectDisconnect');
const infoFields = getButton('infoFields');
const cellularSimInfoAdvanced =
getButton('cellularSimInfoAdvanced');
const advancedFields = getButton('advancedFields');
const deviceFields = getButton('deviceFields');
const toggleBtn =
internetDetailPage.shadowRoot!
.querySelector<CellularRoamingToggleButtonElement>(
'cellular-roaming-toggle-button');
assertTrue(!!toggleBtn);
const allowDataRoamingButton = toggleBtn.getCellularRoamingToggle();
const networkChooseMobile =
internetDetailPage.shadowRoot!
.querySelector<NetworkChooseMobileElement>(
'network-choose-mobile');
let apnElement: CrLinkRowElement|NetworkApnListElement|null =
internetDetailPage.shadowRoot!.querySelector<CrLinkRowElement>(
'#apnSubpageButton');
if (!isApnRevampEnabled) {
apnElement =
internetDetailPage.shadowRoot!
.querySelector<NetworkApnListElement>('network-apnlist');
}
const networkIpConfig =
internetDetailPage.shadowRoot!
.querySelector<NetworkIpConfigElement>('network-ip-config');
const networkNameservers =
internetDetailPage.shadowRoot!
.querySelector<NetworkNameserversElement>(
'network-nameservers');
const networkProxySection =
internetDetailPage.shadowRoot!
.querySelector<NetworkProxySectionElement>(
'network-proxy-section');
assertTrue(!!allowDataRoamingButton);
assertTrue(!!networkChooseMobile);
assertTrue(!!apnElement);
assertTrue(!!networkIpConfig);
assertTrue(!!networkNameservers);
assertTrue(!!networkProxySection);
assertFalse(connectDisconnectButton.disabled);
assertFalse(allowDataRoamingButton.disabled);
assertFalse(infoFields.disabled);
assertFalse(cellularSimInfoAdvanced.disabled);
assertFalse(advancedFields.disabled);
assertFalse(deviceFields.disabled);
assertFalse(networkChooseMobile.disabled);
assertFalse(apnElement.disabled);
assertFalse(networkIpConfig.disabled);
assertFalse(networkNameservers.disabled);
assertFalse(networkProxySection.disabled);
// Mock device being inhibited.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
inhibitReason: InhibitReason.kConnectingToProfile,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertTrue(connectDisconnectButton.disabled);
assertTrue(allowDataRoamingButton.disabled);
assertTrue(infoFields.disabled);
assertTrue(cellularSimInfoAdvanced.disabled);
assertTrue(advancedFields.disabled);
assertTrue(deviceFields.disabled);
assertTrue(networkChooseMobile.disabled);
assertTrue(apnElement.disabled);
assertTrue(networkIpConfig.disabled);
assertTrue(networkNameservers.disabled);
assertTrue(networkProxySection.disabled);
// Uninhibit.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertFalse(connectDisconnectButton.disabled);
assertFalse(allowDataRoamingButton.disabled);
assertFalse(infoFields.disabled);
assertFalse(cellularSimInfoAdvanced.disabled);
assertFalse(advancedFields.disabled);
assertFalse(deviceFields.disabled);
assertFalse(networkChooseMobile.disabled);
assertFalse(apnElement.disabled);
assertFalse(networkIpConfig.disabled);
assertFalse(networkNameservers.disabled);
assertFalse(networkProxySection.disabled);
});
});
test('Cellular page disabled when blocked by policy', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const cellularNetwork = getManagedProperties(
NetworkType.kCellular, 'cellular', OncSource.kDevice);
// Required for connectDisconnectButton to be rendered.
cellularNetwork.connectionState = ConnectionStateType.kNotConnected;
cellularNetwork.typeProperties.cellular!.allowRoaming =
OncMojo.createManagedBool(false);
// Required for advancedFields to be rendered.
cellularNetwork.typeProperties.cellular!.networkTechnology = 'LTE';
// Required for infoFields to be rendered.
cellularNetwork.typeProperties.cellular!.servingOperator = {
name: 'name',
code: '',
country: '',
};
// Required for deviceFields to be rendered.
const TEST_ICCID = '11111111111111111';
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
cellularNetwork.typeProperties.cellular!.supportNetworkScan = true;
cellularNetwork.source = OncSource.kNone;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
internetDetailPage.globalPolicy = {
...getDefaultGlobalPolicy(),
allowOnlyPolicyCellularNetworks: true,
};
await flushTasks();
const connectDisconnectButton = getButton('connectDisconnect');
assertTrue(connectDisconnectButton.hidden);
assertTrue(connectDisconnectButton.disabled);
assertNull(internetDetailPage.shadowRoot!.querySelector('#infoFields'));
const cellularSimInfoAdvanced = getButton('cellularSimInfoAdvanced');
assertFalse(cellularSimInfoAdvanced.disabled);
assertFalse(cellularSimInfoAdvanced.hidden);
const advancedFields = getButton('advancedFields');
assertFalse(advancedFields.disabled);
assertFalse(advancedFields.hidden);
const deviceFields = getButton('deviceFields');
assertFalse(deviceFields.disabled);
assertFalse(deviceFields.hidden);
assertNull(internetDetailPage.shadowRoot!.querySelector(
'cellular-roaming-toggle-button'));
assertNull(internetDetailPage.shadowRoot!.querySelector(
'network-choose-mobile'));
assertNull(
internetDetailPage.shadowRoot!.querySelector('network-apnlist'));
assertNull(
internetDetailPage.shadowRoot!.querySelector('network-ip-config'));
assertNull(
internetDetailPage.shadowRoot!.querySelector('network-nameservers'));
assertNull(internetDetailPage.shadowRoot!.querySelector(
'network-proxy-section'));
});
// Syntactic sugar for running test twice with different values for the
// apnRevamp feature flag.
[true, false].forEach(isApnRevampEnabled => {
test('Show/Hide APN row correspondingly to ApnRevamp flag', async () => {
loadTimeData.overrideValues({isApnRevampEnabled});
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const apnName = 'test';
const testIccid = '11111';
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.connectedApn = {
accessPointName: '',
id: '',
authentication: ApnAuthenticationType.kAutomatic,
language: undefined,
localizedName: undefined,
name: undefined,
password: undefined,
username: undefined,
attach: undefined,
state: ApnState.kEnabled,
ipType: ApnIpType.kAutomatic,
apnTypes: [],
source: ApnSource.kModb,
};
cellularNetwork.typeProperties.cellular!.connectedApn!.accessPointName =
apnName;
cellularNetwork.typeProperties.cellular!.iccid = testIccid;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
// Set cellular network as active SIM so that APN row should show up if
// the flag is enabled.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: testIccid,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
const getCrLink = () =>
internetDetailPage.shadowRoot!.querySelector('#apnSubpageButton');
const getApn = () => getCrLink() ?
getCrLink()!.shadowRoot!.querySelector('#subLabel') :
null;
if (isApnRevampEnabled) {
assertTrue(!!getApn());
assertEquals(apnName, getApn()!.textContent!.trim());
const name = 'name';
cellularNetwork.typeProperties.cellular!.connectedApn.name = name;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
assertTrue(!!getApn());
assertEquals(name, getApn()!.textContent!.trim());
assertFalse(getCrLink()!.hasAttribute('warning'));
// Adding a restricted connectivity state should cause the sublabel to
// be a warning.
cellularNetwork.portalState = PortalState.kNoInternet;
cellularNetwork.connectionState = ConnectionStateType.kPortal;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
assertTrue(getCrLink()!.hasAttribute('warning'));
} else {
assertNull(getApn());
}
});
});
[true, false].forEach(isApnRevampAndAllowApnModificationPolicyEnabled => {
test(
`Managed APN icon visibility when ` +
`isApnRevampAndAllowApnModificationPolicyEnabled is ${
isApnRevampAndAllowApnModificationPolicyEnabled}`,
async () => {
loadTimeData.overrideValues({
isApnRevampEnabled: true,
isApnRevampAndAllowApnModificationPolicyEnabled:
isApnRevampAndAllowApnModificationPolicyEnabled,
});
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const apnName = 'test';
const testIccid = '11111';
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.connectedApn = {
accessPointName: '',
id: '',
authentication: ApnAuthenticationType.kAutomatic,
language: undefined,
localizedName: undefined,
name: undefined,
password: undefined,
username: undefined,
attach: undefined,
state: ApnState.kEnabled,
ipType: ApnIpType.kAutomatic,
apnTypes: [],
source: ApnSource.kModb,
};
cellularNetwork.typeProperties.cellular!.connectedApn!
.accessPointName = apnName;
cellularNetwork.typeProperties.cellular!.iccid = testIccid;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
// Set cellular network as active SIM so that APN row should show up
// if the flag is enabled.
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: testIccid,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertTrue(!!internetDetailPage.shadowRoot!.querySelector(
'#apnSubpageButton'));
// Check for APN policies managed icon.
const getApnManagedIcon = () =>
internetDetailPage.shadowRoot!.querySelector('#apnManagedIcon');
assertFalse(!!getApnManagedIcon());
internetDetailPage.globalPolicy = {
...getDefaultGlobalPolicy(),
allowApnModification: true,
};
await flushTasks();
assertFalse(!!getApnManagedIcon());
internetDetailPage.globalPolicy = {
...getDefaultGlobalPolicy(),
allowApnModification: false,
};
await flushTasks();
assertEquals(
isApnRevampAndAllowApnModificationPolicyEnabled,
!!getApnManagedIcon());
});
});
test('Cellular network not found while in detail subpage', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
// Simulate navigating to mobile data subpage.
let params = new URLSearchParams();
params.append(
'type', OncMojo.getNetworkTypeString(NetworkType.kCellular));
Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
assertEquals(routes.INTERNET_NETWORKS, Router.getInstance().currentRoute);
await flushTasks();
// Navigate to cellular detail page. Because the network is not found, the
// page should navigate backwards.
const popStatePromise = eventToPromise('popstate', window);
params = new URLSearchParams();
params.append('guid', 'cellular_guid');
params.append('type', 'Cellular');
params.append('name', 'cellular');
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await popStatePromise;
assertEquals(routes.INTERNET_NETWORKS, Router.getInstance().currentRoute);
});
// Regression test for b/281728200.
test('Cellular network not found while not in detail subpage', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
// Simulate navigating to top-level internet page.
let params = new URLSearchParams();
Router.getInstance().navigateTo(routes.INTERNET, params);
assertEquals(routes.INTERNET, Router.getInstance().currentRoute);
// Simulate navigating to mobile data subpage.
params = new URLSearchParams();
params.append(
'type', OncMojo.getNetworkTypeString(NetworkType.kCellular));
Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
assertEquals(routes.INTERNET_NETWORKS, Router.getInstance().currentRoute);
await flushTasks();
// Trigger |internetDetailPage| attempting to fetch the network. Because
// the page is not the current route, it should not trigger a navigation
// backwards.
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
assertEquals(routes.INTERNET_NETWORKS, Router.getInstance().currentRoute);
});
test(
'Show/Hide toggle correspondingly to SuppressTextMessages flag',
async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const TEST_ICCID = '11111111111111111';
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
const getSuppressTextMessagesToggle = () =>
internetDetailPage.shadowRoot!.querySelector(
'#suppressTextMessagesToggle');
assertTrue(!!getSuppressTextMessagesToggle());
});
test('Suppress text messages manually', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const TEST_ICCID = '11111111111111111';
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
cellularNetwork.typeProperties.cellular!.allowTextMessages = {
activeValue: true,
policySource: PolicySource.kNone,
policyValue: false,
};
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
const networkToggle = internetDetailPage.shadowRoot!
.querySelector<NetworkConfigToggleElement>(
'#suppressTextMessagesToggle');
assertTrue(!!networkToggle);
assertTrue(networkToggle.checked);
networkToggle.click();
await mojoApi.whenCalled('setProperties');
const props = mojoApi.getPropertiesToSetForTest();
assertTrue(!!props);
assertFalse(
props.typeConfig.cellular!.textMessageAllowState!.allowTextMessages);
});
test(
'Suppress text messages toggle only shown for active SIM', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const TEST_ICCID = '11111111111111111';
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
await flushTasks();
const getSuppressTextMessagesToggle = () =>
internetDetailPage.shadowRoot!.querySelector(
'#suppressTextMessagesToggle');
assertNull(getSuppressTextMessagesToggle());
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
assertTrue(!!getSuppressTextMessagesToggle());
});
test('Suppress text messages via policy', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true);
const TEST_ICCID = '11111111111111111';
const cellularNetwork =
getManagedProperties(NetworkType.kCellular, 'cellular');
cellularNetwork.typeProperties.cellular!.allowTextMessages = {
activeValue: true,
policySource: PolicySource.kDevicePolicyEnforced,
policyValue: false,
};
cellularNetwork.typeProperties.cellular!.iccid = TEST_ICCID;
mojoApi.setManagedPropertiesForTest(cellularNetwork);
internetDetailPage.init('cellular_guid', 'Cellular', 'cellular');
mojoApi.setDeviceStateForTest({
...getDefaultDeviceStateProps(),
deviceState: DeviceStateType.kEnabled,
simInfos: [{
iccid: TEST_ICCID,
isPrimary: true,
slotId: 0,
eid: '',
}],
});
await flushTasks();
const networkToggle = internetDetailPage.shadowRoot!
.querySelector<NetworkConfigToggleElement>(
'#suppressTextMessagesToggle');
assertTrue(!!networkToggle);
assertTrue(networkToggle.checked);
const crToggle =
networkToggle.shadowRoot!.querySelector<HTMLButtonElement>(
'cr-toggle');
assertTrue(!!crToggle);
assertTrue(crToggle.disabled);
assertTrue(!!networkToggle.shadowRoot!.querySelector(
'cr-policy-network-indicator-mojo'));
});
});
suite('DetailsPageEthernet', () => {
test('LoadPage', () => {
init();
});
test('Eth1', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kEthernet, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kEthernet, 'eth1'),
]);
internetDetailPage.init('eth1_guid', 'Ethernet', 'eth1');
assertEquals('eth1_guid', internetDetailPage.guid);
await flushTasks();
await mojoApi.whenCalled('getManagedProperties');
});
test('Deep link to configure ethernet button', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kEthernet, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kEthernet, 'eth1'),
]);
const CONFIGURE_ETHERNET_SETTING =
settingMojom.Setting.kConfigureEthernet.toString();
const params = new URLSearchParams();
params.append('guid', 'eth1_guid');
params.append('type', 'Ethernet');
params.append('name', 'eth1');
params.append('settingId', CONFIGURE_ETHERNET_SETTING);
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await flushTasks();
const deepLinkElement = getButton('configureButton');
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
`Configure ethernet button should be focused for settingId=${
CONFIGURE_ETHERNET_SETTING}.`);
});
});
suite('DetailsPageTether', () => {
test('LoadPage', () => {
init();
});
test(
'Create tether network, first connection attempt shows tether dialog',
async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kTether, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kTether, 'tether1'),
]);
internetDetailPage.init('tether1_guid', 'Tether', 'tether1');
assertEquals('tether1_guid', internetDetailPage.guid);
await flushTasks();
await mojoApi.whenCalled('getManagedProperties');
const connect =
internetDetailPage.shadowRoot!.querySelector<HTMLButtonElement>(
'#connectDisconnect');
assertTrue(!!connect);
const tetherDialog =
internetDetailPage.shadowRoot!.querySelector('#tetherDialog');
assertTrue(!!tetherDialog);
let crDialog =
tetherDialog.shadowRoot!.querySelector<CrDialogElement>(
'#dialog');
assertTrue(!!crDialog);
assertFalse(crDialog.open);
let showTetherDialogFinished: (val: null) => void;
const showTetherDialogPromise = new Promise((resolve) => {
showTetherDialogFinished = resolve;
});
const showTetherDialog = internetDetailPage['showTetherDialog_'];
internetDetailPage['showTetherDialog_'] = () => {
showTetherDialog.call(internetDetailPage);
showTetherDialogFinished(null);
};
connect.click();
await showTetherDialogPromise;
crDialog = tetherDialog.shadowRoot!.querySelector<CrDialogElement>(
'#dialog');
assertTrue(!!crDialog);
assertTrue(crDialog.open);
});
test('Deep link to disconnect tether network', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kTether, true);
setNetworksForTest([
OncMojo.getDefaultNetworkState(NetworkType.kTether, 'tether1'),
]);
const tetherNetwork =
getManagedProperties(NetworkType.kTether, 'tether1');
tetherNetwork.connectable = true;
mojoApi.setManagedPropertiesForTest(tetherNetwork);
await flushTasks();
const DISCONNECT_TETHER_NETWORK_SETTING =
settingMojom.Setting.kDisconnectTetherNetwork.toString();
const params = new URLSearchParams();
params.append('guid', 'tether1_guid');
params.append('type', 'Tether');
params.append('name', 'tether1');
params.append('settingId', DISCONNECT_TETHER_NETWORK_SETTING);
Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
await flushTasks();
const deepLinkElement =
getButton('connectDisconnect').shadowRoot!.querySelector('cr-button');
assertTrue(!!deepLinkElement);
await waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
`Disconnect tether button should be focused for settingId=${
DISCONNECT_TETHER_NETWORK_SETTING}.`);
});
});
suite('DetailsPageAutoConnect', () => {
test('Auto Connect toggle updates after GUID change', async () => {
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifi1 =
getManagedProperties(NetworkType.kWiFi, 'wifi1', OncSource.kDevice);
wifi1.typeProperties.wifi!.autoConnect = OncMojo.createManagedBool(true);
mojoApi.setManagedPropertiesForTest(wifi1);
const wifi2 =
getManagedProperties(NetworkType.kWiFi, 'wifi2', OncSource.kDevice);
wifi2.typeProperties.wifi!.autoConnect = OncMojo.createManagedBool(false);
mojoApi.setManagedPropertiesForTest(wifi2);
internetDetailPage.init('wifi1_guid', 'WiFi', 'wifi1');
await flushTasks();
let toggle =
internetDetailPage.shadowRoot!
.querySelector<SettingsToggleButtonElement>('#autoConnectToggle');
assertTrue(!!toggle);
assertTrue(toggle.checked);
internetDetailPage.init('wifi2_guid', 'WiFi', 'wifi2');
await flushTasks();
toggle =
internetDetailPage.shadowRoot!.querySelector('#autoConnectToggle');
assertTrue(!!toggle);
assertFalse(toggle.checked);
});
test('Auto Connect updates don\'t trigger a re-save', async () => {
const defaultNetworkStateProps: NetworkStateProperties = {
guid: '',
connectable: false,
connectRequested: false,
connectionState: ConnectionStateType.kOnline,
errorState: undefined,
name: '',
portalState: PortalState.kUnknown,
portalProbeUrl: undefined,
priority: 0,
proxyMode: ProxyMode.kDirect,
prohibitedByPolicy: false,
source: OncSource.kNone,
type: NetworkType.kAll,
typeState: {
cellular: undefined,
ethernet: undefined,
tether: undefined,
vpn: undefined,
wifi: undefined,
},
};
init();
mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
let wifi1 =
getManagedProperties(NetworkType.kWiFi, 'wifi1', OncSource.kDevice);
wifi1.typeProperties.wifi!.autoConnect = OncMojo.createManagedBool(true);
mojoApi.setManagedPropertiesForTest(wifi1);
assertEquals(undefined, mojoApi.methodCalled('setProperties'));
internetDetailPage.init('wifi1_guid', 'WiFi', 'wifi1');
internetDetailPage.onNetworkStateChanged(
{...defaultNetworkStateProps, guid: 'wifi1_guid'});
await flushTasks();
let toggle =
internetDetailPage.shadowRoot!
.querySelector<SettingsToggleButtonElement>('#autoConnectToggle');
assertTrue(!!toggle);
assertTrue(toggle.checked);
// Rebuild the object to force polymer to recognize a change.
wifi1 =
getManagedProperties(NetworkType.kWiFi, 'wifi1', OncSource.kDevice);
wifi1.typeProperties.wifi!.autoConnect = OncMojo.createManagedBool(false);
mojoApi.setManagedPropertiesForTest(wifi1);
internetDetailPage.onNetworkStateChanged(
{...defaultNetworkStateProps, guid: 'wifi1_guid'});
await flushTasks();
toggle =
internetDetailPage.shadowRoot!
.querySelector<SettingsToggleButtonElement>('#autoConnectToggle');
assertTrue(!!toggle);
assertFalse(toggle.checked);
});
});
});