[QA] #533 언급 적은 식당 제외 필터 — 검증 통과, 회귀 테스트 추가

- 설계서(docs/design/533-min-mentions-filter/README.md) 대비 구현 일치 확인
  (backend RestaurantMapper video_count/min_mentions, frontend 필터 UI)
- dev API 실측: min_mentions 0/1/2/3/5/100 전 구간 경계 위반 0건
  (=2→116개, =3→36개, DISTINCT+서브쿼리 중복 없음, 기존 필터 조합 회귀 없음)
- passesMinMentions()를 lib/filters.ts로 추출(동작 변경 없음)하고
  frontend/__tests__/filters.test.ts 6케이스 추가(경계값/null 처리 등)
- 백엔드 빌드, tsc, 프론트 전체 jest(6 suites, 32 tests) 통과

Refs #533
This commit is contained in:
joungmin
2026-07-27 13:55:41 +09:00
parent c13b976ca3
commit 1815a4c4b2
4 changed files with 72 additions and 1 deletions

View File

@@ -15,6 +15,7 @@ import MyReviewsList from "@/components/MyReviewsList";
import BottomSheet from "@/components/BottomSheet";
import FilterSheet, { FilterOption } from "@/components/FilterSheet";
import { getCuisineIcon, getPhosphorCuisineIcon } from "@/lib/cuisine-icons";
import { passesMinMentions } from "@/lib/filters";
import Icon from "@/components/Icon";
import FoodIcon from "@/components/FoodIcon";
import * as PhosphorIcons from "@phosphor-icons/react";
@@ -249,7 +250,7 @@ export default function Home() {
if (channelFilter && !(r.channels || []).includes(channelFilter)) return false;
if (cuisineFilter && !matchCuisineFilter(r.cuisine_type, cuisineFilter)) return false;
if (priceFilter && !matchPriceGroup(r.price_range, priceFilter)) return false;
if (minMentions > 0 && (r.video_count ?? 0) < minMentions) return false;
if (!passesMinMentions(r.video_count, minMentions)) return false;
if (countryFilter) {
const parsed = parseRegion(r.region);
if (!parsed || parsed.country !== countryFilter) return false;

View File

@@ -0,0 +1,23 @@
// 클라이언트 필터 순수 함수 — #533
// page.tsx 의 filteredRestaurants 에서 사용하는 경계 로직을 테스트 가능하도록 분리.
/**
* "의미있는 언급 수(video_count)" 기준으로 식당을 포함할지 판정한다.
* 설계서: docs/design/533-min-mentions-filter/README.md
*
* - minMentions <= 0(기본값) → 필터 미적용, 항상 true.
* - videoCount 가 null/undefined(미산정) → 0 으로 간주.
* - videoCount >= minMentions 인 경우에만 true (경계값 포함).
*
* 예) passesMinMentions(1, 2) → false (1회는 2회 미만이라 제외)
* passesMinMentions(2, 2) → true (경계값 포함)
* passesMinMentions(null, 2) → false (미산정은 0 취급)
* passesMinMentions(0, 0) → true (필터 미적용)
*/
export function passesMinMentions(
videoCount: number | null | undefined,
minMentions: number
): boolean {
if (minMentions <= 0) return true;
return (videoCount ?? 0) >= minMentions;
}