summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--desktop/packages/mullvad-vpn/test/e2e/mocked/app-upgrade.spec.ts569
1 files changed, 278 insertions, 291 deletions
diff --git a/desktop/packages/mullvad-vpn/test/e2e/mocked/app-upgrade.spec.ts b/desktop/packages/mullvad-vpn/test/e2e/mocked/app-upgrade.spec.ts
index 3d2817ee71..0bd6f51ef6 100644
--- a/desktop/packages/mullvad-vpn/test/e2e/mocked/app-upgrade.spec.ts
+++ b/desktop/packages/mullvad-vpn/test/e2e/mocked/app-upgrade.spec.ts
@@ -8,354 +8,341 @@ import { MockedTestUtils, startMockedApp } from './mocked-utils';
let page: Page;
let util: MockedTestUtils;
-test.beforeAll(async () => {
- ({ page, util } = await startMockedApp());
+test.describe('App upgrade', () => {
+ const mockedVersion = '2100.1';
+ const mockedChangelog = [
+ 'This is a changelog.',
+ 'Each item is on a separate line.',
+ 'There are three items.',
+ ];
- await util.sendMockIpcResponse<IAppVersionInfo>({
- channel: 'upgradeVersion-',
- response: {
- supported: true,
- suggestedIsBeta: false,
- suggestedUpgrade: {
- version: '2100.1',
- changelog: [
- 'This is a changelog.',
- 'Each item is on a separate line.',
- 'There are three items.',
- ],
- },
- },
- });
-});
+ test.beforeAll(async () => {
+ ({ page, util } = await startMockedApp());
-test.afterEach(async () => {
- await new Promise((resolve) => {
- setTimeout(() => {
- resolve(null);
- }, 5000);
- });
-});
-
-test.afterAll(async () => {
- await page.close();
-});
-
-test('App should navigate to App upgrade view', async () => {
- await util.waitForNavigation(() => page.click('button[aria-label="Settings"]'));
- await util.waitForNavigation(() => page.getByRole('button', { name: 'App info' }).click());
- await util.waitForNavigation(() =>
- page.getByRole('button', { name: 'Update available' }).click(),
- );
-});
-
-test('App should display version and changelog of new upgrade', async () => {
- const headingText = await page
- .getByRole('heading', {
- name: 'Version',
- })
- .textContent();
- expect(headingText).toBe('Version 2100.1');
-
- const changelogList = page.getByRole('list');
- const changelogListText = await changelogList.textContent();
- expect(changelogListText).toEqual(
- 'This is a changelog.Each item is on a separate line.There are three items.',
- );
-
- const changelogListItems = page.getByRole('listitem');
- const changelogListItemsCount = await changelogListItems.count();
- expect(changelogListItemsCount).toBe(3);
-});
+ await util.sendMockIpcResponse<IAppVersionInfo>({
+ channel: 'upgradeVersion-',
+ response: {
+ supported: true,
+ suggestedIsBeta: false,
+ suggestedUpgrade: {
+ version: mockedVersion,
+ changelog: mockedChangelog,
+ },
+ },
+ });
-test('App should start upgrade when clicking Download & install button', async () => {
- const downloadAndInstallButton = page.getByRole('button', {
- name: 'Download and install',
+ await util.waitForNavigation(() => page.click('button[aria-label="Settings"]'));
+ await util.waitForNavigation(() => page.getByRole('button', { name: 'App info' }).click());
+ await util.waitForNavigation(() =>
+ page.getByRole('button', { name: 'Update available' }).click(),
+ );
});
- const appUpgradePromise = util.mockIpcHandle({
- channel: 'appUpgrade',
- response: undefined,
+ test.afterAll(async () => {
+ await page.close();
});
- await downloadAndInstallButton.click();
+ const resolveIpcHandle = async (test: Promise<void>, trigger: Promise<void>) => {
+ // The promise is resolved when its handle has been called.
+ // The handle should be called when the trigger is called.
+ const promise = await Promise.all([test, trigger]);
+ expect(promise).toBeTruthy();
+ };
- // The appUpgrade promise is resolved when its handle has been called.
- // The handle should be called when the Download & install button is clicked.
- await appUpgradePromise;
+ const selectors = {
+ downloadAndInstallButton: () =>
+ page.getByRole('button', {
+ name: 'Download and install',
+ }),
+ installButton: () =>
+ page.getByRole('button', {
+ name: 'Install update',
+ }),
+ cancelButton: () =>
+ page.getByRole('button', {
+ name: 'Cancel',
+ }),
+ retryButton: () =>
+ page.getByRole('button', {
+ name: 'Retry download',
+ }),
+ reportProblemButton: () =>
+ page.getByRole('button', {
+ name: 'Report a problem',
+ }),
+ downloadProgressBar: () => page.getByRole('progressbar'),
+ } as const;
- // Mock that we have started downloading the upgrade
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_DOWNLOAD_STARTED',
- },
- });
+ const startAppUpgrade = async () => {
+ const downloadAndInstallButton = selectors.downloadAndInstallButton();
- await expect(downloadAndInstallButton).toBeHidden();
-});
+ await resolveIpcHandle(
+ util.mockIpcHandle({
+ channel: 'appUpgrade',
+ response: undefined,
+ }),
+ downloadAndInstallButton.click(),
+ );
-test('App should show Cancel button after upgrade started', async () => {
- const cancelButton = page.getByRole('button', {
- name: 'Cancel',
- });
- await expect(cancelButton).toBeVisible();
- await expect(cancelButton).toBeEnabled();
-});
+ // Mock that we have started downloading the upgrade
+ await util.sendMockIpcResponse<AppUpgradeEvent>({
+ channel: 'app-upgradeEvent',
+ response: {
+ type: 'APP_UPGRADE_STATUS_DOWNLOAD_STARTED',
+ },
+ });
+ };
-test('App should show indeterminate download progress after upgrade started', async () => {
- // TODO: Improve by using aria labels
- await expect(page.getByText('Downloading...')).toBeVisible();
- await expect(page.getByText('Starting download...')).toBeVisible();
- await expect(page.getByText('0%')).toBeVisible();
+ const expectProgress = async (progress: number, expectLabel?: boolean) => {
+ if (expectLabel) {
+ await expect(page.getByText(`${progress}%`)).toBeVisible();
+ }
- const downloadProgressBarValue = await page
- .getByRole('progressbar')
- .getAttribute('aria-valuenow');
- expect(downloadProgressBarValue).toEqual('0');
-});
+ const downloadProgressBarValue = await selectors
+ .downloadProgressBar()
+ .getAttribute('aria-valuenow');
+ expect(downloadProgressBarValue).toEqual(progress.toString());
+ };
-test('App should show download progress after receiving event', async () => {
- // Mock that we have started downloading the upgrade
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_DOWNLOAD_PROGRESS',
- progress: 90,
- server: 'cdn.mullvad.net',
- timeLeft: 120,
- },
- });
-
- // TODO: Improve by using aria labels
- await expect(page.getByText('Downloading from: cdn.mullvad.net')).toBeVisible();
- await expect(page.getByText('About 2 minutes remaining...')).toBeVisible();
+ test.describe('Should display changelog', () => {
+ test('Should display new version number as heading', async () => {
+ const headingText = await page
+ .getByRole('heading', {
+ name: 'Version',
+ })
+ .textContent();
+ expect(headingText).toBe(`Version ${mockedVersion}`);
+ });
- const downloadProgressBarValue = await page
- .getByRole('progressbar')
- .getAttribute('aria-valuenow');
- expect(downloadProgressBarValue).toEqual('90');
-});
+ test('Should display new version changelog', async () => {
+ const changelogList = page.getByRole('list');
+ const changelogListText = await changelogList.textContent();
+ expect(changelogListText).toEqual(mockedChangelog.join(''));
-test('App should cancel upgrade when clicking the Cancel button', async () => {
- const cancelButton = page.getByRole('button', {
- name: 'Cancel',
+ const changelogListItems = page.getByRole('listitem');
+ const changelogListItemsCount = await changelogListItems.count();
+ expect(changelogListItemsCount).toBe(mockedChangelog.length);
+ });
});
- const appUpgradeAbortPromise = util.mockIpcHandle({
- channel: 'appUpgradeAbort',
- response: undefined,
- });
+ test.describe('Should download upgrade', () => {
+ test('Should start upgrade when clicking Download & install button', async () => {
+ await startAppUpgrade();
+ const downloadAndInstallButton = selectors.downloadAndInstallButton();
+ await expect(downloadAndInstallButton).toBeHidden();
+ });
- await cancelButton.click();
+ test('Should show indeterminate download progress after upgrade started', async () => {
+ // TODO: Improve by using aria labels
+ await expect(page.getByText('Downloading...')).toBeVisible();
+ await expect(page.getByText('Starting download...')).toBeVisible();
- // The appUpgradeAbort promise is resolved when its handle has been called.
- // The handle should be called when the cancel button is clicked.
- await appUpgradeAbortPromise;
+ await expectProgress(0, true);
+ });
- // After the app upgrade abort RPC is sent we expect to receive an aborted
- // event.
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_ABORTED',
- },
- });
+ test('Should show download progress after receiving event', async () => {
+ const mockedProgress = 90;
+ // Mock that we have started downloading the upgrade
+ await util.sendMockIpcResponse<AppUpgradeEvent>({
+ channel: 'app-upgradeEvent',
+ response: {
+ type: 'APP_UPGRADE_STATUS_DOWNLOAD_PROGRESS',
+ progress: mockedProgress,
+ server: 'cdn.mullvad.net',
+ timeLeft: 120,
+ },
+ });
- // The cancel button should be hidden when the upgrade is aborted
- await expect(cancelButton).toBeHidden();
+ await expect(page.getByText('Downloading from: cdn.mullvad.net')).toBeVisible();
+ await expect(page.getByText('About 2 minutes remaining...')).toBeVisible();
- // The Download & install button should become visible again
- const downloadAndInstallButton = page.getByRole('button', {
- name: 'Download and install',
- });
- await expect(downloadAndInstallButton).toBeVisible();
-});
+ await expectProgress(mockedProgress, true);
+ });
-test('App should start upgrade again when clicking Download & install button', async () => {
- const downloadAndInstallButton = page.getByRole('button', {
- name: 'Download and install',
- });
+ test('Should verify installer when download is complete', async () => {
+ // Mock that we have started verifying the upgrade
+ await util.sendMockIpcResponse<AppUpgradeEvent>({
+ channel: 'app-upgradeEvent',
+ response: {
+ type: 'APP_UPGRADE_STATUS_VERIFYING_INSTALLER',
+ },
+ });
- const appUpgradePromise = util.mockIpcHandle({
- channel: 'appUpgrade',
- response: undefined,
- });
+ await expect(page.getByText('Verifying installer')).toBeVisible();
+ await expect(page.getByText('Download complete')).toBeVisible();
- await downloadAndInstallButton.click();
+ await expectProgress(100);
+ });
- // The appUpgrade promise is resolved when its handle has been called.
- // The handle should be called when the Download & install button is clicked.
- await appUpgradePromise;
+ test('Should show that it has verified the installer when verification is complete', async () => {
+ // Mock that we have verified the upgrade
+ await util.sendMockIpcResponse<AppUpgradeEvent>({
+ channel: 'app-upgradeEvent',
+ response: {
+ type: 'APP_UPGRADE_STATUS_VERIFIED_INSTALLER',
+ },
+ });
- // Mock that we have started downloading the upgrade
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_DOWNLOAD_STARTED',
- },
- });
+ await expect(page.getByText('Verification successful! Starting installer...')).toBeVisible();
+ await expect(page.getByText('Download complete')).toBeVisible();
- await expect(downloadAndInstallButton).toBeHidden();
-});
-
-test('App should show that it is verifying the installer when download is complete', async () => {
- // Mock that we have started verifying the upgrade
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_VERIFYING_INSTALLER',
- },
+ await expectProgress(100);
+ });
});
- // TODO: Improve by using aria labels
- await expect(page.getByText('Verifying installer')).toBeVisible();
- await expect(page.getByText('Download complete')).toBeVisible();
+ test.describe('Should handle failing to download upgrade', () => {
+ test('Should handle failing to download upgrade', async () => {
+ // Mock that we have encountered an error the upgrade
+ await util.sendMockIpcResponse<AppUpgradeError>({
+ channel: 'app-upgradeError',
+ response: 'DOWNLOAD_FAILED',
+ });
- const downloadProgressBarValue = await page
- .getByRole('progressbar')
- .getAttribute('aria-valuenow');
- expect(downloadProgressBarValue).toEqual('100');
-});
+ await expect(
+ page.getByText(
+ 'Unable to download update. Check your connection and/or firewall then try again. If this problem persists, please contact support.',
+ ),
+ ).toBeVisible();
-test('App should show that it has verified the installer when verification is complete', async () => {
- // Mock that we have verified the upgrade
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_VERIFIED_INSTALLER',
- },
- });
+ const retryDownloadButton = selectors.retryButton();
+ await expect(retryDownloadButton).toBeVisible();
- // TODO: Improve by using aria labels
- await expect(page.getByText('Verification successful! Starting installer...')).toBeVisible();
- await expect(page.getByText('Download complete')).toBeVisible();
+ const reportProblemButton = selectors.reportProblemButton();
+ await expect(reportProblemButton).toBeVisible();
+ });
+ test('Should handle retrying downloading upgrade', async () => {
+ const retryDownloadButton = selectors.retryButton();
- const downloadProgressBarValue = await page
- .getByRole('progressbar')
- .getAttribute('aria-valuenow');
- expect(downloadProgressBarValue).toEqual('100');
-});
+ await resolveIpcHandle(
+ util.mockIpcHandle({
+ channel: 'appUpgrade',
+ response: undefined,
+ }),
+ retryDownloadButton.click(),
+ );
-test('App should handle failing to automatically start installer', async () => {
- // Mock the verified upgrade installer path
- await util.sendMockIpcResponse<IAppVersionInfo>({
- channel: 'upgradeVersion-',
- response: {
- supported: true,
- suggestedIsBeta: false,
- suggestedUpgrade: {
- version: '2100.1',
- changelog: [
- 'This is a changelog.',
- 'Each item is on a separate line.',
- 'There are three items.',
- ],
- verifiedInstallerPath: '/tmp/dummy-path',
- },
- },
+ await expect(page.getByText('Downloading...')).toBeVisible();
+ await expect(page.getByText('Starting download...')).toBeVisible();
+ await expectProgress(0, true);
+ });
});
- await util.sendMockIpcResponse<AppUpgradeError>({
- channel: 'app-upgradeError',
- response: 'START_INSTALLER_AUTOMATIC_FAILED',
- });
+ test.describe('Should handle failing to start installer', () => {
+ test('Should handle failing to automatically start installer', async () => {
+ // Mock the verified upgrade installer path
+ await util.sendMockIpcResponse<IAppVersionInfo>({
+ channel: 'upgradeVersion-',
+ response: {
+ supported: true,
+ suggestedIsBeta: false,
+ suggestedUpgrade: {
+ version: mockedVersion,
+ changelog: mockedChangelog,
+ verifiedInstallerPath: '/tmp/dummy-path',
+ },
+ },
+ });
- // TODO: Improve by using aria labels
- await expect(page.getByText('Verification successful! Ready to install.')).toBeVisible();
+ await util.sendMockIpcResponse<AppUpgradeError>({
+ channel: 'app-upgradeError',
+ response: 'START_INSTALLER_AUTOMATIC_FAILED',
+ });
- const downloadProgressBar = page.getByRole('progressbar');
- await expect(downloadProgressBar).not.toBeVisible();
-});
+ await expect(page.getByText('Verification successful! Ready to install.')).toBeVisible();
-test('App should handle failing to manually start installer', async () => {
- const installUpdateButton = page.getByRole('button', {
- name: 'Install update',
- });
+ const downloadProgressBar = selectors.downloadProgressBar();
+ await expect(downloadProgressBar).not.toBeVisible();
+ });
- const appUpgradePromise = util.mockIpcHandle({
- channel: 'appUpgrade',
- response: undefined,
- });
+ test('Should handle failing to manually start installer', async () => {
+ const installUpdateButton = selectors.installButton();
- await installUpdateButton.click();
+ await resolveIpcHandle(
+ util.mockIpcHandle({
+ channel: 'appUpgrade',
+ response: undefined,
+ }),
+ installUpdateButton.click(),
+ );
- // The appUpgrade promise is resolved when its handle has been called.
- // The handle should be called when the Install update button is clicked.
- await appUpgradePromise;
+ // Mock that we have encountered an error the upgrade
+ await util.sendMockIpcResponse<AppUpgradeError>({
+ channel: 'app-upgradeError',
+ response: 'START_INSTALLER_FAILED',
+ });
- // Mock that we have encountered an error the upgrade
- await util.sendMockIpcResponse<AppUpgradeError>({
- channel: 'app-upgradeError',
- response: 'START_INSTALLER_FAILED',
- });
+ await expect(installUpdateButton).not.toBeVisible();
- await expect(installUpdateButton).not.toBeVisible();
+ await expect(
+ page.getByText(
+ 'Could not start the update installer, try downloading it again. If this problem persists, please contact support.',
+ ),
+ ).toBeVisible();
+ const retryDownloadButton = selectors.retryButton();
+ await expect(retryDownloadButton).toBeVisible();
- await expect(
- page.getByText(
- 'Could not start the update installer, try downloading it again. If this problem persists, please contact support.',
- ),
- ).toBeVisible();
- const retryDownloadButton = page.getByRole('button', {
- name: 'Retry download',
- });
- await expect(retryDownloadButton).toBeVisible();
+ const reportProblemButton = selectors.reportProblemButton();
+ await expect(reportProblemButton).toBeVisible();
+ });
- const reportProblemButton = page.getByRole('button', {
- name: 'Report a problem',
- });
- await expect(reportProblemButton).toBeVisible();
-});
+ test('Should handle retrying downloading upgrade', async () => {
+ const retryDownloadButton = selectors.retryButton();
-test('App should handle retrying downloading the update', async () => {
- const retryDownloadButton = page.getByRole('button', {
- name: 'Retry download',
- });
+ await resolveIpcHandle(
+ util.mockIpcHandle({
+ channel: 'appUpgrade',
+ response: undefined,
+ }),
+ retryDownloadButton.click(),
+ );
- const appUpgradePromise = util.mockIpcHandle({
- channel: 'appUpgrade',
- response: undefined,
+ await expect(page.getByText('Downloading...')).toBeVisible();
+ await expect(page.getByText('Starting download...')).toBeVisible();
+ await expectProgress(0, true);
+ });
});
- await retryDownloadButton.click();
+ test.describe('Should cancel download', () => {
+ test('Should show Cancel button after upgrade started', async () => {
+ await startAppUpgrade();
+ const cancelButton = selectors.cancelButton();
+ await expect(cancelButton).toBeVisible();
+ await expect(cancelButton).toBeEnabled();
+ });
- // The appUpgrade promise is resolved when its handle has been called.
- // The handle should be called when the Retry download button is clicked.
- await appUpgradePromise;
+ test('Should cancel upgrade when clicking the Cancel button', async () => {
+ const cancelButton = selectors.cancelButton();
- // TODO: Improve by using aria labels
- await expect(page.getByText('Downloading...')).toBeVisible();
- await expect(page.getByText('Starting download...')).toBeVisible();
- await expect(page.getByText('0%')).toBeVisible();
+ await resolveIpcHandle(
+ util.mockIpcHandle({
+ channel: 'appUpgradeAbort',
+ response: undefined,
+ }),
+ cancelButton.click(),
+ );
- const downloadProgressBarValue = await page
- .getByRole('progressbar')
- .getAttribute('aria-valuenow');
- expect(downloadProgressBarValue).toEqual('0');
-});
-
-test('App should handle starting installer again if installer was started but did not close the app', async () => {
- // Mock that we have started the installer. In the real app this event is sent
- // after a timeout if the GUI is still running after the installer has been started
- await util.sendMockIpcResponse<AppUpgradeEvent>({
- channel: 'app-upgradeEvent',
- response: {
- type: 'APP_UPGRADE_STATUS_STARTED_INSTALLER',
- },
- });
+ // After the app upgrade abort RPC is sent we expect to receive an aborted
+ // event.
+ await util.sendMockIpcResponse<AppUpgradeEvent>({
+ channel: 'app-upgradeEvent',
+ response: {
+ type: 'APP_UPGRADE_STATUS_ABORTED',
+ },
+ });
- const installUpdateButton = page.getByRole('button', {
- name: 'Install update',
- });
+ // The cancel button should be hidden when the upgrade is aborted
+ await expect(cancelButton).toBeHidden();
- const appUpgradePromise = util.mockIpcHandle({
- channel: 'appUpgrade',
- response: undefined,
- });
+ // The Download & install button should become visible again
+ const downloadAndInstallButton = selectors.downloadAndInstallButton();
+ await expect(downloadAndInstallButton).toBeVisible();
+ });
- await installUpdateButton.click();
+ test('Should start upgrade again when clicking Download & install button', async () => {
+ await startAppUpgrade();
+ const downloadAndInstallButton = selectors.downloadAndInstallButton();
- // The appUpgrade promise is resolved when its handle has been called.
- // The handle should be called when the Install update button is clicked.
- await appUpgradePromise;
+ await expect(downloadAndInstallButton).toBeHidden();
+ });
+ });
});