본문으로 바로가기
Devpeon
Dev.peon · 개발노동자
Engineering

AI 코드 리뷰 · 프론트엔드 · Agent Skill · React Testing Library

AI 프론트엔드 코드 리뷰 Skill: 결함을 행동 테스트로 연결하는 법

AI 프론트엔드 코드 리뷰를 취향 지적이 아닌 재현 가능한 결함으로 바꾸는 방법을 살펴봅니다. 리뷰 범위, 심각도, 행동 소유자, React 테스트까지 공개 자료로 분석합니다.

1. AI 프론트엔드 코드 리뷰가 취향 목록이 되는 이유

AI 프론트엔드 코드 리뷰를 요청했는데 useMemo나 폴더 이름 같은 취향 지적만 늘고, 저장 실패나 키보드 접근성 같은 실제 회귀는 놓친 경험이 있을 겁니다. 문제는 모델이 할 말이 부족해서가 아니라, 리뷰 범위와 결함으로 인정할 증거 기준이 없다는 데 있습니다.

이 글은 특정 오픈소스의 코드 리뷰 Skill과 테스트 Skill을 따라가며, diff에서 행동 소유자를 찾고 재현 가능한 finding을 확정한 뒤 React 행동 테스트로 보호하는 과정을 설명합니다. 글을 읽고 나면 팀이 반복해서 놓치는 프론트엔드 회귀를 같은 판단 절차로 바꾸는 방법까지 적용할 수 있습니다.

여기서 Skill은 해당 제품에 내장된 코드 리뷰 기능이 아닙니다. 특정 오픈소스에 기여하는 AI 코딩 에이전트가 읽는 작업 절차입니다. 공개 파일만으로 모든 PR에서 이 Skill이 자동 실행된다고 볼 근거도 없습니다. 핵심은 자동화 횟수가 아니라, 사람이 리뷰를 요청했을 때 AI가 같은 순서와 증거 기준으로 판단하도록 만든 구조에 있습니다.

본문에서는 프로젝트명을 특정 오픈소스라는 가명으로 부르고, 인용 블록의 프로젝트 고유 식별자도 일반 placeholder로 치환했습니다. 실제 프로젝트와 원문 링크, 분석 기준은 마지막 출처 섹션에만 정리했으며 공개 저장소에서 알 수 없는 실제 사용 횟수나 결함 감소율은 추정하지 않습니다.

2. Skill은 언제 실행해야 하는가

특정 오픈소스의 web/AGENTS.mdweb/ 아래 변경에 적용하도록 배치된 지역 지침입니다. 이 파일은 테스트 정책의 소유자와 Skill을 불러야 하는 조건을 짧게 연결합니다.

편집 발췌 1: 특정 오픈소스, web/AGENTS.md, L1-L14. 프로젝트 식별자를 치환했습니다.

원문 발췌공개 지침 · 편집 발췌
## Frontend Workflow- Read `docs/test.md` only for frontend test work and `docs/lint.md` only when running or changing static checks.- Use the repo-local `how-to-write-component` skill when implementation requires component ownership, state, data-flow, effect, or interaction-boundary decisions. Do not load it for test-only, copy-only, or styling-only changes.- Use `frontend-code-review` only for explicit frontend review or audit requests, including test reviews. Use `frontend-testing` when writing or changing Vitest or React Testing Library tests.

구현, 리뷰, 테스트는 서로 다른 의도입니다. 기능 구현만 요청했는데 긴 리뷰를 덧붙이거나, 코드 리뷰만 요청했는데 파일부터 수정하면 사용자는 현재 단계와 변경 권한을 잃습니다. 특정 오픈소스는 명시적인 리뷰·감사 요청에서만 리뷰 Skill을 사용하고, Vitest나 React Testing Library 테스트를 작성하거나 바꿀 때만 테스트 Skill을 사용합니다.

리뷰 Skill의 frontmatter는 입력 범위도 세 가지로 한정합니다.

  • 현재 작업 중인 변경 전체를 보는 pending-change review
  • 특정 파일과 판단에 필요한 주변 코드만 보는 file-focused review
  • 대화에 붙인 diff 안에서 판단하는 pasted-diff review

따라서 “Skill을 사용한다”는 말은 거대한 체크리스트를 항상 펼친다는 뜻이 아닙니다. 작업 의도를 분류하고, 허용된 범위 안에서 필요한 절차를 선택한다는 뜻에 가깝습니다.

3. diff에서 행동 소유자로 리뷰 범위를 넓히는 법

