@automattic/charts 1.10.0 → 1.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/index.cjs +5917 -5783
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +44 -3
- package/dist/index.d.cts +66 -13
- package/dist/index.d.ts +67 -14
- package/dist/index.js +1159 -1015
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +27 -4
- package/src/charts/heatmap-chart/heatmap-chart.tsx +115 -49
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +39 -4
- package/src/charts/heatmap-chart/private/heatmap-context.ts +10 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +3 -2
- package/src/charts/heatmap-chart/private/index.ts +2 -0
- package/src/charts/heatmap-chart/private/use-heatmap-colors.ts +6 -2
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +57 -1
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +91 -3
- package/src/charts/heatmap-chart/test/use-heatmap-colors.test.ts +4 -0
- package/src/charts/heatmap-chart/types.ts +28 -0
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +12 -0
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +65 -37
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +46 -6
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +0 -6
- package/src/charts/private/with-responsive/test/with-responsive.test.tsx +229 -18
- package/src/charts/private/with-responsive/with-responsive.module.scss +20 -1
- package/src/charts/private/with-responsive/with-responsive.tsx +114 -65
- package/src/hooks/test/use-chart-margin.test.tsx +8 -5
- package/src/hooks/use-chart-margin.tsx +11 -1
- package/src/providers/chart-context/global-charts-provider.tsx +7 -0
- package/src/providers/chart-context/test/chart-context.test.tsx +40 -0
- package/src/providers/chart-context/types.ts +3 -0
- package/src/types.ts +9 -6
- package/src/utils/color-utils.ts +28 -0
- package/src/utils/test/color-utils.test.ts +29 -0
|
@@ -213,6 +213,57 @@ describe( 'HeatmapChart', () => {
|
|
|
213
213
|
expect( grid ).not.toHaveAttribute( 'aria-activedescendant' );
|
|
214
214
|
} );
|
|
215
215
|
|
|
216
|
+
// Calendar ragged edges: hidden cells keep their grid slot but paint
|
|
217
|
+
// nothing and take no interaction.
|
|
218
|
+
const raggedData: HeatmapColumn[] = [
|
|
219
|
+
{ label: 'W1', data: [ { value: null, hidden: true }, { value: 1 }, { value: 2 } ] },
|
|
220
|
+
{ label: 'W2', data: [ { value: 3 }, { value: null, hidden: true }, { value: 4 } ] },
|
|
221
|
+
{ label: 'W3', data: [ { value: 5 }, { value: 6 }, { value: null, hidden: true } ] },
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
test( 'hidden cells render as empty slots outside the accessibility tree', () => {
|
|
225
|
+
renderChart( { data: raggedData } );
|
|
226
|
+
expect( screen.getAllByTestId( 'heatmap-cell' ) ).toHaveLength( 6 );
|
|
227
|
+
expect( screen.getAllByTestId( 'heatmap-cell-hidden' ) ).toHaveLength( 3 );
|
|
228
|
+
expect( screen.getAllByRole( 'gridcell' ) ).toHaveLength( 6 );
|
|
229
|
+
} );
|
|
230
|
+
|
|
231
|
+
test( 'keyboard navigation skips hidden cells and never lands on them', async () => {
|
|
232
|
+
renderChart( { data: raggedData, rowLabels: [ 'Mon', 'Tue', 'Wed' ] } );
|
|
233
|
+
const grid = screen.getByRole( 'grid', { name: /heatmap/i } );
|
|
234
|
+
const user = userEvent.setup();
|
|
235
|
+
|
|
236
|
+
// The initial selection starts past the hidden leading slot (0,0).
|
|
237
|
+
grid.focus();
|
|
238
|
+
await user.keyboard( '{ArrowDown}' );
|
|
239
|
+
expect( grid ).toHaveAttribute(
|
|
240
|
+
'aria-activedescendant',
|
|
241
|
+
expect.stringMatching( /-cell-0-1$/ )
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
// ArrowRight steps over the hidden (1,1) to (2,1).
|
|
245
|
+
await user.keyboard( '{ArrowRight}' );
|
|
246
|
+
expect( grid ).toHaveAttribute(
|
|
247
|
+
'aria-activedescendant',
|
|
248
|
+
expect.stringMatching( /-cell-2-1$/ )
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Only a hidden slot (2,2) lies below — the selection stays put.
|
|
252
|
+
await user.keyboard( '{ArrowDown}' );
|
|
253
|
+
expect( grid ).toHaveAttribute(
|
|
254
|
+
'aria-activedescendant',
|
|
255
|
+
expect.stringMatching( /-cell-2-1$/ )
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
// ArrowLeft steps back over the hidden (1,1) to (0,1); ArrowUp has
|
|
259
|
+
// only the hidden (0,0) above, so the selection stays again.
|
|
260
|
+
await user.keyboard( '{ArrowLeft}{ArrowUp}' );
|
|
261
|
+
expect( grid ).toHaveAttribute(
|
|
262
|
+
'aria-activedescendant',
|
|
263
|
+
expect.stringMatching( /-cell-0-1$/ )
|
|
264
|
+
);
|
|
265
|
+
} );
|
|
266
|
+
|
|
216
267
|
test( 'rows contain gridcell children in the ARIA hierarchy', () => {
|
|
217
268
|
renderChart();
|
|
218
269
|
const rows = screen.getAllByRole( 'row' );
|
|
@@ -222,12 +273,19 @@ describe( 'HeatmapChart', () => {
|
|
|
222
273
|
} );
|
|
223
274
|
} );
|
|
224
275
|
|
|
225
|
-
test( '
|
|
276
|
+
test( 'keeps a strict grid → row structure (column labels live in a row, not directly under the grid)', () => {
|
|
277
|
+
renderChart();
|
|
278
|
+
// The header row is aria-hidden, so include hidden elements when querying for it.
|
|
279
|
+
const rows = screen.getAllByRole( 'row', { hidden: true } );
|
|
280
|
+
const headerRow = rows.find( row => within( row ).queryByText( 'W1' ) );
|
|
281
|
+
expect( headerRow ).toBeDefined();
|
|
282
|
+
} );
|
|
283
|
+
|
|
284
|
+
test( 'leaves the cell gap to WPDS tokens in non-compact mode (no inline override)', () => {
|
|
226
285
|
renderChart();
|
|
227
286
|
const grid = screen.getByRole( 'grid', { name: /heatmap/i } );
|
|
228
|
-
// Non-compact sets no inline gap
|
|
287
|
+
// Non-compact sets no inline gap — the SCSS falls back to the WPDS token.
|
|
229
288
|
expect( grid.style.getPropertyValue( '--heatmap-cell-gap' ) ).toBe( '' );
|
|
230
|
-
expect( grid.style.getPropertyValue( '--heatmap-cell-radius' ) ).toBe( '' );
|
|
231
289
|
} );
|
|
232
290
|
|
|
233
291
|
test( 'applies the compact gap inline from the theme compactCellGap', () => {
|
|
@@ -252,6 +310,36 @@ describe( 'HeatmapChart', () => {
|
|
|
252
310
|
expect( grid.style.gridTemplateColumns ).toContain( 'var(--heatmap-cell-size)' );
|
|
253
311
|
} );
|
|
254
312
|
|
|
313
|
+
test( 'caps cell width without changing the normal vertical layout', () => {
|
|
314
|
+
renderChart( { maxCellWidth: 64 } );
|
|
315
|
+
const chart = screen.getByTestId( 'heatmap-chart' );
|
|
316
|
+
const grid = screen.getByRole( 'grid', { name: /heatmap/i } );
|
|
317
|
+
|
|
318
|
+
expect( grid.style.gridTemplateColumns ).toContain( 'minmax(0px, 64px)' );
|
|
319
|
+
expect( grid.style.gridTemplateRows ).toContain( 'minmax(0px, 1fr)' );
|
|
320
|
+
expect( chart ).not.toHaveClass( 'heatmap-chart--height-capped' );
|
|
321
|
+
expect( grid ).not.toHaveClass( 'heatmap-chart__grid--height-capped' );
|
|
322
|
+
} );
|
|
323
|
+
|
|
324
|
+
test( 'content-sizes the vertical layout when cell height is capped', () => {
|
|
325
|
+
renderChart( { maxCellHeight: 42 } );
|
|
326
|
+
const chart = screen.getByTestId( 'heatmap-chart' );
|
|
327
|
+
const grid = screen.getByRole( 'grid', { name: /heatmap/i } );
|
|
328
|
+
|
|
329
|
+
expect( grid.style.gridTemplateColumns ).toContain( 'minmax(0px, 1fr)' );
|
|
330
|
+
expect( grid.style.gridTemplateRows ).toContain( 'minmax(0px, 42px)' );
|
|
331
|
+
expect( chart ).toHaveClass( 'heatmap-chart--height-capped' );
|
|
332
|
+
expect( grid ).toHaveClass( 'heatmap-chart__grid--height-capped' );
|
|
333
|
+
} );
|
|
334
|
+
|
|
335
|
+
test( 'applies independent minimum cell width and height floors', () => {
|
|
336
|
+
renderChart( { minCellWidth: 44, minCellHeight: 32 } );
|
|
337
|
+
const grid = screen.getByRole( 'grid', { name: /heatmap/i } );
|
|
338
|
+
|
|
339
|
+
expect( grid.style.gridTemplateColumns ).toContain( 'minmax(44px, 1fr)' );
|
|
340
|
+
expect( grid.style.gridTemplateRows ).toContain( 'minmax(32px, 1fr)' );
|
|
341
|
+
} );
|
|
342
|
+
|
|
255
343
|
test( 'applies the primaryColor prop as the cell-scale color', () => {
|
|
256
344
|
renderChart( { primaryColor: '#abcdef' } );
|
|
257
345
|
const grid = screen.getByRole( 'grid', { name: /heatmap/i } );
|
|
@@ -31,4 +31,8 @@ describe( 'getNormalizedValue', () => {
|
|
|
31
31
|
test( 'returns 1 when min === max', () => {
|
|
32
32
|
expect( getNormalizedValue( 7, [ 7, 7 ] ) ).toBe( 1 );
|
|
33
33
|
} );
|
|
34
|
+
|
|
35
|
+
test( 'returns 0 for an all-zero extent so a no-activity grid stays at the scale bottom', () => {
|
|
36
|
+
expect( getNormalizedValue( 0, [ 0, 0 ] ) ).toBe( 0 );
|
|
37
|
+
} );
|
|
34
38
|
} );
|
|
@@ -6,6 +6,13 @@ export type HeatmapCell = {
|
|
|
6
6
|
/** Per-cell label used in the tooltip / accessible name. */
|
|
7
7
|
label?: string;
|
|
8
8
|
value: number | null;
|
|
9
|
+
/**
|
|
10
|
+
* Leave the cell's grid slot empty: nothing is painted and the cell is
|
|
11
|
+
* skipped by hover and keyboard navigation, while the slot keeps its
|
|
12
|
+
* place so the rest of the grid doesn't shift. For calendar edges, where
|
|
13
|
+
* days completing the first/last week fall outside the covered range.
|
|
14
|
+
*/
|
|
15
|
+
hidden?: boolean;
|
|
9
16
|
};
|
|
10
17
|
|
|
11
18
|
/** A heatmap column (rendered left→right); its cells render top→bottom. */
|
|
@@ -32,6 +39,27 @@ export interface HeatmapChartProps
|
|
|
32
39
|
compact?: boolean;
|
|
33
40
|
/** Render the numeric value inside each cell. Default `! compact`. */
|
|
34
41
|
showValues?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Cap a cell's width (px) in non-compact mode. Cells grow up to the cap
|
|
44
|
+
* and stop instead of splitting the whole container width, so sparse
|
|
45
|
+
* ranges don't produce oversized cells; narrow containers still shrink
|
|
46
|
+
* them. Ignored in compact mode, which uses a fixed cell size.
|
|
47
|
+
*/
|
|
48
|
+
maxCellWidth?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Cap a cell's height (px) in non-compact mode. Applying this cap
|
|
51
|
+
* content-sizes the chart vertically so rows do not absorb unused height.
|
|
52
|
+
* Ignored in compact mode, which uses a fixed cell size.
|
|
53
|
+
*/
|
|
54
|
+
maxCellHeight?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Floor a cell's width (px) in non-compact mode. Below it the grid stops
|
|
57
|
+
* shrinking and overflows its container instead, so a scrollable wrapper
|
|
58
|
+
* can take over for long ranges. Default 0 (cells shrink freely).
|
|
59
|
+
*/
|
|
60
|
+
minCellWidth?: number;
|
|
61
|
+
/** Floor a cell's height (px) in non-compact mode; see `minCellWidth`. */
|
|
62
|
+
minCellHeight?: number;
|
|
35
63
|
/**
|
|
36
64
|
* Color the cell scale interpolates toward at the highest value
|
|
37
65
|
* (this prop > theme `heatmapChart.primaryColor` > palette `colors[0]`).
|
|
@@ -73,9 +73,21 @@
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
.valueContainer {
|
|
76
|
+
align-items: center;
|
|
76
77
|
justify-content: flex-end;
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
.deltaValue {
|
|
81
|
+
display: inline-block;
|
|
82
|
+
font-variant-numeric: tabular-nums;
|
|
83
|
+
min-width: 3ch;
|
|
84
|
+
text-align: end;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.deltaPlaceholder {
|
|
88
|
+
text-align: center;
|
|
89
|
+
}
|
|
90
|
+
|
|
79
91
|
.overlayLabel {
|
|
80
92
|
align-items: center;
|
|
81
93
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @wordpress/no-unsafe-wp-apis */
|
|
2
|
-
import { __experimentalGrid as Grid } from '@wordpress/components';
|
|
2
|
+
import { __experimentalGrid as Grid, VisuallyHidden } from '@wordpress/components';
|
|
3
3
|
import { Fragment } from '@wordpress/element';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
import { Icon, chevronRight } from '@wordpress/icons';
|
|
@@ -65,6 +65,14 @@ const defaultDeltaFormatter = ( value: number ): string => {
|
|
|
65
65
|
const getBarWidth = ( share: number ): string =>
|
|
66
66
|
`calc(${ share }% - var(--a8c--charts--leaderboard--bar--hover-inset, 0px) * ${ share } / 100)`;
|
|
67
67
|
|
|
68
|
+
const hasComparisonValue = (
|
|
69
|
+
entry: LeaderboardEntry
|
|
70
|
+
): entry is LeaderboardEntry & {
|
|
71
|
+
previousValue: number;
|
|
72
|
+
previousShare: number;
|
|
73
|
+
delta: number;
|
|
74
|
+
} => entry.previousValue != null && entry.previousShare != null && entry.delta != null;
|
|
75
|
+
|
|
68
76
|
const BarLabel = ( { label }: { label: LeaderboardEntry[ 'label' ] } ) => (
|
|
69
77
|
<>{ typeof label === 'string' ? <Text className={ styles.label }>{ label }</Text> : label }</>
|
|
70
78
|
);
|
|
@@ -87,39 +95,43 @@ const BarWithLabel = ( {
|
|
|
87
95
|
isPrimaryVisible?: boolean;
|
|
88
96
|
isComparisonVisible?: boolean;
|
|
89
97
|
animation?: boolean;
|
|
90
|
-
} ) =>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
98
|
+
} ) => {
|
|
99
|
+
const showComparisonBar = withComparison && ! withOverlayLabel && isComparisonVisible;
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
className={ clsx( styles.barWithLabelContainer, {
|
|
104
|
+
[ styles[ 'is-overlay' ] ]: withOverlayLabel,
|
|
105
|
+
} ) }
|
|
106
|
+
>
|
|
107
|
+
<BarLabel label={ entry.label } />
|
|
108
|
+
|
|
109
|
+
{ isPrimaryVisible && (
|
|
110
|
+
<div
|
|
111
|
+
className={ clsx( styles.bar, {
|
|
112
|
+
[ styles[ 'bar--animated' ] ]: animation,
|
|
113
|
+
} ) }
|
|
114
|
+
style={ {
|
|
115
|
+
width: getBarWidth( entry.currentShare ),
|
|
116
|
+
backgroundColor: primaryColor,
|
|
117
|
+
} }
|
|
118
|
+
></div>
|
|
119
|
+
) }
|
|
120
|
+
|
|
121
|
+
{ showComparisonBar && hasComparisonValue( entry ) && (
|
|
122
|
+
<div
|
|
123
|
+
className={ clsx( styles.bar, {
|
|
124
|
+
[ styles[ 'bar--animated' ] ]: animation,
|
|
125
|
+
} ) }
|
|
126
|
+
style={ {
|
|
127
|
+
width: getBarWidth( entry.previousShare ),
|
|
128
|
+
backgroundColor: secondaryColor,
|
|
129
|
+
} }
|
|
130
|
+
></div>
|
|
131
|
+
) }
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
123
135
|
|
|
124
136
|
/**
|
|
125
137
|
* LeaderboardChart component displays a ranked list of data with progress bars
|
|
@@ -335,7 +347,11 @@ const LeaderboardChartInternal: FC< LeaderboardChartProps > = ( {
|
|
|
335
347
|
) : (
|
|
336
348
|
<Grid templateColumns="minmax(0, 1fr) auto" rowGap={ rowGap } columnGap={ columnGap }>
|
|
337
349
|
{ data.map( entry => {
|
|
338
|
-
const
|
|
350
|
+
const showComparisonColumn = withComparison && isComparisonVisible;
|
|
351
|
+
const hasDeltaValue = hasComparisonValue( entry );
|
|
352
|
+
const showComparisonValue = showComparisonColumn && hasDeltaValue;
|
|
353
|
+
const showComparisonPlaceholder = showComparisonColumn && ! hasDeltaValue;
|
|
354
|
+
const colorIndex = showComparisonValue ? Math.sign( entry.delta ) + 1 : 1;
|
|
339
355
|
const deltaColor = deltaColors[ colorIndex ];
|
|
340
356
|
|
|
341
357
|
const rowCells = (
|
|
@@ -362,11 +378,23 @@ const LeaderboardChartInternal: FC< LeaderboardChartProps > = ( {
|
|
|
362
378
|
>
|
|
363
379
|
{ isPrimaryVisible && <Text>{ valueFormatter( entry.currentValue ) }</Text> }
|
|
364
380
|
|
|
365
|
-
{
|
|
366
|
-
<Text style={ { color: deltaColor } }>
|
|
381
|
+
{ showComparisonValue && (
|
|
382
|
+
<Text className={ styles.deltaValue } style={ { color: deltaColor } }>
|
|
367
383
|
{ deltaFormatter( entry.delta ) }
|
|
368
384
|
</Text>
|
|
369
385
|
) }
|
|
386
|
+
|
|
387
|
+
{ showComparisonPlaceholder && (
|
|
388
|
+
<Text
|
|
389
|
+
className={ clsx( styles.deltaValue, styles.deltaPlaceholder ) }
|
|
390
|
+
style={ { color: deltaColor } }
|
|
391
|
+
>
|
|
392
|
+
<span aria-hidden="true">-</span>
|
|
393
|
+
<VisuallyHidden as="span">
|
|
394
|
+
{ __( 'No comparison data', 'jetpack-charts' ) }
|
|
395
|
+
</VisuallyHidden>
|
|
396
|
+
</Text>
|
|
397
|
+
) }
|
|
370
398
|
</Stack>
|
|
371
399
|
</>
|
|
372
400
|
);
|
|
@@ -78,6 +78,30 @@ describe( 'LeaderboardChart', () => {
|
|
|
78
78
|
expect( screen.getByText( '-8%' ) ).toBeInTheDocument();
|
|
79
79
|
} );
|
|
80
80
|
|
|
81
|
+
it( 'shows a placeholder when a row has no previous value', () => {
|
|
82
|
+
render(
|
|
83
|
+
<LeaderboardChart
|
|
84
|
+
data={ [
|
|
85
|
+
...mockData,
|
|
86
|
+
{
|
|
87
|
+
id: 'new',
|
|
88
|
+
label: 'New Source',
|
|
89
|
+
currentValue: 100,
|
|
90
|
+
currentShare: 1,
|
|
91
|
+
},
|
|
92
|
+
] }
|
|
93
|
+
withComparison={ true }
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
expect( screen.getByText( '+25%' ) ).toBeInTheDocument();
|
|
98
|
+
expect( screen.getByText( '-8%' ) ).toBeInTheDocument();
|
|
99
|
+
expect( screen.getByText( 'New Source' ) ).toBeInTheDocument();
|
|
100
|
+
expect( screen.getByText( '-' ) ).toHaveAttribute( 'aria-hidden', 'true' );
|
|
101
|
+
expect( screen.getByText( 'No comparison data' ) ).toBeInTheDocument();
|
|
102
|
+
expect( screen.queryByText( '+100%' ) ).not.toBeInTheDocument();
|
|
103
|
+
} );
|
|
104
|
+
|
|
81
105
|
it( 'shows custom label when provided', () => {
|
|
82
106
|
render(
|
|
83
107
|
<LeaderboardChart
|
|
@@ -348,12 +372,6 @@ describe( 'LeaderboardChart', () => {
|
|
|
348
372
|
} );
|
|
349
373
|
|
|
350
374
|
describe( 'Responsive wrapper', () => {
|
|
351
|
-
it( 'fills parent container (height:100%) by default', () => {
|
|
352
|
-
render( <LeaderboardChart data={ mockData } /> );
|
|
353
|
-
const wrapper = screen.getByTestId( 'responsive-wrapper' );
|
|
354
|
-
expect( wrapper ).toHaveStyle( { height: '100%' } );
|
|
355
|
-
} );
|
|
356
|
-
|
|
357
375
|
it( 'applies explicit width and height to chart container', () => {
|
|
358
376
|
const { useParentSize } = jest.requireMock( '@visx/responsive' );
|
|
359
377
|
useParentSize.mockReturnValue( {
|
|
@@ -403,6 +421,28 @@ describe( 'LeaderboardChart', () => {
|
|
|
403
421
|
expect( screen.getByRole( 'button' ) ).toHaveAccessibleName( /Direct.*12\.5K/ );
|
|
404
422
|
} );
|
|
405
423
|
|
|
424
|
+
it( 'does not include the missing comparison dash in interactive row names', () => {
|
|
425
|
+
render(
|
|
426
|
+
<LeaderboardChart
|
|
427
|
+
data={ [
|
|
428
|
+
{
|
|
429
|
+
id: 'new',
|
|
430
|
+
label: 'New Source',
|
|
431
|
+
currentValue: 100,
|
|
432
|
+
currentShare: 1,
|
|
433
|
+
onClick: jest.fn(),
|
|
434
|
+
},
|
|
435
|
+
] }
|
|
436
|
+
withComparison={ true }
|
|
437
|
+
/>
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
expect( screen.getByRole( 'button' ) ).toHaveAccessibleName(
|
|
441
|
+
/New Source.*100.*No comparison data/
|
|
442
|
+
);
|
|
443
|
+
expect( screen.getByRole( 'button' ) ).not.toHaveAccessibleName( /-/ );
|
|
444
|
+
} );
|
|
445
|
+
|
|
406
446
|
it( 'derives the accessible name from an image label via its alt text', () => {
|
|
407
447
|
render(
|
|
408
448
|
<LeaderboardChart
|
|
@@ -226,12 +226,6 @@ describe( 'PieSemiCircleChart', () => {
|
|
|
226
226
|
} );
|
|
227
227
|
|
|
228
228
|
describe( 'Responsive wrapper', () => {
|
|
229
|
-
it( 'fills parent container (height:100%) by default', () => {
|
|
230
|
-
render( <PieSemiCircleChart data={ mockData } /> );
|
|
231
|
-
const wrapper = screen.getByTestId( 'responsive-wrapper' );
|
|
232
|
-
expect( wrapper ).toHaveStyle( { height: '100%' } );
|
|
233
|
-
} );
|
|
234
|
-
|
|
235
229
|
it( 'constrains chart to 2:1 ratio from measured dimensions', () => {
|
|
236
230
|
// Mock returns width:400, height:200, so chart renders at 400×200 (2:1 ratio)
|
|
237
231
|
render( <PieSemiCircleChart data={ mockData } /> );
|