Protractor running in docker returns element not existing but in localhost does

protractor element all
protractor onprepare
protractor expectedconditions
protractor api
protractor style guide
protractor async/await
protractor sendkeys
protractor ispresent

I've been trying to run some protractor testing inside a Docker but I've found a problem which I can't solve myself. Protractor says that the element does not exist inside the web page in Docker, but it does in localhost. Also, the CURL to the web page exposes HTML elements (as you know, not the HTML inside Angular components) but still doesn't find the element.

First of all, testing is working properly at localhost:

/*********** TESTING **********/
beforeAll(function(){
    browser.sleep(1).then(function() {
        console.log('Browser running ...');
    });

    browser.driver.manage().window().getSize().then(function(size) {
        console.log('Starting browser size', size);
    });

    browser.get(specifiedURL+"/app/users/#/register");

    browser.waitForAngular(); //We expect to wait for angular to be loaded so browser can load correctly his components        

    browser.getCurrentUrl().then(function(url){
        console.info("Browser redirected to "+url);
    });

    browser.refresh();  //Refresh the view so it loads the content properly at the specified ngStorage-project url
});

And two tests

it("should redirect to the specified page", function(){
    expect(browser.getCurrentUrl()).toEqual(specifiedURL+"/app/users/#/register");
});

it("should exists a surname input in the page",function(){
    var displaySurnameInput = element(by.id('signup-surname'));

    browser.wait(function() {
         return displaySurnameInput.isPresent();
    }, 5000);

    expect(displaySurnameInput.getText()).toEqual('');
});

The config file like

    let SpecReporter = require('jasmine-spec-reporter').SpecReporter;

exports.config = {
  framework: "jasmine2",
  suites: {
    login: "tests/e2e/login/**/*Spec.js"
  },
  multiCapabilities: [{
    browserName: "chrome",
    chromeOptions: {
      args: [ "--headless", "--window-size=1200x800", "--disable-gpu", "--test-type", "--no-sandbox"]
    }
  }],
  jasmineNodeOpts: {
    showColors: true,
    silent: true,
    defaultTimeoutInterval: 360000,
    print: function () { }
  },
  onPrepare: function () {
    jasmine.getEnv().addReporter(new SpecReporter({
      spec: {
        displayStacktrace: false
      }
    }));
  }
}

The Docker is linked to a docker-nginx server exposed to port 80, so we can check if a project is correctly running or not (which it is). As i run the docker command:

docker run -it -v /dev/shm:/dev/shm --privileged -e SCREEN_WIDTH=1920 -e SCREEN_HEIGHT=1480 -e SCREEN_DEPTH=24 --link ify-nginx:ify-nginx ify/test-runner bash

