From 6f3dadcb4601a3dd8eaccc014fc25c6e072e7b8d Mon Sep 17 00:00:00 2001 From: crab85193 Date: Wed, 18 Dec 2024 00:10:47 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E9=83=BD=E9=81=93=E5=BA=9C?= =?UTF-8?q?=E7=9C=8C=E9=81=B8=E6=8A=9E=E3=81=A8=E4=BA=BA=E5=8F=A3=E3=83=87?= =?UTF-8?q?=E3=83=BC=E3=82=BF=E8=A1=A8=E7=A4=BA=E6=A9=9F=E8=83=BD=E3=81=AE?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/PopulationSelector.tsx | 80 +++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/components/PopulationSelector.tsx diff --git a/src/components/PopulationSelector.tsx b/src/components/PopulationSelector.tsx new file mode 100644 index 0000000..d0ec13c --- /dev/null +++ b/src/components/PopulationSelector.tsx @@ -0,0 +1,80 @@ +import React, { useState } from "react"; +import { fetchPopulation } from "../api/population"; // 人口データを取得するAPI +import { Prefecture } from "../types/prefecture"; // 都道府県の型 +import { PopulationCategory } from "../types/population"; // 人口データのカテゴリ型 + +interface PopulationSelectorProps { + prefectures: Prefecture[]; +} + +const PopulationSelector: React.FC = ({ + prefectures, +}) => { + const [selectedPrefecture, setSelectedPrefecture] = useState( + null + ); + const [populationData, setPopulationData] = useState< + PopulationCategory[] | null + >(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const handlePrefectureChange = async ( + event: React.ChangeEvent + ) => { + const prefCode = event.target.value; + setSelectedPrefecture(prefCode); + setLoading(true); + setError(null); + + try { + const data = await fetchPopulation(prefCode); + setPopulationData(data); + } catch (error) { + setError("人口データの取得に失敗しました. " + error); + } finally { + setLoading(false); + } + }; + + return ( +
+

人口データ選択

+ + + {loading &&

読み込み中...

} + + {error &&

{error}

} + + {populationData && ( +
+

年別人口データ

+ {populationData.map((category) => ( +
+

{category.label}

+
    + {category.data.map((entry) => ( +
  • + {entry.year}: {entry.value}人 (比率: {entry.rate}%) +
  • + ))} +
+
+ ))} +
+ )} +
+ ); +}; + +export default PopulationSelector; From 7825a2e9f14f24fd592da0d492ca215ee7e5a7d2 Mon Sep 17 00:00:00 2001 From: crab85193 Date: Wed, 18 Dec 2024 00:10:57 +0900 Subject: [PATCH 2/2] =?UTF-8?q?test:=20PopulationSelector=20=E3=82=B3?= =?UTF-8?q?=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=81=AE?= =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tests/PopulationSelector.test.tsx | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/tests/PopulationSelector.test.tsx diff --git a/src/tests/PopulationSelector.test.tsx b/src/tests/PopulationSelector.test.tsx new file mode 100644 index 0000000..cb4ea06 --- /dev/null +++ b/src/tests/PopulationSelector.test.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import PopulationSelector from "./../components/PopulationSelector"; +import { fetchPopulation } from "../api/population"; +import { Prefecture } from "../types/prefecture"; +import { PopulationCategory } from "../types/population"; + +jest.mock("../api/population"); + +describe("PopulationSelector", () => { + const mockPrefectures: Prefecture[] = [ + { prefCode: 1, prefName: "北海道" }, + { prefCode: 2, prefName: "青森県" }, + ]; + + it("都道府県を選択し、人口データが表示される", async () => { + const mockPopulationData: PopulationCategory[] = [ + { + label: "年少人口", + data: [{ year: 1960, value: 1681479, rate: 33.37 }], + }, + ]; + + (fetchPopulation as jest.Mock).mockResolvedValue(mockPopulationData); + + render(); + + fireEvent.change(screen.getByRole("combobox"), { target: { value: "1" } }); + + await waitFor(() => screen.getByText("年少人口")); + + expect(screen.getByText("年少人口")).toBeInTheDocument(); + expect( + screen.getByText("1960: 1681479人 (比率: 33.37%)") + ).toBeInTheDocument(); + }); + + it("人口データの取得中にエラーメッセージが表示される", async () => { + (fetchPopulation as jest.Mock).mockRejectedValue(new Error("API Error")); + + render(); + + fireEvent.change(screen.getByRole("combobox"), { target: { value: "1" } }); + + await waitFor(() => screen.getByText(/人口データの取得に失敗しました/i)); + + expect( + screen.getByText(/人口データの取得に失敗しました/i) + ).toBeInTheDocument(); + }); +});