Im using jest to run tests in my monorepo.
These tests have interdependencies to other subpackages of the monorepo.
Everything works great localy.
But the gitlab-ci pipeline fails, cause it cant resolve the interdependencies...
Simplyfied project structure:
packages
-core
--src
---core.js
--package.json
-advanced
--src
---advanced.js
---advanced.test.js
--package.json
.gitlab-ci.yml
jest.config.js
package.json
Simplyfied jest.config.js:
module.exports = {
projects: ['packages/*'],
rootDir: __dirname,
roots: ['<rootDir>/packages'],
testMatch: ['**/*.test.js'],
}
Simplyfied core/package.json:
{
"name": "#myProject/core",
"version": "1.0.0"
}
Simplyfied advanced/package.json:
{
"name": "#myProject/advanced",
"version": "1.0.0",
"dependencies": {
"#myProject/core": "^1.0.0"
}
}
Simplyfied advanced.test.js:
import thisthat from 'randomBibX'
import others from 'randomBibY'
import core from '#myproject/core'
//doTests
Simplyfied package.json:
{
"scripts": {
"test": "jest"
}
"devDependencies": {
"randomBibX": "^1.0.0",
"randomBibY": "^1.0.0"
}
}
Simplyfied .gitlab-ci.yml:
image: node:10
stages:
- setup
- test
setup:
stage: setup
script:
- yarn config set cache-folder /cache/.yarn
- yarn install --non-interactive --frozen-lockfile
artifacts:
expire_in: 1hour
paths:
- node_modules
- "packages/*/node_modules"
jest:
stage: test
dependencies:
- setup
script:
- "[ ! -d node_modules/ ] && yarn install --non-interactive --frozen-lockfile"
- yarn test
The error:
FAIL packages/advanced/src/advanced.test.js
● Test suite failed to run
Cannot find module '#myProject/core' from 'advanced.test.js'
The solution was, to build the project before testing
Improved .gitlab-ci.yml:
image: node:10
stages:
- setup
- test
installAndBuild:
stage: setup
script:
- yarn config set cache-folder /cache/.yarn
- yarn install --non-interactive --frozen-lockfile
- yarn lerna run build --stream
artifacts:
expire_in: 1hour
paths:
- node_modules
- "packages/*/node_modules"
jest:
stage: test
dependencies:
- installAndBuild
script:
- "[ ! -d node_modules/ ] && yarn install --non-interactive --frozen-lockfile"
- yarn test
Related
I registered test-coverage ci in github actions
name: TEST-COVERAGE
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- name: Checkout source code
uses: actions/checkout#v3
- name: Set up Nest.js
uses: actions/setup-node#v3
with:
node-version: ${{ matrix.node-version }}
- name: Set up Node_modules
run: |
cd ./client
rm -rf node_modules
yarn install --immutable --immutable-cache --check-cache
cd ..
cd ./server/gateway
rm -rf node_modules
npm ci
cd ../services/core
rm -rf node_modules
npm ci
cd ../auth
rm -rf node_modules
npm ci
cd ../ticket
rm -rf node_modules
npm ci
- name: Run Test Coverage
run: |
rm -rf node_modules
npm ci
npm run coveralls
- name: Coveralls
uses: coverallsapp/github-action#master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
I passed all the test cases with jest, and while executing it, a situation occurred where the Github action suddenly stopped. Even locally, the test code passes and does not emit an error message, but it stops without any output, so it cannot be solved.
Error: Process completed with exit code 1.
Below is my Current Directory
client
server
gateway
auth
core
ticket
At first, it seemed to be a Github action memory leak, so when I changed the npm install command to npm ci, it ran fine. However, as we added and expanded new features, npm ci encountered the same problem.
https://github.com/boostcampwm-2022/web03-FanUP/actions/runs/3521371482/jobs/5903147717
This is github actions result
"scripts": {
"test": "jest --detectOpenHandles --forceExit",
"coverage": "jest --detectOpenHandles --coverage --forceExit",
"coveralls": "jest --coverage --detectOpenHandles --forceExit && coveralls < ./coverage/lcov.info"
},
I have script for pipeline like this .
I have two stages one for dependencies and tests
On the tests i have error when the script below is launched
- node_modules/.bin/ng test --code-coverage --watch=false --browsers=GitlabHeadlessChrome
image: ubuntu:latest
variables:
OUTPUT_PATH: "$CI_PROJECT_DIR/artifacts"
stages:
- install
- test
cache:
key:
files:
- package-lock.json
paths:
- node_modules
policy: pull
install_dependencies:
stage: install
image: node:15.13.0-alpine3.10
script:
- npm install
cache:
key:
files:
- package-lock.json
paths:
- node_modules
test_verydashboard:
stage: test
needs: [ "install_dependencies" ]
image: node:12-alpine
before_script:
- apk add chromium
- export CHROME_BIN=/usr/bin/chromium-browser
script:
- node_modules/.bin/ng test --code-coverage --watch=false --browsers=GitlabHeadlessChrome
coverage: '/Statements\s+:\s\d+.\d+%/'
artifacts:
name: "tests-and-coverage"
reports:
coverage_report:
coverage_format: cobertura
path: $OUTPUT_PATH/coverage/cobertura-coverage.xml
cache:
key:
files:
- yarn.lock
paths:
- node_modules
policy: pull
and on the test stage i have this error
Here is the error log message:
[3:40:55 PM] [semantic-release] › ✖ The command "git push --dry-run
--no-verify https://gitlab-ci-token:[secure]#[repository-url].git
HEAD:main" failed with the error message remote: You are not allowed
to upload code.
fatal: unable to access 'https://gitlab-ci-token:[secure]#[repository-url]/': The requested URL returned error: 403.
I have a GITLAB_TOKEN set up in the repository settings with all the necessary permissions, but it seems it isn't even being used:
Here is my .releaserc.json config:
{
"branches": ["main", { "name": "beta", "prerelease": true }],
"plugins": [
"#semantic-release/commit-analyzer",
"#semantic-release/release-notes-generator",
"#semantic-release/changelog",
"#semantic-release/npm",
"#semantic-release/gitlab",
[
"#semantic-release/git",
{
"assets": ["package.json", "package-lock.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
]
]
}
Here it's my .gitlab-ci.yml config:
# NodeJs image
image: node:16
# STAGES
stages:
- checks
- build
- release
# SETUP
before_script:
- node -v
- npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
- npm ci --cache .npm --prefer-offline
# JOBS
lint:
stage: checks
script:
- npm run lint
test:
stage: checks
script:
- npm run test:ci
build:
stage: build
script:
- npm run build
release:
stage: release
only:
- main
script:
- npx semantic-release
And here are the semantic release dependencies I'm using and it's versions:
"#semantic-release/changelog": "^6.0.1",
"#semantic-release/git": "^10.0.1",
"#semantic-release/gitlab": "^7.0.4",
"#semantic-release": "^19.0.2",
The GITLAB_TOKEN is a member of the repository as a maintainer (just like the other repositories where semantic release is working):
Any suggestions?
So in the end the problem was that I had to add the created GITLAB_TOKEN access token in Settings > CI/CD > Variables
Currently I have a working circleci yaml file but it runs a separate test script for each app. It's not "DRY" and I think a better solution would be to run the test script from the root and loop over each app...but I can't figure out how to do that. I've seen some examples but anytime I try to apply them, circle can't seem to find the clover files so I'm not sure what I'm doing wrong. I'd LOVE to run everything in parallel too but my first need is to just eliminate all the extra steps.
This is the current setup:
file system structure:
- apps
- **app1**
- coverage
- clover.xml
- coverage-final.json
- src
- test-files
package.json
- **app2**
- coverage
- clover.xml
- coverage-final.json
- src
- test-files
package.json
- **app3**
- coverage
- clover.xml
- coverage-final.json
- src
- test-files
package.json
- package.json
root/package.json scripts
{
"scripts": {
"lint": "lerna run lint --concurrency=2",
"build": "lerna run build --concurrency=1 --stream",
"bootstrap:ci": "lerna bootstrap --ci --concurrency=2"
"test": "CI=true lerna run test:coverage --concurrency=2 --stream -- --coverage",
"test:app1": "cd apps/enhanced-date-editor && npm run test:coverage",
"test:app2": "cd apps/input-fields-group && npm run test:coverage",
"test:app3": "cd apps/markdown-items-list && npm run test:coverage",
},
"devDependencies": {
"lerna": "^3.22.1"
}
}
app[1/2/3]/package.json scripts
{
"scripts": {
"build": "react-scripts build",
"test": "react-scripts test",
"test:coverage": "npm t -- --coverage",
"deploy": "s3 bucket script",
},
"jest": {
"collectCoverageFrom": [
"**/*.{js,jsx,tsx}",
"!**/node_modules/**",
"!**/vendor/**"
]
}
}
circleci/config.yml
version: 2.1
executors:
node:
docker:
- image: cimg/node:14.15.4
jobs:
prepare:
executor: node
steps:
- checkout
- run:
name: Install dependencies
command: |
npm i
npm run bootstrap:ci
- persist_to_workspace:
root: .
paths:
- .
lint:
executor: node
steps:
- attach_workspace:
at: .
- run:
name: lint
command: npm run lint
test-reporter:
executor: node
steps:
- run:
name: Setup Code Climate test-reporter
command: |
# download test reporter as a static binary
mkdir -p testing-workspace/test-results/coverage
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > testing-workspace/cc-test-reporter
chmod +x testing-workspace/cc-test-reporter
- persist_to_workspace:
root: testing-workspace
paths:
- cc-test-reporter
test-app1:
executor: node
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:app1
testing-workspace/cc-test-reporter format-coverage \
"apps/app1/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.app1.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.app1.json
test-app2:
executor: node
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:app2
testing-workspace/cc-test-reporter format-coverage \
"apps/app2/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.app2.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.app2.json
test-app3:
executor: node
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:app3
testing-workspace/cc-test-reporter format-coverage \
"apps/app3/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.app3.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.app3.json
ship-all-the-test-results:
executor: node
steps:
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: sum coverage
command: testing-workspace/cc-test-reporter sum-coverage -o testing-workspace/test-results/coverage/coverage.total.json testing-workspace/test-results/coverage/coverage.*.json;
- run:
name: ship results to code climate
command: testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
- store_artifacts:
path: testing-workspace/test-results
destination: test-results
- store_test_results:
path: testing-workspace/test-results
workflows:
build-test-deploy:
jobs:
- prepare
- lint:
requires:
- prepare
- test-reporter:
requires:
- lint
- test-app1:
requires:
- test-reporter
- test-app2:
requires:
- test-reporter
- test-app3:
requires:
- test-reporter
- ship-all-the-test-results:
requires:
- test-app1
- test-app2
- test-app3
Example of what I've tried
testing-workspace/cc-test-reporter before-build
npm run test
testing-workspace/cc-test-reporter format-coverage apps/**/coverage/clover.xml --input-type clover --output apps/**/coverage/coverage-final.json
testing-workspace/cc-test-reporter sum-coverage apps/**/coverage/coverage-final.json --output testing-workspace/test-results/coverage/codeclimate.total.json
testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
testing-workspace/cc-test-reporter after-build --exit-code $?
error was git head does not match
Another Example of what I have tried
#!/bin/bash -eo pipefail
# notify codeclimate that a build is coming
testing-workspace/cc-test-reporter before-build
# run tests
# will receive a list of test files and the CircleCI CLI will split them by timing data.
TESTFILES=$(circleci tests glob "apps/**.js" | circleci tests split)
npm run test ${TESTFILES}
# format test results
testing-workspace/cc-test-reporter format-coverage "**/**/clover.xml" --input-type clover --output "apps/**/coverage/coverage-final.json"
# combine test results
testing-workspace/cc-test-reporter sum-coverage -o testing-workspace/test-results/coverage/coverage.total.json "apps/**/coverage/coverage-final.json"
# upload test results to codeclimate
testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
# notify codeclimate that build is completed
testing-workspace/cc-test-reporter after-build --exit-code $?
error was ```could not find coverage file //clover.xml
could not find any files in search paths for clover. search paths were: //clover.xml, build/logs/clover.xml, clover.xml ``
There is no loop in CircleCI config syntax, but you can make the config more DRY by adding a parameter for the app to your test-app job.
version: 2.1
executors:
node:
docker:
- image: cimg/node:14.15.4
jobs:
prepare:
executor: node
steps:
- checkout
- run:
name: Install dependencies
command: |
npm i
npm run bootstrap:ci
- persist_to_workspace:
root: .
paths:
- .
lint:
executor: node
steps:
- attach_workspace:
at: .
- run:
name: lint
command: npm run lint
test-reporter:
executor: node
steps:
- run:
name: Setup Code Climate test-reporter
command: |
# download test reporter as a static binary
mkdir -p testing-workspace/test-results/coverage
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > testing-workspace/cc-test-reporter
chmod +x testing-workspace/cc-test-reporter
- persist_to_workspace:
root: testing-workspace
paths:
- cc-test-reporter
test-app:
executor: node
parameters:
app_name:
type: string
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:<< parameters.app_name >>
testing-workspace/cc-test-reporter format-coverage \
"apps/<< parameters.app_name >>/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.<< parameters.app_name >>.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.<< parameters.app_name >>.json
ship-all-the-test-results:
executor: node
steps:
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: sum coverage
command: testing-workspace/cc-test-reporter sum-coverage -o testing-workspace/test-results/coverage/coverage.total.json testing-workspace/test-results/coverage/coverage.*.json;
- run:
name: ship results to code climate
command: testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
- store_artifacts:
path: testing-workspace/test-results
destination: test-results
- store_test_results:
path: testing-workspace/test-results
workflows:
build-test-deploy:
jobs:
- prepare
- lint:
requires:
- prepare
- test-reporter:
requires:
- lint
- test-app:
name: test-app1
app_name: app1
requires:
- test-reporter
- test-app:
name: test-app2
app_name: app2
requires:
- test-reporter
- test-app:
name: test-app3
app_name: app3
requires:
- test-reporter
- ship-all-the-test-results:
requires:
- test-app1
- test-app2
- test-app3
To me, it looks like mocha's --recursive flag is working correctly on my machine, but being ignored during CI automated testing. This means that only 60 tests are executed in CircleCI, but ~100 are executed when I run npm test on my machine.
Partial Project Structure
|--/test
|----mocha.opts
|----lifecycle.test.js
|----/integration
|------/models
|--------Thing.test.js
|------/controllers
|--------/thing
|----------thingAction.test.js
|--/.circleci
|----config.yml
mocha.opts
--recursive
--timeout 20000
--reporter list
--exit
.circleci/config.yml
# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/node:8.11
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/mongo:3.4.4
working_directory: ~/repo
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: yarn install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
# run tests!
- run: yarn test
package.json
"devDependencies": {
"mocha": "^5.2.0",
},
"scripts": {
"test": "npm run lint && npm run mocha-tests && echo 'Done.'",
"lint": "eslint . --max-warnings=0 --report-unused-disable-directives && echo 'Your .js files look so good.' && lesshint assets/styles/ --max-warnings=0 && echo 'Your .less files look good, too.'",
"mocha-tests": "node ./node_modules/mocha/bin/mocha test/lifecycle.test.js test/integration/**/*.test.js",
}
In this example, both Thing.test.js and thingAction.test.js are being executed localy, but only Thing.test.js is executed during the CircleCI build. Put another way, test/integration/**/*.test.js matches both file names locally, but only the top subdirectory in CircleCI.
How do I make sure all the test scripts get run?
The issue can be solved by giving a single quote in your test command when defining targeted test files so it would be
"scripts": {
"mocha-tests": "node ./node_modules/mocha/bin/mocha 'test/lifecycle.test.js' 'test/integration/**/*.test.js'",
}
Without quote, glob pattern won't work correctly especially in linux environment.