STORYBOOK WEB-COMPONENTS UI-DEVELOPMENT FRONTEND COMPONENT-LIBRARY DOCUMENTATION TESTING DEVELOPER-EXPERIENCE WEB-STANDARDS

Storybook.js untuk Web Components: Membangun, Mendokumentasikan, dan Menguji Komponen UI Mandiri

⏱️ 11 menit baca
👨‍💻

Storybook.js untuk Web Components: Membangun, Mendokumentasikan, dan Menguji Komponen UI Mandiri

1. Pendahuluan

Sebagai seorang developer web, kita sering dihadapkan pada tantangan untuk membangun komponen UI yang reusable, maintainable, dan konsisten di berbagai proyek. Terlebih lagi, ketika kita bekerja dalam tim atau di lingkungan design system, dokumentasi yang jelas dan cara untuk menguji setiap state komponen menjadi krusial.

Di sinilah Web Components dan Storybook.js datang sebagai pasangan yang serasi. Web Components menawarkan cara standar untuk membangun komponen UI yang mandiri dan framework-agnostic, sementara Storybook menyediakan isolated development environment untuk mengembangkan, mendokumentasikan, dan menguji komponen-komponen tersebut.

Bayangkan Anda sedang membangun sebuah tombol (<my-button>). Tombol ini mungkin memiliki berbagai state: aktif, nonaktif, loading, dengan ikon, tanpa ikon, dll. Tanpa Storybook, Anda harus menjalankan seluruh aplikasi, menavigasi ke halaman yang relevan, dan memanipulasi state aplikasi hanya untuk melihat bagaimana tombol tersebut berperilaku. Ini tidak efisien dan rentan kesalahan.

Dengan Storybook, Anda bisa melihat semua state tombol Anda dalam satu tempat, berinteraksi dengannya, dan bahkan membagikannya dengan desainer atau product manager tanpa perlu menjalankan aplikasi utama. Artikel ini akan memandu Anda cara mengintegrasikan Storybook.js dengan Web Components Anda, sehingga alur kerja pengembangan UI Anda menjadi jauh lebih efisien dan menyenangkan.

2. Mengapa Web Components dan Storybook Adalah Pasangan Ideal?

Sebelum kita masuk ke praktik, mari kita pahami mengapa kombinasi ini sangat powerful:

📌 Analogi: Jika Web Components adalah bata lego individual yang bisa Anda buat sendiri dengan instruksi perakitan yang jelas, maka Storybook adalah meja kerja khusus dengan lampu sorot dan katalog lengkap di mana Anda bisa merakit dan memamerkan setiap bata lego Anda dalam berbagai bentuk dan warna, tanpa harus membangun seluruh istana lego terlebih dahulu.

3. Setup Awal Storybook untuk Web Components

Mari kita mulai dengan menyiapkan proyek sederhana. Kita akan menggunakan Lit, sebuah library ringan untuk membangun Web Components, karena Lit membuat prosesnya lebih mudah dan menyenangkan.

Pertama, buat proyek baru:

# Buat direktori proyek
mkdir my-web-component-project
cd my-web-component-project

# Inisialisasi npm
npm init -y

# Install Lit
npm install lit

Sekarang, mari kita instal Storybook. Storybook memiliki preset untuk Web Components, yang akan mempermudah konfigurasi awal.

npx storybook@latest init --type web-components

Perintah di atas akan:

Setelah instalasi selesai, Anda bisa menjalankan Storybook dengan:

npm run storybook

