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
66.15k stars 3.61k forks source link

[Feature] Playwright.connect() for remote connection #4687

Closed yury-s closed 2 years ago

yury-s commented 3 years ago

Current API allows to connect to Playwright server remotely by means of browserType.launchServer() and browserType.connect(). This requires launching local instance of playwright first and then establishing connections to each of the browsers individually. This can be replaced with a single client->server connection when creating Playwright client (e.g. new Playwright(<websocket address>). Among other things this approach doesn't require launching Playwright driver on the client side, so language bindings wouldn't need to bundle it in such cases.

pavelfeldman commented 3 years ago

I don't think we have enough data to move further with this one, punting for now.

vania-pooh commented 3 years ago

@pavelfeldman at least there should be some way to connect to remote web socket. Otherwise you limit Playwright to local test execution only.

pavelfeldman commented 3 years ago

Let me clarify why I closed it. This request was not about ability to connect remotely, this will still be our goal. This bug was about internal design, not requiring the driver internally when connecting remotely from the language ports (Python, Java, etc). Original bug claims:

This requires launching local instance of playwright first and then establishing connections to each of the browsers individually.

I think this is Ok since during the inner loop, developers run full Playwright anyways

This can be replaced with a single client->server connection when creating Playwright client (e.g. new Playwright().

And while it can be done, I think it is a wrong direction from the layering standpoint. We can optimize the language ports significantly if we don't mix those aspects and keep driver and rpc aspects separate.

fehmer commented 3 years ago

hi @pavelfeldman ,

This request was not about ability to connect remotely, this will still be our goal.

That's good news. Some bugs/feature request got linked to this issue, I guess that's why the closing caused confusion. Is there a issue/feature request we can use instead to keep track of this in the linked issues?

kumaraditya303 commented 3 years ago

Another use case would be to run Playwright browser instances on a remote server and run the clients as light weight docker container e.g. alpine linux to run the tests without using driver locally.

pavelfeldman commented 2 years ago

It looks like the industry has settled on the browserType.connect. Please file a new issue if you are still interested in this functionality.

sridharreddysuram123 commented 2 years ago

@pavelfeldman at least there should be some way to connect to remote web socket. Otherwise you limit Playwright to local test execution only.

Any solution for this?

dskochubey commented 1 year ago

@pavelfeldman I’m currently evaluating 1.27 with LambdaTest. I’m following LambdaTest example of using browserType.connect() or browserType.launch() to connect to a remote browser. Playwright returns error browserType.launch: Playwright version 1.27.0 not supported. Supported versions are 1.19.0 to 1.24.2. I didn’t find any announcements that that feature doesn’t supported any more and what use instead. Can anybody clarify on this?

P.S. with 1.24.2 everything works just fine.

pavelfeldman commented 1 year ago

Looks like Lambdateat is only supporting old versions of Playwright?

dskochubey commented 1 year ago

@pavelfeldman It seems that issue is on Playwright's side. I use the Playwright method browserType.connect(wsEndpoint[, options]) with wsEndpoing provided by LambdaTest. When running a test, Playwright throws the error: browserType.connect: Playwright version 1.27.0 not supported. Supported versions are 1.19.0 to 1.24.2.

gointoit commented 10 months ago

@pavelfeldman at least there should be some way to connect to remote web socket. Otherwise you limit Playwright to local test execution only.

Any solution for this? 😄

jfrantzius commented 7 months ago

In my case I want to run my Java test on a non-supported platform in Jenkins, while connecting to a Playwright server (which runs using the official docker image). Because my Jenkins is air-gapped, I need to disable the browsers download.

The problem now is that Playwright.create() (in PlaywrightImpl.createImpl() always creates a process for a local driver, which then fails for me like this:

/tmp/playwright-java-7549223223667235521/node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /tmp/playwright-java-7549223223667235521/node)
/tmp/playwright-java-7549223223667235521/node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by /tmp/playwright-java-7549223223667235521/node)
/tmp/playwright-java-7549223223667235521/node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /tmp/playwright-java-7549223223667235521/node)
/tmp/playwright-java-7549223223667235521/node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by /tmp/playwright-java-7549223223667235521/node)
/tmp/playwright-java-7549223223667235521/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /tmp/playwright-java-7549223223667235521/node)
/tmp/playwright-java-7549223223667235521/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /tmp/playwright-java-7549223223667235521/node)
Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set
java.io.IOException: Stream closed
    at java.base/java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:442)
    at java.base/java.io.OutputStream.write(OutputStream.java:157)
    at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81)
    at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142)
    at com.microsoft.playwright.impl.WriterThread.run(PipeTransport.java:167)
