webdriverio-community / wdio-docker-service

Docker service for Webdriver.io
MIT License
38 stars 14 forks source link

Calling `browser.mock` in a docker container fails with `ECONNREFUSED` #104

Closed johnson-tyl closed 3 years ago

johnson-tyl commented 3 years ago

Originally logged here: https://github.com/webdriverio/webdriverio/issues/6997


If you run a test that needs browser.mock inside docker container, it fails on node-fetch ClientRequest with ECONNREFUSED error.

Exception:

FetchError: Failed to fetch browser webSocket URL from http://localhost:39857/json/version: request to http://localhost:39857/json/version failed, reason: connect ECONNREFUSED 127.0.0.1:39857
    at ClientRequest.<anonymous> (C:\Users\user\workspace\node.js\tyl-e2e-reviews\node_modules\node-fetch\lib\index.js:1461:11)
    at Socket.socketErrorListener (_http_client.js:426:9)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)
    at Browser.runCommandWithHooks (C:\Users\user\workspace\node.js\tyl-e2e-reviews\node_modules\@wdio\sync\build\wrapCommand.js:100:24)
    at Browser.wrapCommandFn (C:\Users\user\workspace\node.js\tyl-e2e-reviews\node_modules\@wdio\sync\build\wrapCommand.js:67:44)
    at LoginPage.setPassword (C:\Users\user\workspace\node.js\tyl-e2e-reviews\tests\pages\app\application\login.page.js:36:29)

NOTE: The port seen above is not same every time, so cant expose it either.

Environment (please complete the following information):

Config of WebdriverIO

exports.config = {
    runner: 'local',
    hostname: 'localhost',
    path: '/wd/hub',
    outputDir: './logs',

    capabilities: [
    {
        "maxInstances": 5,
        "browserName": "chrome",
        "goog:chromeOptions": {
            "args": [
                "--start-maximized"
            ],
            "prefs": {
                "credentials_enable_service": false,
                "profile": {
                    "password_manager_enabled": false
                }
            }
        }
    }],
    services:
        [
            [wdioScreenshot],
            'shared-store',
            'docker'
        ],
    dockerOptions: {
        image: 'selenium/standalone-chrome-debug',
        healthCheck: {
            url: 'http://localhost:4444',
            maxRetries: 3,
            inspectInterval: 1000,
            startDelay: 2000
        },
        options: {
            p: ['4444:4444', '5900:5900'],
            shmSize: '2g'
        }
    },
    dockerLogs: 'logs',
}

Describe the bug I am running my existing local tests inside the docker container using the wdio-docker-service and the tests that were running successfully locally dont run inside the container, where it encounters the browser.mock() call, its throwing the error mentioned above.

To Reproduce Steps to reproduce the behavior:

  1. Setup a project with latest WebdriverIO and wdio-docker-service
  2. Write a test that uses browser.mock()
  3. Setup the tests to run inside the container using the instructions from here
  4. Run the tests

Expected behavior The test should pass when running inside the container.

Log Nothing in logs, see the exception above.

stsvilik commented 3 years ago

@johnson-tyl If all you need is to expose an extra port from the docker container (and you can somehow "fix" it to be the same all the time), then all you need to do is expose it via dockerOptions.options.p (just like in example you have, just add one more to an array).

johnson-tyl commented 3 years ago

This port is random, if I knew what it was I would have exposed it.

Do you know of any way to fix this port before running?

stsvilik commented 3 years ago

Not sure how to fix it, but there is a way to expose a range of ports in Docker, which you could try. Isn't there a range for these ports?

johnson-tyl commented 3 years ago

I managed to fix the debugger port and expose it in docker but now it throws socket hang up error.

FetchError: Failed to fetch browser webSocket URL from http://localhost:9222/json/version: request to http://localhost:9222/json/version failed, reason: socket hang up
    at ClientRequest.<anonymous> (C:\Users\user\workspace\node.js\app\node_modules\node-fetch\lib\index.js:1461:11)
    at Socket.socketOnEnd (_http_client.js:453:9)
    at endReadableNT (_stream_readable.js:1220:12)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)
    at Browser.runCommandWithHooks (C:\Users\user\workspace\node.js\app\node_modules\@wdio\sync\build\wrapCommand.js:100:24)
    at Browser.wrapCommandFn (C:\Users\user\workspace\node.js\app\node_modules\@wdio\sync\build\wrapCommand.js:67:44)

Any idea how to fix this, I am not running it headless, will that make any difference?

stsvilik commented 3 years ago

Help me understand where this call is initiated. Is Chrome (in remote debug mode) running inside a container or outside on your machine?