frontend-code-review/SKILL.md의 첫 부분에는 리뷰 대상을 넓혀 가는 순서와 문제로 인정할 조건이 함께 적혀 있습니다.

편집 발췌 2: 특정 오픈소스, .agents/skills/frontend-code-review/SKILL.md, L1-L19. 프로젝트 식별자를 치환했습니다.

원문 발췌공개 Skill · 편집 발췌
---name: frontend-code-reviewdescription: Use only when the user explicitly requests a review or audit of frontend code under `web/` or `packages/[project-ui]/`. Supports pending-change, file-focused, and pasted-diff reviews. Do not use for implementation-only requests, diagnosis without review intent, or backend-only code.---# Frontend Code ReviewReview the requested scope for concrete, reproducible regressions.## Evidence First1. Establish the review scope from the requested files or current diff.2. Read the changed lines, their behavior owner, and the nearest scoped `AGENTS.md`.3. Trace public consumers, generated contracts, primitive APIs, or runtime configuration only when they decide correctness.4. Report only findings tied to an observable failure, violated contract, security boundary, or demonstrated maintenance risk.

첫 단계는 저장소 전체 탐색이 아니라 요청한 파일이나 diff로 범위를 고정하는 일입니다. 그다음 바뀐 줄에서 멈추지 않고 해당 행동을 실제로 소유한 컴포넌트, hook, query까지 읽습니다. 공용 UI primitive, 생성된 API 계약, 다른 소비자나 런타임 설정은 문제 여부를 결정할 때만 따라갑니다.

예를 들어 저장 버튼의 아이콘만 바뀌었다면 데이터 계층 전체를 읽을 이유가 없습니다. 반대로 mutation의 오류 처리까지 바뀌었다면 버튼 JSX만 보고 제출 상태가 복구되는지 판단할 수 없습니다. 이 경우에만 query와 오류 경계로 범위를 넓힙니다.

Skill은 변경의 단서에 따라 reference를 선택합니다. DOM 의미·키보드·포커스는 accessibility-ui.md, 생성 client·mutation·URL 상태는 data-query-contracts.md, 실제 비용이 확인된 waterfall·bundle·render 문제는 performance.md를 읽습니다. 편집 발췌 2가 연결한 Rule Routing은 “diff와 맞는 pack만 읽는다”는 원칙을 명시합니다.

이 구조는 컨텍스트를 무조건 줄이기 위한 장치가 아닙니다. 현재 결함을 판정하는 데 필요한 근거는 따라가되, 관계없는 규칙이 리뷰의 우선순위를 흐리지 않게 만드는 장치입니다.

4. 재현 가능한 결함과 심각도 판정 기준

특정 오픈소스의 리뷰 Skill은 문제의 종류보다 실패의 영향을 기준으로 심각도를 정합니다. 편집 발췌 2가 연결한 Severity And Output은 다음 경계를 둡니다.

  • P0: 보안·개인정보 유출, 데이터 손실, 프로덕션 중단, 핵심 흐름의 접근 불가
  • P1: 사용자에게 보이는 회귀, API·권한 계약 위반, hydration 실패, 핵심 상호작용 파손
  • P2: 잘못된 동작으로 이어질 가능성이 구체적인 유지보수·성능·테스트·접근성 결함
  • P3: 작지만 실행 가능한 정리. 철저한 감사를 요청하지 않았다면 생략

같은 키보드 문제라도 보조 설명을 열지 못하는 경우와 계정 복구를 완료하지 못하는 경우의 영향은 다릅니다. useMemo가 없다는 사실만으로 성능 결함이 되지도 않습니다. 특정 오픈소스의 성능 reference는 이 기준을 한 문장으로 고정합니다.

편집 발췌 3: 특정 오픈소스, .agents/skills/frontend-code-review/references/performance.md, L1-L15.

원문 발췌공개 Skill · 편집 발췌
Review performance only where there is realistic impact. Do not request `memo`, `useMemo`, `useCallback`, virtualization, or caching as style preferences.

서로 독립적인 요청을 순서대로 기다려 실제 지연을 만들거나, 드물게 여는 대형 편집기를 첫 화면 bundle에 넣는다면 영향 경로를 설명할 수 있습니다. 단순한 계산을 memoize하지 않았다는 사실은 그 자체로 사용자 실패가 아닙니다.

접근성도 마감 단계의 장식이 아니라 correctness로 취급합니다. accessibility-ui.md는 키보드 접근 불가, accessible name 누락, 포커스 손실, 닿을 수 없는 popup을 실제 결함으로 봅니다. 다만 자동화된 semantic query가 전체 접근성 준수를 증명하는 것은 아니므로 브라우저와 보조 기술 검증이 남을 수 있습니다.

