├── .github └── workflows │ └── build.yml ├── Dockerfile ├── LICENSE ├── README.md ├── display-chromium ├── hooks └── build ├── xvfb-chromium └── xvfb-chromium-webgl /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: 'build images' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '7 5 * * *' 7 | push: 8 | 9 | jobs: 10 | docker: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Prepare 17 | id: prep 18 | run: | 19 | DOCKER_IMAGE=trion/ng-cli-karma 20 | VERSION=latest 21 | SHORTREF=${GITHUB_SHA::8} 22 | 23 | #use branch as version 24 | if [[ $GITHUB_REF == refs/heads/* ]]; then 25 | VERSION=${GITHUB_REF#refs/heads/} 26 | [ $VERSION == "master" ] && VERSION=latest 27 | fi 28 | 29 | #use tag as version 30 | if [[ $GITHUB_REF == refs/tags/* ]]; then 31 | VERSION=${GITHUB_REF#refs/tags/} 32 | fi 33 | 34 | #use version as image tag 35 | TAGS="${DOCKER_IMAGE}:${VERSION}" 36 | 37 | # If version is a number also tag it 'latest'. 38 | if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 39 | TAGS="$TAGS,${DOCKER_IMAGE}:latest" 40 | fi 41 | 42 | echo ::set-output name=tags::${TAGS} 43 | echo ::set-output name=docker_image::${DOCKER_IMAGE} 44 | 45 | - name: Set up QEMU 46 | uses: docker/setup-qemu-action@master 47 | with: 48 | platforms: all 49 | 50 | - name: Set up Docker Buildx 51 | id: buildx 52 | uses: docker/setup-buildx-action@master 53 | 54 | - name: Cache Docker layers 55 | uses: actions/cache@v3 56 | with: 57 | path: /tmp/.buildx-cache 58 | key: ${{ runner.os }}-buildx-${{ github.sha }} 59 | restore-keys: | 60 | ${{ runner.os }}-buildx- 61 | 62 | - name: Login to DockerHub 63 | if: github.event_name != 'pull_request' 64 | uses: docker/login-action@v2 65 | with: 66 | username: ${{ secrets.DOCKER_USERNAME }} 67 | password: ${{ secrets.DOCKER_PASSWORD }} 68 | 69 | - name: Build 70 | uses: docker/build-push-action@v3 71 | with: 72 | builder: ${{ steps.buildx.outputs.name }} 73 | context: . 74 | file: ./Dockerfile 75 | #google chrome is just amd64, uses chromium from newer debian as replacement 76 | #platforms: linux/amd64,linux/arm64,linux/arm/v7 77 | platforms: linux/amd64,linux/arm64 78 | push: true 79 | tags: ${{ steps.prep.outputs.tags }} 80 | cache-from: type=local,src=/tmp/.buildx-cache 81 | cache-to: type=local,dest=/tmp/.buildx-cache-new 82 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM trion/ng-cli:latest 2 | 3 | ARG CHROME_VERSION= USER_ID=1000 4 | 5 | LABEL chrome=$CHROME_VERSION ng-cli='20.0.1' 6 | 7 | USER root 8 | 9 | COPY xvfb-chromium /usr/bin/xvfb-chromium 10 | COPY xvfb-chromium-webgl /usr/bin/xvfb-chromium-webgl 11 | COPY display-chromium /usr/bin/display-chromium 12 | 13 | RUN apt-get update \ 14 | && apt-get install -y \ 15 | xvfb \ 16 | libxss1 \ 17 | libosmesa6 \ 18 | libgconf-2-4 \ 19 | wget \ 20 | apt-transport-https \ 21 | && MACH=$(uname -m) \ 22 | && [ $MACH = "x86_64" ] && ( \ 23 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ 24 | && (dpkg -i google-chrome-stable_current_amd64.deb; apt-get -fy install; rm google-chrome-stable_current_amd64.deb; apt-get clean; rm -rf /var/lib/apt/lists/* ) \ 25 | && mv /usr/bin/google-chrome /usr/bin/google-chrome.real \ 26 | && mv /opt/google/chrome/chrome /opt/google/chrome/google-chrome.real \ 27 | && ln -s /usr/lib/x86_64-linux-gnu/libOSMesa.so.6 /opt/google/chrome/libosmesa.so \ 28 | ) || true \ 29 | && [ $MACH != "x86_64" ] && ( \ 30 | echo "deb http://deb.debian.org/debian buster main" >> /etc/apt/sources.list.d/debian.list \ 31 | && echo "deb http://deb.debian.org/debian buster-updates main" >> /etc/apt/sources.list.d/debian.list \ 32 | && echo 'Package: chromium*' >> /etc/apt/preferences.d/chromium.pref \ 33 | && echo 'Pin: origin "ftp.debian.org"' >> /etc/apt/preferences.d/chromium.pref \ 34 | && echo 'Pin-Priority: 700' >> /etc/apt/preferences.d/chromium.pref \ 35 | && apt-get update; apt-get -fy install chromium; apt-get clean; rm -rf /var/lib/apt/lists/* \ 36 | && mv /usr/bin/chromium /usr/bin/google-chrome.real \ 37 | ) || true \ 38 | && rm -f /etc/alternatives/google-chrome \ 39 | && ln -s /opt/google/chrome/google-chrome.real /etc/alternatives/google-chrome \ 40 | && ln -s /usr/bin/xvfb-chromium /usr/bin/google-chrome \ 41 | && ln -s /usr/bin/xvfb-chromium /usr/bin/chromium-browser 42 | 43 | 44 | # This may be desired, but breaks past behaviour 45 | # https://github.com/trion-development/docker-ng-cli-karma/issues/23 46 | # USER $USER_ID 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-ng-cli-karma 2 | 3 | Docker container to run Karma tests with Angular CLI inside Docker using Xvfb 4 | 5 | This image is sponsored and maintained by https://www.trion.de/ - trion offers commercial training and consulting for all things Docker and Angular. 6 | 7 | ## Example usage 8 | ``` 9 | docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng new MyDemo 10 | cd MyDemo 11 | docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng serve --host 0.0.0.0 12 | docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng serve --host :: #ipv6 13 | docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng build 14 | ``` 15 | 16 | If you want to clone additional git repositories, f.e. from package.json, and you run with a different user than uid 1000 you need to mount the passwd since git requires to resolve the uid. 17 | 18 | ``` 19 | docker run -u $(id -u) --rm -p 4200:4200 -v /etc/passwd:/etc/passwd -v "$PWD":/app trion/ng-cli npm install 20 | ``` 21 | 22 | 23 | ## Running karma unit tests in docker container 24 | ``` 25 | docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng test 26 | ``` 27 | 28 | ## Running karma unit tests in docker container, exiting after test run 29 | ``` 30 | docker run -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng test --watch false 31 | ``` 32 | 33 | ## Using WebGL 34 | WebGL is supported using Mesa software rendering. Since this is much slower it is not enabled by default. 35 | 36 | In order to use the WebGL configuration, you need to use `xvfb-chromium-webgl` instead of using the regular chromium wrapper, called as `chrome` or `chromium`. 37 | 38 | That wrapper has the additional switches `--enable-webgl --ignore-gpu-blacklist` enabled, which are required for software WebGL rendering. 39 | 40 | This can be configured in the karma configuration, f.e. 41 | 42 | ``` 43 | browsers: ['/usr/bin/xvfb-chromium-webgl'], 44 | ``` 45 | 46 | or you can specify the chrome excutable using the `CHROME_BIN` environment variable like 47 | 48 | ``` 49 | docker run -e CHROME_BIN=/usr/bin/xvfb-chromium-webgl -u $(id -u) --rm -v "$PWD":/app trion/ng-cli-karma ng test --watch false 50 | ``` 51 | 52 | ## Interactive debugging 53 | Instead of running on the hidden Xvfb, you can also run the provided Chrome on a real display. 54 | To do so you need to export the display, bind the /tmp sockets, and select the provided `display-chromium` 55 | startup wrapper via the `CHROME_BIN` environment variable: 56 | 57 | ``` 58 | docker run -e DISPLAY=:0 -e CHROME_BIN=/usr/bin/display-chromium -u $(id -u) --rm -v /tmp:/tmp -v "$PWD":/app trion/ng-cli-karma ng test 59 | ``` 60 | 61 | If you forget to expose the /tmp/.X* socket you'll get an error message like: 62 | ``` 63 | ERROR:nacl_helper_linux.cc(310)] NaCl helper process running without a sandbox! 64 | ``` 65 | 66 | ## What about *-headless browsers 67 | Mozilla Firefox and Google Chrome are in the process to provide headless browsers capable of executing integration tests. 68 | 69 | Currently WebGL needs the mesa software renderer for Chrome, but it will change to the swift renderer, see https://bugs.chromium.org/p/chromium/issues/detail?id=617551 70 | 71 | Mozilla is still working on headless support in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1338004 72 | 73 | ## What if tests are not running (reliably) 74 | Run the tests in interactive debugging mode (see above) and check the browser console. 75 | 76 | If there are errors like `Failed to load resource: net::ERR_INSUFFICIENT_RESOURCES` or `An error was thrown in afterAll Error: Can't find ./some-file.ts] (required by other-file.ts) at require` it may be that the browser is running out of shared memory. Try to either increase the shared memory with the docker parameter `--shm-size 1G` or disable shared memory usage by specifying the flag `--disable-dev-shm-usage` for Chromium/Chrome. 77 | 78 | -------------------------------------------------------------------------------- /display-chromium: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | google-chrome.real --disable-dev-shm-usage --no-sandbox --no-first-run $@ 4 | 5 | -------------------------------------------------------------------------------- /hooks/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # $IMAGE_NAME var is injected into the build so the tag is correct. 3 | 4 | CHROME_VERSION=$(curl -sSL 'http://omahaproxy.appspot.com/all?csv=1' | grep linux,stable | cut -d ',' -f 3) 5 | echo "Chrome: $CHROME_VERSION" 6 | 7 | docker build \ 8 | --build-arg CHROME_VERSION=$CHROME_VERSION \ 9 | -t $IMAGE_NAME . 10 | -------------------------------------------------------------------------------- /xvfb-chromium: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find_free_servernum() { 4 | i=0 5 | while [ -f /tmp/.X$i-lock ]; do 6 | i=$(($i + 1)) 7 | done 8 | echo $i 9 | } 10 | 11 | export DISPLAY=":$(find_free_servernum)" 12 | Xvfb "$DISPLAY" -ac -screen 0 "${XVFB_WHD:-1280x720x16}" -nolisten tcp +render & 13 | xvfb_pid=$! 14 | 15 | echo "(wrapper:) launching with: $@" 16 | 17 | function cleanup { 18 | kill -TERM $xvfb_pid > /dev/null 2>&1 19 | } 20 | 21 | trap cleanup EXIT 22 | 23 | google-chrome.real --disable-dev-shm-usage --no-sandbox --disable-gpu --no-first-run $@ 24 | -------------------------------------------------------------------------------- /xvfb-chromium-webgl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find_free_servernum() { 4 | i=0 5 | while [ -f /tmp/.X$i-lock ]; do 6 | i=$(($i + 1)) 7 | done 8 | echo $i 9 | } 10 | 11 | export DISPLAY=":$(find_free_servernum)" 12 | Xvfb "$DISPLAY" -ac -screen 0 "${XVFB_WHD:-1280x800x16}" -nolisten tcp +render & 13 | xvfb_pid=$! 14 | 15 | function cleanup { 16 | kill -TERM $xvfb_pid > /dev/null 2>&1 17 | } 18 | 19 | trap cleanup EXIT 20 | 21 | google-chrome.real --no-sandbox --no-first-run --use-gl=osmesa --enable-webgl --ignore-gpu-blacklist --window-size=1024,768 $@ 22 | --------------------------------------------------------------------------------