@@ -49,8 +49,11 @@ const RESULTS: ResultResponse[] = [
4949 } ,
5050] ;
5151
52+ const COMPARISON_COLUMNS_A = [ 'name' ] ;
53+ const COMPARISON_COLUMNS_B = [ 'display_name' ] ;
54+
5255test ( 'shows clearer labels and explanations for one-sided and ignored rows' , ( ) => {
53- render ( < ResultsTable results = { RESULTS } /> ) ;
56+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
5457
5558 expect ( screen . getByText ( 'Only in File A' ) ) . toBeInTheDocument ( ) ;
5659 expect ( screen . getByText ( 'Ignored in File B' ) ) . toBeInTheDocument ( ) ;
@@ -65,7 +68,7 @@ test('shows clearer labels and explanations for one-sided and ignored rows', ()
6568} ) ;
6669
6770test ( 'uses shared theme surface classes for table states instead of hardcoded dark overlays' , ( ) => {
68- render ( < ResultsTable results = { RESULTS } /> ) ;
71+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
6972
7073 expect ( screen . getByText ( 'A-1' ) ) . toHaveClass ( 'kinetic-surface-subtle' ) ;
7174
@@ -77,8 +80,24 @@ test('uses shared theme surface classes for table states instead of hardcoded da
7780 expect ( screen . getByText ( 'Value Differences' ) . previousElementSibling ) . toHaveClass ( 'kinetic-surface-accent' ) ;
7881} ) ;
7982
83+ test ( 'lets matching rows expand paired file values for inspection' , ( ) => {
84+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
85+
86+ const matchRow = screen . getByText ( 'B-2' ) . closest ( 'tr' ) ;
87+ expect ( within ( matchRow as HTMLElement ) . getByRole ( 'button' , { name : / i n s p e c t / i } ) ) . toBeInTheDocument ( ) ;
88+
89+ fireEvent . click ( within ( matchRow as HTMLElement ) . getByRole ( 'button' , { name : / i n s p e c t / i } ) ) ;
90+
91+ expect ( screen . getByText ( 'Paired Values' ) ) . toBeInTheDocument ( ) ;
92+ expect ( screen . getAllByText ( 'File A' ) . length ) . toBeGreaterThan ( 0 ) ;
93+ expect ( screen . getAllByText ( 'File B' ) . length ) . toBeGreaterThan ( 0 ) ;
94+ expect ( screen . getAllByText ( 'Alpha' ) . length ) . toBeGreaterThan ( 0 ) ;
95+ expect ( screen . getAllByText ( 'Bravo' ) . length ) . toBeGreaterThan ( 0 ) ;
96+ expect ( screen . getAllByText ( 'display_name' ) . length ) . toBeGreaterThan ( 0 ) ;
97+ } ) ;
98+
8099test ( 'filters visible rows by search query across keys and values' , ( ) => {
81- render ( < ResultsTable results = { RESULTS } /> ) ;
100+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
82101
83102 const search = screen . getByPlaceholderText ( 'Search keys or values' ) ;
84103 fireEvent . change ( search , { target : { value : 'gamma' } } ) ;
@@ -90,7 +109,7 @@ test('filters visible rows by search query across keys and values', () => {
90109} ) ;
91110
92111test ( 'sorts rows by key when the header is clicked' , ( ) => {
93- render ( < ResultsTable results = { RESULTS } /> ) ;
112+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
94113
95114 fireEvent . click ( screen . getByRole ( 'button' , { name : / k e y / i } ) ) ;
96115
@@ -244,7 +263,7 @@ test('sorts rows by diff count descending when the details header is clicked twi
244263} ) ;
245264
246265test ( 'updates the controlled search input value synchronously on each keystroke' , ( ) => {
247- render ( < ResultsTable results = { RESULTS } /> ) ;
266+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
248267
249268 const search = screen . getByPlaceholderText ( 'Search keys or values' ) ;
250269
@@ -260,7 +279,7 @@ test('updates the controlled search input value synchronously on each keystroke'
260279} ) ;
261280
262281test ( 'updates sort state from the transition-driven header action' , ( ) => {
263- render ( < ResultsTable results = { RESULTS } /> ) ;
282+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
264283
265284 const keySort = screen . getByRole ( 'button' , { name : / k e y / i } ) ;
266285 const keyHeader = keySort . closest ( 'th' ) ;
@@ -273,17 +292,18 @@ test('updates sort state from the transition-driven header action', () => {
273292} ) ;
274293
275294test ( 'renders long diff column names with the larger wrapped header treatment' , ( ) => {
276- render ( < ResultsTable results = { RESULTS } /> ) ;
295+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
277296
278297 fireEvent . click ( screen . getByRole ( 'button' , { name : / 1 d i f f / i } ) ) ;
279298
280- const columnHeader = screen . getByText ( 'name' ) ;
299+ const columnHeader = screen . getAllByText ( 'name' ) . find ( ( element ) => element . classList . contains ( 'break-all' ) ) ;
300+ expect ( columnHeader ) . toBeTruthy ( ) ;
281301 expect ( columnHeader ) . toHaveClass ( 'break-all' ) ;
282302 expect ( columnHeader ) . toHaveClass ( 'table-chip' ) ;
283303} ) ;
284304
285305test ( 'positions the mismatch diff arrow on the same row as the value boxes' , ( ) => {
286- render ( < ResultsTable results = { RESULTS } /> ) ;
306+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
287307
288308 fireEvent . click ( screen . getByRole ( 'button' , { name : / 1 d i f f / i } ) ) ;
289309
@@ -293,15 +313,23 @@ test('positions the mismatch diff arrow on the same row as the value boxes', ()
293313} ) ;
294314
295315test ( 'shows the selected-filter empty-state copy when there are zero total results' , ( ) => {
296- render ( < ResultsTable results = { [ ] } totalResultsCount = { 0 } /> ) ;
316+ render ( < ResultsTable results = { [ ] } totalResultsCount = { 0 } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
297317
298318 expect ( screen . getByText ( 'No results match the selected filter' ) ) . toBeInTheDocument ( ) ;
299319 expect ( screen . queryByText ( 'No results match the current filter and search.' ) ) . not . toBeInTheDocument ( ) ;
300320} ) ;
301321
302322test ( 'shows the current-filter-and-search empty-state copy when rows exist but none survive filtering' , ( ) => {
303- render ( < ResultsTable results = { [ ] } totalResultsCount = { RESULTS . length } /> ) ;
323+ render ( < ResultsTable results = { [ ] } totalResultsCount = { RESULTS . length } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
304324
305325 expect ( screen . getByText ( 'No results match the current filter and search.' ) ) . toBeInTheDocument ( ) ;
306326 expect ( screen . queryByText ( 'No results match the selected filter' ) ) . not . toBeInTheDocument ( ) ;
307327} ) ;
328+
329+ test ( 'renders comparison column names alongside result values' , ( ) => {
330+ render ( < ResultsTable results = { RESULTS } comparisonColumnsA = { COMPARISON_COLUMNS_A } comparisonColumnsB = { COMPARISON_COLUMNS_B } /> ) ;
331+
332+ const row = screen . getByText ( 'Alpha' ) . closest ( 'tr' ) ;
333+ expect ( within ( row as HTMLElement ) . getByText ( 'name' ) ) . toBeInTheDocument ( ) ;
334+ expect ( within ( row as HTMLElement ) . getByText ( 'display_name' ) ) . toBeInTheDocument ( ) ;
335+ } ) ;
0 commit comments