Испытания Dockerized Angular E2E проходят на локальной машине, но время ожидания в Travis CI - PullRequest
0 голосов
/ 03 марта 2019

Я попытался докернизировать свои угловые тесты e2e.Просто я создал файл docker-compose.test.yml:

version: "3.4"

services:
  # set up angular app
  angular:
    build: 
      context: ./frontend
      dockerfile: sample.Dockerfile
      target: test
    image: angular:test
    container_name: angular
    ports: 
      - "4200:4200"
    depends_on: 
      - nodejs 
    command: npm run e2e -- --protractor-config=e2e/protractor-docker.conf.js --host 0.0.0.0

  nodejs:
    build:
      context: ./backend
      dockerfile: Dockerfile
      target: development
    image: nodejs:dev
    container_name: nodejs
    ports: 
      - "3000:3000"
    networks:
      - backend
    depends_on: 
      - db
    restart: always
  # the mongo database
  db:
    image: mongo
    container_name: db
    networks: 
      - backend
    ports: 
      - "27017:27017"
networks: 
  backend: 
    driver: bridge

Для настройки транспортира я следовал учебному пособию, найденному по этой ссылке:

Угловое учебное пособие для ТрэвисаCI

Я должен был внести некоторые коррективы, например:

let config = require('./protractor.conf').config;

// Tell protrator where the chrome driver is
// https://gitlab.com/dasch8/angular-ci/
// https://hub.docker.com/r/weboaks/node-karma-protractor-chrome/
config.chromeDriver = "/usr/bin/chromedriver";

config.allScriptsTimeout = 60000;

config.getPageTimeout = 60000;

config.jasmineNodeOpts.defaultTimeoutInterval = 60000;

// have it connect to the angular app
// config.baseUrl = "http://angular:4200";

config.capabilities = {
  browserName: 'chrome',
  chromeOptions: {
    args: ['--headless', '--no-sandbox', '--disable-gpu']
  },

};


exports.config = config;

Используя конфигурацию, тесты e2e прошли успешно на моей локальной машине.Однако, когда я запускаю это в скрипте для .travis.yml:

before_script: 
    - docker-compose -f docker-compose.test.yml build
  script:
    - docker-compose -f docker-compose.test.yml run --name angular -p 4200:4200 angular

Travis CI не удается.Вывод:

 - Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
  - Failed: Timed out waiting for asynchronous Angular tasks to finish after 60 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular

Это очень странно, потому что я написал:

import { AppPage } from './app.po';

// Test bed
describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display navbar with title',  () => {
    page.navigateTo().then(() => {
      console.log('Successfully connected to the page');
    });

    expect(page.getHeaderText()).toEqual('hobbies');

  });
});

И в журналах Travis CI журнал выводит:

Успешноподключен к странице.Остальные журналы находятся здесь:

Мои журналы Travis CI

Я не уверен, что делаю неправильно.Это так странно, тест проходит на моей локальной машине.Я попытался решить эту проблему по-другому, используя изображения selenium / hub и selenium / node-chrome, и заставил транспортир подключиться к этому серверу selenium.Это та же история.Я заставил его работать на моей локальной машине, но он не работает в TravisCI.Я спрошу о проблеме селена в другом вопросе.

Ответы [ 3 ]

0 голосов
/ 05 марта 2019

Я последовал за ответом К. Пека.Я проверил на своей локальной машине, и это сработало;однако, это все еще не работало в TravisCI, как показано в моих журналах:

TravisCI logs .

Я даже установил тайм-аут ожидания на 11 секунд, и тесты все равно не прошли.Затем я увеличил allScriptsTimeout в protractor-docker.conf.js до 180000. После этого испытания прошли:

Мой журнал Travis CI об успешном угловом тесте E2E

Однако тестирование заняло 2 минуты и 10 секунд.Это расстраивает, потому что я просто проверял, появляется ли заголовок на панели навигации.Боюсь, что если я проверю что-то, например, форму и нажатие кнопок, Travis CI может даже занять больше времени.

0 голосов
/ 07 марта 2019

наконец-то решил это !!!Итак, я нашел эту ссылку и черпал вдохновение: Chrome недоступен в Docker Network

К счастью, конфигурации, которые использовал индивидуум, были почти одинаковыми, но интересная часть заключалась в том, чтоотдельные пользователи выполняли обратное проксирование к своему веб-приложению.

Я сделал то же самое:

#default.conf for proxy service

upstream docker-web {

    #docker angular container
    server angular:4200; 
}

upstream docker-node {

    #docker nodejs container
    server nodejs:3000;
}

