Pada artikel series ReactJS Bahasa Indonesia ini Konsep Koding akan berbagi tutorial mengenai unit testing menggunakan RTL (React Testing Library) dan Jest. Sebelum memulai tutorial apa sih itu  Unit Test?

#20 Tutorial ReactJS Unit Test React Testing Library Dan Jest
#20 Tutorial ReactJS Unit Test React Testing Library Dan Jest


Pengujian uni atau Unit Testt adalah proses pengembangan perangkat lunak di mana bagian terkecil yang dapat diuji dari suatu aplikasi, yang disebut unit, diperiksa secara individual dan independen untuk pengoperasian yang tepat.

Tutorial ReactJS Unit Test React Testing Library Dan Jest

Sebelum memulai tutorial ini kita harus membuat project React dulu disini untuk tutorial React Unit test saya akan menggunakan Typescript untuk yang menggunakan Javascript bisa tetap mengikuti hanya perlu menghpaus tipe data pada kode.

Pertmana buat project React baru dengan perintah di bawah ini :

npx create-react-app my-app --template typescript

Setelah itu modifikasi App.tsx menjadi seperti di bawah ini, disini kita akan menggunakan api dari https://api.nationalize.io/?name :

import { useState } from "react";
import "./App.css";

interface PersonData {
  country_id: string;
  probability: number;
}

function App() {
  const [nationalities, setNationalities] = useState<PersonData[]>([]);
  const [message, setMessage] = useState<string>("");
  const [personName, setPersonName] = useState<string>("");

  async function fetchNationalities() {
    try {
      const data = await (
        await fetch(`https://api.nationalize.io/?name=${personName}`)
      ).json();
      const hasCountryData = data.country && data.country.length;
      const nationalities = hasCountryData ? data.country : [];
      setNationalities(nationalities);

      const message = hasCountryData
        ? `${data.country.length} guess(es) found`
        : "No nationality match found";
      setMessage(message);
    } catch (err: any) {
      console.log(`err: ${err.message}`);
      setNationalities([]);
      setMessage("Could not fetch nationalities, try again later.");
    }
  }

  async function handleSubmit(e: any) {
    e.preventDefault();
    await fetchNationalities();
  }

  return (
    <div className="App">
      <header className="App-header">
        <div className="title-form">
          <h2>Check Name's Nationalities percent</h2>
          <div style={{ marginBottom: "20px" }}>
            <form name="nationalities-form" onSubmit={handleSubmit}>
              <input
                name="personName"
                type="text"
                onChange={(e) => setPersonName(e.target.value)}
                value={personName}
                placeholder="Enter a person's name"
              />
              <button onClick={handleSubmit}>Get Nationalities</button>
            </form>
          </div>
        </div>
        <div className="results">
          <div className="message">{message}</div>
          <div className="nationalities">
            {Array.isArray(nationalities) &&
              nationalities.map((nationality) => {
                const flagUrl = `https://flagcdn.com/w160/${nationality.country_id.toLowerCase()}.jpg`;
                const altText = `${nationality.country_id} flag`;
                return (
                  <div key={nationality.country_id}>
                    <h3>
                      {nationality.country_id} -{" "}
                      {(nationality.probability * 100).toFixed(2)}%
                    </h3>{" "}
                    <img
                      src={flagUrl}
                      alt={altText}
                      style={{
                        border: "1px solid black",
                      }}
                    />
                  </div>
                );
              })}
          </div>
        </div>
      </header>
    </div>
  );
}

export default App;


Setelah itu buat mockdata dengan nama file mock.tsx kemudian ketikan kode di bawah ini:

const nameNationalizeResponse = {
  name: "john",
  country: [
    {
      country_id: "US",
      probability: 0.048398225615958565,
    },
    {
      country_id: "IM",
      probability: 0.04438246053773764,
    },
    {
      country_id: "IE",
      probability: 0.042102085396037124,
    },
  ],
};

