From 787a964a0e96d7c25c4dd0b907ba9ac3ed3467a9 Mon Sep 17 00:00:00 2001 From: chanwoo7 Date: Sun, 4 Oct 2026 21:45:57 +0900 Subject: [PATCH 1/2] =?UTF-8?q?test:=20=EA=B2=80=EC=83=89=20=EC=B9=A9=20sp?= =?UTF-8?q?ec=EC=9D=98=20=EC=85=80=20=EC=9D=B4=EB=A6=84=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=A5=BC=20=EC=86=90=EC=9E=A1=EC=9D=B4=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=A1=9C=20=EB=B0=94=EA=BF=94=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EC=8B=9C=EA=B0=84=20=EC=B4=88=EA=B3=BC=20?= =?UTF-8?q?=ED=95=B4=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - main CI·로컬 전체 실행에서 드래그 흐름 테스트가 5초 제한 초과(5.3~5.6초)로 실패 → 이미지 빌드·배포가 건너뛰어짐 - 계측(단독): rowOf = getByRole('cell', { name }) 13회가 578ms(회당 약 44ms, 모든 셀의 접근 가능한 이름 계산), 버튼 aria-label 조회는 회당 약 12ms - rowOf를 손잡이 버튼에서 행을 잡게, 표 대기 10곳도 손잡이 이름으로(tableReady) → 드래그 테스트 단독 1152 → 680ms, 전체 실행 부하 5.6초 → 3.2초 --- .../search-chips/pages/search-chips.spec.tsx | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/features/search-chips/pages/search-chips.spec.tsx b/src/features/search-chips/pages/search-chips.spec.tsx index 440de23..c34b80c 100644 --- a/src/features/search-chips/pages/search-chips.spec.tsx +++ b/src/features/search-chips/pages/search-chips.spec.tsx @@ -84,9 +84,14 @@ const keywordsInTable = () => .getAllByRole('row') .slice(1) .map((r) => within(r).getAllByRole('cell')[1]!.textContent); -const rowOf = (keyword: string) => screen.getByRole('cell', { name: keyword }).closest('tr')!; const handleOf = (keyword: string) => screen.getByRole('button', { name: `${keyword} 순서 바꾸기` }); +// 셀 이름 조회(getByRole('cell', { name }))는 모든 셀의 접근 가능한 이름을 계산해 회당 수십 ms가 든다 — +// aria-label로 바로 찾히는 손잡이에서 행을 잡는다(전체 실행 부하에서 드래그 흐름이 5초를 넘던 원인) +const rowOf = (keyword: string) => handleOf(keyword).closest('tr')!; +/** 표가 그려질 때까지 기다린다 — 셀 이름 대신 손잡이 이름으로(같은 이유) */ +const tableReady = (keyword = '생일') => + screen.findByRole('button', { name: `${keyword} 순서 바꾸기` }); const dataTransfer = () => ({ effectAllowed: 'none', dropEffect: 'none', @@ -125,7 +130,7 @@ describe('검색 칩 목록', () => { { keyword: '도시락 케이크', status: '숨김', period: '제한 없음' }, ])('$keyword: $status · $period', async ({ keyword, status, period }) => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); const cells = within(rowOf(keyword)).getAllByRole('cell'); expect(cells[0]).toHaveTextContent(String(CHIPS.findIndex((c) => c.keyword === keyword) + 1)); expect(cells[2]).toHaveTextContent(status); @@ -218,7 +223,7 @@ describe('검색 칩 순서 변경', () => { return HttpResponse.json({ data: { adminReorderSearchKeywordChips: [] } }); }), ); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); const handle = handleOf('생일'); expect(handle).toHaveAccessibleDescription( '손잡이를 끌거나, 손잡이에서 ↑↓ 키로 순서를 바꿉니다.', @@ -256,7 +261,7 @@ describe('검색 칩 순서 변경', () => { it('맨 뒤 칩에서 ↓를 누르면 맨 뒤라고 알리고 순서는 그대로다', async () => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); handleOf('도시락 케이크').focus(); await userEvent.keyboard('{ArrowDown}'); expect(screen.getByRole('status')).toHaveTextContent('이미 맨 뒤입니다.'); @@ -265,7 +270,7 @@ describe('검색 칩 순서 변경', () => { it('손잡이를 끌어 다른 칩 위에 놓으면 그 자리로 옮기고, 되돌리기로 서버 순서로 돌아간다', async () => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); const dt = dataTransfer(); // 손잡이를 누르기 전에는 행을 끌 수 없다 expect(rowOf('추석')).toHaveAttribute('draggable', 'false'); @@ -299,7 +304,7 @@ describe('검색 칩 순서 변경', () => { it('손잡이를 눌렀다 끌지 않고 떼면 행은 다시 끌 수 없다', async () => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); fireEvent.pointerDown(handleOf('생일')); expect(rowOf('생일')).toHaveAttribute('draggable', 'true'); fireEvent.pointerUp(handleOf('생일')); @@ -308,7 +313,7 @@ describe('검색 칩 순서 변경', () => { it('끌지 않은 채 들어온 드래그(파일 등)는 무시한다', async () => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); fireEvent.drop(rowOf('생일'), { dataTransfer: dataTransfer() }); expect(keywordsInTable()[0]).toBe('생일'); expect(screen.queryByText('순서를 바꿨습니다.')).not.toBeInTheDocument(); @@ -316,7 +321,7 @@ describe('검색 칩 순서 변경', () => { it('원래 자리로 되돌려 놓으면 바뀐 것이 없어 저장 줄이 사라진다', async () => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); handleOf('생일').focus(); await userEvent.keyboard('{ArrowDown}'); expect(screen.getByText('순서를 바꿨습니다.')).toBeInTheDocument(); @@ -326,7 +331,7 @@ describe('검색 칩 순서 변경', () => { it('저장 전에는 추가·수정·삭제를 막고 이유를 알린다', async () => { boot(); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); handleOf('생일').focus(); await userEvent.keyboard('{ArrowDown}'); const reason = '바꾼 순서를 저장하거나 되돌린 뒤에 할 수 있습니다.'; @@ -355,7 +360,7 @@ describe('검색 칩 순서 변경', () => { statusCode: 400, }), ); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); handleOf('생일').focus(); await userEvent.keyboard('{ArrowDown}'); await userEvent.click(screen.getByRole('button', { name: '순서 저장' })); @@ -381,7 +386,7 @@ describe('검색 칩 순서 변경', () => { statusCode: 400, }), ); - await screen.findByRole('cell', { name: '생일' }); + await tableReady(); handleOf('생일').focus(); await userEvent.keyboard('{ArrowDown}'); await userEvent.click(screen.getByRole('button', { name: '순서 저장' })); From 6d38474a15c0549eb010a62968c7312702970b9f Mon Sep 17 00:00:00 2001 From: chanwoo7 Date: Sun, 4 Oct 2026 21:48:04 +0900 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20BE=20develop=20=EC=8A=A4=ED=82=A4?= =?UTF-8?q?=EB=A7=88=20=EB=8F=99=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- schema/schema.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema/schema.graphql b/schema/schema.graphql index e129e94..342fd26 100644 --- a/schema/schema.graphql +++ b/schema/schema.graphql @@ -1,4 +1,4 @@ -# 생성 파일 — 수정하지 않는다. caquick-be local@9c15e94d1458101007ed17b4462ec131daa6a4dc 의 src/features/**/*.graphql 64개를 경로순으로 합쳤다. +# 생성 파일 — 수정하지 않는다. caquick-be local@234063bf62d2bf40170c1b3bae454081977ce981 의 src/features/**/*.graphql 64개를 경로순으로 합쳤다. # 갱신: pnpm schema:pull [ref] # ---- src/features/audit-log/audit-log.types.graphql ----