microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
67.23k stars 3.7k forks source link

[BUG] Unable to download file on grid #15999

Open sachin6757 opened 2 years ago

sachin6757 commented 2 years ago

Context:

Bug Description

We have testcases to test the download functionality from the application. We have used promise to wait for the download to verify if the file is getting downloaded.

When we run testcase locally it works fine. However when we try to run testcase on selenium grid its failing with following error:

File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/playwright.py", line 149, in grpc_channel yield playwright_pb2_grpc.PlaywrightStub(self._channel) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/keywords/promises.py", line 143, in _wait_for_download response = stub.WaitForDownload(Request().FilePath(path=str(file_path))) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/grpc/_channel.py", line 946, in __call__ return _end_unary_response_blocking(state, call, False, None) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/grpc/_channel.py", line 849, in _end_unary_response_blocking raise _InactiveRpcError(state) grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.RESOURCE_EXHAUSTED details = "Error: download.saveAs: canceled" debug_error_string = "{"created":"@1658769026.465787000","description":"Error received from peer ipv6:[::1]:54106","file":"src/core/lib/surface/call.cc","file_line":967,"grpc_message":"Error: download.saveAs: canceled","grpc_statu... [ Message content over the limit has been removed. ] return promises[0].result() File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 428, in result return self.__get_result() File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result raise self._exception File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/keywords/promises.py", line 143, in _wait_for_download response = stub.WaitForDownload(Request().FilePath(path=str(file_path))) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 130, in __exit__ self.gen.throw(type, value, traceback) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/playwright.py", line 153, in grpc_channel raise AssertionError(error.details()) AssertionError: Error: download.saveAs: canceled

pavelfeldman commented 2 years ago

We would need exact steps to follow in order to address this.

sachin6757 commented 2 years ago

@pavelfeldman , We are using robotframework browser library. Please find steps below:

  1. Start selenium grid using docker swarm.
  2. Set SELENIUM_REMOTE_URL=http://x.x.x.x:4444/wd/hub
  3. Execute testcase which has promise to validate download file
  4. Verify downloaded file should be present in path specified

Here testcase is failing at step 4. The file is not getting download. However this testcase pass when testcase is not run on grid.

Below is the error log:

Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/playwright.py", line 149, in grpc_channel yield playwright_pb2_grpc.PlaywrightStub(self._channel) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/keywords/promises.py", line 143, in _wait_for_download response = stub.WaitForDownload(Request().FilePath(path=str(file_path))) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/grpc/_channel.py", line 946, in __call__ return _end_unary_response_blocking(state, call, False, None) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/grpc/_channel.py", line 849, in _end_unary_response_blocking raise _InactiveRpcError(state) grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.RESOURCE_EXHAUSTED details = "Error: download.saveAs: canceled" debug_error_string = "{"created":"@1659031595.482469000","description":"Error received from peer ipv6:[::1]:59436","file":"src/core/lib/surface/call.cc","file_line":967,"grpc_message":"Error: download.saveAs: canceled","grpc_statu... [ Message content over the limit has been removed. ] return promises[0].result() File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 428, in result return self.__get_result() File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result raise self._exception File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/keywords/promises.py", line 143, in _wait_for_download response = stub.WaitForDownload(Request().FilePath(path=str(file_path))) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 130, in __exit__ self.gen.throw(type, value, traceback) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Browser/playwright.py", line 153, in grpc_channel raise AssertionError(error.details()) AssertionError: Error: download.saveAs: canceled

Ghislain89 commented 2 years ago

I'm not entirely sure this is a bug, likely a missing feature. Your browser is running in a docker container, whilst the test runner is likely running on a different container/host/virtual machine. Your assertion is by default looking at the file path on the host that is executing the tests.

I guess if Playwright wants to support this they'll have to somehow interface with Selenium to fetch the document. Suggestion: Could you create a volume mount that is accessible from both the host as well as the docker container? You could try downloading to that asserting it.

In the past I did this with an samba share. To avoid complexity we just run use the docker container supplied by Playwright to execute the tests in.

avishekjana-89 commented 2 years ago

I am facing same issue while trying to download file in docker container through grid. I was trying to see the behaviour by simply clicking download button, observed that file downloading is failing with 'Failed - Download Error' in chrome taskbar. Although while running same container in selenium, working as expected.

Can someone look into the issue.

avishekjana-89 commented 2 years ago

I'm not entirely sure this is a bug, likely a missing feature. Your browser is running in a docker container, whilst the test runner is likely running on a different container/host/virtual machine. Your assertion is by default looking at the file path on the host that is executing the tests.

I guess if Playwright wants to support this they'll have to somehow interface with Selenium to fetch the document. Suggestion: Could you create a volume mount that is accessible from both the host as well as the docker container? You could try downloading to that asserting it.

In the past I did this with an samba share. To avoid complexity we just run use the docker container supplied by Playwright to execute the tests in.

I tried with same directory volumes mapping b/w host and container. But still same behaviour is being observed.

volumes:

Playwright code snippet's await _page.GotoAsync("https://www.browserstack.com/test-on-the-right-mobile-devices"); var waitForDownloadTask = _page.WaitForDownloadAsync(); await _page.Locator(".icon-csv").ClickAsync(); var download = await waitForDownloadTask; await download.SaveAsAsync("/tmp/file.csv");

avishekjana-89 commented 2 years ago

We would need exact steps to follow in order to address this.

I have provided more details on this issue in below. Can you check please now.

rdark100 commented 1 year ago

Any progress on this? I'm facing the same issue. I have to run tests remotely (on grid), because I need the same environment for development (my local machine is on windows) and on CI/CD with linux, because I also test graphs via screenshots. So I have to run tests on grid and download is not working. I'm using .NET playwright

