blob: 6f78ff0dbbe82b1c3b39dc45e9262b879d44916f [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @type {?SettingsCrostiniPageElement} */
let crostiniPage = null;
/** @type {?TestCrostiniBrowserProxy} */
let crostiniBrowserProxy = null;
function setCrostiniPrefs(enabled, optional = {}) {
const {
sharedPaths = {},
sharedUsbDevices = [],
forwardedPorts = [],
crostiniMicSharingEnabled = false,
arcEnabled = false,
} = optional;
crostiniPage.prefs = {
arc: {
enabled: {value: arcEnabled},
},
crostini: {
enabled: {value: enabled},
port_forwarding: {ports: {value: forwardedPorts}},
},
guest_os: {
paths_shared_to_vms: {value: sharedPaths},
},
};
crostiniBrowserProxy.sharedUsbDevices = sharedUsbDevices;
crostiniBrowserProxy.crostiniMicSharingEnabled = crostiniMicSharingEnabled;
Polymer.dom.flush();
}
/**
* Checks whether a given element is visible to the user.
* @param {!Element} element
* @returns {boolean}
*/
function isVisible(element) {
return !!(element && element.getBoundingClientRect().width > 0);
}
suite('CrostiniPageTests', function() {
setup(function() {
crostiniBrowserProxy = new TestCrostiniBrowserProxy();
settings.CrostiniBrowserProxyImpl.instance_ = crostiniBrowserProxy;
PolymerTest.clearBody();
crostiniPage = document.createElement('settings-crostini-page');
document.body.appendChild(crostiniPage);
testing.Test.disableAnimationsAndTransitions();
});
teardown(function() {
crostiniPage.remove();
settings.Router.getInstance().resetRouteForTesting();
});
suite('MainPage', function() {
setup(function() {
setCrostiniPrefs(false);
});
test('Enable', function() {
const button = crostiniPage.$$('#enable');
assertTrue(!!button);
assertFalse(!!crostiniPage.$$('.subpage-arrow'));
assertFalse(button.disabled);
button.click();
Polymer.dom.flush();
assertEquals(
1, crostiniBrowserProxy.getCallCount('requestCrostiniInstallerView'));
setCrostiniPrefs(true);
assertTrue(!!crostiniPage.$$('.subpage-arrow'));
});
test('ButtonDisabledDuringInstall', async function() {
const button = crostiniPage.$$('#enable');
assertTrue(!!button);
await test_util.flushTasks();
assertFalse(button.disabled);
cr.webUIListenerCallback('crostini-installer-status-changed', true);
await test_util.flushTasks();
assertTrue(button.disabled);
cr.webUIListenerCallback('crostini-installer-status-changed', false);
await test_util.flushTasks();
assertFalse(button.disabled);
});
test('Deep link to setup Crostini', async () => {
loadTimeData.overrideValues({isDeepLinkingEnabled: true});
assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
const params = new URLSearchParams;
params.append('settingId', '800');
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI, params);
const deepLinkElement = crostiniPage.$$('#enable');
await test_util.waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
'Enable Crostini button should be focused for settingId=800.');
});
});
suite('SubPageDetails', function() {
/** @type {?SettingsCrostiniSubPageElement} */
let subpage;
setup(async function() {
setCrostiniPrefs(true, {arcEnabled: true});
loadTimeData.overrideValues({
showCrostiniExportImport: true,
showCrostiniContainerUpgrade: true,
showCrostiniPortForwarding: true,
showCrostiniDiskResize: true,
arcAdbSideloadingSupported: true,
});
settings.Router.getInstance().navigateTo(settings.routes.CROSTINI);
crostiniPage.$$('#crostini').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-subpage');
assertTrue(!!subpage);
});
suite('SubPageDefault', function() {
test('Basic', function() {
assertTrue(!!subpage.$$('#crostini-shared-paths'));
assertTrue(!!subpage.$$('#crostini-shared-usb-devices'));
assertTrue(!!subpage.$$('#crostini-export-import'));
assertTrue(!!subpage.$$('#crostini-enable-arc-adb'));
assertTrue(!!subpage.$$('#remove'));
assertTrue(!!subpage.$$('#container-upgrade'));
assertTrue(!!subpage.$$('#crostini-port-forwarding'));
assertTrue(!!subpage.$$('#crostini-mic-sharing-toggle'));
assertTrue(!!subpage.$$('#crostini-disk-resize'));
});
test('SharedPaths', async function() {
assertTrue(!!subpage.$$('#crostini-shared-paths'));
subpage.$$('#crostini-shared-paths').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-shared-paths');
assertTrue(!!subpage);
});
test('ContainerUpgrade', function() {
assertTrue(!!subpage.$$('#container-upgrade cr-button'));
subpage.$$('#container-upgrade cr-button').click();
assertEquals(
1,
crostiniBrowserProxy.getCallCount(
'requestCrostiniContainerUpgradeView'));
});
test('ContainerUpgradeButtonDisabledOnUpgradeDialog', async function() {
const button = subpage.$$('#container-upgrade cr-button');
assertTrue(!!button);
await test_util.flushTasks();
assertFalse(button.disabled);
cr.webUIListenerCallback('crostini-upgrader-status-changed', true);
await test_util.flushTasks();
assertTrue(button.disabled);
cr.webUIListenerCallback('crostini-upgrader-status-changed', false);
await test_util.flushTasks();
assertFalse(button.disabled);
});
test('ContainerUpgradeButtonDisabledOnInstall', async function() {
const button = subpage.$$('#container-upgrade cr-button');
assertTrue(!!button);
await test_util.flushTasks();
assertFalse(button.disabled);
cr.webUIListenerCallback('crostini-installer-status-changed', true);
await test_util.flushTasks();
assertTrue(button.disabled);
cr.webUIListenerCallback('crostini-installer-status-changed', false);
await test_util.flushTasks();
assertFalse(button.disabled);
});
test('InstallerStatusQueriedOnAttach', async function() {
// We navigated the page during setup, so this request should've been
// triggered by here.
assertTrue(
crostiniBrowserProxy.getCallCount(
'requestCrostiniInstallerStatus') >= 1);
});
test('Export', async function() {
assertTrue(!!subpage.$$('#crostini-export-import'));
subpage.$$('#crostini-export-import').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertTrue(!!subpage.$$('#export cr-button'));
subpage.$$('#export cr-button').click();
assertEquals(
1, crostiniBrowserProxy.getCallCount('exportCrostiniContainer'));
});
test('Deep link to backup linux', async () => {
loadTimeData.overrideValues({isDeepLinkingEnabled: true});
assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
const params = new URLSearchParams;
params.append('settingId', '802');
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_EXPORT_IMPORT, params);
Polymer.dom.flush();
subpage = crostiniPage.$$('settings-crostini-export-import');
const deepLinkElement = subpage.$$('#export cr-button');
await test_util.waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
'Export button should be focused for settingId=802.');
});
test('Import', async function() {
assertTrue(!!subpage.$$('#crostini-export-import'));
subpage.$$('#crostini-export-import').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
subpage.$$('#import cr-button').click();
await test_util.flushTasks();
subpage = subpage.$$('settings-crostini-import-confirmation-dialog');
subpage.$$('cr-dialog cr-button[id="continue"]').click();
assertEquals(
1, crostiniBrowserProxy.getCallCount('importCrostiniContainer'));
});
test('ExportImportButtonsGetDisabledOnOperationStatus', async function() {
assertTrue(!!subpage.$$('#crostini-export-import'));
subpage.$$('#crostini-export-import').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertFalse(subpage.$$('#export cr-button').disabled);
assertFalse(subpage.$$('#import cr-button').disabled);
cr.webUIListenerCallback(
'crostini-export-import-operation-status-changed', true);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertTrue(subpage.$$('#export cr-button').disabled);
assertTrue(subpage.$$('#import cr-button').disabled);
cr.webUIListenerCallback(
'crostini-export-import-operation-status-changed', false);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertFalse(subpage.$$('#export cr-button').disabled);
assertFalse(subpage.$$('#import cr-button').disabled);
});
test(
'ExportImportButtonsDisabledOnWhenInstallingCrostini',
async function() {
assertTrue(!!subpage.$$('#crostini-export-import'));
subpage.$$('#crostini-export-import').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertFalse(subpage.$$('#export cr-button').disabled);
assertFalse(subpage.$$('#import cr-button').disabled);
cr.webUIListenerCallback('crostini-installer-status-changed', true);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertTrue(subpage.$$('#export cr-button').disabled);
assertTrue(subpage.$$('#import cr-button').disabled);
cr.webUIListenerCallback(
'crostini-installer-status-changed', false);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-export-import');
assertFalse(subpage.$$('#export cr-button').disabled);
assertFalse(subpage.$$('#import cr-button').disabled);
});
test('ToggleCrostiniMicSharingCancel', async function() {
// Crostini is assumed to be running when the page is loaded.
assertTrue(!!subpage.$$('#crostini-mic-sharing-toggle'));
assertFalse(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
setCrostiniPrefs(true, {crostiniMicSharingEnabled: true});
cr.webUIListenerCallback(
'crostini-mic-sharing-enabled-changed',
crostiniBrowserProxy.crostiniMicSharingEnabled);
assertTrue(subpage.$$('#crostini-mic-sharing-toggle').checked);
subpage.$$('#crostini-mic-sharing-toggle').click();
await test_util.flushTasks();
assertTrue(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
const dialog = subpage.$$('settings-crostini-mic-sharing-dialog');
const dialogClosedPromise = test_util.eventToPromise('close', dialog);
dialog.$$('#cancel').click();
await Promise.all([dialogClosedPromise, test_util.flushTasks()]);
// Because the dialog was cancelled, the toggle should not have changed.
assertFalse(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
assertTrue(subpage.$$('#crostini-mic-sharing-toggle').checked);
});
test('ToggleCrostiniMicSharingShutdown', async function() {
// Crostini is assumed to be running when the page is loaded.
assertTrue(!!subpage.$$('#crostini-mic-sharing-toggle'));
assertFalse(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
setCrostiniPrefs(true, {crostiniMicSharingEnabled: false});
cr.webUIListenerCallback(
'crostini-mic-sharing-enabled-changed',
crostiniBrowserProxy.crostiniMicSharingEnabled);
assertFalse(subpage.$$('#crostini-mic-sharing-toggle').checked);
subpage.$$('#crostini-mic-sharing-toggle').click();
await test_util.flushTasks();
assertTrue(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
const dialog = subpage.$$('settings-crostini-mic-sharing-dialog');
const dialogClosedPromise = test_util.eventToPromise('close', dialog);
dialog.$$('#shutdown').click();
await Promise.all([dialogClosedPromise, test_util.flushTasks()]);
assertEquals(1, crostiniBrowserProxy.getCallCount('shutdownCrostini'));
assertEquals(
1,
crostiniBrowserProxy.getCallCount('setCrostiniMicSharingEnabled'));
cr.webUIListenerCallback(
'crostini-mic-sharing-enabled-changed',
crostiniBrowserProxy.crostiniMicSharingEnabled);
assertFalse(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
assertTrue(subpage.$$('#crostini-mic-sharing-toggle').checked);
// Crostini is now shutdown, this means that it doesn't need to be
// restarted in order for changes to take effect, therefore no dialog is
// needed and the mic sharing settings can be changed immediately.
subpage.$$('#crostini-mic-sharing-toggle').click();
await test_util.flushTasks();
cr.webUIListenerCallback(
'crostini-mic-sharing-enabled-changed',
crostiniBrowserProxy.crostiniMicSharingEnabled);
assertFalse(!!subpage.$$('settings-crostini-mic-sharing-dialog'));
assertFalse(subpage.$$('#crostini-mic-sharing-toggle').checked);
});
test('Remove', async function() {
assertTrue(!!subpage.$$('#remove cr-button'));
subpage.$$('#remove cr-button').click();
assertEquals(
1, crostiniBrowserProxy.getCallCount('requestRemoveCrostini'));
setCrostiniPrefs(false);
await test_util.eventToPromise('popstate', window);
assertEquals(
settings.Router.getInstance().getCurrentRoute(),
settings.routes.CROSTINI);
assertTrue(!!crostiniPage.$$('#enable'));
});
test('RemoveHidden', async function() {
// Elements are not destroyed when a dom-if stops being shown, but we
// can check if their rendered width is non-zero. This should be
// resilient against most formatting changes, since we're not relying on
// them having any exact size, or on Polymer using any particular means
// of hiding elements.
assertTrue(!!subpage.shadowRoot.querySelector('#remove').clientWidth);
cr.webUIListenerCallback('crostini-installer-status-changed', true);
await test_util.flushTasks();
assertFalse(!!subpage.shadowRoot.querySelector('#remove').clientWidth);
cr.webUIListenerCallback('crostini-installer-status-changed', false);
await test_util.flushTasks();
assertTrue(!!subpage.shadowRoot.querySelector('#remove').clientWidth);
});
test('HideOnDisable', async function() {
assertEquals(
settings.Router.getInstance().getCurrentRoute(),
settings.routes.CROSTINI_DETAILS);
setCrostiniPrefs(false);
await test_util.eventToPromise('popstate', window);
assertEquals(
settings.Router.getInstance().getCurrentRoute(),
settings.routes.CROSTINI);
});
test('DiskResizeOpensWhenClicked', async function() {
assertTrue(!!subpage.$$('#showDiskResizeButton'));
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo',
{succeeded: true, canResize: true, isUserChosenSize: true});
subpage.$$('#showDiskResizeButton').click();
await test_util.flushTasks();
const dialog = subpage.$$('settings-crostini-disk-resize-dialog');
assertTrue(!!dialog);
});
test('Deep link to resize disk', async () => {
loadTimeData.overrideValues({isDeepLinkingEnabled: true});
assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
assertTrue(!!subpage.$$('#showDiskResizeButton'));
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo',
{succeeded: true, canResize: true, isUserChosenSize: true});
const params = new URLSearchParams;
params.append('settingId', '805');
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_DETAILS, params);
const deepLinkElement = subpage.$$('#showDiskResizeButton');
await test_util.waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
'Resize disk button should be focused for settingId=805.');
});
});
suite('SubPagePortForwarding', function() {
/** @type {?SettingsCrostiniPortForwarding} */
let subpage;
setup(async function() {
crostiniBrowserProxy.portOperationSuccess = true;
setCrostiniPrefs(true, {
forwardedPorts: [
{
port_number: 5000,
protocol_type: 0,
label: 'Label1',
},
{
port_number: 5001,
protocol_type: 1,
label: 'Label2',
},
]
});
await test_util.flushTasks();
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_PORT_FORWARDING);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
assertTrue(!!subpage);
});
test('DisplayPorts', async function() {
// Extra list item for the titles.
assertEquals(
3, subpage.shadowRoot.querySelectorAll('.list-item').length);
});
test('AddPortSuccess', async function() {
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
subpage.$$('#addPort cr-button').click();
await test_util.flushTasks();
subpage = subpage.$$('settings-crostini-add-port-dialog');
const portNumberInput = subpage.$$('#portNumberInput');
portNumberInput, focus();
portNumberInput.value = '5002';
portNumberInput, blur();
assertEquals(portNumberInput.invalid, false);
const portLabelInput = subpage.$$('#portLabelInput');
portLabelInput.value = 'Some Label';
subpage.$$('cr-dialog cr-button[id="continue"]').click();
assertEquals(
1, crostiniBrowserProxy.getCallCount('addCrostiniPortForward'));
});
test('AddPortFail', async function() {
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
subpage.$$('#addPort cr-button').click();
await test_util.flushTasks();
subpage = subpage.$$('settings-crostini-add-port-dialog');
const portNumberInput = subpage.$$('#portNumberInput');
const portLabelInput = subpage.$$('#portLabelInput');
const continueButton = subpage.$$('cr-dialog cr-button[id="continue"]');
assertEquals(portNumberInput.invalid, false);
portNumberInput.focus();
portNumberInput.value = '1023';
continueButton.click();
assertEquals(
0, crostiniBrowserProxy.getCallCount('addCrostiniPortForward'));
assertEquals(continueButton.disabled, true);
assertEquals(portNumberInput.invalid, true);
assertEquals(
portNumberInput.errorMessage,
loadTimeData.getString('crostiniPortForwardingAddError'));
portNumberInput.value = '65536';
assertEquals(continueButton.disabled, true);
assertEquals(portNumberInput.invalid, true);
assertEquals(
portNumberInput.errorMessage,
loadTimeData.getString('crostiniPortForwardingAddError'));
portNumberInput.focus();
portNumberInput.value = '5000';
portNumberInput.blur();
subpage.$$('cr-dialog cr-button[id="continue"]').click();
assertEquals(continueButton.disabled, true);
assertEquals(portNumberInput.invalid, true);
assertEquals(
portNumberInput.errorMessage,
loadTimeData.getString('crostiniPortForwardingAddExisting'));
portNumberInput.focus();
portNumberInput.value = '1024';
portNumberInput.blur();
assertEquals(continueButton.disabled, false);
assertEquals(portNumberInput.invalid, false);
assertEquals(portNumberInput.errorMessage, '');
});
test('AddPortCancel', async function() {
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
subpage.$$('#addPort cr-button').click();
await test_util.flushTasks();
subpage = subpage.$$('settings-crostini-add-port-dialog');
subpage.$$('cr-dialog cr-button[id="cancel"]').click();
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
assertTrue(!!subpage);
});
test('RemoveAllPorts', async function() {
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
subpage.$$('#showRemoveAllPortsMenu').click();
await test_util.flushTasks();
subpage.$$('#removeAllPortsButton').click();
assertEquals(
1,
crostiniBrowserProxy.getCallCount('removeAllCrostiniPortForwards'));
});
test('RemoveSinglePort', async function() {
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
subpage.$$('#showRemoveSinglePortMenu0').click();
await test_util.flushTasks();
subpage.$$('#removeSinglePortButton').click();
assertEquals(
1, crostiniBrowserProxy.getCallCount('removeCrostiniPortForward'));
});
test('ActivateSinglePortSucess', async function() {
assertFalse(subpage.$$('#errorToast').open);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
subpage.$$('#toggleActivationButton0').click();
await test_util.flushTasks();
assertEquals(
1,
crostiniBrowserProxy.getCallCount('activateCrostiniPortForward'));
assertFalse(subpage.$$('#errorToast').open);
});
test('ActivateSinglePortFail', async function() {
await test_util.flushTasks();
crostiniBrowserProxy.portOperationSuccess = false;
assertFalse(subpage.$$('#errorToast').open);
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
const crToggle = subpage.$$('#toggleActivationButton1');
assertEquals(crToggle.checked, false);
crToggle.click();
await test_util.flushTasks();
assertEquals(
1,
crostiniBrowserProxy.getCallCount('activateCrostiniPortForward'));
assertEquals(crToggle.checked, false);
assertTrue(subpage.$$('#errorToast').open);
});
test('DeactivateSinglePort', async function() {
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-port-forwarding');
const crToggle = subpage.$$('#toggleActivationButton0');
crToggle.checked = true;
crToggle.click();
await test_util.flushTasks();
assertEquals(
1,
crostiniBrowserProxy.getCallCount('deactivateCrostiniPortForward'));
});
test('ActivePortsChanged', async function() {
setCrostiniPrefs(true, {
forwardedPorts: [
{
port_number: 5000,
protocol_type: 0,
label: 'Label1',
},
]
});
const crToggle = subpage.$$('#toggleActivationButton0');
cr.webUIListenerCallback(
'crostini-port-forwarder-active-ports-changed',
[{'port_number': 5000, 'protocol_type': 0}]);
await test_util.flushTasks();
assertTrue(crToggle.checked);
cr.webUIListenerCallback(
'crostini-port-forwarder-active-ports-changed', []);
await test_util.flushTasks();
assertFalse(crToggle.checked);
});
test('PortPrefsChange', async function() {
setCrostiniPrefs(true, {
forwardedPorts: [
{
port_number: 5000,
protocol_type: 0,
label: 'Label1',
},
{
port_number: 5001,
protocol_type: 0,
label: 'Label1',
},
]
});
assertEquals(
3, subpage.shadowRoot.querySelectorAll('.list-item').length);
setCrostiniPrefs(true, {
forwardedPorts: [
{
port_number: 5000,
protocol_type: 0,
label: 'Label1',
},
{
port_number: 5001,
protocol_type: 0,
label: 'Label1',
},
{
port_number: 5002,
protocol_type: 0,
label: 'Label1',
},
]
});
assertEquals(
4, subpage.shadowRoot.querySelectorAll('.list-item').length);
setCrostiniPrefs(true, {forwardedPorts: []});
assertEquals(
0, subpage.shadowRoot.querySelectorAll('.list-item').length);
});
test('CrostiniStopAndStart', async function() {
const crToggle = subpage.$$('#toggleActivationButton0');
assertFalse(crToggle.disabled);
cr.webUIListenerCallback('crostini-status-changed', false);
assertTrue(crToggle.disabled);
cr.webUIListenerCallback('crostini-status-changed', true);
assertFalse(crToggle.disabled);
});
});
suite('DiskResize', async function() {
let dialog;
/**
* Helper function to assert that the expected block is visible and the
* others are not.
* @param {!string} selector
*/
function assertVisibleBlockIs(selector) {
const selectors =
['#unsupported', '#resize-block', '#error', '#loading'];
assertTrue(isVisible(dialog.$$(selector)));
selectors.filter(s => s !== selector).forEach(s => {
assertFalse(isVisible(dialog.$$(s)));
});
}
const ticks = [
{label: 'label 0', value: 0, ariaLabel: 'label 0'},
{label: 'label 10', value: 10, ariaLabel: 'label 10'},
{label: 'label 100', value: 100, ariaLabel: 'label 100'}
];
const resizeableData = {
succeeded: true,
canResize: true,
isUserChosenSize: true,
isLowSpaceAvailable: false,
defaultIndex: 2,
ticks: ticks
};
const sparseDiskData = {
succeeded: true,
canResize: true,
isUserChosenSize: false,
isLowSpaceAvailable: false,
defaultIndex: 2,
ticks: ticks
};
async function clickShowDiskResize(userChosen) {
await crostiniBrowserProxy.resolvePromises('getCrostiniDiskInfo', {
succeeded: true,
canResize: true,
isUserChosenSize: userChosen,
ticks: ticks,
defaultIndex: 2
});
subpage.$$('#showDiskResizeButton').click();
await test_util.flushTasks();
dialog = subpage.$$('settings-crostini-disk-resize-dialog');
if (userChosen) {
// We should be on the loading page but unable to kick off a resize
// yet.
assertTrue(!!dialog.$$('#loading'));
assertTrue(dialog.$$('#resize').disabled);
}
}
setup(async function() {
assertTrue(!!subpage.$$('#showDiskResizeButton'));
const subtext = subpage.$$('#diskSizeDescription');
});
test('ResizeUnsupported', async function() {
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', {succeeded: true, canResize: false});
assertFalse(isVisible(subpage.$$('#showDiskResizeButton')));
assertEquals(
subpage.$$('#diskSizeDescription').innerText,
loadTimeData.getString('crostiniDiskResizeNotSupportedSubtext'));
});
test('ResizeButtonAndSubtextCorrectlySet', async function() {
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', resizeableData);
const button = subpage.$$('#showDiskResizeButton');
const subtext = subpage.$$('#diskSizeDescription');
assertEquals(
button.innerText,
loadTimeData.getString('crostiniDiskResizeShowButton'));
assertEquals(subtext.innerText, 'label 100');
});
test('ReserveSizeButtonAndSubtextCorrectlySet', async function() {
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', sparseDiskData);
const button = subpage.$$('#showDiskResizeButton');
const subtext = subpage.$$('#diskSizeDescription');
assertEquals(
button.innerText,
loadTimeData.getString('crostiniDiskReserveSizeButton'));
assertEquals(
subtext.innerText,
loadTimeData.getString(
'crostiniDiskResizeDynamicallyAllocatedSubtext'));
});
test('ResizeRecommendationShownCorrectly', async function() {
await clickShowDiskResize(true);
const diskInfo = resizeableData;
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', diskInfo);
assertTrue(isVisible(dialog.$$('#recommended-size')));
assertFalse(isVisible(dialog.$$('#recommended-size-warning')));
});
test('ResizeRecommendationWarningShownCorrectly', async function() {
await clickShowDiskResize(true);
const diskInfo = resizeableData;
diskInfo.isLowSpaceAvailable = true;
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', diskInfo);
assertFalse(isVisible(dialog.$$('#recommended-size')));
assertTrue(isVisible(dialog.$$('#recommended-size-warning')));
});
test('MessageShownIfErrorAndCanRetry', async function() {
await clickShowDiskResize(true);
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', {succeeded: false, isUserChosenSize: true});
// We failed, should have a retry button.
let button = dialog.$$('#retry');
assertVisibleBlockIs('#error');
assertTrue(isVisible(button));
assertTrue(dialog.$$('#resize').disabled);
assertFalse(dialog.$$('#cancel').disabled);
// Back to the loading screen.
button.click();
await test_util.flushTasks();
assertVisibleBlockIs('#loading');
assertTrue(dialog.$$('#resize').disabled);
assertFalse(dialog.$$('#cancel').disabled);
// And failure page again.
await crostiniBrowserProxy.rejectPromises('getCrostiniDiskInfo');
button = dialog.$$('#retry');
assertTrue(isVisible(button));
assertVisibleBlockIs('#error');
assertTrue(dialog.$$('#resize').disabled);
assertTrue(dialog.$$('#resize').disabled);
assertFalse(dialog.$$('#cancel').disabled);
});
test('MessageShownIfCannotResize', async function() {
await clickShowDiskResize(true);
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo',
{succeeded: true, canResize: false, isUserChosenSize: true});
assertVisibleBlockIs('#unsupported');
assertTrue(dialog.$$('#resize').disabled);
assertFalse(dialog.$$('#cancel').disabled);
});
test('ResizePageShownIfCanResize', async function() {
await clickShowDiskResize(true);
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', resizeableData);
assertVisibleBlockIs('#resize-block');
assertEquals(ticks[0].label, dialog.$$('#label-begin').innerText);
assertEquals(ticks[2].label, dialog.$$('#label-end').innerText);
assertEquals(2, dialog.$$('#diskSlider').value);
assertFalse(dialog.$$('#resize').disabled);
assertFalse(dialog.$$('#cancel').disabled);
});
test('InProgressResizing', async function() {
await clickShowDiskResize(true);
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', resizeableData);
const button = dialog.$$('#resize');
button.click();
await test_util.flushTasks();
assertTrue(button.disabled);
assertFalse(isVisible(dialog.$$('#done')));
assertTrue(isVisible(dialog.$$('#resizing')));
assertFalse(isVisible(dialog.$$('#resize-error')));
assertTrue(dialog.$$('#cancel').disabled);
});
test('ErrorResizing', async function() {
await clickShowDiskResize(true);
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', resizeableData);
const button = dialog.$$('#resize');
button.click();
await crostiniBrowserProxy.resolvePromises('resizeCrostiniDisk', false);
assertFalse(button.disabled);
assertFalse(isVisible(dialog.$$('#done')));
assertFalse(isVisible(dialog.$$('#resizing')));
assertTrue(isVisible(dialog.$$('#resize-error')));
assertFalse(dialog.$$('#cancel').disabled);
});
test('SuccessResizing', async function() {
await clickShowDiskResize(true);
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', resizeableData);
const button = dialog.$$('#resize');
button.click();
await crostiniBrowserProxy.resolvePromises('resizeCrostiniDisk', true);
// Dialog should close itself.
await test_util.eventToPromise('close', dialog);
});
test('DiskResizeConfirmationDialogShownAndAccepted', async function() {
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', sparseDiskData);
await clickShowDiskResize(false);
// Dismiss confirmation.
let confirmationDialog =
subpage.$$('settings-crostini-disk-resize-confirmation-dialog');
assertTrue(isVisible(confirmationDialog.$$('#continue')));
assertTrue(isVisible(confirmationDialog.$$('#cancel')));
confirmationDialog.$$('#continue').click();
await test_util.eventToPromise('close', confirmationDialog);
assertFalse(isVisible(confirmationDialog));
dialog = subpage.$$('settings-crostini-disk-resize-dialog');
assertTrue(!!dialog);
assertTrue(isVisible(dialog.$$('#resize')));
assertTrue(isVisible(dialog.$$('#cancel')));
// Cancel main resize dialog.
dialog.$$('#cancel').click();
await test_util.eventToPromise('close', dialog);
assertFalse(isVisible(dialog));
// On another click, confirmation dialog should be shown again.
await clickShowDiskResize(false);
confirmationDialog =
subpage.$$('settings-crostini-disk-resize-confirmation-dialog');
assertTrue(isVisible(confirmationDialog.$$('#continue')));
confirmationDialog.$$('#continue').click();
await test_util.eventToPromise('close', confirmationDialog);
// Main dialog should show again.
dialog = subpage.$$('settings-crostini-disk-resize-dialog');
assertTrue(!!dialog);
assertTrue(isVisible(dialog.$$('#resize')));
assertTrue(isVisible(dialog.$$('#cancel')));
});
test('DiskResizeConfirmationDialogShownAndCanceled', async function() {
await crostiniBrowserProxy.resolvePromises(
'getCrostiniDiskInfo', sparseDiskData);
await clickShowDiskResize(false);
const confirmationDialog =
subpage.$$('settings-crostini-disk-resize-confirmation-dialog');
assertTrue(isVisible(confirmationDialog.$$('#continue')));
assertTrue(isVisible(confirmationDialog.$$('#cancel')));
confirmationDialog.$$('#cancel').click();
await test_util.eventToPromise('close', confirmationDialog);
assertFalse(!!subpage.$$('settings-crostini-disk-resize-dialog'));
});
});
});
suite('SubPageSharedPaths', function() {
let subpage;
setup(async function() {
setCrostiniPrefs(
true, {sharedPaths: {path1: ['termina'], path2: ['termina']}});
await test_util.flushTasks();
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_SHARED_PATHS);
await test_util.flushTasks();
Polymer.dom.flush();
subpage = crostiniPage.$$('settings-crostini-shared-paths');
assertTrue(!!subpage);
});
test('Basic', function() {
assertEquals(
3, subpage.shadowRoot.querySelectorAll('.settings-box').length);
assertEquals(2, subpage.shadowRoot.querySelectorAll('.list-item').length);
});
test('Remove', async function() {
assertFalse(subpage.$.crostiniInstructionsRemove.hidden);
assertFalse(subpage.$.crostiniList.hidden);
assertTrue(subpage.$.crostiniListEmpty.hidden);
assertTrue(!!subpage.$$('.list-item cr-icon-button'));
const rows = '.list-item:not([hidden])';
assertEquals(2, subpage.shadowRoot.querySelectorAll(rows).length);
{
// Remove first shared path, still one left.
subpage.$$('.list-item cr-icon-button').click();
const [vmName, path] =
await crostiniBrowserProxy.whenCalled('removeCrostiniSharedPath');
assertEquals('termina', vmName);
assertEquals('path1', path);
setCrostiniPrefs(true, {sharedPaths: {path2: ['termina']}});
}
await test_util.flushTasks();
Polymer.dom.flush();
assertEquals(1, subpage.shadowRoot.querySelectorAll(rows).length);
assertFalse(subpage.$.crostiniInstructionsRemove.hidden);
{
// Remove remaining shared path, none left.
crostiniBrowserProxy.resetResolver('removeCrostiniSharedPath');
subpage.$$(`${rows} cr-icon-button`).click();
const [vmName, path] =
await crostiniBrowserProxy.whenCalled('removeCrostiniSharedPath');
assertEquals('termina', vmName);
assertEquals('path2', path);
setCrostiniPrefs(true, {sharedPaths: {}});
}
await test_util.flushTasks();
Polymer.dom.flush();
// Verify remove instructions are hidden, and empty list message is shown.
assertTrue(subpage.$.crostiniInstructionsRemove.hidden);
assertTrue(subpage.$.crostiniList.hidden);
assertFalse(subpage.$.crostiniListEmpty.hidden);
});
test('RemoveFailedRetry', async function() {
// Remove shared path fails.
crostiniBrowserProxy.removeSharedPathResult = false;
subpage.$$('.list-item cr-icon-button').click();
await crostiniBrowserProxy.whenCalled('removeCrostiniSharedPath');
Polymer.dom.flush();
assertTrue(subpage.$$('#removeSharedPathFailedDialog').open);
// Click retry and make sure 'removeCrostiniSharedPath' is called
// and dialog is closed/removed.
crostiniBrowserProxy.removeSharedPathResult = true;
subpage.$$('#removeSharedPathFailedDialog')
.querySelector('.action-button')
.click();
await crostiniBrowserProxy.whenCalled('removeCrostiniSharedPath');
assertFalse(!!subpage.$$('#removeSharedPathFailedDialog'));
});
});
suite('SubPageSharedUsbDevices', function() {
let subpage;
setup(async function() {
setCrostiniPrefs(true, {
sharedUsbDevices: [
{
guid: '0001',
name: 'usb_dev1',
shared: false,
shareWillReassign: false
},
{
guid: '0002',
name: 'usb_dev2',
shared: true,
shareWillReassign: false
},
{
guid: '0003',
name: 'usb_dev3',
shared: false,
shareWillReassign: true
},
]
});
await test_util.flushTasks();
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_SHARED_USB_DEVICES);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-shared-usb-devices');
assertTrue(!!subpage);
});
test('USB devices are shown', function() {
assertEquals(3, subpage.shadowRoot.querySelectorAll('.toggle').length);
});
test('USB shared state is updated by toggling', async function() {
assertTrue(!!subpage.$$('.toggle'));
subpage.$$('.toggle').click();
await test_util.flushTasks();
Polymer.dom.flush();
const args =
await crostiniBrowserProxy.whenCalled('setCrostiniUsbDeviceShared');
assertEquals('0001', args[0]);
assertEquals(true, args[1]);
// Simulate a change in the underlying model.
cr.webUIListenerCallback('crostini-shared-usb-devices-changed', [
{
guid: '0001',
name: 'usb_dev1',
shared: true,
shareWillReassign: false
},
]);
Polymer.dom.flush();
assertEquals(1, subpage.shadowRoot.querySelectorAll('.toggle').length);
});
test('Show dialog for reassign', async function() {
const items = subpage.shadowRoot.querySelectorAll('.toggle');
assertEquals(3, items.length);
// Clicking on item[2] should show dialog.
assertFalse(!!subpage.$$('#reassignDialog'));
items[2].click();
Polymer.dom.flush();
assertTrue(subpage.$$('#reassignDialog').open);
// Clicking cancel will close the dialog.
subpage.$$('#cancel').click();
Polymer.dom.flush();
assertFalse(!!subpage.$$('#reassignDialog'));
// Clicking continue will call the proxy and close the dialog.
items[2].click();
Polymer.dom.flush();
assertTrue(subpage.$$('#reassignDialog').open);
subpage.$$('#continue').click();
Polymer.dom.flush();
assertFalse(!!subpage.$$('#reassignDialog'));
const args =
await crostiniBrowserProxy.whenCalled('setCrostiniUsbDeviceShared');
assertEquals('0003', args[0]);
assertEquals(true, args[1]);
});
});
suite('SubPageArcAdb', function() {
let subpage;
setup(async function() {
setCrostiniPrefs(true, {arcEnabled: true});
loadTimeData.overrideValues({
arcAdbSideloadingSupported: true,
});
await test_util.flushTasks();
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_ANDROID_ADB);
await test_util.flushTasks();
subpage = crostiniPage.$$('settings-crostini-arc-adb');
assertTrue(!!subpage);
});
test('Deep link to enable adb debugging', async () => {
loadTimeData.overrideValues({isDeepLinkingEnabled: true});
assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
const params = new URLSearchParams;
params.append('settingId', '804');
settings.Router.getInstance().navigateTo(
settings.routes.CROSTINI_ANDROID_ADB, params);
Polymer.dom.flush();
const deepLinkElement = subpage.$$('#arcAdbEnabledButton');
await test_util.waitAfterNextRender(deepLinkElement);
assertEquals(
deepLinkElement, getDeepActiveElement(),
'Enable adb debugging button should be focused for settingId=804.');
});
});
});