Files
tasteby/frontend/__tests__/RestaurantDetail.test.tsx
joungmin fd4ab18fbf [QA] #545 해외 식당 예약 버튼 숨김 — 회귀 테스트 추가 및 검증 통과
RestaurantDetail.tsx의 isKoreaRestaurant() 게이트가 설계서 인수조건과
일치함을 확인. 국내/해외/URL-NONE/좌표없음 fallback 등 5개 경계 케이스를
자동화 RTL 테스트로 검증(수동 육안 QA를 대체). tsc 및 전체 jest 스위트
통과.

Refs #545
2026-07-27 13:50:32 +09:00

118 lines
4.4 KiB
TypeScript

/**
* #545 — 해외 식당 상세에서 테이블링/캐치테이블 예약 버튼 숨김 회귀 테스트.
* 좌표 기반(isKoreaRestaurant) 판정으로 국내/해외 식당에서 버튼 노출 여부가
* 올바르게 갈리는지 검증한다.
*/
import { act, render, screen } from "@testing-library/react";
import RestaurantDetail from "@/components/RestaurantDetail";
import type { Restaurant } from "@/lib/api";
// 컴포넌트 마운트 시 발생하는 비동기 데이터 로딩(영상/리뷰 등)을 플러시해
// act() 경고 없이 안정적으로 렌더 결과를 검증한다.
async function flush() {
await act(async () => {
await Promise.resolve();
});
}
jest.mock("@/lib/api", () => ({
getToken: jest.fn(() => null),
api: {
getRestaurantVideos: jest.fn(() => Promise.resolve([])),
getFavoriteStatus: jest.fn(() => Promise.resolve({ favorited: false })),
getReviews: jest.fn(() =>
Promise.resolve({ reviews: [], avg_rating: null, review_count: 0 })
),
getMemo: jest.fn(() => Promise.resolve(null)),
},
}));
function makeRestaurant(overrides: Partial<Restaurant>): Restaurant {
return {
id: "r1",
name: "테스트 식당",
address: null,
region: null,
latitude: 37.5,
longitude: 127.0,
cuisine_type: null,
price_range: null,
google_place_id: null,
tabling_url: null,
catchtable_url: null,
business_status: null,
rating: null,
rating_count: null,
phone: null,
website: null,
...overrides,
};
}
describe("RestaurantDetail — #545 해외 식당 예약 버튼 숨김", () => {
it("국내 식당(좌표 기반)이면 테이블링/캐치테이블 버튼이 보인다", async () => {
const restaurant = makeRestaurant({
latitude: 37.5665,
longitude: 126.978, // 서울
tabling_url: "https://tabling.example.com/1",
catchtable_url: "https://catchtable.example.com/1",
});
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
await flush();
expect(screen.getByText("테이블링에서 줄서기")).toBeInTheDocument();
expect(screen.getByText("캐치테이블에서 예약하기")).toBeInTheDocument();
});
it("해외 식당(좌표가 KR bbox 밖)이면 두 버튼 모두 숨겨진다 (대표 발견 케이스)", async () => {
const restaurant = makeRestaurant({
latitude: 13.7563,
longitude: 100.5018, // 방콕
tabling_url: "https://tabling.example.com/1",
catchtable_url: "https://catchtable.example.com/1",
});
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
await flush();
expect(screen.queryByText("테이블링에서 줄서기")).not.toBeInTheDocument();
expect(screen.queryByText("캐치테이블에서 예약하기")).not.toBeInTheDocument();
});
it("해외 식당이어도 예약 URL이 없으면 애초에 버튼이 없다 (회귀 없음 확인)", async () => {
const restaurant = makeRestaurant({
latitude: 35.6762,
longitude: 139.6503, // 도쿄
tabling_url: null,
catchtable_url: null,
});
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
await flush();
expect(screen.queryByText("테이블링에서 줄서기")).not.toBeInTheDocument();
expect(screen.queryByText("캐치테이블에서 예약하기")).not.toBeInTheDocument();
});
it("좌표 없는 구 데이터는 region으로 fallback되어 국내로 간주된다 (기존 동작 유지)", async () => {
const restaurant = makeRestaurant({
latitude: undefined as unknown as number,
longitude: undefined as unknown as number,
region: null,
tabling_url: "https://tabling.example.com/1",
catchtable_url: null,
});
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
await flush();
expect(screen.getByText("테이블링에서 줄서기")).toBeInTheDocument();
});
it("예약 URL이 'NONE' 문자열이면 국내 식당이어도 버튼이 없다 (기존 게이트 유지)", async () => {
const restaurant = makeRestaurant({
latitude: 37.5665,
longitude: 126.978,
tabling_url: "NONE",
catchtable_url: "NONE",
});
render(<RestaurantDetail restaurant={restaurant} onClose={() => {}} />);
await flush();
expect(screen.queryByText("테이블링에서 줄서기")).not.toBeInTheDocument();
expect(screen.queryByText("캐치테이블에서 예약하기")).not.toBeInTheDocument();
});
});