Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend code for quitOnClose option #3843

Conversation

adamkpickering
Copy link
Member

Closes #3261.

@adamkpickering adamkpickering force-pushed the 3261-optionally-shut-down-on-window-close branch 4 times, most recently from 861193c to 0c6a9f8 Compare January 27, 2023 20:49
@adamkpickering adamkpickering marked this pull request as ready for review February 6, 2023 17:35
@gaktive gaktive requested a review from mook-as February 6, 2023 19:15
Copy link
Contributor

@mook-as mook-as left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a few lint issues found by CI as well.

e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
e2e/quit-on-close.e2e.spec.ts Show resolved Hide resolved
e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
await sleep(waitTime);
const browserWindowHandle = await electronApp.browserWindow(page);
browserWindowHandle.evaluate((browserWindow: Electron.BrowserWindow) => browserWindow.close());
await sleep(waitTime);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume we're waiting for the shutdown to complete? Since the CI machines are randomly slow, it would be good if there's something we could actually poll for (which would let us have a much longer maximum wait time, and finish much sooner on average).

Copy link
Member Author

@adamkpickering adamkpickering Feb 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to get something like this working, but haven't been able to. The way I've tried is to listen to the quit event on Electron.app, and set a variable when the event fires:

  test('should quit when quitOnClose is true and window is closed', async() => {
    createDefaultSettings({ window: { quitOnClose: true } });
    const {electronApp, page} = await startRancherDesktop(__filename);
    const browserWindowHandle = await electronApp.browserWindow(page);

    let hasQuit = false;
    electronApp.evaluate(({app}) => {
      app.on('quit', () => {
        console.log('quit event occurred')
        hasQuit = true;
      });
    });

    browserWindowHandle.evaluate((browserWindow: Electron.BrowserWindow) => browserWindow.close());

    const sleepTime = 5000;
    const iterCount = 6;
    for (let i = 0; i < iterCount; i++) {
      console.log(`hasQuit: ${ hasQuit }`)
      if (hasQuit) {
        return;
      }
      await sleep(sleepTime)
    }
    // fail the test if RD has not quit by now
    expect(true).toBe(false);
  });

But it doesn't seem to work. I'm not very confident with playwright though. Maybe you can see something I'm doing wrong? Or maybe you're away of another way of doing it? I can't think of anything else...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe .evaluate works something like serializing the function to text, and eval() it on the other side. So in your case, hasQuit isn't getting a closure, so it's never set to true on the test side.

In my case, I do everything within evaluate(), and it only returns a Promise<boolean> which the documentation says it can.

@adamkpickering adamkpickering force-pushed the 3261-optionally-shut-down-on-window-close branch from 0c6a9f8 to daba531 Compare February 7, 2023 20:50
@adamkpickering adamkpickering force-pushed the 3261-optionally-shut-down-on-window-close branch from daba531 to 3ba5abb Compare February 7, 2023 21:12
@ericpromislow
Copy link
Contributor

I can't get the e2e test to start running on both linux and mac

@adamkpickering adamkpickering force-pushed the 3261-optionally-shut-down-on-window-close branch from 40773ac to c159bcb Compare February 9, 2023 17:46
mook-as
mook-as previously approved these changes Feb 9, 2023
Copy link
Contributor

@mook-as mook-as left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works fine for me on mac & Windows, and CI (running Linux) look fine with it too.

* @param testPath The path to the test file.
*/
export async function startRancherDesktop(testPath: string): Promise<{electronApp: ElectronApplication, page: Page}> {
const electronApp = await _electron.launch({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we call await electronApp.context.tracing.start({ screenshots: true, snapshots: true }); somewhere in this function?

});
});

async function pollForQuit(electronApp: ElectronApplication): Promise<boolean> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works fine, but has a minimum run time of 30s (for the case where we don't want to quit).

Possible alternate, but I'm not sure I've got enough of a wait in:

function closeAllWindows(electronApp: ElectronApplication): Promise<boolean> {
  return electronApp.evaluate(async({ app, BrowserWindow }) => {
    const quitReady = new Promise<boolean>((resolve) => {
      app.on('will-quit', () => resolve(true));
      app.on('window-all-closed', () => {
        setTimeout(() => resolve(false), 1_000);
      });
    });

    await Promise.all(BrowserWindow.getAllWindows().map((window) => {
      return new Promise<void>((resolve) => {
        window.on('closed', resolve);
        window.close();
      });
    }));

    return await quitReady;
  });
}


  test('should quit when quitOnClose is true and window is closed', async() => {
    createDefaultSettings({ window: { quitOnClose: true } });
    const { electronApp } = await startRancherDesktop(__filename);

    await expect(closeAllWindows(electronApp)).resolves.toBe(true);
  });

Copy link
Member Author

@adamkpickering adamkpickering Feb 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a better way to do it. I have to say though, I'm confused as to why my use of electronApp.evaluate above doesn't work, whereas its use here does. Can you not refer to a variable from an outer scope or something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above — yeah, I think evaluate() is really serialize-and-eval(), so closures wouldn't work. This is why in my implementation all of the work happens inside the evaluate() call (in the Electron process), and only a boolean is returned to the test process.

@adamkpickering adamkpickering force-pushed the 3261-optionally-shut-down-on-window-close branch 2 times, most recently from 0f13f16 to 622cf9a Compare February 10, 2023 16:56
Copy link
Contributor

@mook-as mook-as left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty happy with it, just some nits.

e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
e2e/quit-on-close.e2e.spec.ts Outdated Show resolved Hide resolved
@@ -6,7 +6,7 @@ import os from 'os';
import path from 'path';
import util from 'util';

import { ElectronApplication, expect } from '@playwright/test';
import { expect, _electron, ElectronApplication, Page } from '@playwright/test';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, ElectronApplication and Page can be changed to an import type, but that's mostly just moving deck chairs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's alright, I'd like to keep it as it is. The following link is convincing to me: microsoft/TypeScript#39861

@adamkpickering adamkpickering force-pushed the 3261-optionally-shut-down-on-window-close branch from 622cf9a to c9e68a8 Compare February 10, 2023 19:15
@ericpromislow
Copy link
Contributor

ericpromislow commented Feb 10, 2023

e2e tests pass now on my machines

@adamkpickering adamkpickering merged commit bdd0637 into rancher-sandbox:main Feb 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Window closing optionally shuts down app [2d]
3 participants