From ec98372d9535fe58dca70d8d41745d20bf3a693a Mon Sep 17 00:00:00 2001 From: Kate Date: Fri, 6 Feb 2026 18:31:34 -0800 Subject: [PATCH 1/4] Update issues table to use LabelLists instead of custom labels --- frontend/src/components/IssuesTable.tsx | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/IssuesTable.tsx b/frontend/src/components/IssuesTable.tsx index d0c2f53d97..1e4805ca5e 100644 --- a/frontend/src/components/IssuesTable.tsx +++ b/frontend/src/components/IssuesTable.tsx @@ -5,6 +5,8 @@ import Image from 'next/image' import { useRouter } from 'next/navigation' import type React from 'react' +import { LabelList } from 'components/LabelList' + export type IssueRow = { objectID: string number: number @@ -141,23 +143,12 @@ const IssuesTable: React.FC = ({ {/* Labels */} - {issue.labels && issue.labels.length > 0 ? ( -
- {issue.labels.slice(0, maxVisibleLabels).map((label) => ( - - {label} - - ))} - {issue.labels.length > maxVisibleLabels && ( - - +{issue.labels.length - maxVisibleLabels} more - - )} -
- ) : null} + {/* Assignee */} From a1826b897e38c9e043d4aee90f06b5e2ddb8c269 Mon Sep 17 00:00:00 2001 From: Kate Date: Fri, 6 Feb 2026 18:43:06 -0800 Subject: [PATCH 2/4] Add tests --- .../unit/components/IssuesTable.test.tsx | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/frontend/__tests__/unit/components/IssuesTable.test.tsx b/frontend/__tests__/unit/components/IssuesTable.test.tsx index d6f7a05835..933b19c4df 100644 --- a/frontend/__tests__/unit/components/IssuesTable.test.tsx +++ b/frontend/__tests__/unit/components/IssuesTable.test.tsx @@ -2,6 +2,7 @@ import { render, screen, fireEvent, within } from '@testing-library/react' import '@testing-library/jest-dom' import React from 'react' import IssuesTable, { type IssueRow } from 'components/IssuesTable' +import { LabelList } from 'components/LabelList' jest.mock('next/navigation', () => ({ useRouter: () => ({ @@ -47,6 +48,36 @@ jest.mock('@heroui/tooltip', () => ({ }, })) +interface MockLabelListProps { + entityKey: string + labels: string[] + maxVisible?: number + className?: string +} + +const MockLabelList = (props: MockLabelListProps) => { + const { entityKey, labels, maxVisible = 5, className } = props + if (!labels || labels.length === 0) return null + const visibleLabels = labels.slice(0, maxVisible) + const remainingCount = labels.length - maxVisible + return ( +
+ {visibleLabels.map((label) => ( + + {label} + + ))} + {remainingCount > 0 && ( + +{remainingCount} more + )} +
+ ) +} + +jest.mock('components/LabelList', () => ({ + LabelList: jest.fn((props: MockLabelListProps) => ), +})) + const mockIssues: IssueRow[] = [ { objectID: '1', @@ -102,6 +133,10 @@ describe('', () => { issues: mockIssues, } + beforeEach(() => { + jest.mocked(LabelList).mockClear() + }) + describe('Rendering', () => { it('renders table view', () => { render() @@ -200,6 +235,67 @@ describe('', () => { render() expect(screen.getByText('+2 more')).toBeInTheDocument() }) + + it('uses LabelList with entityKey derived from issue objectID', () => { + render() + expect(LabelList).toHaveBeenCalledTimes(1) + expect(LabelList).toHaveBeenCalledWith( + expect.objectContaining({ + entityKey: 'issue-1', + labels: ['bug', 'enhancement'], + maxVisible: 5, + }), + undefined + ) + }) + + it('passes maxVisibleLabels to LabelList as maxVisible', () => { + render( + + ) + expect(LabelList).toHaveBeenCalledTimes(1) + expect(LabelList).toHaveBeenCalledWith( + expect.objectContaining({ + entityKey: 'issue-1', + labels: ['bug', 'enhancement'], + maxVisible: 3, + }), + undefined + ) + }) + + it('passes empty array to LabelList when issue has no labels', () => { + render() + expect(LabelList).toHaveBeenCalledTimes(1) + expect(LabelList).toHaveBeenCalledWith( + expect.objectContaining({ + entityKey: 'issue-3', + labels: [], + maxVisible: 5, + }), + undefined + ) + }) + + it('calls LabelList once per issue row with correct labels', () => { + render() + expect(LabelList).toHaveBeenCalledTimes(3) + expect(LabelList).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ entityKey: 'issue-1', labels: ['bug', 'enhancement'] }), + undefined + ) + expect(LabelList).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ entityKey: 'issue-2', labels: ['documentation'] }), + undefined + ) + expect(LabelList).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ entityKey: 'issue-3', labels: [] }), + undefined + ) + }) }) describe('Assignee Column', () => { From f20ad45fc6ddd3e052a4f40c8f116da2ce907852 Mon Sep 17 00:00:00 2001 From: Kate Date: Fri, 6 Feb 2026 18:48:51 -0800 Subject: [PATCH 3/4] Update code --- .../__tests__/unit/components/IssuesTable.test.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/__tests__/unit/components/IssuesTable.test.tsx b/frontend/__tests__/unit/components/IssuesTable.test.tsx index 933b19c4df..9c12bb2841 100644 --- a/frontend/__tests__/unit/components/IssuesTable.test.tsx +++ b/frontend/__tests__/unit/components/IssuesTable.test.tsx @@ -67,14 +67,14 @@ const MockLabelList = (props: MockLabelListProps) => { {label} ))} - {remainingCount > 0 && ( - +{remainingCount} more - )} + {remainingCount > 0 && +{remainingCount} more} ) } jest.mock('components/LabelList', () => ({ + // Must match the module export name for the mock to be used by IssuesTable + // eslint-disable-next-line @typescript-eslint/naming-convention -- component export name LabelList: jest.fn((props: MockLabelListProps) => ), })) @@ -250,9 +250,7 @@ describe('', () => { }) it('passes maxVisibleLabels to LabelList as maxVisible', () => { - render( - - ) + render() expect(LabelList).toHaveBeenCalledTimes(1) expect(LabelList).toHaveBeenCalledWith( expect.objectContaining({ From b8a9584fd4a74f5a4932e92e9efd37358fd406cb Mon Sep 17 00:00:00 2001 From: Kate Date: Fri, 6 Feb 2026 18:59:39 -0800 Subject: [PATCH 4/4] Add more tests --- .../unit/components/IssuesTable.test.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/frontend/__tests__/unit/components/IssuesTable.test.tsx b/frontend/__tests__/unit/components/IssuesTable.test.tsx index 9c12bb2841..f9c805d183 100644 --- a/frontend/__tests__/unit/components/IssuesTable.test.tsx +++ b/frontend/__tests__/unit/components/IssuesTable.test.tsx @@ -275,6 +275,24 @@ describe('', () => { ) }) + it('passes empty array to LabelList when issue.labels is undefined', () => { + const issueWithUndefinedLabels = { + ...mockIssues[0], + objectID: 'undefined-labels', + labels: undefined, + } as IssueRow + render() + expect(LabelList).toHaveBeenCalledTimes(1) + expect(LabelList).toHaveBeenCalledWith( + expect.objectContaining({ + entityKey: 'issue-undefined-labels', + labels: [], + maxVisible: 5, + }), + undefined + ) + }) + it('calls LabelList once per issue row with correct labels', () => { render() expect(LabelList).toHaveBeenCalledTimes(3)