johnson-tyl commented 3 years ago

This is my test setup:

Docker options:

dockerOptions: {
        image: 'selenium/standalone-chrome-debug',
        healthCheck: {
            url: 'http://localhost:4444',
            maxRetries: 3,
            inspectInterval: 1000,
            startDelay: 2000
        },
        options: {
            expose: [ 9222 ],
            p: ['4444:4444', '5900:5900', '0.0.0.0:9222:9222'],
            shmSize: '2g'
        }

Capablities:

capabilities: [
    {
        "maxInstances": 5,
        "browserName": "chrome",
        "goog:chromeOptions": {
            "args": [
                "--remote-debugging-address=0.0.0.0",
                "--remote-debugging-port=9222",
                "--start-maximized"
            ],
            "prefs": {
                "credentials_enable_service": false,
                "profile": {
                    "password_manager_enabled": false
                }
            }
        },
        "cjson:metadata": {
            "browser": {
                "name": "chrome",
                "version": "latest"
            },
            "platform": {
                "name": "windows",
                "version": "10.0.19042"
            }
        }
    }
]

Services:

services:
        [
            [wdioScreenshot],
            [rerunService, {rerunDataDir: './report/rerun'}],
            'shared-store',
            'docker'
        ]

Let me know if you need anything else please.

stsvilik commented 3 years ago

Could you try to remove expose option and just use p with 9222:9222?

johnson-tyl commented 3 years ago

Could you try to remove expose option and just use p with 9222:9222?

Have done that too, same result I am afraid.

johnson-tyl commented 3 years ago

you mean also remove 0.0.0.0 from p?

stsvilik commented 3 years ago

Yep

johnson-tyl commented 3 years ago

Yep

tried that too, same error, any other ideas?

stsvilik commented 3 years ago

Hard to say because I'm still fuzzy about which side attempts to make a connection. If test running on your machine is trying to connect to debug port inside a container, then localhost should resolve fine since that port is exposed. If it's the code inside container which attempts to access port outside via localhost, then it will not work since to a Docker that name points to itself.

johnson-tyl commented 3 years ago

Since devtools run inside the chrome browser (inside container), its possible the call might be from the inside of the container. Someone had a similar problem using wdio-docker-service and devtools as service, https://github.com/stsvilik/wdio-docker-service/issues/78 not sure if their problem was resolved.

stsvilik commented 3 years ago

Maybe this will help if you can change the host to which it attempts to connect. https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach

johnson-tyl commented 3 years ago

Thanks @stsvilik, I tried changing the remote-debugging-address to "host.docker.internal" but getting the same error.

"goog:chromeOptions": {
            "args": [
                "--remote-debugging-address=host.docker.internal",
                "--remote-debugging-port=9222",
                "--start-maximized"
            ],
            "prefs": {
                "credentials_enable_service": false,
                "profile": {
                    "password_manager_enabled": false
                }
            }
        },

Tried the 2nd option of adding network: 'host' to dockerOptions but that's throwing error starting docker, looks like its only supported in Docker on Linux (I am on Windows):

dockerOptions: {
    image: 'selenium/standalone-chrome-debug',
    healthCheck: {
        url: 'http://localhost:4444',
        maxRetries: 3,
        inspectInterval: 1000,
        startDelay: 2000
    },
    options: {
        p: ['4444:4444', '5900:5900', '0.0.0.0:9222:9222'],
        network: 'host',
        shmSize: '2g'
    }
}

Anything more you can recommend please? I am not a regular Docker user, so not very good at troubleshooting these issues, so any help is appreciated.

johnson-tyl commented 3 years ago

Looks like I found the solution to the problem, the only way it exposes the port outside of container is when you run it headless, this is completely odd.

Tried it after reading it a few different places on Stackoverflow, last one being: https://stackoverflow.com/questions/48319240/chrome-fails-to-serve-from-debugging-port-inside-docker-container

stsvilik commented 3 years ago

I would add host to the Docker with IP of host machine and use that host name with remote debugging address.

johnson-tyl commented 3 years ago

If I add IP address of host, it will fail when one of my colleagues run it, as they wont have the same IP address as my machine?

CristobalBautista commented 2 years ago

@johnson-tyl Hi, I'm trying to run the browser.mock() command in a docker container as well, but I'm getting the same error you got. Did you manage to make it work? I'm already running it in --headless and set the --remote-debugging-port=9222, but same error.

gianlucamangiapelo commented 2 years ago

Hy @johnson-tyl I'm trying to fix this issue also on my side. Can you share with us your configurations that allows to use .mock() with no issue?

Thanks