Ini akan membuka Storybook di browser Anda (biasanya http://localhost:6006). Anda akan melihat contoh komponen yang sudah dibuatkan oleh Storybook.

4. Menulis Stories Pertama Anda untuk Komponen Kustom

Sekarang, mari kita buat Web Component kita sendiri dan tulis stories untuknya. Kita akan membuat komponen tombol sederhana.

src/components/my-button.js:

import { LitElement, html, css } from 'lit';

export class MyButton extends LitElement {
  static properties = {
    label: { type: String },
    variant: { type: String }, // primary, secondary, danger
    disabled: { type: Boolean },
  };

  static styles = css`
    :host {
      display: inline-block;
    }
    button {
      padding: 10px 20px;
      border: none;
      border-radius: 4px;
      font-size: 16px;
      cursor: pointer;
      transition: background-color 0.2s ease;
    }
    button:hover {
      opacity: 0.9;
    }
    button:disabled {
      opacity: 0.6;
      cursor: not-allowed;
    }

    /* Variants */
    .primary {
      background-color: #007bff;
      color: white;
    }
    .secondary {
      background-color: #6c757d;
      color: white;
    }
    .danger {
      background-color: #dc3545;
      color: white;
    }
  `;

  constructor() {
    super();
    this.label = 'Click Me';
    this.variant = 'primary';
    this.disabled = false;
  }

  render() {
    return html`
      <button class="${this.variant}" ?disabled="${this.disabled}">
        ${this.label}
      </button>
    `;
  }
}

customElements.define('my-button', MyButton);

Sekarang, mari kita buat story untuk komponen <my-button> ini.

src/components/my-button.stories.js:

import { html } from 'lit';
import '../components/my-button.js'; // Import komponen kita

// Metadata tentang komponen kita
export default {
  title: 'Components/MyButton', // Nama di Storybook UI
  component: 'my-button', // Nama tag Web Component kita
  parameters: {
    layout: 'centered', // Untuk menempatkan komponen di tengah kanvas Storybook
  },
  // Definisi argumen (props) yang bisa diubah di Storybook UI
  argTypes: {
    label: { control: 'text', description: 'Teks yang ditampilkan pada tombol.' },
    variant: {
      control: 'select',
      options: ['primary', 'secondary', 'danger'],
      description: 'Gaya visual tombol.',
    },
    disabled: { control: 'boolean', description: 'Menentukan apakah tombol dinonaktifkan.' },
    onClick: { action: 'clicked', description: 'Event handler saat tombol diklik.' },
  },
};

// Template dasar untuk Story kita
const Template = ({ label, variant, disabled, onClick }) =>
  html`<my-button
    .label="${label}"
    .variant="${variant}"
    ?disabled="${disabled}"
    @click="${onClick}"
  ></my-button>`;

// Definisi Stories
export const Primary = Template.bind({});
Primary.args = {
  label: 'Primary Button',
  variant: 'primary',
};

export const Secondary = Template.bind({});
Secondary.args = {
  label: 'Secondary Button',
  variant: 'secondary',
};

export const Danger = Template.bind({});
Danger.args = {
  label: 'Danger Button',
  variant: 'danger',
};

export const Disabled = Template.bind({});
Disabled.args = {
  label: 'Disabled Button',
  disabled: true,
};

export const WithCustomLabel = Template.bind({});
WithCustomLabel.args = {
  label: 'Kirim Data',
  variant: 'primary',
};

💡 Tips Penting:

Setelah Anda menyimpan file ini dan Storybook berjalan, Anda akan melihat MyButton di sidebar. Klik di sana, dan Anda akan melihat semua stories yang telah Anda definisikan, lengkap dengan kontrol interaktif!

5. Dokumentasi Otomatis dan Interaktif

Salah satu fitur terbaik Storybook adalah kemampuannya untuk menghasilkan dokumentasi komponen secara otomatis. Dengan addon Docs, setiap story Anda tidak hanya menampilkan komponen, tetapi juga cuplikan kode, tabel properti (berdasarkan argTypes), dan ruang untuk menambahkan deskripsi Markdown.

Anda tidak perlu melakukan konfigurasi tambahan jika Anda menggunakan npx storybook@latest init. Addon Docs sudah terinstal dan terkonfigurasi secara default.

Manfaat Dokumentasi Otomatis:

Untuk melihat dokumentasi, di Storybook UI, navigasikan ke komponen MyButton, lalu klik tab “Docs”. Anda akan melihat detail setiap story, properti yang tersedia, dan contoh penggunaan.

6. Menguji Komponen dengan Play Function

Storybook tidak hanya untuk pengembangan dan dokumentasi, tetapi juga untuk pengujian! Dengan play function dan addon @storybook/addon-interactions, Anda bisa menulis skenario pengujian interaksi langsung di Storybook. Ini memungkinkan Anda untuk memverifikasi perilaku komponen secara otomatis di berbagai state.

Mari kita tambahkan play function ke salah satu story tombol kita.

Pertama, pastikan Anda memiliki @storybook/addon-interactions dan @storybook/test terinstal. Jika Anda menggunakan npx storybook@latest init, ini seharusnya sudah ada.

// src/components/my-button.stories.js (lanjutan)
import { html } from 'lit';
import { userEvent, within } from '@storybook/test'; // Import untuk pengujian interaksi
import '../components/my-button.js';

// ... (metadata dan Template yang sudah ada) ...

export const InteractivePrimary = Template.bind({});
InteractivePrimary.args = {
  label: 'Interactive Button',
  variant: 'primary',
};

InteractivePrimary.play = async ({ canvasElement, args }) => {
  const canvas = within(canvasElement);
  const button = canvas.getByRole('button');

  // Simulasi klik tombol
  await userEvent.click(button);

  // Verifikasi bahwa event onClick telah dipanggil
  // args.onClick adalah action mock yang didefinisikan di argTypes
  await expect(args.onClick).toHaveBeenCalled();

  // Verifikasi bahwa tombol tidak disabled
  await expect(button).not.toBeDisabled();
};

export const DisabledInteraction = Template.bind({});
DisabledInteraction.args = {
  label: 'Disabled Button',
  disabled: true,
  variant: 'secondary',
};

DisabledInteraction.play = async ({ canvasElement, args }) => {
  const canvas = within(canvasElement);
  const button = canvas.getByRole('button');

  // Coba klik tombol yang disabled
  await userEvent.click(button);

  // Verifikasi bahwa event onClick TIDAK dipanggil
  await expect(args.onClick).not.toHaveBeenCalled();

  // Verifikasi bahwa tombol memang disabled
  await expect(button).toBeDisabled();
};

Ketika Anda melihat story InteractivePrimary atau DisabledInteraction di Storybook, Anda akan melihat indikator “Play” dan proses pengujian akan dijalankan secara otomatis. Jika ada kegagalan, Anda akan melihat pesan error. Ini sangat berguna untuk:

🎯 Target: Memastikan bahwa komponen UI Anda tidak hanya terlihat benar, tetapi juga berperilaku sesuai harapan di berbagai skenario interaksi.

7. Tips dan Best Practices untuk Alur Kerja yang Optimal

Untuk memaksimalkan penggunaan Storybook dengan Web Components Anda, pertimbangkan tips berikut:

Kesimpulan

Mengintegrasikan Storybook.js dengan Web Components adalah strategi yang sangat efektif untuk membangun, mendokumentasikan, dan menguji komponen UI yang robust dan reusable. Anda tidak hanya akan mempercepat proses pengembangan, tetapi juga meningkatkan kualitas kode, konsistensi UI, dan kolaborasi dalam tim. Dengan isolasi yang ditawarkan Storybook, Anda bisa fokus pada satu komponen pada satu waktu, memastikan setiap state dan interaksi berfungsi dengan sempurna sebelum diintegrasikan ke dalam aplikasi yang lebih besar.

Jadi, tunggu apa lagi? Mulailah petualangan Anda dengan Storybook dan Web Components, dan rasakan sendiri perbedaannya dalam alur kerja pengembangan UI Anda!

🔗 Baca Juga