Daftar Isi

Membuat Unit Test Menggunakan Vitest dan Mengintegrasikan dengan GitHub Actions

Serial - TypeScript Dasar

This article has been translated into English version: Creating Unit Tests Using Vitest and Integrating with GitHub Actions

Pendahuluan

Testing adalah bagian penting dalam pengembangan aplikasi yang berkualitas, memastikan kode berfungsi seperti yang diharapkan dan mencegah regresi saat aplikasi berkembang. Dalam artikel ini, kita akan mempelajari cara mengimplementasikan unit testing menggunakan Vitest—framework testing yang cepat dan terintegrasi sempurna dengan Vite—lalu menghubungkannya dengan codecov.io untuk mendapatkan laporan visual tentang seberapa baik test kita mencakup kode aplikasi, dan akhirnya mengotomatisasi seluruh proses ini dengan GitHub Actions sehingga test akan berjalan secara otomatis setiap kali ada perubahan kode, menjamin kualitas aplikasi tetap terjaga tanpa intervensi manual.

Prasyarat

Sebelum lanjut, pastikan teman-teman sudah mengecek part sebelumnya di sini ya:

  1. Implementasi Code Coverage di GitHub Actions Menggunakan Codecov
  2. Menambahkan Linter dan Formatter pada Projek TypeScript

Langkah 1: Menginstal Vitest

Mari kita instal Vitest beserta plugin untuk coverage:

pnpm add -D vitest @vitest/coverage-v8

Langkah 2: Mengkonfigurasi Vitest

Tambahkan konfigurasi Vitest ke file vite.config.ts:

import { defineConfig, loadEnv } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd());

  return {
    plugins: [tsconfigPaths()],
    base: env.VITE_ASSET_URL || "/",
    test: {
      globals: true,
      environment: "jsdom",
      coverage: {
        provider: "v8",
        reporter: ["text", "json", "html"],
        exclude: ["node_modules/", "tests/"],
      },
    },
  };
});

Langkah 3: Menambahkan Script Testing di package.json

Tambahkan script untuk menjalankan test dan coverage di package.json:

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext .ts",
    "format": "prettier --write \"**/*.{css,js,json,jsx,ts,tsx}\"",
    "test": "vitest run",
    "coverage": "vitest run --coverage"
  }
}

Langkah 4: Membuat Unit Test Sederhana

Buat folder tests di root projek dan tambahkan file test sederhana:

import { describe, it, expect } from "vitest";

describe("Example test", () => {
  it("should pass", () => {
    expect(1 + 1).toBe(2);
  });
});

Langkah 5: Mengintegrasikan dengan GitHub Actions

GitHub Actions memungkinkan kita untuk mengotomatisasi proses build, test, dan deployment. Buat folder .github/workflows dan tambahkan file main.yml:

name: CI & CD

on:
  push:
    branches:
      - main
  workflow_dispatch:
  pull_request:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: true

env:
  NODE_VERSION: 22.14.0
  PNPM_VERSION: 10.8.1

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "pnpm"

      - name: Install dependencies
        run: pnpm install

      - name: Run test with coverage
        run: pnpm run coverage

      - name: Upload results to Codecov
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true

      - name: Build
        run: pnpm run build
        env:
          VITE_ASSET_URL: ${{ secrets.VITE_ASSET_URL }}

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./dist

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    runs-on: ubuntu-latest

    needs: test

    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

Secara sederhana, script di atas akan bekerja dengan urutan sebagai berikut.

  1. Saat ada push ke branch main atau pull request dibuat, workflow akan berjalan.
  2. Job test akan:
    • Menginstal PNPM dan Node.js
    • Menginstal dependensi proyek
    • Menjalankan test dengan coverage
    • Mengunggah hasil coverage ke Codecov
    • Mem-build proyek
    • Menyiapkan dan mengunggah hasil build untuk GitHub Pages
  3. Setelah job test selesai, job deploy akan men-deploy hasil build ke GitHub Pages.

Langkah 6: Mengintegrasikan dengan Codecov

Codecov adalah platform yang membantu melacak cakupan kode. Untuk detil tentang cara menghubungkan Codecov dengan repositori GitHub Anda, Anda bisa mengecek artikel yang sudah pernah saya tulis sebelumnya di bawah ini.

Implementasi Code Coverage di GitHub Actions Menggunakan Codecov

Langkah 7: Menambahkan Badge ke README.md

Tambahkan badge GitHub Actions dan Codecov ke file README.md untuk menampilkan status build dan cakupan kode.

# Nama Projek

