Search code examples
fluttercontinuous-integrationgitlab-ciflutter-webflutter-test

How do I run Flutter integration tests on Gitlab CI pipeline?


I'm working on a Flutter project and need to run integration tests on a Gitlab CI pipeline.

The tests work fine locally, launching chromedriver -port=4444 and then flutter drive --driver=integration_test/test_driver/integration_test.dart --target=integration_test/integration/app_test.dart.

However, I cannot get them to run in CI. My yaml file looks like this :

...

test_ui_integration:
  needs: 
    - build_deploy_user_service
    - populate_db
  tags:
    - docker
  stage: test_ui_integration
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: always
  before_script:
    - chromedriver --port=4444 & # launching the chromedriver
    - sleep 10
  script:
    - cd $CI_PROJECT_DIR/ui
    - npm ${NODE_INSTALL_OPTIONS:-i}
    - npm run build
    - flutter drive --driver=integration_test/test_driver/integration_test.dart --target=integration_test/integration/app_test.dart -d chrome --web-run-headless --headless
    # - flutter drive --driver=integration_test/test_driver/integration_test.dart --target=integration_test/integration/app_test.dart  -d web-server --headless
    # - flutter drive --driver=integration_test/test_driver/integration_test.dart --target=integration_test/integration/app_test.dart   -d web-server --release --web-run-headless --headless
  timeout: 40 minutes

(note that the pipeline is using a docker img with chromedriver and Flutter installed)

I have tried all kinds of different combination for the flags, as seen here too. However, none of it seems to work: Even locally, I cannot get the test to run headless-ly (without a browser).

The CI step usually gets stuck on something like this, until it times out :

=== running with flags -d web-server --web-run-headless --headless ===

Waiting for connection from debug service on Web Server...         37.1s
integration_test/integration/app_test.dart is being served at http://localhost:44415
The web-server device requires the Dart Debug Chrome extension for debugging. Consider using the Chrome or Edge devices for an improved development workflow.
...
=== running with flags -d chrome --web-run-headless --headless ===

