diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d7dcec..fcc8380 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,9 +7,23 @@ on: branches: ["main"] jobs: + create-envfile: + runs-on: ubuntu-latest + steps: + - name: Make envfile + uses: SpicyPizza/create-envfile@v2.0 + with: + envkey_REACT_APP_YUMEMI_API_URL: ${{ secrets.YUMEMI_API_URL }} + envkey_REACT_APP_YUMEMI_API_KEY: ${{ secrets.YUMEMI_API_KEY }} + directory: ./ + file_name: .env + fail_on_empty: false + sort_keys: false + build: name: build runs-on: ubuntu-latest + needs: create-envfile steps: - uses: actions/checkout@v3 - name: yarn install diff --git a/.github/workflows/deploy-ph-pages.yml b/.github/workflows/deploy-ph-pages.yml index 42eaef9..aaa8178 100644 --- a/.github/workflows/deploy-ph-pages.yml +++ b/.github/workflows/deploy-ph-pages.yml @@ -22,9 +22,10 @@ jobs: - name: Make envfile uses: SpicyPizza/create-envfile@v2.0 with: + envkey_REACT_APP_YUMEMI_API_URL: ${{ secrets.YUMEMI_API_URL }} envkey_REACT_APP_YUMEMI_API_KEY: ${{ secrets.YUMEMI_API_KEY }} directory: ./ - file_name: .env.production + file_name: .env fail_on_empty: false sort_keys: false diff --git a/.gitignore b/.gitignore index 4d29575..8692cf6 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/package.json b/package.json index bcbca48..718f5c3 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@types/node": "^16.7.13", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "axios": "^1.7.9", "jest": "^29.7.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -47,6 +48,7 @@ "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@eslint/js": "^9.16.0", "@testing-library/dom": "^10.4.0", + "dotenv": "^16.4.7", "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-config-react": "^1.1.7", @@ -60,6 +62,9 @@ "typescript-eslint": "^8.18.0" }, "jest": { + "setupFiles": [ + "dotenv/config" + ], "transform": { "^.+\\.tsx?$": "ts-jest" }, diff --git a/src/api/prefectures.ts b/src/api/prefectures.ts new file mode 100644 index 0000000..66061b6 --- /dev/null +++ b/src/api/prefectures.ts @@ -0,0 +1,23 @@ +import axios from "axios"; +import { Prefecture } from "../types/prefecture"; + +export const fetchPrefectures = async (): Promise => { + try { + const response = await axios.get( + `${process.env.REACT_APP_YUMEMI_API_URL}/prefectures`, + { + headers: { + "X-API-KEY": process.env.REACT_APP_YUMEMI_API_KEY!, + }, + } + ); + + if (response.status !== 200) { + throw new Error("Failed to fetch prefectures"); + } + + return response.data as Prefecture[]; + } catch (error) { + throw new Error("Error fetching prefectures: " + error); + } +}; diff --git a/src/tests/prefectures.test.ts b/src/tests/prefectures.test.ts new file mode 100644 index 0000000..f7fb20a --- /dev/null +++ b/src/tests/prefectures.test.ts @@ -0,0 +1,44 @@ +import axios from "axios"; +import { fetchPrefectures } from "./../api/prefectures"; +import { Prefecture } from "../types/prefecture"; + +jest.mock("axios"); +const mockedAxios = axios as jest.Mocked; + +describe("fetchPrefectures", () => { + it("正常に都道府県データを取得できる", async () => { + const mockData: Prefecture[] = [ + { prefCode: 1, prefName: "北海道" }, + { prefCode: 2, prefName: "青森県" }, + { prefCode: 3, prefName: "宮城県" }, + ]; + + mockedAxios.get.mockResolvedValue({ status: 200, data: mockData }); + + const result = await fetchPrefectures(); + + expect(result).toEqual(mockData); + expect(mockedAxios.get).toHaveBeenCalledWith( + `${process.env.REACT_APP_YUMEMI_API_URL}/prefectures`, + { + headers: { + "X-API-KEY": process.env.REACT_APP_YUMEMI_API_KEY!, + }, + } + ); + }); + + it("APIがエラーを返した場合、エラーをスローする", async () => { + mockedAxios.get.mockRejectedValue(new Error("API Error")); + + await expect(fetchPrefectures()).rejects.toThrow("API Error"); + expect(mockedAxios.get).toHaveBeenCalledWith( + `${process.env.REACT_APP_YUMEMI_API_URL}/prefectures`, + { + headers: { + "X-API-KEY": process.env.REACT_APP_YUMEMI_API_KEY!, + }, + } + ); + }); +}); diff --git a/src/types/prefecture.ts b/src/types/prefecture.ts new file mode 100644 index 0000000..2778524 --- /dev/null +++ b/src/types/prefecture.ts @@ -0,0 +1,4 @@ +export interface Prefecture { + prefCode: number; + prefName: string; +} diff --git a/yarn.lock b/yarn.lock index eb9691d..0b6ec53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3147,6 +3147,15 @@ axe-core@^4.10.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df" integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== +axios@^1.7.9: + version "1.7.9" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" + integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" @@ -4369,6 +4378,11 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +dotenv@^16.4.7: + version "16.4.7" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" + integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== + dunder-proto@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.0.tgz#c2fce098b3c8f8899554905f4377b6d85dabaa80" @@ -5242,7 +5256,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -8708,6 +8722,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.15.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6"