[![License](https://badgen.net/github/license/username/project "License")](LICENSE.md)
[![Test Status](https://github.com/username/project/actions/workflows/main.yml/badge.svg "Test Status")](https://github.com/username/project/actions/workflows/main.yml)
[![Coverage Status](https://codecov.io/gh/username/project/graph/badge.svg "Coverage Status")](https://codecov.io/gh/username/project)

Deskripsi singkat projek Anda.

Langkah 8: Menambahkan File Test yang Lebih Kompleks

Mari tambahkan contoh kode tentang perhitungan sederhana. Silakan buat file baru di src/utils/calculator.ts seperti contoh di bawah ini.

export function add(a: number, b: number): number {
  return a + b;
}

export function subtract(a: number, b: number): number {
  return a - b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

export function divide(a: number, b: number): number {
  if (b === 0) {
    throw new Error("Division by zero");
  }

  return a / b;
}

Untuk mengecek apakah hasil eksekusi kode di atas sudah sesuai dengan ekspektasi kita atau belum, kita perlu menambahkan unit test baru di tests/utils/calculator.test.ts seperti contoh di bawah ini.

import { describe, it, expect } from "vitest";
import { add, subtract, multiply, divide } from "@/src/utils/calculator";

describe("Calculator", () => {
  describe("add", () => {
    it("should add two positive numbers", () => {
      expect(add(1, 2)).toBe(3);
    });

    it("should add a positive and a negative number", () => {
      expect(add(1, -2)).toBe(-1);
    });
  });

  describe("subtract", () => {
    it("should subtract two positive numbers", () => {
      expect(subtract(3, 2)).toBe(1);
    });

    it("should subtract a negative from a positive number", () => {
      expect(subtract(3, -2)).toBe(5);
    });
  });

  describe("multiply", () => {
    it("should multiply two positive numbers", () => {
      expect(multiply(2, 3)).toBe(6);
    });

    it("should multiply a positive and a negative number", () => {
      expect(multiply(2, -3)).toBe(-6);
    });
  });

  describe("divide", () => {
    it("should divide two positive numbers", () => {
      expect(divide(6, 3)).toBe(2);
    });

    it("should throw an error when dividing by zero", () => {
      expect(() => divide(6, 0)).toThrow("Division by zero");
    });
  });
});

Langkah 9: Menjalankan Test Secara Lokal

Ada 2 opsi yang bisa kita gunakan untuk menjalankan unit test di atas menggunakan Vitest:

  1. Tes biasa.

    pnpm run test

    Hasilnya bisa dilihat pada contoh di bawah ini.

  2. Tes sekaligus dengan analisa code coverage.

    pnpm run coverage

    Hasilnya bisa dilihat pada contoh di bawah ini.

Hasil dari kedua script tersebut baik tes biasa maupun dengan menambahkan opsi code coverage sama-sama berhasil dan menunjukkan jumlah passed yang sama (1 passed). Hanya saja ada tambahan coverage report pada pnpm run coverage.

Langkah 10: Mengupload Projek ke GitHub

Sekarang kita perlu membuat repositori baru di GitHub, menginisialisasi Git di projek lokal Anda, dan mem-push projek tersebut ke GitHub.

git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/username/project.git
git push -u origin main

Silakan ganti https://github.com/username/project.git sesuai remote URL yang sudah anda buat sebelumnya.

Panduan selengkapnya bisa anda cek langsung di dokumentasi resmi GitHub di https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-new-repository.

Berikut ini adalah contoh dari projek yang saya push langsung ke GitHub milik saya sendiri di https://github.com/ngodingbang/rwid-typescript.

https://github.com/ngodingbang/rwid-typescript
https://github.com/ngodingbang/rwid-typescript

Ketika Anda berhasil mem-push projek anda ke GitHub repository, maka script GitHub Actions yang sudah kita tambahkan di .github/workflows/main.yml akan otomatis berjalan seperti contoh di bawah ini.

https://github.com/ngodingbang/rwid-typescript/actions
https://github.com/ngodingbang/rwid-typescript/actions

Jika GitHub Actions berjalan dengan baik, kita bisa melihat job deploy yang difungsikan untuk men-deploy hasil build ke GitHub Pages akan muncul seperti contoh di bawah ini.

https://github.com/ngodingbang/rwid-typescript/actions/runs/14548369259
https://github.com/ngodingbang/rwid-typescript/actions/runs/14548369259
Hasil build yang sudah di-publish di GitHub Pages (https://ngodingbang.my.id/rwid-typescript)
Hasil build yang sudah di-publish di GitHub Pages (https://ngodingbang.my.id/rwid-typescript)

Kesimpulan

Selamat! Anda telah berhasil mengimplementasikan unit testing menggunakan Vitest, mengintegrasikannya dengan Codecov untuk melacak cakupan kode, dan mengotomatisasi proses ini menggunakan GitHub Actions. Dengan konfigurasi ini, setiap kali Anda push ke repositori, kode Anda akan otomatis diuji dan laporan cakupan kode akan diperbarui.

Praktik ini sangat penting dalam pengembangan aplikasi modern, membantu Anda mendeteksi bug lebih awal dan memastikan kualitas kode yang konsisten. Badge di README.md juga memberikan transparansi tentang status projek Anda kepada kontributor dan pengguna.

Konten Terkait