Devops CICD run ReactJS application while testing with jest + puppeteer Scenario
I'm working on getting my end-to-end tests to work in a GitLab pipeline. Currently all the tests run locally but I'm having an issue getting them to run using GitLab's continuous integration feature.
When running the tests locally puppeteer will use a headless version of chrome for end-to-end tests but the ReactJS' CRA server has to be running for this to work. To get the CRA server running locally I use npm start in one terminal and once it is fully running I can run npm test in a different terminal. During testing Puppeteer uses headless Chromium to run e2e tests on the site.
The Issue
npm start starts my CRA server but that process doesn't stop as I'm not sure how to stop it unless I manually quit it. This hangs docker and blocks me from ever starting my tests.
Question
How can I start my application with npm start and once it starts then run npm run test:e2e ? Ultimately I'd like to quit CRA once the tests are completed.
Current Pipeline yml
image: node:10.19.0
stages:
  - test
  - build
  - deploy

cache:
  # untracked: true
  key:
    files:
      - package-lock.json
  paths:
    - node_modules
#test_async:
#  script:
#    - npm install
#    - node ./specs/start.js ./specs/async.spec.js

before_script:
  - apt-get update &amp;&amp; apt-get install -y lftp gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
  - if [ ! -d &quot;node_modules&quot; ]; then npm install; fi

test:
  stage: test
  script:
    - npm start
    - npm run test:e2e

build:
  stage: build
  script:
    - npm run build

# deploy-to-staging:
#   stage: deploy
#   script:
#     - lftp -e &quot;open ftp.mediajackagency.com; user $MJA_FTP_USER $MJA_FTP_PASS; mirror --reverse --verbose build/ /var/www/domains/projects/my-project/build/; bye&quot;
#   environment:
#     name: staging
#     url: http://dev.mediajackagency.com/projects/my-project/build
#   when: manual
#   only:
#     - dev
I switched to using a production build for testing by use of a local webserver. I leveraging the [jest-puppeteer][1] library which allows you to start a webserver with your tests.
jest-puppeteer.config.js
/**
 * find all flags at the following site @jkr
 * https://jestjs.io/docs/en/cli
 */

module.exports = {
    launch: {
        devtools: true, // allows for use of 'debugger;' in tests
        // executablePath: '/usr/bin/chromium-browser',
        headless: true,
        defaultViewport: {
            width: 1024,
            height: 768,
            //isMobile: true,
            //hasTouch: true,
        },
        ignoreDefaultArgs: ['--disable-extensions'],
        args: [
            '--enable-font-antialiasing',
            '--font-render-hinting=medium',
            '--disable-gpu',
            '--disable-dev-shm-usage',
            '--disable-setuid-sandbox',
            '--no-first-run',
            '--no-sandbox', // GOOD
            '--no-zygote',
            '--single-process', // GOOD

            &quot;--renderer&quot;,
            &quot;--no-service-autorun&quot;,
            &quot;--no-experiments&quot;,
            &quot;--no-default-browser-check&quot;,
            &quot;--disable-extensions&quot;,
        ]
    },
    server: { // launches webserver just for tests @jkr
        command: 'npm run test:webserver'
        // cd build &amp;&amp; ../node_modules/local-web-server/bin/cli.js --port 3000 --spa index.html
    },
    browser: 'chromium',
    browserContext: 'default'
};

.gitlab-ci.yml
image: node:10.19.0 # https://hub.docker.com/_/node/
# image: node:latest

cache:
  # untracked: true
  key: my-project-name
  # key: ${CI_COMMIT_REF_SLUG} # per branch
  # key:
  #   files:
  #     - package-lock.json # only update cache when this file changes (not working) @jkr
  paths:
    - .npm/
    - node_modules
    - build

stages:
  - prepare # can install ci-deps here ? @jkr
  - test # uses test:build specifically @jkr
  - build
  - deploy

# before_install:

before_script:
  - npm ci --cache .npm --prefer-offline #
#   # - apt-get update &amp;&amp; apt-get install -y lftp gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
#   - if [ ! -d &quot;node_modules&quot; ]; then set NODE_ENV=dev &amp;&amp; npm install; fi # make sure dev dependencies are installed todo: 'if' needs to be verified working @jkr
#   # - npm install
#   # - if [ ! -d &quot;build&quot; ]; then npm run build; fi

prepare: # could this job be in a before_script for test ? @jkr
  stage: prepare
  script:
    - npm install
    - npm run build:test
  # cache:
  #   paths:
  #     - node_modules
  #   policy: push

test:
  stage: test
  script:
    - npm run test:ci-deps
    - npm run test:e2e # runs puppeteer tests @jkr

build:
  stage: build
  script:
    - npm run build
  # artifacts:
  #   paths:
  #     - build

deploy-ftp:
  stage: deploy
  script:
    - lftp -e &quot;open ftp.my.domain.com; user $MJA_FTP_USER $MJA_FTP_PASS; mirror --reverse --verbose build/ /var/www/domains/dev/projects/my-project/build/; bye&quot;
  environment:
    name: staging
    url: http://my.domain.com/my-project/build
  when: manual
  only:
    - dev