diff --git a/jobs/templates/includes/stage-cypress-tests.groovy.j2 b/jobs/templates/includes/stage-cypress-tests.groovy.j2 index 69108b3..2353a20 100644 --- a/jobs/templates/includes/stage-cypress-tests.groovy.j2 +++ b/jobs/templates/includes/stage-cypress-tests.groovy.j2 @@ -1,148 +1,154 @@ stage('Cypress tests') { steps { script { // set some useful environment variables env.SORRY_CYPRESS_NETWORK = "sorry-cypress-network-${env.JOB_NAME}-${env.BUILD_ID}" env.SORRY_CYPRESS_BUILD_ID = "${env.JOB_NAME}-${env.BUILD_ID}" // create a dedicated docker network to allow communication between sorry-cypress // container and tests runner container sh 'docker network create --driver bridge $SORRY_CYPRESS_NETWORK' // pull sorry-cypress docker image def sorryCypressDirector = docker.image('agoldis/sorry-cypress-director') sorryCypressDirector.pull() // execute sorry-cypress as a sidecar container sorryCypressDirector.withRun("--network-alias sorry-cypress --network ${env.SORRY_CYPRESS_NETWORK}") { c -> // run cypress tests into dedicated container with mounted yarn cache docker.image('swh-jenkins/cypress').inside("--network ${env.SORRY_CYPRESS_NETWORK} --mount type=volume,src=shared-jenkins-cachedir,dst=/home/jenkins/.cache") { script { sh ''' # ensure sorry-cypress server is up wait-for-it sorry-cypress:1234 # install swh-web python requirements python3 -m pip install --no-use-pep517 --user -e .[testing] # ensure to remove previous test dbs (in case something went wrong when cleaning workspace) rm -f swh-web-test*.sqlite3* # apply django migrations and create users (will produce swh-web-test.sqlite3 file) python3 swh/web/manage.py migrate --settings=swh.web.settings.tests for create_users_script in swh/web/tests/create_test_* do cat $create_users_script | python3 swh/web/manage.py shell --settings=swh.web.settings.tests done # build swh-web static assets in test mode (for code coverage) yarn install --frozen-lockfile yarn build-test # change cypress API URL using cy2 one time to avoid race condition # https://github.com/sorry-cypress/cy2/issues/16 node -e "const { patch } = require('cy2'); \ async function main() { \ await patch('http://sorry-cypress:1234'); \ } \ main().catch(console.error);" # create needed folders for code coverage outputs mkdir -p cypress/coverage mkdir -p cypress/coverage_output mkdir .nyc_output mkdir .nyc_outputs # create dedicated X11 server manually for cypress tests (recommended for parallel mode) # https://docs.cypress.io/guides/continuous-integration/introduction#Xvfb Xvfb -screen 0 1920x1080x24 :99 & ''' parallel([ // create n cypress processes that will run tests affected by sorry-cypress in parallel {% for n in range(1, nb_cypress_runners + 1) %} 'Cypress runner {{ n }}': { sh ''' # export cypress parallel build id (used internally by swh-web to setup cypress parallel tests) export CYPRESS_PARALLEL_BUILD_ID={{ n }} # force use of manually created X11 server export DISPLAY=:99 + # to avoid possible race conditions, each cypress runner will execute tests from + # a copy of the swh-web repository filesystem (without root hidden folders) + mkdir .swh-web{{ n }} + cp -r ./* .swh-web{{ n }} + cd .swh-web{{ n }} + # copy database file to the one that will be used by django for that test runner cp swh-web-test.sqlite3 swh-web-test{{ n }}.sqlite3 # run django server on a dedicated port for that test runner and wait for it to be up python3 swh/web/manage.py runserver --nostatic --settings=swh.web.settings.tests 0.0.0.0:500{{ n }}& wait-for-it -t 90 localhost:500{{ n }} # execute cypress tests yarn run cypress run --record --key swh-web --parallel --config baseUrl=http://localhost:500{{ n }} --ci-build-id $SORRY_CYPRESS_BUILD_ID # copy nyc coverage outputs to dedicated merge folders for later processing - cp cypress/coverage{{ n }}/coverage-final.json cypress/coverage_output/coverage-final{{ n }}.json - cp .nyc_output{{ n }}/out.json .nyc_outputs/out{{ n }}.json + cp cypress/coverage{{ n }}/coverage-final.json ../cypress/coverage_output/coverage-final{{ n }}.json + cp .nyc_output{{ n }}/out.json ../.nyc_outputs/out{{ n }}.json ''' }, {% endfor %} ]) } } } } } post { always { junit( allowEmptyResults: true, testResults: 'cypress/junit/results/*.xml', ) sh ''' # generate HTML report for tests yarn run mochawesome || true # merge code coverage data produced by each cypress runner yarn run nyc merge cypress/coverage_output cypress/coverage/coverage-final.json yarn run nyc merge .nyc_outputs .nyc_output/out.json # generate coverage reports yarn run nyc report --reporter=lcov || true yarn run nyc report --reporter=cobertura || true # remove node_modules folder rm -rf node_modules # remove docker network created at the beginning of that stage docker network rm $SORRY_CYPRESS_NETWORK || true ''' publishHTML (target: [ allowMissing: true, alwaysLinkToLastBuild: false, keepAll: true, reportDir: 'cypress/mochawesome/report', reportFiles: 'mochawesome.html', reportName: "Mochawesome Tests Report" ]) publishHTML (target: [ allowMissing: true, alwaysLinkToLastBuild: false, keepAll: true, reportDir: 'cypress/coverage/lcov-report', reportFiles: 'index.html', reportName: "Istanbul Code Coverage" ]) publishCoverage( adapters: [ coberturaAdapter(path: 'cypress/coverage/cobertura-coverage.xml'), ], tag: 'cypress', ) } } }