Introduction
SonarQube is a tool that helps you catch bugs and vulnerabilities in your app. Working together with ESLint and Unit tests, it provides a great code quality scan.
On this tutorial, I will show you how to set up SonarQube and run locally over a React TypeScript project. Then, we will improve SonarQube analysis by adding ESLint and Jest reports.
The topics are organized as follow:
- Step 1: Create a React Project with TypeScript
- Step 2: Install SonarQube
- Step 3: Configuring SonarQube over our React + TypeScript project
- Configure Jest to send information to SonarQube
- Configure ESLint to send information to SonarQube
- Useful Tips
So, let's start!
Prerequisites
You need to have already installed on your computer:
— Node.js (version >= 10).
— Docker
— Docker Compose
Step 1. Create a React Project with TypeScript
The following command will create a project inside a folder 'my-app'.
On terminal, run:
npx create-react-app my-app --template typescript
Step 2. Install SonarQube
We will use an official Docker Compose file to install it.
Download Docker Compose file
On the SonarSource Github, download the following docker compose file (SonarQube with Postgres):
https://github.com/SonarSource/docker-sonarqube/blob/master/example-compose-files/sq-with-postgres/docker-compose.yml
Run Docker Compose file
It is time to run our Docker Compose 'docker-compose.yml' file.
Before running it, we need to increase the memory dedicated for Docker, otherwise, when we try to run it, we will get the following error:
To solve this problem, execute the follow command.
On terminal:
sudo sysctl -w vm.max_map_count=262144
Now, let's run 'docker-compose.yml' file. Inside the same directory where the file is located, run:
On terminal:
docker-compose up
PS: To keep SonarQube running you will need to let this terminal window open. Whenever you want to stop SonarQube from running, just press Ctrl+C on the terminal (or close it).
Open another terminal window to execute other commands when needed.
Check installation
Check if installation succeeded by opening SonarQube at localhost. SonarQube will be available on port 9000.
SonarQube UI:
Log in
Click on Login and enter with the follow credentials:
Login: admin
Password: admin
Step 3. Configuring SonarQube over our React + TypeScript project
At this moment we have:
- React + TypeScript project created
- SonarQube running
It is time to configure SonarQube on our React + TypeScript project.
Install SonarQube Scanner package
sonarqube-scanner: https://www.npmjs.com/package/sonarqube-scanner
It runs sonarQube analysis over our project and sends the information to SonarQube application.
Inside the React project directory 'my-app/', run on terminal:
npm install --save-dev sonarqube-scanner
SonarQube Configuration File
On the root of the project, create a 'sonarqube-scanner.js' file.
'sonarqube-scanner.js' file content:
const scanner = require("sonarqube-scanner");
scanner(
{
serverUrl: "http://localhost:9000",
login: "admin",
password: "admin",
options: {
"sonar.sources": "./src",
},
},
() => process.exit()
);
Note: Using login and password is not safe and we are doing it just to simplify the configuration process.
You can see the best solution for this security problem at the end of this article, on '_Useful Tips' Section_
Running SonarQube
SonarQube is already set up! To see its analysis over our code, we need to run SonarQube Scanner.
Before running it, let's add a code smell to our code! (to see it on SonarQube analysis)
On 'App.tsx' file:
// ...
function App() {
//'Empty block statement' code smell
try{
}
catch(e){
}
return (
// ...
)
}
Running SonarQube Scanner
Now, let's call SonarQube Scanner to send the report to SonarQube.
On terminal:
node sonarqube-scanner.js
After some time, it will print the message below:
SonarQube Scanner analysis finished.
Let's check the results on http://localhost:9000
Cool!
To see a detailed list of problems pointed out, just click on 'Issues' tab.
Issues detailed list:
And if you click over the issue, it'll show you all the lines related to the problem.
Detailed Issue:
Cool, right?
Configure Jest to send information to SonarQube
We've seen SonarQube power by itself. Now, let's improve it by sending our Unit Test report to it.
Install Jest-Sonar-Reporter package
jest-sonar-reporter: https://www.npmjs.com/package/jest-sonar-reporter
It converts Jest's report output to SonarQube report format.
On terminal:
npm install --save-dev jest-sonar-reporter
Add some Test configurations to Sonar Configuration File
On 'sonarqube-scanner.js' file, add over “options”:
"sonar.exclusions": "**/*.test.tsx",
"sonar.tests": "./src",
"sonar.test.inclusions": "**/*.test.tsx,**/*.test.ts",
"sonar.typescript.lcov.reportPaths": "coverage/lcov.info",
"sonar.testExecutionReportPaths": "test-report.xml"
Test files organized in subfolders: It is not our case, but If your React tests are under a folder ,like 'src/myTests' and sub-folders, you will need to change the follow settings:
"sonar.exclusions": "**/myTests/**",
"sonar.tests": "./src/myTests",
"sonar.test.inclusions": "./src/myTests/**/*.test.tsx,./src/myTests/**/*.test.ts"
Now, we need to tell Jest that on every time that the Unit Tests run, it has to create a report in a format that SonarQube will understand.
So, on package.json, let's change our “test” script:
{
...,
"test": "react-scripts test --watchAll=false --coverage --testResultsProcessor jest-sonar-reporter",
...
}
Let me explain some command options that we've added:
--watchAll=false: It is because when executing 'test' script, React will start a watch-mode menu, so you can select if you want to run all files, specific ones, just the modified ones, etc. In our case, we don't want it to ask anything, but just run all the tests. So we turn off this watch-mode by adding '--watchAll=false' to it.
--coverage: It just tells Jest that the test coverage information should be collected and reported in the output.
--testResultsProcessor jest-sonar-reporter: tells to generate the output in a SonarQube expected format.
SonarQube is ready to receive Jest report data. So let 's do it!.
Running Jest + SonarQube
**Running Jest
**First, run Jest to generate a report output:
On terminal:
npm run test
See that a report called 'test-report.xml' will appear on the root of your project.
Running SonarQube Scanner
Now, let's call SonarQube Scanner to send the report to SonarQube.
On terminal:
node sonarqube-scanner.js
After some time, it will print the message below:
Let's check the results on http://localhost:9000
Our Jest report is now showing on SonarQube report! Cool!
Configure ESLint to send information to SonarQube
We can also execute ESLint over our project files, generate a report and send it to SonarQube.
So, let's do this!
Add Eslint report path to SonarQube Configuration File
On 'sonarqube-scanner.js' file, add over “options”:
"sonar.eslint.reportPaths":"eslint-report.json"
Running ESLint + SonarQube
Running ESLint Before running ESLint, let's add another code smell to our 'App.tsx' file, so we can see the ESLint analysis on our SonarQube Report. An easy code smell to add is to create a variable and not use it on our code.
On 'App.tsx' file:
...
//'Unused variable' code smell
const unusedVar = "";
function App() {
//'Empty block statement' code smell
try{
}
catch(e){
}
return (
// ...
)
}
Code smell added! Now let's run ESLint to generate a report output:
On terminal:
npx eslint -f json -o eslint-report.json .
See that a report called 'eslint-report.json' will appear on the root of your project.
Running SonarQube Scanner Now, let's call SonarQube Scanner to send the report to SonarQube.
On terminal, run:
node sonarqube-scanner.js
After some time, it will print the message below:
Let's check the results on http://localhost:9000
Cool! Another Code Smell appeared in our report!
Let's see the detailed list of problems pointed by SonarQube analysis on 'Issues' tab.
The code smell 'unusedVar' is pointed out as we expected! Cool, right?
Useful Tips
We have finished! But let me give you some very useful tips!
Update .gitignore
Some files such as the reports generated are not useful to push into the repository. I suggest to add the following to your .gitignore file:
#SonarQubetest-report.xml
eslint-report.json
/.scannerwork
Generate user Token to use on SonarQube Configuration File
Expose your login and password on ''sonarqube-scanner.js'' is not safe. To solve this security issue let me show you how to generate and use a token instead:
- Open http://localhost:9000 and log in.
- Click on Administrator icon then click at 'My Account'
- On the Administrator screen, select 'Security' tab. Enter a Token Name and click on 'Generate' button.
- A token will show on the screen. Copy it and store it in a safe place.
user token generated
- On ''sonarqube-scanner.js”:
- Add the following line with the generated Token:
token: "3aa403f1ad2065ea2b4b837262ca2cad96e3cd7a"
- Remove the following lines:
login:"admin",
password:"admin"
- Resulting in the follow:
const scanner = require('sonarqube-scanner');
scanner(
{
serverUrl: "http://localhost:9000",
token: "3aa403f1ad2065ea2b4b837262ca2cad96e3cd7a",
options: {
// ...
And it's done!
Organize all of your scripts over 'package.json' file
To better organize your project, let all the scripts on “package.json” file.
"scripts": {
// ...
"test": "react-scripts test",
"test:noWatch":"npm run test -- --watchAll=false",
"test:report": "npm run test:noWatch -- --coverage --testResultsProcessor jest-sonar-reporter",
"lint": "eslint --fix",
"lint:report":"npm run lint -- -f json -o eslint-report.json",
"sonar": "node sonarqube-scanner.js"
},
And then you can use it like:
- To run Jest over all the project in watch-mode:
npm run test
- To run Jest over all the project without watch-mode:
npm run test:noWatch
- To run Jest over all the project without watch-mode and generate a report:
npm run test:report
- To run ESLint over all the project
npm run lint -- .
- To run ESLint over all the project and generate a report:
npm run lint:report -- .
- To run SonarQube Scanner
npm run sonar
Configure these validations also on your CI pipeline:
SonarQube was built to run over a CI pipeline and guarantee that no bad code will be deployed. So, I strongly recommend setting it up on your CI (Continuous Integration) pipeline process.
PS: We can discuss about this CI configuration on another time. The main goal here was to run and use SonarQube locally.
Thanks!
Many thanks! Hope you enjoyed!