java.io.IOException: Stream closed
    at java.base/java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:442)
    at java.base/java.io.OutputStream.write(OutputStream.java:157)
    at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81)
    at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142)
    at java.base/java.io.FilterOutputStream.close(FilterOutputStream.java:182)
    at com.microsoft.playwright.impl.PipeTransport.close(PipeTransport.java:93)
    at com.microsoft.playwright.impl.PipeTransport.poll(PipeTransport.java:71)
    at com.microsoft.playwright.impl.Connection.processOneMessage(Connection.java:200)
    at com.microsoft.playwright.impl.ChannelOwner.runUntil(ChannelOwner.java:118)
    at com.microsoft.playwright.impl.Connection.sendMessage(Connection.java:126)
    at com.microsoft.playwright.impl.ChannelOwner.sendMessage(ChannelOwner.java:106)
    at com.microsoft.playwright.impl.Connection$Root.initialize(Connection.java:82)
    at com.microsoft.playwright.impl.Connection.initializePlaywright(Connection.java:177)
    at com.microsoft.playwright.impl.PlaywrightImpl.createImpl(PlaywrightImpl.java:52)
    at com.microsoft.playwright.impl.PlaywrightImpl.create(PlaywrightImpl.java:35)
    at com.microsoft.playwright.Playwright.create(Playwright.java:110)
    at com.microsoft.playwright.Playwright.create(Playwright.java:114)

Currently I see no way to work around this problem, does anybody perhaps know a solution? Or would this require the feature this issue is asking for?

Also asking in https://stackoverflow.com/questions/78041616/how-to-connect-to-remote-playwright-server-without-creating-local-driver

jfrantzius commented 7 months ago

I tried to workaround by initializing a Java PlaywrightImpl on a redirected stdin+stdout of the driver running in a separate container, instead of it starting a local process and using that process' stdin+stdout (as the implementation in com.microsoft.playwright.impl.PlaywrightImpl.createImpl(CreateOptions, boolean) currently does):

        try {
            Socket socket = new Socket(LOCALHOST_IP, 2020);
            receiveFromServerInputStream = socket.getInputStream();
            writeToServerOutputStream = socket.getOutputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Connection connection = new Connection(new PipeTransport(receiveFromServerInputStream, writeToServerOutputStream), env);
        PlaywrightImpl result = connection.initializePlaywright();

That separate container (mcr.microsoft.com/playwright/java:v1.39.0-jammy) has this start script:

# extract the driver npm 
unzip /root/.m2/repository/com/microsoft/playwright/driver-bundle/1.39.0/driver-bundle-1.39.0.jar -d /root/driver-bundle

# install netcat
apt-get update && apt-get install -y netcat
# create a TCP socket to make server i/o accessible from outside container
nc -l -p 2020 &  

# start the driver and redirect i/o to TCP socket  
cd /root/driver-bundle/driver/linux-arm64
echo Starting Playwright driver  
PW_LANG_NAME=java DEBUG=pw:api ./playwright.sh run-driver 2>&1 | nc localhost 2020 

I thought that this should work in theory, but in practice I haven't found out why it is stuck here:

"main" #1 prio=5 os_prio=31 cpu=11837.15ms elapsed=5470.87s tid=0x0000000128810800 nid=0x2803 waiting on condition  [0x000000016beff000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@11.0.18/Native Method)
    - parking to wait for  <0x00000006c66166b0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(java.base@11.0.18/LockSupport.java:234)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(java.base@11.0.18/AbstractQueuedSynchronizer.java:2123)
    at java.util.concurrent.ArrayBlockingQueue.poll(java.base@11.0.18/ArrayBlockingQueue.java:432)
    at com.microsoft.playwright.impl.PipeTransport.poll(PipeTransport.java:68)
    at com.microsoft.playwright.impl.Connection.processOneMessage(Connection.java:200)
    at com.microsoft.playwright.impl.ChannelOwner.runUntil(ChannelOwner.java:118)
    at com.microsoft.playwright.impl.Connection.sendMessage(Connection.java:126)
    at com.microsoft.playwright.impl.ChannelOwner.sendMessage(ChannelOwner.java:106)
    at com.microsoft.playwright.impl.Connection$Root.initialize(Connection.java:82)
    at com.microsoft.playwright.impl.Connection.initializePlaywright(Connection.java:177)

I have not clue how to debug the connection unfortunately ...

slav4ik51493 commented 3 months ago

@jfratzius

Did you find any solution for this? I've also problem when I need to connect to remote browser on the server without running locally node process and save memory. I'm working with .NET and I had the idea prevent running node process and just creating websocket to remote browser.