docker returns 中的 Protractor 运行 元素不存在但在本地主机中存在

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

我一直在尝试 运行 在 Docker 中进行一些量角器测试,但我发现了一个我自己无法解决的问题。 Protractor 表示该元素不存在于 Docker 的网页中,但它存在于 localhost 中。此外,网页的 CURL 公开了 HTML 元素(如您所知,不是 Angular 组件内的 HTML )但仍然找不到该元素。

首先,测试在本地主机上正常工作:

/*********** 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
});

还有两个测试

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('');
});

配置文件如

    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
      }
    }));
  }
}

Docker 链接到暴露在端口 80 上的 docker-nginx 服务器,因此我们可以检查项目是否正确 运行ning(它是) . 正如我 运行 docker 命令:

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

我可以使用 CURL 访问网页,它会在浏览器中显示网页 HTML(实际上与本地主机 returns 中的 curl 结果相同)但不知何故量角器未在 URL 元素内找到(我已经尝试通过多个 jasmine 函数获取该元素,但仍然发生同样的问题)。

本地主机 PROTRACTOR_RESULT

DOCKER PROTRACTOR_RESULT

谢谢!

编辑1:

在 docker 中使用这个会产生错误,但在 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('');
});

错误(由于我是新手,我不能粘贴超过 2 张图片,所以我将代码粘贴在这里)

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

EDIT2:

使用

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

我已经打印了显示组件的 html...但不是内部 html(它放置了正确的 ID 和实际的输入元素)

    <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>

我可以 运行 一个通过搜索元素 by.model 的测试,但它没有引用内部输入,因为它应该使用 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('');
});

问题依旧,无法获取 angular 组件的内部 html

编辑3:

我已经测试了这个页面 https://docs.angularjs.org/examples/example-heroComponentSimple/index.html 并暴露了 HTML,它似乎可以读取组件的内部 html。

HTML 暴露:

 <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>

测试:

        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);
    });

你少了一个“;”在 browser.wait 内 return 的末尾。 另外,尝试

return displaySurnameInput.isPresent();

5 秒是否足以加载页面?

您还可以通过禁用报告库来禁用获取有关问题的更多详细信息。或者它可能有显示更多详细信息的选项。

如果使用 browser.ignoreSynchronisation = true;在 browser.wait 之前和等待之后为 false,它会改变什么吗?

Docker 试图连接 http://ify-nginx/api/ 上不存在的 API... 该调用期望在注册表单上生成必填字段列表。返回 null 时,不会生成字段,本身,量角器什么也找不到。

正如您在上面看到的,这里发生了一些奇怪的事情 (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>

我们在 api 代码中得到一个 if 检查 url 是 'localhost' 还是服务器 ip,而不是 'ify-nginx'。当检测到 ify-nginx 时,api 域被重定向到它,它不会加载内容。

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.

有点误导,或者是因为我的英语不好。 我也有一个类似的错误。所以我试着解释我是如何解决我的问题的。

  1. 进行头脑风暴:可能是什么原因?有时它会超过 1。确保你一步一步地找出什么不起作用,什么是 100% 起作用。您尝试使用 browser.wait 调试量角器应用程序,这是正确的方向,但是 it will not work in Node.js 8+, you may want to try out protractor snapshot
  2. 写下这些原因,对我来说有:https(我有一个自我分配的证书,可以在访问像 https://localhost:8443 这样的网站时手动验证),localhost 可能适用于开发,例如在 mac 上,但在 docker 容器中可能无法工作,因为每个容器都有不同的 ip(我更喜欢 docker-compose,因为它更干净?)并且您可以将静态 ip 分配给 docker 个容器(我也不知道)
  3. 从 http 和 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. 使用一些docker命令进行调试,这里快照量角器就派上用场了: 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 对我来说,第二个对我帮助最大(将快照从 docker 复制到我的 dev/host),因为我看到的是空白页
  5. docker-compose.yml: 为3张图片分配静态ip

    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. 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 实际上对于 localhost 来说已经足够了,但是对于任意地址 ssl 我还在寻找它......:) 祝福