Skip to content

[BUG] webServer.reuseExistingServer is broken on node 18 #24101

Closed

Description

System info

  • Playwright Version: [v1.35.1]
  • Operating System: [All]
  • Browser: [All]

Source code

  • I provided exact source code that allows reproducing the issue locally.

Link to the GitHub repository with the repro

Steps

  1. Clone this repo and using your shell of choice navigate to the root of the repo.
  2. Execute npm start. This will build and run an angular app.
  3. Once the angular app is running, execute npm test

When running with node 16.19.1 the output after step 3 is:

> [email protected] test
> npx playwright test


Running 1 test using 1 worker

  ✓  1 [chromium] › example.spec.ts:3:5 › dummy test (1.8s)

  1 passed (2.6s)

When running with node 18.16.0 the output after step 3 is:

> [email protected] test
> npx playwright test

[WebServer] ? Port 4200 is already in use.
Would you like to use a different port? (Y/n) [WebServer]
Error: Timed out waiting 30000ms from config.webServer.

As you can see, it tries to execute the webServer.command and then eventually times out because the port is already taken.

Expected

When running on node 18.16.0 it should NOT try to execute the webServer.command when webServer.reuseExistingServer is set to true.

Actual

When running on node 18.16.0 it executes the webServer.command when webServer.reuseExistingServer is set to true.

Other

I used nvm to swap between node versions whilst testing this.

