Search code examples
node.jsdockerselenium-webdriverdockerfile

Docker + Selenium Chrome driver error: Server terminated early with status 127


I have a Docker script that runs some Selenium test scripts.

Here are the Dockerfile contents:

FROM selenium/hub:nightly

WORKDIR /usr/src/app

RUN sudo apt-get update

COPY . /usr/src/app/

RUN sudo curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -

RUN sudo apt-get install nodejs -y

CMD ./start.sh

The "start.sh" file looks a bit like this:

#!/usr/bin/env bash
echo "init..."

npm run test:dev

"test" is a NodeJs command (from package.json) which runs:

"test": "cucumber-js features/"

This loads the Selenium Chrome driver and runs a series of Selenium/Cucumber tests.

When run on the desktop (MacOS), everything works great! When I run this using Docker, I get the following error at the beginning of each test. I assume that the test cannot even begin because it cannot load the Chrome driver:

Error: Server terminated early with status 127
    at /usr/src/app/node_modules/selenium-webdriver/remote/index.js:259:24

The commands that I'm using to build & run docker are:

docker build - < Dockerfile && docker run selenium_automation_tests < Dockerfile

The contents of our run.sh file are:

#!/usr/bin/env bash
docker build --platform linux/x86_64 -t selenium_automation_tests .
docker run --platform linux/x86_64 -d -p 4442-4444:4442-4444  -it selenium_automation_tests #/bin/bash

I've searched Google & stackoverflow for this error ("Server terminated early with status 127") and have tried a lot of the suggestions, but so far nothing has worked. What can I do to get rid of this error and run the Selenium/Cucumber tests in Docker?


Solution

  • Assuming that your project looks something like this:

    ├── Dockerfile
    ├── features
    │   ├── step_definitions
    │   │   └── test_steps.js
    │   └── test.feature
    ├── package.json
    ├── run.sh
    └── start.sh
    

    🗎 Dockerfile

    FROM selenium/standalone-chrome:latest
    
    USER root
    
    RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
        apt-get install -y nodejs
    
    WORKDIR /usr/src/app
    
    COPY . .
    
    RUN npm install
    
    RUN chmod +x ./start.sh
    
    USER seluser
    
    CMD ["./start.sh"]
    

    🗎 package.json

    {
      "name": "selenium-test",
      "type": "module",
      "version": "1.0.0",
      "main": "index.js",
      "scripts": {
        "test:dev": "cucumber-js features/"
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "express": "^4.18.2",
        "selenium-webdriver": "^4.18.1",
        "supabase": "^1.145.4"
      },
      "keywords": [],
      "description": "",
      "devDependencies": {
        "@cucumber/cucumber": "^10.3.1",
        "chai": "^5.1.0",
        "chromedriver": "^122.0.6"
      }
    }
    

    🗎 test.feature

    Feature: Chrome Loads Page
    
      Scenario: Load example page
        Given I am on the example.com page
        Then the page has loaded
    

    🗎 test_steps.js (The various options ensure that Chrome will run happily inside a container. They might not all be necessary.)

    import { Given, Then, After } from '@cucumber/cucumber';
    import { Builder, By, until } from 'selenium-webdriver';
    import assert from 'assert';
    import chrome from 'selenium-webdriver/chrome.js';
    
    let driver;
    
    let options = new chrome.Options();
    options.addArguments('--headless');
    options.addArguments('--no-sandbox');
    options.addArguments('--disable-dev-shm-usage');
    options.addArguments('--disable-gpu');
    options.addArguments('--disable-extensions');
    options.addArguments('--remote-debugging-port=9222');
    
    Given('I am on the example.com page', async function () {
      driver = await new Builder().forBrowser('chrome').setChromeOptions(options).build();
      await driver.get('http://www.example.com');
    });
    
    Then('the page has loaded', async function () {
      let element = await driver.wait(until.elementLocated(By.css('h1')), 10000);
      let text = await element.getText();
      
      assert.strictEqual(text, "Example Domain", 'The page did not load correctly.');
    });
    
    After(async function () {
      if (driver) {
        await driver.quit();
      }
    });
    

    The run.sh and start.sh files are the same as the ones provided in the question.

    enter image description here