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

[BUG][Electron] filechooser event not emitted when dialog.show(Open|Save)Dialog is called #8278

Open
OiNutter opened this issue Aug 18, 2021 · 14 comments

Comments

@OiNutter
Copy link

Duplicate of #5013. Full details and repro steps available there.

Opening new issue as requested by maintainers on original issue.

This is definitely a blocker for our integration tests as we need to test open and save functionality in our app and we're not able to select the files in the dialogs.

@tgdcat
Copy link

tgdcat commented Nov 19, 2021

I'm also having trouble with showOpenDialogSync and showSaveDialogSync because the test stopped.
Is there any workaround?

@wsw0108
Copy link

wsw0108 commented Jan 10, 2022

I have create a test repo to trying to mock electron dialog like spectron-fake-dialog does, but failed.

Does not work, but returned mocked is true.
https://github.com/wsw0108/electron-playwright-test/blob/master/test/test.js#L74-L81

This console.log does not write to file.
https://github.com/wsw0108/electron-playwright-test/blob/master/test/preload.js#L37

Does anyone may have time to help to find out why?

@Daveiano
Copy link

I am also having this issue and have been looking for a solution.

@wsw0108 I am quite new to JS testing, but I will have a look into your code if I get some time. Please report back!

@wsw0108
Copy link

wsw0108 commented Jan 11, 2022

@Daveiano I have found the fail cause, it's the async thing of electron ipc. The mock works actually.

@wsw0108
Copy link

wsw0108 commented Jan 11, 2022

Based on spectron-fake-dialog, I wrote a little library to fake electron dialog for playwright/electron,
https://github.com/wsw0108/playwright-fake-dialog

@MikeJerred
Copy link

Based on spectron-fake-dialog, I wrote a little library to fake electron dialog for playwright/electron, https://github.com/wsw0108/playwright-fake-dialog

Awesome! Can actually simplify this and just do:

const electronApp = await playwright._electron.launch({ args: ['./main.js']});

// ...

// in test:
electronApp.evaluate(
  async({ dialog }, filePaths) => {
    dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths });
  },
  ['file.txt']
);

@wsw0108
Copy link

wsw0108 commented Jan 11, 2022

@MikeJerred Elegant solution.

Can I use your idea to update my repo?

@MikeJerred
Copy link

@MikeJerred Elegant solution.

Can I use your idea to update my repo?

Yep of course

@Daveiano
Copy link

@wsw0108 I am getting this error when using playwright-fake-dialog

page.evaluate: ReferenceError: require is not defined
    at eval (eval at evaluate (:3:2389), <anonymous>:2:31)
    at t.default.evaluate (<anonymous>:3:2412)
    at t.default.<anonymous> (<anonymous>:1:44)

    at ipcRendererSendSyncAsync (/var/www/weather-data-center-electron-forge/node_modules/playwright-fake-dialog/index.js:12:15)
    at mock (/var/www/weather-data-center-electron-forge/node_modules/playwright-fake-dialog/index.js:22:10)
    at /var/www/weather-data-center-electron-forge/src/main/renderer-empty.test.ts:93:13
    at fulfilled (/var/www/weather-data-center-electron-forge/src/main/renderer-empty.test.ts:5:58)

Setup is the following:

import { _electron as electron } from "playwright-core";
const { launch, mock } = require('playwright-fake-dialog')

...

beforeAll(async () => {
  // Launch Electron app.
  electronApp = await launch(electron, {
    args: [
      '.'
    ],
    env: {
      ...process.env
    },
  });

  // Get the first window that the app opens, wait if necessary.
  page = await electronApp.firstWindow();

  // Wait for frame actually loaded.
  await page.waitForSelector('main');

  // Direct Electron console to Node terminal.
  page.on('console', console.log);
});

...

it('should import new data', async () => {
  await mock(page, [
    {
      method: 'showOpenDialog',
      value: {
        filePaths: [`${__dirname.replace('src/main', '')}tests/data/upload-data-start-16-08-21-30-09-21-1196-records.csv`]
      }
    }
  ]);

  await page.click('button#import');
});

Any help and suggestions would be very appreciated!

@wsw0108
Copy link

wsw0108 commented Jan 12, 2022

https://github.com/wsw0108/electron-playwright-test/blob/e3c6ff53d9d71360270ddd37305b188b8273d2c5/app/main/index.js#L43

using 0.1.0 needs above lines in your electron main.js.

If you use html input, just use filechooser from playwright.

@Daveiano
Copy link

Ah, got you, thank you!

I got it working now with the snippet from @MikeJerred, many thanks for that!

wsw0108 added a commit to wsw0108/playwright-fake-dialog that referenced this issue Jan 12, 2022
@FomerMay
Copy link

FomerMay commented Mar 22, 2022

H, i need some help to use the playwright-fake-dialog, do i need any code from "test/preload.js"?(https://github.com/wsw0108/electron-playwright-test/blob/master/test/preload.js).

This is my code

await mock(electronApp, [
   {
     method: 'showOpenDialog',
     value: {
       filePaths: [join(__dirname, 'minimal.pdf')]
     }
   }
 ])
 await newPage.click('[e2e-id="action-bar-create"]');

And i get this ERROR in our Log-File:
"fs.api.selectFilesWithOpenDialog (id 46189c0c) - failed due to error: n.a.dialog.showOpenDialog is not a function"

Our Application uses Electron 9, could that be a problem?

@dquak
Copy link

dquak commented Jan 30, 2024

Based on spectron-fake-dialog, I wrote a little library to fake electron dialog for playwright/electron, https://github.com/wsw0108/playwright-fake-dialog

Awesome! Can actually simplify this and just do:

const electronApp = await playwright._electron.launch({ args: ['./main.js']});

// ...

// in test:
electronApp.evaluate(
  async({ dialog }, filePaths) => {
    dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths });
  },
  ['file.txt']
);

best method, you can also control dialogs like so:

const dialogControlHandler = electronApp.evaluateHandler(() => {
  let resolve;
  const promise = new Promise(res => { resolve = res; });
  
  return {promise, resolve};
});


const dialogOptions = await electronApp.evaluate(
 async({ dialog },{ dialogControlHandler }) => {
   return new Promise(res => {
     dialog.showMessageBox = (options) => {
       res(options);
       return dialogControlHandler.promise;
     };
   });
  },
 { dialogControlHandler }
);

//Now you have the dialog options avaliable at `dialogOptions` (eg: dialogOptions.title)

//Choose how to resolve the dialog:
dialogControlHandler.evaluate( ({ resolve }) => resolve({response: 1, checkboxchecked: false}) );

@mxschmitt
Copy link
Member

Investigation:

  • Upstream Electron method ShowOpenDialog calls immediately OS APIs
  • When dealing with normal file pickers, upstream its a noop when intercepted like here in this cp
  • Probably a new event should be introduced so Electron can wait for it and return the value once emitted. Since Electron API would be different. event -> path[] all the time. It's never a file content etc.
  • Similar / different request is about setInputFiles should set path property. There we should extend 'DOM.setFileInputFiles' so it sets the path. [Feature] Set File.path property when uploading files with Electron #10527

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants