And now here I am.
The problem is, of course, that playwright (being a test tool) operates in a sandbox environment. So any downloads are put somewhere on the file system, but where? Having now figured this out, I can confirm that it also clears them up once the test has finished.
However, all is not lost. A quick web search reveals this suggestion from Microsoft. So let's try that (at least, translating to Java). In the same project, I added a new test script, TestDownloads and put (basically) this code into it:
public static void main(String[] args) {The first few lines should be familiar. I'm navigating to a different (somewhat random) page as being somewhere that I can easily push a "download" button. The idea (as I see it) is that the onDownload method will fire the callback when it sees the download take place. But no joy. Nothing comes out.
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false).setSlowMo(50));
Page page = browser.newPage();
page.navigate("https://pixabay.com/photos/flowers-meadow-sunlight-summer-276014/");
page.onDownload(d -> { System.out.println("Download found at " + d.path());});
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
It's interesting that this doesn't work. The documentation says it should, and simply not firing seems an egregious bug. But looking at this code, we don't interact with playwright after setting up the onDownload, so maybe it just never gets to fire (if it has to fire from the main thread, not a background thread). Is there some kind of loop we can go to?
I found waitForClose, and it seems reasonable that that would do the job. If nothing else, it seems an upgrade on that 10s sleep we've got there. But then, just down from waitForClose is waitForDownload, which also returns the Download object. Let's try that!
Download download = page.waitForDownload(() -> { });Lo and behold, it works! More than that, the onDownload also fires, so now we have two lines of output. I also replaced my sleep with waitForClose, and that works too, including firing the onDownload callback (this is fired when the download happens; it doesn't wait until the browser is closed).
Path isAt = download.path();
System.out.println("Download found at " + isAt);
So, we have two ways of doing this: a notification method and explicitly waiting. I'm not entirely sure which one I prefer. The onDownload method has the advantage that it wil capture multiple downloads. The waitForDownload method has the advantage of clarity: we are clearly waiting for a download to happen.
So, now we have a path. This is where we learn that it is indeed under /tmp, and is indeed deleted when the test is cleaned up after we close the browser.
Copying the file
What we need to do is to copy the file somewhere else where it will be safe. Obviously, this should involve some kind of argument to the program - I'll do that in the "real" FBAR program - but the easier thing is just to say I'll copy it to "normal" /tmp.File isAt = download.path().toFile();And, running this, we end up with:
File saveAs = new File("/tmp", isAt.getName());
System.out.println("Copying " + isAt + " to " + saveAs);
try {
Utils.copyFile(download.path().toFile(), saveAs);
} catch (IOException e) {
e.printStackTrace();
}
-rw-rw-r-- 1 gareth gareth 370627 Jan 13 03:48 /tmp/5ea3c1a8-2dfc-416c-9559-13eed8f6153fThis is checked in and tagged as PLAYWRIGHT_CATCH_DOWNLOADS.
One Last Thing ...
When I went to actually submit the form and capture the download in real life, I found I couldn't. I can't rightly say if this is a change since last year, or if I did something cunning last year. But this year, there are JavaScript alerts that pop up when you sign and submit the form and (by default) Playwright just cancels them. A quick web search gives the answer though and a few minutes later I'd added this code:page.onDialog(dialog -> {I ran through it all and, lo and behold, everything worked and I had a copy of the downloaded form in my long-lasting directory.
System.out.println("Dialog message: " + dialog.message());
System.out.println("Dialog prompt: " + dialog.defaultValue());
dialog.accept();
});
No comments:
Post a Comment