blob: 617eea133d4c28b950df90498961ed0c78743516 [file] [log] [blame]
// Copyright 2019 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.
import 'chrome://crostini-installer/app.js';
import {BrowserProxy} from 'chrome://crostini-installer/browser_proxy.js';
import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
import {flushTasks} from 'chrome://test/test_util.m.js';
const InstallerState = crostini.mojom.InstallerState;
const InstallerError = crostini.mojom.InstallerError;
class FakePageHandler extends TestBrowserProxy {
constructor() {
super([
'install', 'cancel', 'cancelBeforeStart', 'onPageClosed',
'requestAmountOfFreeDiskSpace'
]);
}
/** @override */
install(diskSize, username) {
this.methodCalled('install', [diskSize, username]);
}
/** @override */
cancel() {
this.methodCalled('cancel');
}
/** @override */
cancelBeforeStart() {
this.methodCalled('cancelBeforeStart');
}
/** @override */
onPageClosed() {
this.methodCalled('onPageClosed');
}
/** @override */
requestAmountOfFreeDiskSpace() {
this.methodCalled('requestAmountOfFreeDiskSpace');
}
}
class FakeBrowserProxy {
constructor() {
this.handler = new FakePageHandler();
this.callbackRouter =
new chromeos.crostiniInstaller.mojom.PageCallbackRouter();
/** @type {appManagement.mojom.PageRemote} */
this.page = this.callbackRouter.$.bindNewPipeAndPassRemote();
}
}
suite('<crostini-installer-app>', () => {
let fakeBrowserProxy;
let app;
setup(async () => {
fakeBrowserProxy = new FakeBrowserProxy();
BrowserProxy.instance_ = fakeBrowserProxy;
app = document.createElement('crostini-installer-app');
PolymerTest.clearBody();
document.body.appendChild(app);
await flushTasks();
});
teardown(function() {
app.remove();
});
const clickButton = async (button) => {
assertFalse(button.hidden);
assertFalse(button.disabled);
button.click();
await flushTasks();
};
const getInstallButton = () => {
return app.$$('#install');
};
const getCancelButton = () => {
return app.$$('.cancel-button');
};
const clickNext = async () => {
await clickButton(app.$.next);
};
const clickInstall = async () => {
await clickButton(getInstallButton());
};
const clickCancel = async () => {
await clickButton(getCancelButton());
};
const clickCustomSize = async () => {
await clickButton(app.$$('#custom-size'));
};
/**
* Checks whether a given element is hidden.
* @param {!Element} element
* @returns {boolean}
*/
function isHidden(element) {
return (
!element || element.getBoundingClientRect().width <= 0 ||
element.hidden);
}
const diskTicks = [
{value: 1000, ariaValue: '1', label: '1'},
{value: 2000, ariaValue: '2', label: '2'}
];
test('installFlow', async () => {
expectFalse(app.$$('#prompt-message').hidden);
expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 0);
// It should wait for disk info to be available.
await clickNext();
await flushTasks();
expectFalse(app.$$('#prompt-message').hidden);
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
await flushTasks();
expectFalse(app.$$('#configure-message').hidden);
await clickCancel(); // Back to the prompt page.
expectFalse(app.$$('#prompt-message').hidden);
await clickNext();
await flushTasks();
expectFalse(app.$$('#configure-message').hidden);
await clickInstall();
await fakeBrowserProxy.handler.whenCalled('install').then(
([diskSize, username]) => {
assertEquals(
username, loadTimeData.getString('defaultContainerUsername'));
});
expectFalse(app.$$('#installing-message').hidden);
expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 1);
expectTrue(getInstallButton().hidden);
fakeBrowserProxy.page.onProgressUpdate(
InstallerState.kCreateDiskImage, 0.5);
await flushTasks();
expectTrue(
!!app.$$('#installing-message > div').textContent.trim(),
'progress message should be set');
expectEquals(
app.$$('#installing-message > paper-progress').getAttribute('value'),
'50');
expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 0);
fakeBrowserProxy.page.onInstallFinished(InstallerError.kNone);
await flushTasks();
expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
});
// We only proceed to the config page if disk info is available. Let's make
// sure if the user click the next button multiple time very soon it dose not
// blow up.
test('multipleClickNextBeforeDiskAvailable', async () => {
expectFalse(app.$$('#prompt-message').hidden);
// It should wait for disk info to be available.
await clickNext();
await clickNext();
await clickNext();
await flushTasks();
expectFalse(app.$$('#prompt-message').hidden);
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
await flushTasks();
// Enter configure page as usual
expectFalse(app.$$('#configure-message').hidden);
// Can back to prompt page as usual.
await clickCancel();
expectFalse(app.$$('#prompt-message').hidden);
await clickNext();
await flushTasks();
// Re-enter configure page as usual
expectFalse(app.$$('#configure-message').hidden);
});
test('straightToErrorPageIfMinDiskUnmet', async () => {
expectFalse(app.$$('#prompt-message').hidden);
fakeBrowserProxy.page.onAmountOfFreeDiskSpace([], 0, false);
await clickNext();
await flushTasks();
expectFalse(app.$$('#error-message').hidden);
expectTrue(
!!app.$$('#error-message > div').textContent.trim(),
'error message should be set');
// We do not show retry button in this case.
assertTrue(getInstallButton().hidden);
});
test('showWarningIfLowFreeSpace', async () => {
expectFalse(app.$$('#prompt-message').hidden);
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, true);
await clickNext();
await flushTasks();
expectFalse(app.$$('#configure-message').hidden);
expectFalse(isHidden(app.$$('#low-free-space-warning')));
});
diskTicks.forEach(async (_, defaultIndex) => {
test(`configDiskSpaceWithDefault-${defaultIndex}`, async () => {
expectFalse(app.$$('#prompt-message').hidden);
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(
diskTicks, defaultIndex, false);
await clickNext();
await flushTasks();
expectFalse(app.$$('#configure-message').hidden);
expectTrue(isHidden(app.$$('#low-free-space-warning')));
expectTrue(isHidden(app.$$('#diskSlider')));
await clickInstall();
await fakeBrowserProxy.handler.whenCalled('install').then(
([diskSize, username]) => {
assertEquals(diskSize, diskTicks[defaultIndex].value);
});
expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 1);
});
});
test('configDiskSpaceWithUserSelection', async () => {
expectFalse(app.$$('#prompt-message').hidden);
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
await clickNext();
await flushTasks();
await clickCustomSize();
await flushTasks();
expectFalse(app.$$('#configure-message').hidden);
expectTrue(isHidden(app.$$('#low-free-space-warning')));
expectFalse(isHidden(app.$$('#diskSlider')));
app.$$('#diskSlider').value = 1;
await clickInstall();
await fakeBrowserProxy.handler.whenCalled('install').then(
([diskSize, username]) => {
assertEquals(diskSize, diskTicks[1].value);
});
expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 1);
});
test('configUsername', async () => {
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
await clickNext();
expectEquals(
app.$.username.value,
loadTimeData.getString('defaultContainerUsername'));
// Test invalid usernames
const invalidUsernames = [
'root', // Unavailable.
'0abcd', // Invalid first character.
'aBcd', // Invalid (uppercase) character.
];
for (const username of invalidUsernames) {
app.$.username.value = username;
await flushTasks();
expectTrue(app.$.username.invalid);
expectTrue(!!app.$.username.errorMessage);
expectTrue(app.$.install.disabled);
}
// Test the empty username. The username field should not show an error, but
// we want the install button to be disabled.
app.$.username.value = '';
await flushTasks();
expectFalse(app.$.username.invalid);
expectFalse(!!app.$.username.errorMessage);
expectTrue(app.$.install.disabled);
// Test a valid username
const validUsername = 'totally-valid_username';
app.$.username.value = validUsername;
await flushTasks();
expectFalse(app.$.username.invalid);
clickInstall();
await fakeBrowserProxy.handler.whenCalled('install').then(
([diskSize, username]) => {
assertEquals(username, validUsername);
});
expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 1);
});
test('errorCancel', async () => {
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
await clickNext();
await clickInstall();
fakeBrowserProxy.page.onInstallFinished(InstallerError.kErrorOffline);
await flushTasks();
expectFalse(app.$$('#error-message').hidden);
expectTrue(
!!app.$$('#error-message > div').textContent.trim(),
'error message should be set');
await clickCancel();
expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
expectEquals(fakeBrowserProxy.handler.getCallCount('cancelBeforeStart'), 0);
expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 0);
});
test('errorRetry', async () => {
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(diskTicks, 0, false);
await clickNext();
await clickInstall();
fakeBrowserProxy.page.onInstallFinished(InstallerError.kErrorOffline);
await flushTasks();
expectFalse(app.$$('#error-message').hidden);
expectTrue(
!!app.$$('#error-message > div').textContent.trim(),
'error message should be set');
await clickInstall();
expectEquals(fakeBrowserProxy.handler.getCallCount('install'), 2);
});
[clickCancel,
() => fakeBrowserProxy.page.requestClose(),
].forEach((canceller, i) => test(`cancelBeforeStart-{i}`, async () => {
await canceller();
await flushTasks();
expectEquals(
fakeBrowserProxy.handler.getCallCount('cancelBeforeStart'),
1);
expectEquals(
fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 0);
}));
// This is a special case that requestClose is different from clicking cancel
// --- instead of going back to the previous page, requestClose should close
// the page immediately.
test('requestCloseAtConfigPage', async () => {
await clickNext(); // Progress to config page.
await fakeBrowserProxy.page.requestClose();
await flushTasks();
expectEquals(fakeBrowserProxy.handler.getCallCount('cancelBeforeStart'), 1);
expectEquals(fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 0);
});
[clickCancel,
() => fakeBrowserProxy.page.requestClose(),
].forEach((canceller, i) => test(`cancelAfterStart-{i}`, async () => {
fakeBrowserProxy.page.onAmountOfFreeDiskSpace(
diskTicks, 0, false);
await clickNext();
await clickInstall();
await canceller();
await flushTasks();
expectEquals(fakeBrowserProxy.handler.getCallCount('cancel'), 1);
expectEquals(
fakeBrowserProxy.handler.getCallCount('onPageClosed'), 0,
'should not close until onCanceled is called');
expectTrue(getInstallButton().hidden);
expectTrue(getCancelButton().disabled);
fakeBrowserProxy.page.onCanceled();
await flushTasks();
expectEquals(
fakeBrowserProxy.handler.getCallCount('onPageClosed'), 1);
}));
});