Playwright: [BUG] Download event not fired when launched with persistent context

Created on 24 Jul 2020  路  6Comments  路  Source: microsoft/playwright

Context:

  • Playwright Version: 1.2.1
  • Operating System: Mac
  • Node version: 14.5
  • Browser: Chromium

Code Snippet

const { chromium } = require("playwright");

(async () => {
  const context = await chromium.launchPersistentContext("./udd", {
    headless: false,
    acceptDownloads: true,
    downloadsPath: "./",
  });
  context.on("page", (page) => {
    page.on("download", (download) => {
      console.log("download", download);
    });
  });

  const newPage = await context.newPage();
  await newPage.goto(
    "https://support.spatialkey.com/spatialkey-sample-csv-data"
  );
  newPage.on("download", (download) => download.path().then(console.log));
})();

Describe the bug

  • When the page loads, click on any of the download links

Expectation:

  • See the path of downloaded file as well as complete download object

Current behavior:

  • Most of the times I don't see any logs
  • At times I would see logs for context based listener
  • I never see the download path's promise being resolved. I think it might be because the download size is too small but I would expect it to keep working properly even for small files.

Is there something wrong with my machine? I tried quitting existing chrome installation and reinstalling all packages to no avail. Any suggestion would be helpful, thanks!

P3-collecting-feedback

Most helpful comment

Can reproduce it on Windows too.

All 6 comments

The same bug is happening with playwright@next as well. Complete version info: "playwright": "^1.2.0-next.1595618348108". Assuming it's something with my setup since such a bug would have been caught by others/tests too.

Can reproduce it on Windows too.

I think you may be hitting this test case which is known to be failing on Chromium Headfull:

https://github.com/microsoft/playwright/blob/fab5eba64fdcbf7f9aa2734377e190070adf1854/test/download.jest.js#L243

The download links on the page to which you are navigating (https://support.spatialkey.com/spatialkey-sample-csv-data) look like:

<a href="http://samplecsvs.s3.amazonaws.com/SalesJan2009.csv" target="_blank" rel="noopener">download .csv file</a>

Note the target="_blank" which matches the linked test case.

Good find @rwoll! I can understand how this is an issue.

Is there a way that download event can be captured at browser level. I am not sure how chrome shows up the global downloads page or even the bottom bar which shows downloaded files. If we could emit a download event at browser level, it should make it immune to this closing-download-page behavior.

Also, do you think a bad-patch for this could be to force keep that new download page open?

Thanks for the help!

Is there a way that download event can be captured at browser level. I am not sure how chrome shows up the global downloads page or even the bottom bar which shows downloaded files. If we could emit a download event at browser level, it should make it immune to this closing-download-page behavior.

I'll defer to the core team as I'm not sure of the exact issue that's going on creating this bug. Some amount of information about the download gets to Playwright (as you'll see in my (hopefully) temporary hack).

Also, do you think a bad-patch for this could be to force keep that new download page open?

I'm not sure how you would force the page to stay open, but maybe that could work. An alternative, which I've been using, works as follows:

After getting a download event, try to get the path info via download.path(), if that doesn't resolve within 3 seconds, compute the path from internal fields on the download event:

const { chromium } = require("playwright");
const fs = require("fs");
const path = require("path");

const FORCE_DOWNLOAD_PATH_TIMEOUT = 3_000; // 3 seconds

const test = async ({ userDataDir, downloadsDir }) => {
  const context = await chromium.launchPersistentContext(userDataDir, {
    headless: false,
    acceptDownloads: true,
    downloadsPath: downloadsDir,
  });

  context.on("page", (page) => {
    page.on("download", async (download) => {
      const dlPath = await new Promise(async (res, reject) => {
        const tid = setTimeout(() => {
          clearTimeout(tid);
          console.info("timedout waiting for path; forcing path");
          res(path.join(download._downloadsPath, download._uuid));
        }, FORCE_DOWNLOAD_PATH_TIMEOUT);

        res(await download.path());
        clearTimeout(tid);
      });

      console.log("download path:", dlPath);
    });
  });

  const newPage = await context.newPage();
  await newPage.goto(
    "https://support.spatialkey.com/spatialkey-sample-csv-data"
  );

  newPage.on("download", (_download) => {});

  await newPage.click("text='download .csv file'");
};

(async (test) => {
  const userDataDir = fs.mkdtempSync("playwright-user-data-");
  const downloadsDir = fs.mkdtempSync("playwright-downloads-");
  try {
    await test({ userDataDir, downloadsDir });
  } catch (error) {
    console.error("error while executing test:", error);
  } finally {
    fs.rmdirSync(userDataDir, { recursive: true });
    fs.rmdirSync(downloadsDir, { recursive: true });
  }
})(test);

After running that script (and manually clicking on one of the download links) you should see output like:

$ node hacks.js 
timedout waiting for path; forcing path
download path: playwright-downloads-cZ4U4l/a43fefeb-b97c-4c35-aeb0-6540efe2f898
timedout waiting for path; forcing path
download path: playwright-downloads-cZ4U4l/95917e0e-bdaa-49bb-80bb-dc9ab8d1305a

@VikramTiwari Let me know if the workaround helps you or if you have questions, and hopefully someone from the PW team can help resolve the underlying issue so this hack isn't needed.

Hey @rwoll, this helped. Thanks a ton! :)

I haven't tried to stop the page from closing but I will try it and update on the status.

Was this page helpful?
0 / 5 - 0 ratings