export default async function mockFetch(url: any): Promise<any> {
  if (url.startsWith("https://api.nationalize.io") && url.includes("john")) {
    return {
      ok: true,
      status: 200,
      json: async () => nameNationalizeResponse,
    };
  }

  throw new Error(`Unhandled request: ${url}`);
}

Terakhir ubah file App.test.tsx dengan kode di bawah ini :

/* eslint-disable testing-library/no-node-access */
import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import App from "./App";
import mockFetch from "./mock";

let windowFetchSpy: any;

beforeEach(() => {
  windowFetchSpy = jest.spyOn(window, "fetch").mockImplementation(mockFetch);
});

afterEach(() => {
  jest.restoreAllMocks();
});

describe("Render app", () => {
  test("renders initial heading and form with elements correctly", () => {
    render(<App />);
    const titleElement = screen.getByText(/Check Name/i);
    expect(titleElement).toBeInTheDocument();
    expect(screen.getByRole("form")).toBeInTheDocument();
    expect(screen.getByRole("textbox")).toBeInTheDocument();
    expect(
      screen.getByRole("button", { name: "Get Nationalities" })
    ).toBeInTheDocument();
  });

  test("should get nationalities for a name", async () => {
    render(<App />);

    //simulate filling up the textbox
    const personNameInput: HTMLInputElement = screen.getByRole("textbox");
    fireEvent.change(personNameInput, { target: { value: "john" } });
    expect(personNameInput.value).toBe("john");

    //click the button
    const getNationalitiesBtn = screen.getByRole("button", {
      name: "Get Nationalities",
    });
    expect(getNationalitiesBtn).not.toBeDisabled();
    userEvent.click(getNationalitiesBtn);

    //verify percent and flag images are displayed
    expect(await screen.findByText("3 guess(es) found")).toBeVisible();

    expect(windowFetchSpy).toHaveBeenCalled();
    expect(windowFetchSpy).toHaveBeenCalledWith(
      "https://api.nationalize.io/?name=john"
    );
    expect(screen.getByText("US - 4.84%")).toBeVisible();
    expect(screen.getByText("IM - 4.44%")).toBeVisible();
    expect(screen.getByText("IE - 4.21%")).toBeVisible();

    const flagImages = screen.getAllByRole("img");
    expect(flagImages).toHaveLength(3);
    expect(flagImages[0]).toHaveAccessibleName("US flag");
    expect(flagImages[1]).toHaveAccessibleName("IM flag");
    expect(flagImages[2]).toHaveAccessibleName("IE flag");
  });

  test("should handle error while getting nationalities for a name", async () => {
    //const consoleLogSpy = jest.spyOn(console, 'log').mockReturnValue(undefined);
    const consoleLogSpy = jest.spyOn(console, "log");

    const { container } = render(<App />);

    const personNameInput: HTMLInputElement = screen.getByRole("textbox");
    fireEvent.change(personNameInput, { target: { value: "error" } });
    expect(personNameInput.value).toBe("error");

    const getNationalitiesBtn = screen.getByRole("button", {
      name: "Get Nationalities",
    });
    expect(getNationalitiesBtn).not.toBeDisabled();
    userEvent.click(getNationalitiesBtn);

    expect(
      await screen.findByText("Could not fetch nationalities, try again later.")
    ).toBeVisible();
    expect(consoleLogSpy).toHaveBeenCalled();
    expect(consoleLogSpy).toHaveBeenCalledWith(
      expect.stringContaining("err: Unhandled request")
    );

    // eslint-disable-next-line testing-library/no-container
    const nationalities = container.getElementsByClassName("nationalities")[0];
    expect(nationalities).toBeEmptyDOMElement();
  });
});

Setelah itu jalankan npm run test maka hasilnya akan seperti gambar di bawah ini:


Sekian tutorial ReactJS unit testing API dengan  React Testing Library Dan Jest, Sekian semoga artikel ReactJS dari Konsep Koding ini dapat bermanfaat dan membantu kamu yang sedang mempelajari ReactJS unit testing api.