Benefits of Continuous Integration
The key advantages of Continuous Integration (CI) include:
- Increased Code Quality
- Faster Development Cycle
- Improved Collaboration
- Visibility
There's no need to elaborate further on these well-known benefits. This project focuses on setting up a CI pipeline for a Serverless application, which automatically runs tests and reports code coverage within GitLab.
Project Creation
Comprehensive information about project creation can be found here in a dedicated post.
You now have a template.yml
file in the sam-project folder.
This TypeScript project includes a basic example of a Lambda function tested using the Jest framework.
Running tests locally
Navigate to the hello-world folder and run the tests locally:
1cd hello-world 2npm i 3npm run test
This runs the test-handler.test.ts
file, producing the following test report:
1 PASS tests/unit/test-handler.test.ts 2 Unit test for app handler 3 ✓ verifies successful response (3 ms) 4 5----------|---------|----------|---------|---------|------------------- 6File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 7----------|---------|----------|---------|---------|------------------- 8All files | 76.66 | 75 | 100 | 76.66 | 9 app.ts | 76.66 | 75 | 100 | 76.66 | 20-26 10----------|---------|----------|---------|---------|------------------- 11Test Suites: 1 passed, 1 total 12Tests: 1 passed, 1 total 13Snapshots: 0 total 14Time: 2.093 s
This report provides basic code coverage information, but we can extend it with a JUnit report.
JUnit reporting
To generate a JUnit report, we’ll use jest-junit, which converts test results to JUnit XML format. This will be crucial for GitLab CI later.
installation
1npm i jest-junit -D
Configuration
Update the jest.config.ts
file to generate the JUnit report:
1export default { 2 transform: { 3 '^.+\\.ts?$': 'ts-jest', 4 }, 5 clearMocks: true, 6 collectCoverage: true, 7 coverageDirectory: 'coverage', 8 coverageProvider: 'v8', 9 testMatch: ['**/tests/unit/*.test.ts'], 10 coverageReporters: ['html', 'text', 'text-summary', 'cobertura'], 11 reporters: [ 12 'default', 13 [ 14 'jest-junit', 15 { 16 outputDirectory: 'junit', 17 outputName: 'jest-junit.xml', 18 }, 19 ], 20 ], 21};
Running
Re-run the tests and observe the newly generated coverage and junit folders:
1npm run test
In the coverage folder, you’ll find detailed information on the tested lines.
The junit folder contains the jest-junit.xml
file, structured like this:
1<?xml version="1.0" encoding="UTF-8"?> 2<testsuites name="jest tests" tests="1" failures="0" errors="0" time="1.117"> 3 <testsuite name="Unit test for app handler" errors="0" failures="0" skipped="0" timestamp="2024-10-09T15:29:17" time="1.061" tests="1"> 4 <testcase classname="Unit test for app handler verifies successful response" name="Unit test for app handler verifies successful response" time="0.004"> 5 </testcase> 6 </testsuite> 7</testsuites>
Running in GitLab CI
Now that we have local test coverage, we will integrate it with GitLab to automate Continuous Integration.
Configuration
Create a .gitlab-ci.yml
file with the following content:
1 2stages: 3 - build 4 - test 5 6"Build": 7 image: public.ecr.aws/sam/build-nodejs18.x 8 stage: build 9 script: 10 - cd hello-world 11 - npm install 12 cache: 13 paths: 14 - hello-world/node_modules/ 15 only: 16 - main 17 artifacts: 18 expire_in: 1 days 19 when: on_success 20 paths: 21 - hello-world/node_modules/ 22 23"Test": 24 image: public.ecr.aws/sam/build-nodejs18.x 25 stage: test 26 only: 27 - merge_requests 28 - main 29 coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/ 30 dependencies: 31 - "Build" 32 script: 33 - node --version 34 - npm --version 35 - cd hello-world 36 - npm install 37 - npm run test 38 artifacts: 39 when: always 40 reports: 41 junit: 42 - hello-world/junit/jest-junit.xml 43 coverage_report: 44 coverage_format: cobertura 45 path: hello-world/coverage/cobertura-coverage.xml
This pipeline contains two stages:
- Build: Installs dependencies.
- Test: Runs tests, calculates coverage, and stores reports.
The coverage parameter of the Test job extracts code coverage from the job’s output using this regex pattern:
1coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
Reporting
GitLab captures coverage data and displays it in various places (badges, pipelines, merge requests, statistics).
JUnit test summaries are also stored and accessible through the GitLab pipeline interface.
Badge
GitLab automatically generates a badge for code coverage, which can be displayed on the project’s homepage by updating the configuration project in General Settings > Badges.
Summary
In this tutorial, we implemented Continuous Integration for an AWS Serverless application. The code coverage indicator enhances code reviews by providing insights directly within GitLab merge requests.
WARNING: If you deploy this app to AWS, remember to clean up AWS resources
1sam delete