Skip to content

Commit

Permalink
Merge pull request #5 from crab85193/develop
Browse files Browse the repository at this point in the history
人口データを取得するAPI呼び出し機能と都道府県選択用チェックボックスコンポーネント(PrefectureCheckbox)を追加
  • Loading branch information
crab85193 authored Dec 17, 2024
2 parents febbe2b + bc06e37 commit 544cc24
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 0 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
"setupFiles": [
"dotenv/config"
],
"setupFilesAfterEnv": [
"./src/tests/setupTests.ts"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
Expand Down
32 changes: 32 additions & 0 deletions src/api/population.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import axios from "axios";
import { PopulationCategory, PopulationResponse } from "../types/population";

export const fetchPopulation = async (
prefCode: string
): Promise<PopulationCategory[]> => {
try {
const response = await axios.get<PopulationResponse>(
`${process.env.REACT_APP_YUMEMI_API_URL}/population/${prefCode}`,
{
headers: {
"X-API-KEY": process.env.REACT_APP_YUMEMI_API_KEY!,
},
}
);

if (response.status !== 200) {
throw new Error("Failed to fetch population data");
}

return response.data.result.data.map((category) => ({
label: category.label,
data: category.data.map((dataItem) => ({
year: dataItem.year,
value: dataItem.value,
rate: dataItem.rate,
})),
}));
} catch (error) {
throw new Error("Error fetching population data: " + error);
}
};
47 changes: 47 additions & 0 deletions src/components/PrefectureCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import { Prefecture } from "../types/prefecture";

interface PrefectureCheckboxProps {
prefectures: Prefecture[];
selectedPrefectures: string[];
onSelect: (selected: string[]) => void;
}

const PrefectureCheckbox: React.FC<PrefectureCheckboxProps> = ({
prefectures,
selectedPrefectures,
onSelect,
}) => {
const handleCheckboxChange = (prefCode: string) => {
if (selectedPrefectures.includes(prefCode)) {
onSelect(selectedPrefectures.filter((code) => code !== prefCode));
} else {
onSelect([...selectedPrefectures, prefCode]);
}
};

return (
<div>
<h3>都道府県選択</h3>
{prefectures.map((prefecture) => (
<div key={prefecture.prefCode}>
<input
type="checkbox"
id={prefecture.prefCode.toString()}
checked={selectedPrefectures.includes(
prefecture.prefCode.toString()
)}
onChange={() =>
handleCheckboxChange(prefecture.prefCode.toString())
}
/>
<label htmlFor={prefecture.prefCode.toString()}>
{prefecture.prefName}
</label>
</div>
))}
</div>
);
};

export default PrefectureCheckbox;
54 changes: 54 additions & 0 deletions src/tests/PrefectureCheckbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import PrefectureCheckbox from "./../components/PrefectureCheckbox";
import { Prefecture } from "../types/prefecture";

const mockPrefectures: Prefecture[] = [
{ prefCode: 1, prefName: "北海道" },
{ prefCode: 2, prefName: "青森県" },
];

describe("PrefectureCheckbox", () => {
it("都道府県のチェックボックスを表示する", () => {
render(
<PrefectureCheckbox
prefectures={mockPrefectures}
selectedPrefectures={[]}
onSelect={() => {}}
/>
);

mockPrefectures.forEach((pref) => {
expect(screen.getByLabelText(pref.prefName)).toBeInTheDocument();
});
});

it("チェックボックスをクリックすると選択状態が変更される", () => {
const mockOnSelect = jest.fn();
render(
<PrefectureCheckbox
prefectures={mockPrefectures}
selectedPrefectures={[]}
onSelect={mockOnSelect}
/>
);

const checkbox = screen.getByLabelText("北海道");
fireEvent.click(checkbox);

expect(mockOnSelect).toHaveBeenCalledWith(["1"]);
});

it("選択済みの都道府県のチェックボックスはチェックされている", () => {
render(
<PrefectureCheckbox
prefectures={mockPrefectures}
selectedPrefectures={["1"]}
onSelect={() => {}}
/>
);

expect(screen.getByLabelText("北海道")).toBeChecked();
expect(screen.getByLabelText("青森県")).not.toBeChecked();
});
});
59 changes: 59 additions & 0 deletions src/tests/population.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import axios from "axios";
import { fetchPopulation } from "../api/population";
import { PopulationCategory } from "../types/population";

jest.mock("axios");
const mockedAxios = axios as jest.Mocked<typeof axios>;

describe("fetchPopulation", () => {
it("正常に人口データを取得できる", async () => {
const mockData: PopulationCategory[] = [
{
label: "年少人口",
data: [{ year: 1960, value: 1681479, rate: 33.37 }],
},
];

const mockResponse = {
message: "success",
result: {
boundaryYear: 2020,
data: mockData,
},
};

mockedAxios.get.mockResolvedValue({ status: 200, data: mockResponse });

const prefCode = "1";

const result = await fetchPopulation(prefCode);

expect(result).toEqual(mockData);
expect(mockedAxios.get).toHaveBeenCalledWith(
`${process.env.REACT_APP_YUMEMI_API_URL}/population/${prefCode}`,
{
headers: {
"X-API-KEY": process.env.REACT_APP_YUMEMI_API_KEY!,
},
}
);
});

it("APIがエラーを返した場合、エラーをスローする", async () => {
mockedAxios.get.mockRejectedValue(new Error("API Error"));

const prefCode = "1";

await expect(fetchPopulation(prefCode)).rejects.toThrow(
"Error fetching population data: Error: API Error"
);
expect(mockedAxios.get).toHaveBeenCalledWith(
`${process.env.REACT_APP_YUMEMI_API_URL}/population/${prefCode}`,
{
headers: {
"X-API-KEY": process.env.REACT_APP_YUMEMI_API_KEY!,
},
}
);
});
});
18 changes: 18 additions & 0 deletions src/types/population.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface PopulationData {
year: number;
value: number;
rate: number;
}

export interface PopulationCategory {
label: string;
data: PopulationData[];
}

export interface PopulationResponse {
message: string;
result: {
boundaryYear: number;
data: PopulationCategory[];
};
}

0 comments on commit 544cc24

Please sign in to comment.