확정된 finding에는 좁은 파일·줄, 재현 조건이나 깨진 계약, 영향, 수정 방향이 들어갑니다. 문제가 없다면 No issues found.라고 쓰고 브라우저·시각·E2E처럼 실행하지 못한 중요한 검증을 따로 남깁니다. 의심을 많이 나열하는 것보다 다른 개발자가 같은 실패를 재현할 수 있는지가 기준입니다.

5. 저장 실패 사례로 리뷰 흐름 따라가기

아래 예시는 특정 오픈소스의 원본 코드가 아니라 앞의 공개 규칙을 설명하기 위해 재구성한 React 사례입니다.

코드 예시React · TSX
<div onClick={handleSave}>  <SaveIcon /></div>

마우스로는 저장할 수 있지만 이 요소에는 버튼의 의미와 키보드 동작, accessible name이 없습니다. 여기에 저장 요청이 실패한 뒤 isSubmitting을 해제하지 않는 코드가 함께 바뀌었다고 가정하면, 사용자는 오류를 본 뒤 다시 저장할 수도 없습니다.

이때 근거 중심 리뷰는 다음처럼 좁혀집니다.

코드 예시실행 흐름
[P1] 저장 실패 후 사용자가 다시 시도할 수 없습니다.위치: SettingsDialog.tsx의 제출 완료 처리재현: 저장 요청이 reject되도록 한 뒤 다시 저장 버튼을 찾습니다.영향: 오류 안내 뒤 제출 상태가 남아 핵심 설정 흐름이 막힙니다.수정 방향: 요청의 성공·실패 공통 완료 경계에서 제출 상태를 복구하고,실제 button 요소와 접근 가능한 이름을 사용하세요.

P1은 이 예시에서 저장이 핵심 사용자 흐름이라는 가정에 따른 등급입니다. 부가 기능이라면 영향에 따라 달라질 수 있습니다. 중요한 부분은 “상태 관리가 아쉽다”가 아니라 실패 조건과 사용자가 막히는 경로가 있다는 점입니다.

수정 역시 HTML 취향이 아니라 계약 복구로 설명할 수 있습니다.

코드 예시React · TSX
<button type="button" aria-label="저장" onClick={handleSave}>  <SaveIcon aria-hidden="true" /></button>

이 변경만으로 비동기 상태 복구가 해결되지는 않습니다. DOM 의미와 mutation 완료 처리는 서로 다른 행동 소유자이므로 각각 확인해야 합니다. 하나의 눈에 띄는 수정으로 전체 finding을 해결했다고 단정하지 않는 것도 증거 중심 리뷰의 일부입니다.

6. finding을 React 행동 테스트로 연결하기

리뷰는 결함을 확정하는 단계이고, 테스트는 보호할 행동과 경계를 선택하는 단계입니다. 특정 오픈소스는 둘을 한 문서에 섞지 않습니다.

편집 발췌 4: 특정 오픈소스, .agents/skills/frontend-testing/SKILL.md, L1-L16. 프로젝트 식별자를 치환했습니다.

원문 발췌공개 Skill · 편집 발췌
---name: frontend-testingdescription: Use when writing or changing Vitest or React Testing Library tests under `web/` or `packages/[project-ui]/`, or when the user explicitly requests frontend test strategy, including evaluation of an existing strategy. Do not use for frontend code-review-only requests, general testability discussion, Python tests, or Cucumber/Playwright E2E.---`web/docs/test.md` is the single policy owner. Read it before changing frontend tests; this skill adds no separate requirements.1. Identify the observable contract and regression risk.2. Choose the smallest boundary that includes the behavior owner.3. Establish the failing case first when practical, then implement one coherent scenario.4. Run the focused spec before the affected suite and relevant static checks.5. Report the behavior verified and any remaining browser, visual, or end-to-end risk.

저장 실패 사례의 observable contract는 “요청이 실패해도 오류를 알리고 다시 저장할 수 있다”입니다. 가장 작은 경계는 제출 상태를 소유한 실제 dialog를 포함해야 합니다. dialog 자체를 mock하면 검증할 행동까지 사라지므로, 현재 계약 바깥에 있는 네트워크 응답만 실패시키는 편이 맞습니다.

다음 테스트 역시 특정 오픈소스의 원본이 아니라 정책을 적용한 재구성 예시입니다.

