[QA] #545 해외 식당 예약 버튼 숨김 — 회귀 테스트 추가 및 검증 통과
RestaurantDetail.tsx의 isKoreaRestaurant() 게이트가 설계서 인수조건과 일치함을 확인. 국내/해외/URL-NONE/좌표없음 fallback 등 5개 경계 케이스를 자동화 RTL 테스트로 검증(수동 육안 QA를 대체). tsc 및 전체 jest 스위트 통과. Refs #545
This commit is contained in:
117
frontend/__tests__/RestaurantDetail.test.tsx
Normal file
117
frontend/__tests__/RestaurantDetail.test.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* #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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user