Activity

  1. pavelfeldman commented on Jul 7, 2023

    @pavelfeldman
    Member

    Here is what I get on Node 18:

    pfeldman@pfeldman-hp:~/tmp/playwright-bug-reuse-existing-server$ node --version
    v18.16.1
    pfeldman@pfeldman-hp:~/tmp/playwright-bug-reuse-existing-server$ npx playwright test
    
    Running 1 test using 1 worker
    
    [WebServer] - Generating browser application bundles (phase: setup)...
    [WebServer] ✔ Browser application bundle generation complete.
    [WebServer] 
    Initial Chunk Files   | Names         |  Raw Size
    vendor.js             | vendor        |   1.97 MB |
    polyfills.js          | polyfills     | 333.15 kB |
    styles.css, styles.js | styles        | 230.67 kB |
    main.js               | main          |  45.98 kB |
    runtime.js            | runtime       |   6.51 kB |
    
    | Initial Total |   2.58 MB
    
    Build at: 2023-07-07T16:53:46.358Z - Hash: 3e0fe3b31bc6d3f9 - Time: 4412ms
    
    ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
    
    
    ✔ Compiled successfully.
      ✓  1 [chromium] › example.spec.ts:3:5 › dummy test (131ms)
    
      1 passed (870ms)
    
  2. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    Since you're running with node 18.6.1, I've installed that version but I still get the same problem:

    > [email protected] test
    > npx playwright test
    
    [WebServer] ? Port 4200 is already in use.
    Would you like to use a different port? (Y/n) [WebServer]
    Error: Timed out waiting 30000ms from config.webServer.
    

    I'm running on Windows build 10.0.19045.0 and through powershell 7.3.5. Any thoughts?

  3. pavelfeldman commented on Jul 7, 2023

    @pavelfeldman
    Member

    I would guess that the problem is due to the ipv4 vs ipv6 mismatch, Node migrated to ipv6 in Node 18. So if you are already running ng on ipv4 elsewhere, it could probably manifest this way. But I'm trying this on Linux and it works fine. I ran npx ng serve --port 4200 on Node 16 and then ran tests on Node 18.

  4. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    Hum... On my windows machine if I try to use the demo repo I provided on this issue and from the root of the repo I run:

    docker run -it --rm --ipc=host --workdir=/app -v "$(Get-Location):/app" mcr.microsoft.com/playwright:v1.35.1-jammy npx playwright test

    I still get an error that indicates that Playwright is trying to execute the webServer.command:

    [WebServer] - Generating browser application bundles (phase: setup)...
    Error: Timed out waiting 30000ms from config.webServer.
    

    P.S: I do know that I didn't start anything on port 4000 inside the container so it would always timeout eventually, but I shouldn't see the message from the WebServer trying to execute the command instruction with will do ng serve and is where that Generating browser application bundles (phase: setup)... message comes from.

  5. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    Well, there's something weird going on.

    It does seem that Playwright tries to execute the webServer.command if I run this docker command from Windows:

    docker run -it --rm --ipc=host --workdir=/app -v "$(Get-Location):/app" mcr.microsoft.com/playwright:v1.35.1-jammy npx playwright test .

    I'm saying it seems to because otherwise I can't explain that WebServer log message which comes from ng serve.

    However, if I do:

    1. docker run -it --rm --ipc=host --workdir=/app -v "$(Get-Location):/app" mcr.microsoft.com/playwright:v1.35.1-jammy
    2. This gets me into a shell in the docker container so now I can run some commands
    3. I start the server by running npx ng serve --port 4200 & which outputs:
    root@adfd8d17e006:/app# npx ng serve --port 4200 &
    [1] 9
    ✔ Browser application bundle generation complete.
    
    Initial Chunk Files   | Names         |  Raw Size
    vendor.js             | vendor        |   1.97 MB |
    polyfills.js          | polyfills     | 333.15 kB |
    styles.css, styles.js | styles        | 230.67 kB |
    main.js               | main          |  45.98 kB |
    runtime.js            | runtime       |   6.51 kB |
    
                          | Initial Total |   2.58 MB
    
    Build at: 2023-07-07T17:25:59.983Z - Hash: 315d6fa9a434d37b - Time: 4745ms
    
    ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
    
    
    ✔ Compiled successfully.
    
    1. I run a wget to see that the app is running fine wget http://localhost:4200:
    root@adfd8d17e006:/app# wget http://localhost:4200
    --2023-07-07 17:26:37--  http://localhost:4200/
    Resolving localhost (localhost)... 127.0.0.1, ::1
    Connecting to localhost (localhost)|127.0.0.1|:4200... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 563 [text/html]
    Saving to: 'index.html'
    
    index.html                                 100%[=====================================================================================>]     563  --.-KB/s    in 0s
    
    2023-07-07 17:26:37 (55.4 MB/s) - 'index.html' saved [563/563]
    
    1. I run the test command npx playwright test and it works as expected, it didn't try to execute the webServer.command:
    root@adfd8d17e006:/app# npx playwright test
    
    Running 1 test using 1 worker
    
      ✓  1 [chromium] › example.spec.ts:3:5 › dummy test (89ms)
    
      1 passed (2.6s)
    
  6. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    I'm so confused right now as to what might be causing this 😵 . So here's what I did:

    1. Pushed a new commit to the demo repo that will change the WebServer URL based on the presence of an environment variable.
    2. Started the app on my Windows machine. The app is running on http://localhost:4200 on my Windows host.
    3. Ran Playwright tests via Docker but setting a gateway that allows Docker to talk with the app running on my Windows host:
    docker run -it --rm --ipc=host --add-host=host.docker.internal:host-gateway --env USE_DOCKER_HOST_WEBSERVER=true --workdir=/app -v "$(Get-Location):/app" mcr.microsoft.com/playwright:v1.35.1-jammy npx playwright test
    
    1. Using node 16 ON MY WINDOWS HOST, the docker test command works as expected. When using node 18 ON MY WINDOWS HOST the docker test command fails because Playwright tries to execute the webServer.command ON THE DOCKER CONTAINER.

    Here's some images:

    Working fine with Node 16:

    A) Run the app
    image

    B) Run the tests via Docker that will connect to the app running on the host. All works as expected.
    image

    Fails in Node 18:

    A) Run the app
    image

    B) Run the tests via Docker that will connect to the app running on the host. Tests fail because tries to execute the webServer.command.
    image

    P.S. - the commit I did to allow this docker connectivity from inside docker container to the app running on docker's host doesn't impact the reproducibility of the bug using the demo repo when running without docker. Following the steps initially describe on this issue still result in error for me when running on Windows.

  7. pavelfeldman commented on Jul 7, 2023

    @pavelfeldman
    Member

    I did not realize there was docker involved in your setup. To re-iterate, the main thing that happened in Node 18 which is different from Node 16 is that the ports are now bound using ipv6 by default. So when you bind :4000, it is [:1]:4000, not 127.0.0.1:4000 anymore. Those are different ports, even though the port number is the same. Browsers (and Playwright) are using technology called Happy Eyeballs to mitigate that, but I'm not sure how this goes through the docker boundary.

  8. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    Pavel Feldman (@pavelfeldman) note that on the original description of the issue there is no Docker involved. For me the issue happens without Docker and running on Windows just by swapping from node 16 to 18.

    I did further testing using Docker after you pointed out you couldn't replicate the issue on linux.

    EDIT:
    Can you replicate what I saw in this comment for instance? I don't understand why it seems Playwright seems to execute the webServer.command.

  9. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    Pavel Feldman (@pavelfeldman) I think part of the issue was that I didn't understand that webServer.reuseExistingServer will fallback to execute the webServer.command if it can't get to the specified webServer.url. As noted in the webServer.reuseExistingServer documentation:

    If true, it will re-use an existing server on the port or url when available. If no server is running on that port or url, it will run the command to start a new server. If false, it will throw if an existing process is listening on the port or url. This should be commonly set to !process.env.CI to allow the local dev server when running tests locally.

    The other part of this issue is very likely related to the change you've mentioned about the fact that Node migrated to ipv6 in Node 18. Somehow that is affecting the way Playwright tries to check if the webServer.url is up and running and then falls back to executing the webServer.command.

  10. edumserrano commented on Jul 7, 2023

    @edumserrano
    Author

    And you were absolutely right regarding the root cause Pavel Feldman (@pavelfeldman) . Thank you very much for pointing me in the right direction.

    On the package.json I changed the npm start command so that it would bind specifically to 127.0.0.1 by passing a --host flag to the ng serve command:

    "start": "npx ng version && npx ng serve --host=127.0.0.1 --port 4200 -o",
    

    And then running npm test or via docker with docker run -it --rm --ipc=host --add-host=host.docker.internal:host-gateway --env USE_DOCKER_HOST_WEBSERVER=true --workdir=/app -v "$(Get-Location):/app" mcr.microsoft.com/playwright:v1.35.1-jammy npx playwright test, everything works as expected.

    Feel free to close this issue.

  11. pavelfeldman commented on Jul 7, 2023

    @pavelfeldman
    Member

    I just noticed that you were using 127.0.0.1 explicitly in your config. Switching it to localhost would trigger all those happy eyeballs paths. But I would recommend keeping it as you have it as it makes everything simpler for both browser and Playwright.

    const host = process.env.USE_DOCKER_HOST_WEBSERVER ? `host.docker.internal` : `127.0.0.1`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions