<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: shang8024</title>
    <description>The latest articles on DEV Community by shang8024 (@shang8024).</description>
    <link>https://dev.to/shang8024</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F982114%2F1fb05a92-0376-4214-ad80-eb67beb0b0d7.png</url>
      <title>DEV Community: shang8024</title>
      <link>https://dev.to/shang8024</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shang8024"/>
    <language>en</language>
    <item>
      <title>Testing React+Node JS app with Jest and Upload coverage report to CodeClimate with Github Action</title>
      <dc:creator>shang8024</dc:creator>
      <pubDate>Thu, 01 Dec 2022 18:26:26 +0000</pubDate>
      <link>https://dev.to/shang8024/testing-reactnode-js-app-with-jest-and-upload-coverage-report-to-codeclimate-with-github-action-4d9p</link>
      <guid>https://dev.to/shang8024/testing-reactnode-js-app-with-jest-and-upload-coverage-report-to-codeclimate-with-github-action-4d9p</guid>
      <description>&lt;p&gt;It is easy to fall into a mindset when we are coding. When writing tests, we often need to consider various situations and make us re-examine our code, which is called Test-Driven-Development.&lt;br&gt;
Writing tests can bring us certain benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To verify the correctness of the code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To avoid errors when modifying code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To avoid errors when other team members modify your code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To facilitate automated testing and deployment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As your app grows larger, it becomes more complex, harder to maintain, and more buggy. Therefore, it's essential to write maintainable and testable code at very early start.&lt;br&gt;
Coverage reports tell you how much code the test cases cover. It provides useful metrics that can help you assess the quality of your test suite. We then can use CodeClimate to analyze the quality of our code from the coverage reports.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Suppose you have already created a React+Node JS app with &lt;code&gt;npm create-react-app&lt;/code&gt; and &lt;code&gt;npm init&lt;/code&gt;, setup express, and maybe have written some routes.&lt;br&gt;
Likely, you will have a similar folder hierarchy in your monorepo as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client
| public
| src
  | App.js
  | index.js
  | app.test.js
  | setupTests.js
  | reportWebVitals.js
| package.json
server
| routes
  | sample.route.js
| package.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tesing your react frontend with Jest and React Testing Library
&lt;/h2&gt;

&lt;p&gt;If you are using &lt;code&gt;create-react-app&lt;/code&gt;, both Jest and React Testing Library are built-in, so we don't need to install them separately.&lt;/p&gt;

&lt;p&gt;By default, Jest will look for files with the &lt;code&gt;.test.js&lt;/code&gt; suffix and files with the &lt;code&gt;.js&lt;/code&gt; suffix in &lt;code&gt;__tests__&lt;/code&gt; folders. &lt;/p&gt;

&lt;p&gt;An example &lt;code&gt;app.test.js&lt;/code&gt; for testing components can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';