I can access the web page using CURL and it shows up the web page HTML in a browser (actually the same result as curl in localhost returns) BUT somehow protractor is not finding inside the URL the element (I've already tried to get the element by multiple jasmine functions and still happens the same problem).

LOCALHOST PROTRACTOR_RESULT

DOCKER PROTRACTOR_RESULT

Thank you!

EDIT1:

Using this inside docker generate an error, but not in localhost

it("should exists a surname input in the page",function(){
    var displaySurnameInput = element(by.id('signup-surname'));

    browser.pause();

    browser.wait(function() {
        return displaySurnameInput.isPresent();
    }, 5000);

    expect(displaySurnameInput.getText()).toEqual('');
});

ERROR (As i'm newbie i cannot paste more than 2 images, so i paste the code here)

[08:33:33] I/protractor -
module.js:487
    throw err;
    ^
Error: Cannot find module '_debugger'

EDIT2:

Using

browser.executeScript("return arguments[0].innerHTML;", $('html')).then(function (content) { console.log(content); }); 

I've printed the html revealing the components... but not the inner html (where it lays the correct ids and the actual input element)

    <section ng-show="step==1" style="overflow:hidden;">
            <ify-input id="signup" field="name" ng-model="user.name" class="ng-pristine ng-untouched ng-valid ng-scope"><!-- ngIf: isAllowed(field) --></ify-input>
            <a id="signup-step1" class="ify-button ng-binding" ng-click="step2()">{{ ("Next" | translate).toUpperCase() }}</a>
    </section>

I can run a test which PASSES searching for the element by.model, but it's not referring to the inner input as it should do with by.id.

it("should find a model.name in the dom", function(){
        var displayNameInput = element(by.model("user.name"));

        browser.wait(function() {
            return displayNameInput.isPresent();
        }, 5000);

        expect(displayNameInput.getText()).toEqual('');
});

The issue remains clear, cannot get the inner html of angular components

EDIT3:

I've tested this page https://docs.angularjs.org/examples/example-heroComponentSimple/index.html and exposed the HTML, and it seems to be reading ok the inner html of the component.

HTML exposed:

 <body ng-app="heroApp" class="ng-scope">
  <!-- components match only elements -->
<div ng-controller="MainCtrl as ctrl" class="ng-scope">
  <b>Hero</b><br>
  <hero-detail hero="ctrl.hero" class="ng-isolate-scope"><span class="ng-binding">Name: Spawn</span></hero-detail>
</div>

The test:

        it("example component web random",function(){
        browser.get("https://docs.angularjs.org/examples/example-heroComponentSimple/index.html");

        browser.waitForAngular();

browser.executeScript("return arguments[0].innerHTML;", $('html')).then(function (content) { console.log(content); });

        expect(element(by.css('.ng-binding')).isPresent()).toBe(true);
    });

You are missing a ";" at the end of the return inside the browser.wait. Also, try with

return displaySurnameInput.isPresent();

And is 5 seconds enough to load the page?

You could also disable get more details about what is wrong by disabling the reporting library. Or maybe it has an option to display more details.

If you use browser.ignoreSynchronisation = true; before the browser.wait and false after the wait, does it change anything?

Failed: Error while waiting for Protractor to sync with the page , [launcher] Running 1 instances of WebDriver Start test Given(/^Something exists$/, function() { browser.get('http://localhost:3000/'); return I know it's not the best to solve like this, but it is working for now and that was @reddynr I do not see you wait for an element or anything after you .get() the page. Running Protractor Headless with Docker Setting up Docker 1st Docker: Selenium Webdriver. This docker image is a Selenium Webdriver server where our specs will be directed against. It contains the Firefox and Chrome to run our specs headless. It also provides us VNC access to check what is going on the browser.

Docker was trying to connect a non existent API at http://ify-nginx/api/... The call was expecting a list of required fields to be generated on the register form. When returning null, fields wouldn't be generate, per-se, protractor couldn't find nothing.

As you can see above, something weird was happening here (ngIf: isAllowed)

<ify-input id="signup" field="name" ng-model="user.name" class="ng-pristine ng-untouched ng-valid ng-scope"><!-- ngIf: isAllowed(field) --></ify-input>

We got an if in the api code checking if the url is 'localhost' or the server ip, not 'ify-nginx'. When ify-nginx is detected, the api domain is redirected to it, and it doesn't load the content.

angular/protractor, I'm very new to using protractor so this very well may be user error, but I've tried true, baseUrl: 'http://localhost:4200/', useAllAngular2AppRoots: true, StaleElementReferenceError: stale element reference: element is not that I am running, but I'm really struggling to understand what state could be  Running Protractor Tests on Docker. This is a simple tutorial that shows how to use docker to run Protractor tests. We would setup a Selenium Grid and run the tests. Prerequisites. Docker needs to be installed on your machine. One can download it from Docker's website and follow the documentation accordingly. It is assumed that , one knows the

Protractor says that the element does not exist inside the web page in Docker, but it does in localhost. Also, the CURL to the web page exposes HTML elements (as you know, not the HTML inside Angular components) but still doesn't find the element.

is a little misleading, or maybe it is because my bad English. I also had a similiar bug. So I try to explain how I solved mine.

  1. do a brainstorming: what could be the reason? Sometimes it will be more than 1. Make sure that you find out step by step what is not working and what is 100% working. You tried to debug protractor app with browser.wait, which is in the right direction, but it will not work in Node.js 8+, you may want to try out protractor snapshot
  2. write those reasons down, for me there were: https (I have an self-assigned certificate to manually verify when going to a site like https://localhost:8443), localhost may work on dev, e.g. on mac, but may not work in docker container since every container gets a different ip (I prefer docker-compose because it is cleaner ?) and you can assign static ip to docker containers (I didn't know that either)
  3. start with http and localhost capabilities: { browserName: 'chrome', chromeOptions: { // for ci test args: ['--headless', 'no-sandbox', "--disable-browser-side-navigation", "--allow-insecure-localhost" /// for https sites: ignore ssl on https://localhost... /// further args please see https://peter.sh/experiments/chromium-command-line-switches/ ] // maybe you want to take some screenshots to test where the error occurs: } }
  4. use some docker commands to debug, here snapshot protractor comes in handy: docker inspect --format "{{json .State.Health }}" [container_name] | jq docker cp [container_id]:/xxx/xxx/xxxLocalhost.png . docker exec -it bewertungsapp_webapp_1 bash # or sh for alpine node For me second one helped me the most (copy the snapshot from docker to my dev/host), because I was seeing a blank page
  5. docker-compose.yml: distribute static ip for 3 images

    version: "3" 
    # docker-compose version: 1.21.1 for version 3 
    
    services:
      server:
        build: server
        ports:
          - "4000:4000"
          - "8443:8443"
        links:
          - mongo
        depends_on:
          - mongo
        networks:
          app_net:
            ipv4_address: 192.17.1.3 # other address will also do, but on my dev 172.17.x.x is reserved for docker e.g.
        healthcheck:
          # test: ["CMD", "curl", "-k", "https://localhost:8443"]
          # test: ifconfig
          test: curl -k http://192.17.1.3:8443 # you may want to install curl first
          # test: curl http://localhost:8443/bundle.js -k -s | grep -C 3 "window.pushNotification"
          interval: 30s
          timeout: 10s
          retries: 3
    
      mongo:
        image: mongo
        ports:
          - "27017:27017"
        networks:
          app_net:
          # static different ip for mongo
            ipv4_address: 192.17.1.2
    
      # this is actually only protractor build for me        
      webapp:
        build: webapp
        restart: on-failure
        depends_on:
          - server
        links:
          - server
          networks:
          app_net:
            # another static different ip for webapp
              ipv4_address: 192.17.1.4
    
      networks:
        app_net:
          driver: bridge
          driver_opts:
            com.docker.network.enable_ipv6: "false"
          ipam:
            driver: default
            config:
            - subnet: 192.17.1.0/24
    
  6. protractor script for screenshot/snapshot

    import fs from 'fs';
    import path from "path";
    
    function writeScreenShot(data, filename) {
        console.info("writeScreenShot filename: ", filename);
        const stream = fs.createWriteStream(filename);
        stream.write(new Buffer(data, 'base64'));
        stream.end();
    }
    
    export function takeScreenshot(browser, timeStamp){
        const pathForScreenshot = path.resolve(__dirname, '../screenshots');
        console.info("takeScreenshot pathForScreenshot: ", pathForScreenshot);
        if (!fs.existsSync(pathForScreenshot)) {
            fs.mkdirSync(pathForScreenshot);
        }
    
        browser.takeScreenshot().then((png) => {
            writeScreenShot(png, path.resolve(pathForScreenshot, timeStamp));
        });
    }
    
    export const baseUrl = 'http://192.17.1.3:8443'; /// docker
    
  7. --allow-insecure-localhost was actually sufficient for localhost, but for arbitrary address ssl I am still searching for it ... :) Best Wishes

webnicer/protractor-headless, Protractor end to end testing for AngularJS - dockerised with headless real Chrome. To be perfectly honest - it is a real chrome running on xvfb. Please note that chrome57 is not available, as it does not work reliably with Ptoractor. There were intermittent test failures, usually around selecting elements by.​binding . Protractor end to end testing for AngularJS - dockerised with headless real Chrome. This image is meant as a drop-in replacement for Protractor, so you can use it virtually in the same way you would use Protractor installed directly on your machine. PhantomJS is discouraged by Protractor creators and for a good reason.

E2E Testing on Angular App with Protractor ( tips included), Protractor is an end-to-end test framework for Angular and AngularJS Protractor runs tests against your application running in a real browser, using ( You can use other instead Jasmine, but I'm not going to talk about those) . return this. own docker image for running protractor otherwise you can simply use an existing  Dear Sylvain, I am very happy to have found your Docker image because I have been trying to get my Angular2 e2e/Protractor tests to run in a Docker environment. With this image that works. However, my Angular unit/karma tests are not abl

Standalone Selenium Server - Protractor, The server forwards commands from your script to the driver and returns To run the Selenium Server on your local machine, use the standalone Selenium Server​. Protractor can test directly against Chrome and Firefox without using a WebDriver is created, but would also like Protractor to use the same browser, so you  Supervisor Process controll system used to manage Xvfb and Selenium background processes needed by Protractor; Running. In order to run tests from a CI system, execute the following: docker run --rm -v <test project location>:/project mrsheepuk/protractor The container will terminate automatically after the tests are completed.

Browser - Protractor, Protractor works with Selenium WebDriver, a browser automation framework. In your Protractor config file (see config.ts), all browser setup is done within the Protractor will run tests in parallel against each set of capabilities. Also, changing the window size during a test will not work in headless mode, but you can set it  This short video tutorial shows how to run Protractor with headless (real) Chrome on Docker. The Docker image is designed as a drop in replacement for Protractor installed directly on the host.

Comments
  • Hello bwarff! It's still happening.. BUT i found a weird behaviour, browser.pause() does not work inside docker so .. i wonder if the issue is about chrome->docker and not protractor->docker
  • You don't have the hand to resume the pause if it's done in docker. But you can display the elements on your page and log them. For instance, you can define a locator like $('html') and display what you have on the page at this moment like this : $('html').getAttribute('textContent').then(function(content) { console.log(content); }); You can display the dom with something else that getAttribute textContent but I don't remember what method to use for that. Also, if you don't refresh the page, is your test ok ?
  • The page refresh is done to properly load the correct api-url from the LocalStorage (I cut out the code, because it didn't think it would matter). I'm trying to expose the dom into console, but i can't :')
  • browser.executeScript("return arguments[0].innerHTML;", $('html')).then(function (content) { console.log(content); }); They changed it with latest protractor version. You have to use executeScript to get the dom instead of getInnerHtml/getOuterHtml. Also makes me think that you could have different versions of protractor inside docker and on your machine. You're probably using protractor-headless with the version 4.0.14 but not on your machine (5.1.x).
  • What I wrote on the last comment is working to display the current dom. Before you could just do $('element').getInnertHtml() and now you have to use executeScript to do the same. You an gather more information about the problem with that.