Nightwatch tests fail when running in docker using selenium/chromedriver

Viewed 90

I am running my whole system using docker-compose and I am trying to execute my end-to-end tests (written with Nightwatch) using a selenium/chrome service that is in the same network. My frontend is VueJS and the image is built from a node base image. I am running the tests with docker-compose exec frontend npm run test-selenium and getting the following output:

> frontend@0.1.0 test-selenium
> nightwatch -c nightwatch-selenium.conf.js


[Login Test] Test Suite
──────────────────────────────────────────────
ℹ Connected to chrome on port 4444 (1494ms).
  Using: chrome (102.0.5005.61) on LINUX.   


  Running login:
───────────────────────────────────────────────────────────────────────────────────────────────────
  ℹ Loaded url http://frontend:8090/login in 2049ms
  NoSuchElementError: An error occurred while running .click() command on <Element [name=@loginBt]>: Timed out while waiting for element "#loginBt" with "css selector" to be present for 5000 milliseconds.
       at Object.login (/app/tests/loginTest.js:8:8)
  NoSuchElementError: An error occurred while running .setValue() command on <Element [name=@emailField]>: Timed out while waiting for element "input[name = "email"]" with "css selector" to be present for 5000 milliseconds.
       at Page.fillUpData (/app/tests/page-objects/loginPage.js:13:21)
       at Object.login (/app/tests/loginTest.js:9:8)
  NoSuchElementError: An error occurred while running .setValue() command on <Element [name=@passField]>: Timed out while waiting for element "input[name = "password"]" 
with "css selector" to be present for 5000 milliseconds.
       at Page.fillUpData (/app/tests/page-objects/loginPage.js:13:21)
       at Object.login (/app/tests/loginTest.js:10:8)
  NoSuchElementError: An error occurred while running .click() command on <Element [name=@submitBt]>: Timed out while waiting for element "button[name = "submit"]" with 
"css selector" to be present for 5000 milliseconds.
       at Object.login (/app/tests/loginTest.js:11:8)
  ✖ Testing if the URL contains '/cards' in 5000ms - expected "contains '/cards'" but got: "http://frontend:8090/login" (5143ms)
    at Object.login (/app/tests/loginTest.js:12:15)


FAILED: 1 assertions failed and  4 errors (28.22s)

When running tests locally, everything is working just fine. For local tests, I am using the chrome driver installed as dev dependency, accessing the frontend using http://localhost:8090/.

It is my first time dealing with E2E tests in docker, so I am not really sure what is going wrong. Any help is appreciated. Please find the source code below. Let me know if I need to add any more information.

  • package.json
"scripts": {
   ...
    "test": "nightwatch",
    "test-selenium": "nightwatch -c nightwatch-selenium.conf.js",
   ...
  },
  • docker-compose.yml
services:
  frontend:
    build:
      context: card-market-frontend/
      dockerfile: Dockerfile
    command: npm run serve
    working_dir: /app
    ports:
      - "8090:8090"

  chrome:
    image: selenium/standalone-chrome:latest
    hostname: chrome
    privileged: true
    shm_size: 2g  
  • When running the tests with the test-selenium command I am using the nightwatch.conf below:
const chromedriver = require("chromedriver");

require("dotenv").config();

module.exports = {
  src_folders: ["/tests"],
  page_objects_path: ["tests/page-objects"],

  test_workers: false,

  selenium: {
    start_process: false,

    cli_args: {
      "webdriver.chrome.driver": chromedriver.path,
    },
  },

  webdriver: {
    start_process: false,
  },

  test_settings: {
    default: {
      selenium_port: 4444,
      selenium_host: "chrome",

      screenshots: {
        enabled: true,
        path: "tests_output/",
        on_failure: true,
      },

      desiredCapabilities: {
        browserName: "chrome",
        chromeOptions: {
          w3c: false,
          args: ["--no-sandbox"],
        },
      },
    },
  },
};
  • My page object loginPage.js
module.exports = {
  url: `http://frontend:8090/login`,
  elements: {
    logoutBt: "#logoutBt",
    loginBt: "#loginBt",
    emailField: 'input[name = "email"]',
    passField: 'input[name = "password"]',
    submitBt: 'button[name = "submit"]',
  },
  commands: [
    {
      fillUpData(selector, data) {
        return this.setValue(selector, data);
      },
    },
  ],
};
  • The test that is running loginTest.js
module.exports = {
  login(browser) {
    const page = browser.page.loginPage();
    const email = "coolEmail@gmail.com";
    const pass = "coolPass";
    page
      .navigate()
      .click("@loginBt")
      .fillUpData("@emailField", email)
      .fillUpData("@passField", pass)
      .click("@submitBt")
      .assert.urlContains("/cards");
  },
};
1 Answers

Your first error is:

NoSuchElementError: An error occurred while running .click() command on <Element [name=@logoutBt]>: Timed out while waiting for element "#logoutBt" with "css selector" to be present for 5000 milliseconds.

which indicates that NoSuchElementError was raised while searching for the Logout button.

However as per the test steps within loginTest.js, ideally you are not supposed to find the Logout button just after navigating to the page:

.navigate()
.click("@logoutBt")

You can find the Logout button only after logging in.


Solution

Ideally, the sequence of the commands will be:

page
  .navigate()
  .click("@loginBt")
  .fillUpData("@emailField", email)
  .fillUpData("@passField", pass)
  .click("@submitBt")
  .assert.urlContains("/cards");
  .click("@logoutBt")
Related