server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://docker-web;
        #proxy_redirect off; 
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
        add_header         X-Upstream $upstream_addr;
    }

    location /api {
        proxy_pass http://docker-node;
        proxy_redirect off; 
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
        add_header         X-Upstream $upstream_addr;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

И для моего углового веб-приложения, размещенного на nginx:

server {
    listen       4200;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }



    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

я создалотдельный контейнер для транспортира, используя мое угловое изображение, которое я предоставлю:

###################
##    builder    ##
###################

FROM  node:10-alpine AS builder
RUN  mkdir -p /usr/src/frontend
WORKDIR /usr/src/frontend
COPY package.json /usr/src/frontend
RUN npm cache clean --force \
  && npm install
COPY . /usr/src/frontend
RUN npm run build -- --prod


##################
##  production  ##
##################

FROM nginx:alpine AS production
COPY --from=builder /usr/src/frontend/dist/frontend /usr/share/nginx/html
COPY --from=builder /usr/src/frontend/nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

#################
## development ##
#################

# because development uses the same stuff from builder image
FROM builder AS development
EXPOSE 4200
CMD ["npm", "start"]


##################
##     test     ##
##################


# because test uses the same stuff from builder image
FROM builder AS test
RUN apk update && \
    apk upgrade && \
    apk add --no-cache chromium nss chromium-chromedriver
EXPOSE 9876
ENV CHROME_BIN /usr/bin/chromium-browser
# just needed the chromedriver!!!
# https://github.com/angular/angular-cli/issues/5019
# https://gitlab.com/dasch8/angular-ci/blob/master/README.md
CMD [ "npm", "run", "test", "--", "--no-watch", "--no-progress", "--browsers=ChromeHeadlessCI"]


FROM production

Затем я создал службу сетки селена и службу узла хрома.Документация по Docker Selenium находится здесь:

Docker Selenium

Моя ошибка заключалась в том, что имена хостов (имена контейнеров / служб в файле docker-compose) не разрешалисьправильно, потому что они не были в той же сети.Поскольку транспортир подключается к селену, а селен обрабатывает тесты E2E, browser.get('http://proxy') не смог найти угловое приложение, потому что Selenium не был в той же сети, что и контейнер прокси.Затем я удалил все сети, которые использовал в своем файле docker-compose, и создал новый файл docker-compose, который включает в себя мой сервис сетки селена (называемый selenium-hub), сервис selenium / node-chrome (называемый chrome_node), стек MEAN (угловой, nodejs, db) и сервис транспортира (путем нацеливания на тестовую сборку из файла Docker).

Мой файл docker-compose.selenium.yml:

version: '3.4'

services:
  selenium-hub:
    image: selenium/hub:3.141.59
    container_name: selenium-hub
    environment: 
      - GRID_TIMEOUT=10000
    ports: 
      - "4444:4444"
    privileged: true
    #tty: true

  chrome_node:
    image: selenium/node-chrome:3.141.59
    volumes: 
      - /dev/shm:/dev/shm
    container_name: chrome_node
    environment:
      - HUB_PORT_4444_TCP_ADDR=selenium-hub
      - HUB_PORT_4444_TCP_PORT=4444
    ports:
      - "5555:5555"
    privileged: true
    depends_on:
      - selenium-hub
    #tty: true
  proxy: 
    build: 
      context: ./proxy
      dockerfile: Dockerfile
    image: proxy
    container_name: proxy
    # HOST:CONTAINER
    ports: 
      - "80:80"
    #tty: true
    depends_on: 
      - angular
  angular:
    build:
      context: ./frontend
      dockerfile: sample.Dockerfile
      target: production
    image: angular:prod
    container_name: angular
    ports:
      - "4200:4200"
    privileged: true 
    depends_on: 
        - nodejs
    #tty: true
  nodejs:
    build:
      context: ./backend
      dockerfile: Dockerfile
      target: development
    image: nodejs:dev
    container_name: nodejs
    ports: 
      - "3000:3000"
    depends_on: 
      - db
    restart: always
    #tty: true
  # the mongo database
  db:
    image: mongo
    container_name: db
    ports: 
      - "27017:27017"
    #tty: true
  protractor:
    build:
      context: ./frontend
      dockerfile: sample.Dockerfile
      target: test
    image: angular:test
    container_name: protractor
    ports: 
      - "9876:9876"
    privileged: true
    depends_on:
      - selenium-hub
      - chrome_node
    #tty: true --> not neccesary
    command: npm run e2e -- --protractor-config=e2e/protractor-ci.conf.js --webdriver-update=false --dev-server-target= 

А вот мой новый конфигурационный файл транспортира:

let config = require('./protractor.conf').config;


// do not use the chromeDriver. If you do, it will not connect to Selenium service
config.directConnect = false;


// have it connect to the angular app
config.baseUrl = "http://proxy";

// Protractor getting the page-timeout
config.getPageTimeout = 60000;

// Selenium Webdriver timeout
config.allScriptsTimeout = 60000;

// Jasmine test script timeout
config.jasmineNodeOpts.defaultTimeoutInterval = 60000;

config.seleniumAddress = 'http://selenium-hub:4444/wd/hub'

config.capabilities = {
  browserName: 'chrome',
  chromeOptions: {
    args: ['--headless', '--disable-gpu', '--no-sandbox'],
  },
};

Флаг --dev-server-target= Давайте рассмотрим угловойне запускать ng serve (потому что мы запускаем наше угловое приложение в nginx).После этого мои тесты прошли !!!И я установил таймауты до 60000, и тесты прошли в течение 3 секунд, большое улучшение !!!!:)

Сценарий, который я использовал в .travis.yml:

before_script: 
        - docker-compose -f docker-compose.selenium.yml build
script:
        - docker-compose -f docker-compose.selenium.yml up -d chrome_node proxy
        - docker container ls
        - docker-compose -f docker-compose.selenium.yml up protractor

А для сети команда docker-compose up сама это обрабатывает, а DNS-распознаватель Docker разрешает имена хостов(наши имена контейнеров / сервисов в файле docker-compose).Подробнее о Docker Compose Network можно найти в документации Docker: Docker Compose и Networks

Вот журналы сборки:

Travis CI logs

Надеюсь, это поможет кому-нибудь в будущем:)

0 голосов
/ 03 марта 2019

Итак, влияет ли добавление ожидания следующим образом?

import { AppPage } from './app.po';

// Test bed
describe('workspace-project App', () => {
  let page: AppPage;

  beforeEach(() => {
    page = new AppPage();
  });

  it('should display navbar with title',  () => {
    page.navigateTo().then(() => {
      console.log('Successfully connected to the page');
    });

browser.ignoreSynchronization = true

driver.wait(function () {
return driver.isElementPresent(page.getHeaderText('hobbies'));
}, timeout);

    expect(page.getHeaderText()).toEqual('hobbies');

    browser.ignoreSynchronization = false;

  });
});
...