This repository aims to illustrate an issue found in WebdriverIO v9.12.1, more precisely with PR #14259. An issue has been opened here.
When running a local WebdriverIO runner starting a web test by calling a Selenoid instance running in Docker, WebdriverIO will receive the browser's container hostname from Selenoid when creating the session. It will then try to use that to connect to BiDi's websocket url :
[0-0] INFO webdriver: Connecting to webSocketUrl ws://8f3a4490710c:4444/session/a8968f21d3d37460598ee9f1e2f4af7f
Since the client can't resolve the container's hostname, which is only known inside the Docker network, it will fail with the following error :
[0-0] node:internal/dns/promises:99
[0-0] this.reject(new DNSException(err, 'getaddrinfo', this.hostname));
[0-0] ^
[0-0]
[0-0] Error: getaddrinfo EAI_AGAIN 8f3a4490710c
[0-0] at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:internal/dns/promises:99:17) {
[0-0] errno: -3001,
[0-0] code: 'EAI_AGAIN',
[0-0] syscall: 'getaddrinfo',
[0-0] hostname: '8f3a4490710c'
[0-0] }
The following sections will help you setup this project to easily reproduce the issue, and offer a dirty patch to illustrate a potential fix.
- node (tested with v22.14.0)
- Docker
-
Clone this repository :
git clone git@github.com:nicolasbouffard/webdriverio-dns-issue.git
-
Pull Selenoid's Chrome browser image :
docker pull selenoid/chrome:128.0
-
Install dependencies :
npm install
-
Run Selenoid :
docker run --rm -d --name selenoid -p 4444:4444 -v /var/run/docker.sock:/var/run/docker.sock -v ./config/:/etc/selenoid/:ro aerokube/selenoid:latest-release
-
Run the test :
npm run wdio
-
Notice the error mentioned in the introduction and the test failing.
-
Apply the dirty patch :
patch -p1 < fix.patch -
Run the test again :
npm run wdio
-
Notice the error mentioned in the introduction is gone and the test passes.
The patch proposed in the fix.patch file just wraps the part of the WebdriverIO upgrade that crashes in a try...catch block :
--- old/node_modules/webdriver/build/node.js
+++ new/node_modules/webdriver/build/node.js
@@ -1861,11 +1861,13 @@
if (isIP(parsedUrl.hostname)) {
return candidateUrls;
}
- const candidateIps = await dns2.lookup(parsedUrl.hostname, { family: 0, all: true });
- if (candidateIps.length > 1) {
- const hostnameMapper = (result) => webSocketUrl.replace(parsedUrl.hostname, result.address);
- candidateUrls.push(...candidateIps.map(hostnameMapper));
- }
+ try {
+ const candidateIps = await dns2.lookup(parsedUrl.hostname, { family: 0, all: true });
+ if (candidateIps.length > 1) {
+ const hostnameMapper = (result) => webSocketUrl.replace(parsedUrl.hostname, result.address);
+ candidateUrls.push(...candidateIps.map(hostnameMapper));
+ }
+ } catch (e) {}
return candidateUrls;
}
async function connectWebsocket(candidateUrls, _) {Most likely a proper fix should do more than this. This is only to illustrate that this part of the code changed in the PR can crash while it could be avoided and not impact the test, as WebdriverIO would fallback to the classic protocol.
As a final demonstration, one can rollback to WebdriverIO v9.12.0 and run the test again and notice that it passes without applying the patch.
-
Clean the dependencies :
npm run clean
-
Install dependencies again :
npm install
-
Rollback WebdriverIO :
npm install @wdio/local-runner@9.12.0
-
Run the test again :
npm run wdio