Waiting for connection from debug service on Chrome...             37.5s
[CHROME]:[1391:1391:0609/090100.591700:ERROR:zygote_host_impl_linux.cc(90)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
Failed to launch browser after 3 tries. Command used to launch it: google-chrome --user-data-dir=/tmp/flutter_tools.RDVJEL/flutter_tools_chrome_device.KRPHNF --remote-debugging-port=41647 --disable-background-timer-throttling --disable-extensions --disable-popup-blocking --bwsi --no-first-run --no-default-browser-check --disable-default-apps --disable-translate http://localhost:35691

I've also noticed that you can run integration tests locally with flutter run path/to/my/test/dart, which is something that the official docs never mention. Is there a difference between the two?

Should I be trying to run the CI tests with a mobile emulator instead?

Any help much appreciated!

EDIT: As requested by @MarkosTh09, here is the dockerfile and relevant CI workflow :

FROM fedora:35

# Add basic tools
RUN dnf -y install git make gcc gcc-c++ wget unzip zip jq diffutils \
 && dnf clean all

# Requirement of openapi generator
RUN dnf install -y java \
 && dnf clean all

# Install python
RUN dnf install -y python3 \
 && dnf clean all

# Install chromedriver
RUN wget https://chromedriver.storage.googleapis.com/99.0.4844.35/chromedriver_linux64.zip \
    && unzip chromedriver_linux64.zip \
    && cp chromedriver /usr/bin/chromedriver \
    && chown root /usr/bin/chromedriver \
    && chmod +x /usr/bin/chromedriver \
    && chmod 755 /usr/bin/chromedriver

# Install chrome
RUN wget https://dl.google.com/linux/chrome/rpm/stable/x86_64/google-chrome-stable-99.0.4844.84-1.x86_64.rpm \
    && yum install ./google-chrome-*.rpm -y

# Install AWS CLI V2
RUN curl -s https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip > awscliv2.zip \
 && unzip awscliv2.zip \
 && ./aws/install \
 && rm -rf aws awscliv2.zip

# Install and configure nvm for npm
# nvm environment variables
ENV NVM_DIR /opt/nvm
RUN mkdir -p $NVM_DIR
ENV NODE_VERSION 16.14.0

# install nvm
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash

# install node and npm
RUN source $NVM_DIR/nvm.sh \
 && nvm install $NODE_VERSION \
 && nvm alias default $NODE_VERSION \
 && nvm use default

# add node and npm to path so the commands are available
ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules
ENV NVM_BIN $NVM_DIR/versions/node/v$NODE_VERSION/bin
ENV NVM_INC $NVM_DIR/versions/node/v$NODE_VERSION/include/node
ENV PATH $NVM_BIN:$PATH

# Install serverless
RUN npm install -g serverless@3.2.0

# Install Flutter
RUN curl -s https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.0.0-stable.tar.xz > flutter.tar.xz \
 && tar xf flutter.tar.xz -C /opt/ \
 && rm flutter.tar.xz
ENV PATH $PATH:/opt/flutter/bin

RUN git config --global --add safe.directory /opt/flutter

CMD [ "/bin/bash" ]
ENTRYPOINT [ "/bin/bash", "-c" ]

include:
  - '/ci/ci-build-deploy.yml'
  - '/ci/ci-tests.yml'
  - '/ci/ci-undeploy.yml'

image: registry.gitlab.com/project/project/build/project-build-env:4

variables:
  PROJECT_API_URL: https://gitlab.com/api/v4/projects/12345678
  NODE_INSTALL_OPTIONS: ci --cache $CI_PROJECT_DIR/.npm --prefer-offline

cache:
  key: PROJECT_NODE_CACHE
  paths:
    - .npm/

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      variables:
        AWS_STAGE: "ci${CI_PIPELINE_ID}"
        STAGE_TYPE: "ci"
    - if: $STAGE_TYPE == "staging" && $AWS_STAGE == "staging"
      variables:
        HOSTED_ZONE_NAME: "staging.project.io"
        FRONT_DOMAIN: "staging.project.io"
    - if: $STAGE_TYPE == "prod" && $AWS_STAGE == "prod"
      variables:
        HOSTED_ZONE_NAME: "project.io"
        FRONT_DOMAIN: "project.io"
    - when: always

stages:
  - build_deploy_user_service
  - build_deploy_shop_service
  - build_deploy_brand_service
  - build_deploy_product_service
  - build_deploy_web_ui
  - build_deploy_reverseproxy
  - test_shop_ws
  - test_brand_ws
  - test_product_ws
  - delete_test_objects
  - populate_db
  - test_ui
  - populate_cognito_test_user
  - test_ui_integration
  - triggerundeploy
  - undeploy

Solution

  • I'm not working anymore on that particular Flutter project, but I've been told the e2e testing works with a setup similar to this:

    Dockerfile

    FROM centos:8
    
    # Failed to download metadata for repo ‘AppStream’ [CentOS] : https://techglimpse.com/failed-metadata-repo-appstream-centos-8/
    RUN cd /etc/yum.repos.d/ && sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
    
    # Add basic tools
    RUN dnf install -y git make gcc gcc-c++ wget unzip zip jq diffutils zlib.i686 ncurses-libs.i686 bzip2-libs.i686 curl which mesa-libGLU patch \
        && dnf clean all
    
    # ............
    
    # Install Flutter
    RUN wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.13.9-stable.tar.xz \
        && tar xf flutter_linux_3.13.9-stable.tar.xz && rm flutter_linux_3.13.9-stable.tar.xz
    
    ENV PATH "$PATH:/flutter/bin"
    
    # Install firebase CLI
    RUN npm install -g firebase-tools
    
    
    # Install Android SDK
    ENV VERSION_TOOLS "9477386"
    ENV ANDROID_SDK_ROOT "/sdk"
    # Keep alias for compatibility
    ENV ANDROID_HOME "${ANDROID_SDK_ROOT}"
    ENV PATH "$PATH:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools"
    
    RUN curl -s https://dl.google.com/android/repository/commandlinetools-linux-${VERSION_TOOLS}_latest.zip > /cmdline-tools.zip \
        && mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools \
        && unzip /cmdline-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools \
        && mv ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest \
        && chmod -R 777 $ANDROID_SDK_ROOT \
        && rm -v /cmdline-tools.zip
    
    RUN mkdir -p $ANDROID_SDK_ROOT/licenses/ \
        && echo "8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > $ANDROID_SDK_ROOT/licenses/android-sdk-license \
        && echo "84831b9409646a918e30573bab4c9c91346d8abd\n504667f4c0de7af1a06de9f4b1727b84351f2910" > $ANDROID_SDK_ROOT/licenses/android-sdk-preview-license \
        && yes | sdkmanager --licenses >/dev/null \
        && chmod -R 777 $ANDROID_SDK_ROOT/licenses/
    
    RUN mkdir -p /root/.android \
        && touch /root/.android/repositories.cfg \
        && sdkmanager --update
    
    ADD docker-env/build/packages.txt /sdk
    RUN sdkmanager --package_file=/sdk/packages.txt && chmod -R 777 $ANDROID_SDK_ROOT
    RUN sdkmanager "system-images;android-33;google_apis;x86_64"
    RUN avdmanager create avd --force --name Pixel5 --abi google_apis/x86_64 --package "system-images;android-33;google_apis;x86_64" --device "pixel_5"
    
    # Configure android emulator
    RUN sed -i 's/disk.dataPartition.size=800M/disk.dataPartition.size=2000M/g' /root/.android/avd/Pixel5.avd/config.ini
    RUN sed -i 's/hw.keyboard=no/hw.keyboard=yes/g' /root/.android/avd/Pixel5.avd/config.ini
    
    CMD [ "/bin/bash" ]
    ENTRYPOINT [ "/bin/bash", "-c" ]
    

    .yml CI file

    Apparently we don't need to use flutter drive anymore on the CI step:

    test_ui:
      tags:
        - docker
      stage: test_ui
      needs:
        - ...
        - ...
      rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
          when: always
      before_script:
        - !reference [.aws-prep, before_script]
      script:
        - git fetch origin
        - export PUB_CACHE=$CI_PROJECT_DIR/.pub-cache
        - export PATH="$PATH":"$PUB_CACHE/bin"
        - echo "to see android emulator test in live, go to http://RUNNER_IP:6080"
        - cd $CI_PROJECT_DIR/mobile/android
        - bundle install
        - bundle exec fastlane android bump_patch
        - cd $CI_PROJECT_DIR/mobile
        - flutter pub get
        - flutter test
        - adb connect <docker_host_ip>:5555
        - flutter test integration_test/*.dart --dart-define=AWS_STAGE=${AWS_STAGE} --dart-define=AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-${GITLAB_TEST_AWS_ACCESS_KEY_ID}} --dart-define=AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-${GITLAB_TEST_AWS_SECRET_ACCESS_KEY}}
      timeout: 60 minute
      retry: 1