코드 예시React · TSX
it("저장 실패 후 다시 시도할 수 있다", async () => {  const user = userEvent.setup();  vi.mocked(saveSettings).mockRejectedValueOnce(new Error("save failed"));  render(<SettingsDialog />);  await user.click(screen.getByRole("button", { name: "저장" }));  expect(await screen.findByRole("alert")).toHaveTextContent(    "저장하지 못했습니다",  );  expect(screen.getByRole("button", { name: "저장" })).toBeEnabled();});

이 테스트는 내부의 isSubmitting 값을 읽지 않습니다. 사용자가 오류를 확인하고 다시 행동할 수 있는지를 검증합니다. 구현이 reducer나 query mutation으로 바뀌더라도 공개 행동이 같으면 테스트의 의미가 유지됩니다. 특정 오픈소스의 테스트 정책도 행동 소유자를 포함하는 가장 작은 경계와 구현이 아닌 관찰 가능한 결과를 요구합니다.

7. 테스트 커버리지보다 사용자 행동 계약을 우선하는 이유

기존 코드베이스에서 테스트를 늘리기 시작하면 숫자를 목표로 삼기 쉽습니다. 그러나 특정 오픈소스의 현재 정책은 반대로 적혀 있습니다.

편집 발췌 5: 특정 오픈소스, web/docs/test.md, L27-L44.

원문 발췌공개 지침 · 편집 발췌
### CoverageCoverage is a diagnostic signal, not a quality target. This guide defines no required percentage and reviewers should not request tests solely to increase coverage. Use a report to find suspicious gaps, then decide whether each gap represents a product risk worth protecting.## Choose the Right BoundaryUse the smallest boundary that includes the behavior owner and proves the product contract without coupling the test to implementation.

coverage는 실행되지 않은 경로를 찾는 단서일 뿐 합격선이 아닙니다. 존재하는 모든 component와 branch에 테스트를 하나씩 붙이면 내부 구조를 반복하는 저가치 테스트가 늘 수 있습니다. 반대로 오류 복구, 권한, URL 상태, 키보드 흐름처럼 실제 사용자가 도달할 수 있는 계약은 파일 수가 적어도 우선순위가 높습니다.

테스트 환경의 경계도 구분해야 합니다. 특정 오픈소스의 web/ 테스트는 happy-dom에서 실행되고, 공용 UI 패키지는 실제 Chromium을 쓰는 Vitest Browser Mode와 Storybook 테스트를 별도로 둡니다. web-tests.yml은 웹 테스트를 네 shard로 나누고 공용 UI의 브라우저·Storybook 검증을 별도 job으로 실행합니다.

Browser Mode가 실제 브라우저를 사용해도 로그인, API, 저장소까지 연결된 E2E를 자동으로 증명하지는 않습니다. layout, focus, animation처럼 happy-dom이 충실히 표현하지 못하는 위험은 브라우저로 올리고, 전체 사용자 여정은 Cucumber/Playwright E2E로 넘깁니다. 실행하지 않은 단계는 “테스트 통과”에 포함하지 않고 검증 공백으로 보고해야 합니다.

8. 요청문에 범위·수정 권한·검증 수준을 쓰는 법

아래 요청문은 특정 오픈소스의 원문이 아니라 공개 Skill의 입력·출력 계약을 적용해 재구성한 예시입니다.

코드 예시실행 흐름
frontend-code-review Skill을 사용해 web/의 현재 변경을 리뷰해 주세요.- 변경된 행동과 그 행동 소유자까지만 추적해 주세요.- 재현 가능한 P0~P2 문제를 먼저 보고하고 아직 수정하지 마세요.- 각 finding에 파일·줄, 재현 조건이나 깨진 계약, 영향, 수정 방향을 적어 주세요.- 문법 취향, 근거 없는 성능 추측, coverage 숫자만으로 만든 지적은 제외해 주세요.- 문제가 없으면 No issues found.와 실행하지 못한 검증을 알려 주세요.finding을 확인한 뒤 수정까지 진행하게 되면 frontend-testing Skill을 사용해가능한 경우 실패 테스트를 먼저 만들고, focused spec → affected suite →관련 정적 검사 순서로 실행해 주세요. 브라우저·시각·E2E 위험은 별도로 남겨 주세요.