avishekjana-89 commented 1 year ago

@pavelfeldman @Ghislain89 is there any plan for priotization on this issue?

mahmutkaya commented 1 year ago

same issue with running in jenkins (playwright v1.32.3, typescript v4.9.5, node v18.15.0)

rphacker1618 commented 1 year ago

We are also facing same issue while running testcase via Jenkins on VM... Please help in resolving this issue

srikanth-gupta commented 1 year ago

Any update on this issue. I'm also facing same issue. Not able to download files when running the Playwright test in Selenium Grid. Getting as 'Failed - Download error'. But, the same is passing in local. I'm using latest Playwright version 1.37.1 version. We have mounted the download location as well which is reachable.

anandhu-co-in commented 1 year ago

Any update on this?

Facing this same issue. On the chrome browser instance started by Playwright in my selenium grid, file downloads fail. I tried opening a new chrome instance manually through the grid UI and tried downloading the same file. There it works

image
ve-ev commented 10 months ago

Plus. Facing the same issue.

IgnasCi commented 10 months ago

Yeah, facing similar issues. Tried to play around and it looks like something gets messed up after PW connection.

  1. Creating a browser session under the grid.
  2. After manually connecting to it (via VNC), all download attempts gets completed.
  3. Creating a connection over cdp to the same session via PW.
    Playwright playwright = Playwright.create();
    Browser browser = playwright.chromium().connectOverCDP(endpointUrl);
  4. After manually connecting to it (via VNC), all download attempts gets 'Download failed' error.

Tried to directly create a grid session - the results are the same.

Map<String, String> env = new HashMap<>();
env.put("SELENIUM_REMOTE_URL", GRID_URL);
Playwright playwright = Playwright.create(new Playwright.CreateOptions().setEnv(env));
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));`
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setAcceptDownloads(true));
context.newPage().navigate("https://www.google.nl/intl/nl/chrome/");
amardeep2006 commented 2 months ago

I can confirm the behavior seen by @anandhu-co-in . The browser launched via Playwright shows Failed - download error on selenium grid.

I looked at the playwright DEBUG logs and this can be interesting . Seems like while setting setDownloadBehavior Playwright is setting downloadPath to a location on test runner windows machine on my laptop.

pw:protocol SEND ► {"id":19,"method":"Browser.setDownloadBehavior","params":{"behavior":"allowAndName","browserContextId":"3DA1D9479BE90414B862A89619609496","downloadPath":"C:\Users\AMAR-D~1\AppData\Local\Temp\playwright-artifacts-XXXXXX99prej","eventsEnabled":true}}

Is there a way we can override setDownloadBehavior , specially downloadPath via config for SELENIUM GRID?

playwright.log

amardeep2006 commented 2 months ago

Did some more hit and trial and seems Playwright does not override downloadsPath config if we run sessions on selenium grid. Anyway even if download would have worked, Playwright still will require a way to download file from remote machine to local.

rkrenovsky commented 2 months ago

Did some more hit and trial and seems Playwright does not override downloadsPath config if we run sessions on selenium grid. Anyway even if download would have worked, Playwright still will require a way to download file from remote machine to local.

It's not an issue if you use docker selenium grid - just mount volume to the downloads path

amardeep2006 commented 2 months ago

Did some more hit and trial and seems Playwright does not override downloadsPath config if we run sessions on selenium grid. Anyway even if download would have worked, Playwright still will require a way to download file from remote machine to local.

It's not an issue if you use docker selenium grid - just mount volume to the downloads path

Thanks @rkrenovsky for workaround suggestion but in my case mounting volume will not work. We are running centralized selenium grid inside Kubernetes . Since Kubernetes Nodes are remote Linux machines and not accessible to developers.

rkrenovsky commented 2 months ago

Did some more hit and trial and seems Playwright does not override downloadsPath config if we run sessions on selenium grid. Anyway even if download would have worked, Playwright still will require a way to download file from remote machine to local.

It's not an issue if you use docker selenium grid - just mount volume to the downloads path

Thanks @rkrenovsky for workaround suggestion but in my case mounting volume will not work. We are running centralized selenium grid inside Kubernetes . Since Kubernetes Nodes are remote Linux machines and not accessible to developers.

Another workaround, that I'm using in my docker MacOS selenium grid, is that I'm copying downloaded files via ssh in my tests

amardeep2006 commented 2 months ago

@rkrenovsky That's not an option in an enterprise environments where Kubernetes Nodes are mostly ephemeral in nature, secured from direct access and containers are prevented from accessing host Nodes. Let's hope this will get addressed as BiDi support matures in Playwright .

jwroberts commented 2 months ago

@amardeep2006 While this is out of scope for playwright and not exactly what you are looking for I have had luck intercepting downloads while using playwright and a remote chromium browser (not selenium grid).

If you grab a CDP session you can use the Fetch domain to intercept the download and read it to your local playwright client. I don't have the code readily handy but in case it helps anyway the gist of the approach is:

It's not ideal but is the best I've been able to do with this problem. YMMV with Selenium grid.

amardeep2006 commented 2 months ago

Thanks a ton for the idea @jwroberts . I was able to get initial success by your idea. Early code I have aded on my repo is very very raw . It needs some polishing. It's not production ready but can be a reference if someone wants to improve it. Please share the code if you already have better version with you. I have added a sample code at my github repo. https://github.com/amardeep2006/selenium-grid-experiments/blob/main/playwright/tests

I will keep adding examples there as I polish this functionality. PS : File upload was positive anticlimax and worked out of box with Playwright.