|
11 | 11 | * limitations under the License. |
12 | 12 | */ |
13 | 13 | import { cleanup, fireEvent, render, screen } from '@testing-library/react'; |
| 14 | +import { ColumnsType } from 'antd/lib/table'; |
14 | 15 | import { act } from 'react'; |
15 | 16 | import { MemoryRouter } from 'react-router-dom'; |
| 17 | +import { ColumnProfile } from '../../../../../generated/entity/data/table'; |
16 | 18 | import { MOCK_TABLE } from '../../../../../mocks/TableData.mock'; |
17 | 19 | import { useTableProfiler } from '../TableProfilerProvider'; |
18 | 20 | import ColumnProfileTable from './ColumnProfileTable'; |
19 | 21 |
|
| 22 | +let capturedColumns: ColumnsType<{ profile?: ColumnProfile }> = []; |
| 23 | + |
20 | 24 | jest.mock('../../../../common/Table/Table', () => |
21 | | - jest.fn().mockImplementation(({ searchProps }) => ( |
22 | | - <div> |
23 | | - <input |
24 | | - data-testid="searchbar" |
25 | | - value={searchProps?.value ?? ''} |
26 | | - onChange={(e) => searchProps?.onSearch?.(e.target.value)} |
27 | | - /> |
28 | | - <div>Table</div> |
29 | | - </div> |
30 | | - )) |
| 25 | + jest.fn().mockImplementation(({ columns, searchProps }) => { |
| 26 | + capturedColumns = columns ?? []; |
| 27 | + |
| 28 | + return ( |
| 29 | + <div> |
| 30 | + <input |
| 31 | + data-testid="searchbar" |
| 32 | + value={searchProps?.value ?? ''} |
| 33 | + onChange={(e) => searchProps?.onSearch?.(e.target.value)} |
| 34 | + /> |
| 35 | + <div>Table</div> |
| 36 | + </div> |
| 37 | + ); |
| 38 | + }) |
31 | 39 | ); |
32 | 40 |
|
33 | 41 | jest.mock('../../../../common/SummaryCard/SummaryCardV1', () => |
@@ -59,7 +67,25 @@ jest.mock( |
59 | 67 | jest.mock('../../../../../utils/CommonUtils', () => ({ |
60 | 68 | formatNumberWithComma: jest.fn(), |
61 | 69 | getTableFQNFromColumnFQN: jest.fn().mockImplementation((fqn) => fqn), |
62 | | - calculatePercentage: jest.fn().mockReturnValue('50%'), |
| 70 | + calculatePercentage: jest |
| 71 | + .fn() |
| 72 | + .mockImplementation( |
| 73 | + ( |
| 74 | + numerator: number, |
| 75 | + denominator: number, |
| 76 | + precision: number, |
| 77 | + format: boolean |
| 78 | + ) => { |
| 79 | + if (denominator === 0) { |
| 80 | + return format ? '0%' : 0; |
| 81 | + } |
| 82 | + const value = parseFloat( |
| 83 | + ((numerator / denominator) * 100).toFixed(precision) |
| 84 | + ); |
| 85 | + |
| 86 | + return format ? `${value}%` : value; |
| 87 | + } |
| 88 | + ), |
63 | 89 | })); |
64 | 90 |
|
65 | 91 | jest.mock('../../../../../utils/TableUtils', () => ({ |
@@ -268,3 +294,81 @@ describe('Test ColumnProfileTable component', () => { |
268 | 294 | }); |
269 | 295 | }); |
270 | 296 | }); |
| 297 | + |
| 298 | +describe('ColumnProfileTable proportion column renders', () => { |
| 299 | + const proportionColumnKeys = [ |
| 300 | + 'nullProportion', |
| 301 | + 'uniqueProportion', |
| 302 | + 'distinctProportion', |
| 303 | + ] as const; |
| 304 | + |
| 305 | + beforeEach(async () => { |
| 306 | + cleanup(); |
| 307 | + await act(async () => { |
| 308 | + render(<ColumnProfileTable />, { wrapper: MemoryRouter }); |
| 309 | + }); |
| 310 | + }); |
| 311 | + |
| 312 | + it.each(proportionColumnKeys)( |
| 313 | + 'should show "0%" instead of "--" when %s is 0', |
| 314 | + (field) => { |
| 315 | + const col = capturedColumns.find((c) => c.key === field); |
| 316 | + const renderFn = col?.render as ( |
| 317 | + profile: ColumnProfile | undefined |
| 318 | + ) => string; |
| 319 | + |
| 320 | + expect(renderFn({ [field]: 0 } as unknown as ColumnProfile)).toBe('0%'); |
| 321 | + } |
| 322 | + ); |
| 323 | + |
| 324 | + it.each(proportionColumnKeys)('should show "--" when %s is null', (field) => { |
| 325 | + const col = capturedColumns.find((c) => c.key === field); |
| 326 | + const renderFn = col?.render as ( |
| 327 | + profile: ColumnProfile | undefined |
| 328 | + ) => string; |
| 329 | + |
| 330 | + expect(renderFn({ [field]: null } as unknown as ColumnProfile)).toBe('--'); |
| 331 | + }); |
| 332 | + |
| 333 | + it.each(proportionColumnKeys)( |
| 334 | + 'should show "--" when %s is undefined', |
| 335 | + (field) => { |
| 336 | + const col = capturedColumns.find((c) => c.key === field); |
| 337 | + const renderFn = col?.render as ( |
| 338 | + profile: ColumnProfile | undefined |
| 339 | + ) => string; |
| 340 | + |
| 341 | + expect(renderFn({} as ColumnProfile)).toBe('--'); |
| 342 | + expect(renderFn(undefined)).toBe('--'); |
| 343 | + } |
| 344 | + ); |
| 345 | + |
| 346 | + it.each(proportionColumnKeys)( |
| 347 | + 'should show correct percentage for a normal value when %s is 0.5', |
| 348 | + (field) => { |
| 349 | + const col = capturedColumns.find((c) => c.key === field); |
| 350 | + const renderFn = col?.render as ( |
| 351 | + profile: ColumnProfile | undefined |
| 352 | + ) => string; |
| 353 | + |
| 354 | + expect(renderFn({ [field]: 0.5 } as unknown as ColumnProfile)).toBe( |
| 355 | + '50%' |
| 356 | + ); |
| 357 | + } |
| 358 | + ); |
| 359 | + |
| 360 | + it.each(proportionColumnKeys)( |
| 361 | + 'should not round small values (%s = 0.001) to 0%', |
| 362 | + (field) => { |
| 363 | + const col = capturedColumns.find((c) => c.key === field); |
| 364 | + const renderFn = col?.render as ( |
| 365 | + profile: ColumnProfile | undefined |
| 366 | + ) => string; |
| 367 | + |
| 368 | + // 0.001 * 100 = 0.1 → rounds to 0.1%, not 0% |
| 369 | + expect(renderFn({ [field]: 0.001 } as unknown as ColumnProfile)).toBe( |
| 370 | + '0.1%' |
| 371 | + ); |
| 372 | + } |
| 373 | + ); |
| 374 | +}); |
0 commit comments