it('renders welcome message', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
  expect(screen.getByText('Learn React')).toBeInTheDocument();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing your node backend with Jest and supertest
&lt;/h2&gt;

&lt;p&gt;To start, you will need to first install the following packages by &lt;code&gt;npm i jest supertest&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;jest&lt;/code&gt;: Jest is a JavaScript testing framework built on top of Jasmine. Unit testing is the main usage of it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;supertest&lt;/code&gt;: Supertest is a SuperAgent driven library for testing HTTP servers. With wich, we can test endpoints and routes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then in &lt;code&gt;package.json&lt;/code&gt;, add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    ...
    "test":  "jest"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will write a sample route first.&lt;br&gt;
In &lt;code&gt;server/routes/sample.test.js&lt;/code&gt;, suppose we have two functions for getting all users and add user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express")
const router = express.Router()
router.get("/getUsers",getUsers)
router.post("/createUser",createUser)

module.exports = router
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in &lt;code&gt;server/tests/sample.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const request = require("supertest");
const express = require("express");
const app = express();
app.use(express.json());
app.use("/", router);
describe("GET /getUsers", () =&amp;gt; {
  it("should return all users", async () =&amp;gt; {
    const res = await request(app).get("/getUsers");
    expect(res.statusCode).toBe(200);
    expect(res.body.length).toBeGreaterThan(0);
  });
});
describe("POST /createUser", () =&amp;gt; {
  it("should not create with empty name", async () =&amp;gt; {
    const req = {name: "",password: "123"};
    const res = await request(app).post("/createUser").type('json').send(req);
    expect(res.statusCode).toBe(400);
  });
  it("should create a user ", async () =&amp;gt; {
    const req = {name: "user",password: "123"};
    const res = await request(app).post("/createUser").type('json').send(req);
    expect(res.statusCode).toBe(200);
    expect(res.body.name).toBe("user");
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing Express+Mongodb
&lt;/h3&gt;

&lt;p&gt;If you are testing with a mongodb, you should always make sure your database is seperate, that the datasets for each test don't interfere with each other. I would recommand using local mongodb.&lt;/p&gt;

&lt;p&gt;You should put your mongodb url in &lt;code&gt;.env&lt;/code&gt; and import &lt;code&gt;dotenv&lt;/code&gt; to get the environment variable. Install &lt;code&gt;dotenv&lt;/code&gt; by &lt;code&gt;npm i dotenv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;server/.env&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MONGODB_URI="mongodb://localhost:27017"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need to connect and disconnect the database before and after each test.&lt;br&gt;
In &lt;code&gt;server/tests/mongo.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require("mongoose");
const request = require("supertest");
const app = require("../app");
require("dotenv").config("../.env");

beforeEach(async () =&amp;gt; {
  await mongoose.connect(process.env.MONGODB_URI);
});

afterEach(async () =&amp;gt; {
  await mongoose.connection.dropDatabase();
  await mongoose.connection.close();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generate test coverage report
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://docs.codeclimate.com/docs/configuring-test-coverage"&gt;Code Climate&lt;/a&gt; documentation, the supported coverage tool for JavaScript is lcov (generated by Istanbul).&lt;br&gt;
In both &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;server&lt;/code&gt; folders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;At root, add the nyc package with &lt;code&gt;npm install --save-dev nyc&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In &lt;code&gt;package.json&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "jest": {
    "coverageReporters": [
      [
        "lcov",
        {
          "projectRoot": ".."
        }
      ]
    ]
  },
  "nyc": {
    "reporter": [
      "lcov"
    ]
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To make &lt;code&gt;jest&lt;/code&gt; and &lt;code&gt;nyc&lt;/code&gt; generate &lt;code&gt;lcov&lt;/code&gt; reports. You can also add other reporters like &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;text-summary&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
For your react frontend, add to the &lt;code&gt;package.json&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    ...
    "coverage":  "react-scripts test --coverage --watchAll=false"
  },
  ...
  "jest": {
    ...
    "transformIgnorePatterns": ["node_modules\/(?!axios)"],
    "collectCoverageFrom": [
      "src/**/*.js",
      "!**/node_modules/**",
    ]
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At the root of &lt;code&gt;client&lt;/code&gt; folder, run &lt;code&gt;npm coverage&lt;/code&gt; to see the coverage report.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Similarly in the node backend, add to the &lt;code&gt;scripts&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    ...
    "coverage": "jest --coverage"
  },
  ...
  "jest": {
    ...
    "transformIgnorePatterns": ["node_modules\/(?!axios)"],
    "testEnvironment": "node",
    "collectCoverageFrom": [
      "**/routes/**/*.js",
      "!**/node_modules/**",
    ]
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At the root of &lt;code&gt;server&lt;/code&gt; folder, run &lt;code&gt;npm coverage&lt;/code&gt; to see the coverage report.&lt;/p&gt;

&lt;p&gt;We can use the property &lt;code&gt;collectCoverageFrom&lt;/code&gt; to specify which files need to be collected, and which files should not be collected (&lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;config.js&lt;/code&gt;, datasets, and so on).&lt;/p&gt;
&lt;h2&gt;
  
  
  Upload coverage report to CodeClimate
&lt;/h2&gt;

&lt;p&gt;Note that you need at least some test coverage to generate a report that is able to be uploaded to CodeClimate, so make sure you followed the previous parts carefully.&lt;/p&gt;

&lt;p&gt;To start, make sure you already have a CodeClimate account.&lt;/p&gt;

&lt;p&gt;On the dashboard, click on "Add a repository" and then "add repo" to link your repo to CodeClimate.&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;repo setting/test coverage&lt;/code&gt; and find the &lt;code&gt;TEST REPORTER ID&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In your Github repo, click on &lt;code&gt;setting/secrets/action&lt;/code&gt;, and add the &lt;code&gt;CC_TEST_REPORTER_ID&lt;/code&gt; as a new secret key.&lt;/p&gt;

&lt;p&gt;Below is an example of the &lt;code&gt;github-action.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: build
on: 
  workflow_dispatch:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
jobs:
  Coverage:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    strategy:
      matrix:
        node-version: [14.x]
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - name: Test Coverage Frontend
      run: |
        cd client
        npm install
        npm coverage

    - name: Test Coverage Backend
      run: |
        cd server
        cp -r .env.example .env
        npm install
        npm coverage

    - name: Test &amp;amp; publish code coverage
      uses: paambaati/codeclimate-action@v3.2.0
      env:
        CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
      with:
        coverageLocations: |
          ${{github.workspace}}/client/coverage/lcov.info:lcov
          ${{github.workspace}}/server/coverage/lcov.info:lcov
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to upload the two coverage tests for react and node at once, we need to set the &lt;code&gt;projectRoot&lt;/code&gt; of the &lt;code&gt;lcov&lt;/code&gt; coverage reporter of jest to the root of our monorepo (using ".." in &lt;code&gt;package.json&lt;/code&gt;).&lt;/p&gt;

</description>
      <category>testing</category>
      <category>react</category>
      <category>node</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