특정 파일만 리뷰하려면 첫 줄에 경로를 쓰고, 붙여 넣은 diff라면 그 범위 밖의 위치를 확정할 수 없다는 한계를 적으면 됩니다. 중요한 것은 Skill 이름보다 다음 네 가지입니다.

  1. 범위: 현재 diff, 특정 파일, 붙여 넣은 코드 중 무엇을 보는가
  2. 판정 기준: 어떤 실패나 계약 위반을 finding으로 인정하는가
  3. 변경 권한: 리뷰만 하는가, finding 확인 뒤 수정하는가
  4. 검증 수준: 어떤 테스트를 실행했고 무엇이 남았는가

사용 중인 에이전트가 저장소의 Skill 형식을 발견하고 읽을 수 있어야 이 절차가 자동으로 적용됩니다. 지원 여부가 불분명하면 SKILL.md 경로와 원하는 범위를 요청문에 직접 적는 편이 안전합니다.

9. 팀용 프론트엔드 리뷰 Skill 만드는 순서

저장소 전체에서 AGENTS.md·Skill·Hook·CI의 역할을 나누는 방법은 AGENTS.md 작성법: AI 코딩을 위한 프로젝트 문서 설계에서 별도로 다룹니다. 여기서는 프론트엔드 리뷰와 행동 테스트의 판단 절차에 집중합니다.

특정 오픈소스의 규칙을 그대로 복사하기 전에 우리 팀이 반복해서 놓치는 실패를 찾아야 합니다. 생성 API client 대신 수동 fetch를 추가하거나, 저장 오류 뒤 버튼이 잠기거나, dialog가 닫힌 뒤 포커스를 잃는 문제처럼 실제 회귀에서 출발하는 편이 좋습니다.

최소 구조는 다음 정도면 충분합니다.

코드 예시실행 흐름
AGENTS.md  저장소 공통 명령과 우선순위apps/web/AGENTS.md  프론트엔드 경계와 Skill 사용 조건.agents/skills/frontend-code-review/SKILL.md  범위 → 증거 → 심각도 → 출력 절차.agents/skills/frontend-code-review/references/  접근성·데이터·성능처럼 변경에 따라 선택할 규칙apps/web/docs/test.md  테스트 정책의 단일 원본

적용 순서는 다음과 같습니다.

  1. 최근 코드 리뷰에서 반복된 실제 사용자 실패 세 가지를 고릅니다.
  2. 루트와 프론트엔드 AGENTS.md에 항상 지킬 경계와 실행 명령을 둡니다.
  3. SKILL.md에는 언제 실행할지, 어디까지 읽을지, 무엇을 finding으로 인정할지 적습니다.
  4. 세부 규칙은 diff에 따라 선택할 reference로 분리합니다.
  5. 테스트 정책의 원본을 한 곳에 두고 Skill은 그 문서를 다시 정의하지 않게 합니다.
  6. focused test, type check, lint, build, CI가 문서의 명령과 실제로 일치하는지 정기적으로 실행합니다.

처음부터 수십 개 규칙을 만들 필요는 없습니다. finding이 자주 거짓 양성이 된다면 증거 기준을 좁히고, 실제 회귀를 놓쳤다면 그때 필요한 reference와 테스트 경계를 추가합니다. Skill도 코드처럼 실패 사례를 통해 유지보수해야 합니다.

10. 결론: 좋은 리뷰는 근거와 중단 조건을 정한다

특정 오픈소스의 프론트엔드 리뷰 방식에서 배울 점은 긴 프롬프트가 아닙니다. 명시적인 리뷰 요청에서만 Skill을 열고, 요청 범위에서 행동 소유자로 이동하며, 정확성에 필요한 계약만 더 따라갑니다. observable failure가 있을 때만 finding을 만들고, 수정 단계에서는 별도의 테스트 Skill이 가장 작은 행동 경계와 검증 순서를 선택합니다.

coverage 숫자와 많은 의견은 이 과정을 대신하지 못합니다. 브라우저·시각·E2E를 실행하지 않았다면 그 공백을 남겨야 하고, 최종 심각도와 수정의 적절성은 여전히 사람이 판단해야 합니다. 좋은 리뷰 Skill은 AI를 무조건 더 많이 말하게 하는 문서가 아니라, 무엇을 근거로 말하고 언제 멈출지를 정하는 작업 인터페이스입니다.

분석한 오픈소스와 원문 출처

이 글은 고정 커밋의 공개 파일을 직접 읽어 작성했으며 Dify의 공식 문서나 공식 입장을 대신하지 않습니다. 저장소 밖의 Skill 사용 빈도, branch protection 설정, 실제 결함 감소 효과는 확인하지 않았습니다.

함께 읽을 글

관련 AI 개발 글

AGENTS.md 작성법: AI 코딩을 위한 프로젝트 문서 설계관련 글 읽기