Skip to content

Commit 81bd75b

Browse files
committed
core unit tests
1 parent 10428e8 commit 81bd75b

20 files changed

+527
-36
lines changed

pages/03-visibility-api.page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ function ExamplePieChart() {
133133
ariaLabel="Pie chart"
134134
series={pieChartSeries}
135135
tooltip={{
136-
content(details) {
136+
body(details) {
137137
return (
138138
<div>
139139
<div style={{ display: "flex", justifyContent: "space-between", gap: "16px", marginLeft: "18px" }}>

pages/website-playground-examples/example-pie-chart-donut-chart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export function ExamplePieChartDonutChart() {
4444
ariaDescription="Donut chart showing generic example data."
4545
series={hideSeries ? null : series}
4646
tooltip={{
47-
content(details) {
47+
body(details) {
4848
return (
4949
<div>
5050
<div style={{ display: "flex", justifyContent: "space-between", gap: "16px", marginLeft: "18px" }}>

pages/website-playground-examples/example-pie-chart-pie-chart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function ExamplePieChartPieChart() {
6262
ariaDescription="Pie chart showing how many resources are currently in which state."
6363
series={hideSeries ? null : series}
6464
tooltip={{
65-
content(details) {
65+
body(details) {
6666
return (
6767
<div>
6868
<div style={{ display: "flex", justifyContent: "space-between", gap: "16px", marginLeft: "18px" }}>

pages/website-playground-examples/example-pie-chart-small-donut-chart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function ExamplePieChartSmallDonutChart() {
4141
ariaDescription="Donut chart showing generic progress."
4242
series={hideSeries ? null : series}
4343
tooltip={{
44-
content(details) {
44+
body(details) {
4545
return (
4646
<div>
4747
<div style={{ display: "flex", justifyContent: "space-between", gap: "16px", marginLeft: "18px" }}>

src/__tests__/__snapshots__/documenter.test.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ inject links, or add expandable items.
167167
"name": "CartesianChartProps.TooltipProps",
168168
"properties": [
169169
{
170-
"name": "content",
170+
"name": "body",
171171
"optional": true,
172172
"type": "(detail: CartesianChartProps.TooltipDetails) => React.ReactNode",
173173
},
@@ -177,14 +177,14 @@ inject links, or add expandable items.
177177
"type": "(detail: CartesianChartProps.TooltipDetails) => React.ReactNode",
178178
},
179179
{
180-
"name": "series",
180+
"name": "header",
181181
"optional": true,
182-
"type": "(detail: CartesianChartProps.TooltipSeriesDetailItem) => CartesianChartProps.TooltipSeriesFormatted",
182+
"type": "(detail: CartesianChartProps.TooltipDetails) => React.ReactNode",
183183
},
184184
{
185-
"name": "title",
185+
"name": "series",
186186
"optional": true,
187-
"type": "(detail: CartesianChartProps.TooltipDetails) => React.ReactNode",
187+
"type": "(detail: CartesianChartProps.TooltipSeriesDetailItem) => CartesianChartProps.TooltipSeriesFormatted",
188188
},
189189
],
190190
"type": "object",
@@ -507,7 +507,7 @@ Supported properties:
507507
"name": "PieChartProps.TooltipProps",
508508
"properties": [
509509
{
510-
"name": "content",
510+
"name": "body",
511511
"optional": true,
512512
"type": "(detail: PieChartProps.TooltipDetails) => React.ReactNode",
513513
},

src/cartesian-chart/chart-tooltip-cartesian.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export function useChartTooltipCartesian(
117117

118118
const tooltipDetails = { x: point.x, items: matchedItems };
119119

120-
const content = props.tooltip?.content?.(tooltipDetails) ?? (
120+
const content = props.tooltip?.body?.(tooltipDetails) ?? (
121121
<ChartSeriesDetails
122122
details={details}
123123
expandedSeries={expandedSeries[point.x]}
@@ -143,7 +143,7 @@ export function useChartTooltipCartesian(
143143
const body = content;
144144

145145
return {
146-
title: props.tooltip?.title?.(tooltipDetails) ?? titleFormatter(point.x),
146+
header: props.tooltip?.header?.(tooltipDetails) ?? titleFormatter(point.x),
147147
body,
148148
footer,
149149
};

src/cartesian-chart/interfaces-cartesian.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ export namespace CartesianChartProps {
163163

164164
export interface TooltipProps {
165165
series?: (detail: TooltipSeriesDetailItem) => TooltipSeriesFormatted;
166-
title?: (detail: TooltipDetails) => React.ReactNode;
167-
content?: (detail: TooltipDetails) => React.ReactNode;
166+
header?: (detail: TooltipDetails) => React.ReactNode;
167+
body?: (detail: TooltipDetails) => React.ReactNode;
168168
footer?: (detail: TooltipDetails) => React.ReactNode;
169169
}
170170

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { render, waitFor } from "@testing-library/react";
5+
import Highcharts from "highcharts";
6+
7+
import "highcharts/modules/no-data-to-display";
8+
import "@cloudscape-design/components/test-utils/dom";
9+
import { CloudscapeHighcharts, CloudscapeHighchartsProps } from "../../../lib/components/core/chart-core";
10+
import testClasses from "../../../lib/components/core/test-classes/styles.selectors";
11+
import createWrapper, { ElementWrapper } from "../../../lib/components/test-utils/dom";
12+
13+
class TestWrapper extends ElementWrapper {
14+
findNoData = () => this.findByClassName(testClasses["no-data"]);
15+
}
16+
17+
function renderChart(props: Partial<CloudscapeHighchartsProps>, Component = CloudscapeHighcharts) {
18+
render(<Component highcharts={Highcharts} className="test-chart" options={{}} {...props} />);
19+
const wrapper = new TestWrapper(createWrapper().findByClassName("test-chart")!.getElement());
20+
return wrapper;
21+
}
22+
23+
const series: Highcharts.SeriesOptionsType[] = [{ type: "line", name: "Line series", data: [1, 2, 3] }];
24+
25+
const noDataContent = {
26+
loading: "no-data: loading",
27+
empty: "no-data: empty",
28+
noMatch: "no-data: no-match",
29+
error: "no-data: error",
30+
};
31+
32+
describe("CloudscapeHighcharts: no-data", () => {
33+
test('does not render no-data when statusType="finished"', () => {
34+
const wrapper = renderChart({
35+
options: { series },
36+
noData: { statusType: "finished", ...noDataContent },
37+
});
38+
39+
expect(wrapper.findNoData()).toBe(null);
40+
});
41+
42+
test('renders no-data loading when statusType="loading"', async () => {
43+
const wrapper = renderChart({
44+
options: { series },
45+
noData: { statusType: "loading", ...noDataContent },
46+
});
47+
48+
await waitFor(() => {
49+
expect(wrapper.findNoData()).not.toBe(null);
50+
expect(wrapper.findNoData()!.getElement().textContent).toBe("no-data: loading");
51+
expect(wrapper.findLiveRegion()!.getElement()).toHaveTextContent("no-data: loading");
52+
});
53+
});
54+
55+
test('renders no-data loading when statusType="error"', async () => {
56+
const wrapper = renderChart({
57+
options: { series },
58+
noData: { statusType: "error", ...noDataContent },
59+
});
60+
61+
await waitFor(() => {
62+
expect(wrapper.findNoData()).not.toBe(null);
63+
expect(wrapper.findNoData()!.getElement().textContent).toBe("no-data: error");
64+
expect(wrapper.findLiveRegion()!.getElement()).toHaveTextContent("no-data: error");
65+
});
66+
});
67+
68+
test('renders no-data empty when statusType="finished" and no series provided', async () => {
69+
const wrapper = renderChart({
70+
options: { series: [] },
71+
noData: { statusType: "finished", ...noDataContent },
72+
});
73+
74+
await waitFor(() => {
75+
expect(wrapper.findNoData()).not.toBe(null);
76+
expect(wrapper.findNoData()!.getElement().textContent).toBe("no-data: empty");
77+
expect(wrapper.findLiveRegion()).toBe(null);
78+
});
79+
});
80+
81+
test('renders no-data no-match when statusType="finished" and no series visible', async () => {
82+
const wrapper = renderChart({
83+
options: { series },
84+
noData: { statusType: "finished", ...noDataContent },
85+
visibleSeries: [],
86+
});
87+
88+
await waitFor(() => {
89+
expect(wrapper.findNoData()).not.toBe(null);
90+
expect(wrapper.findNoData()!.getElement().textContent).toBe("no-data: no-match");
91+
expect(wrapper.findLiveRegion()).toBe(null);
92+
});
93+
});
94+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { render } from "@testing-library/react";
5+
import Highcharts from "highcharts";
6+
7+
import "@cloudscape-design/components/test-utils/dom";
8+
import { CloudscapeHighcharts, CloudscapeHighchartsProps } from "../../../lib/components/core/chart-core";
9+
import createWrapper from "../../../lib/components/test-utils/dom";
10+
11+
function renderChart(props: Partial<CloudscapeHighchartsProps>) {
12+
render(<CloudscapeHighcharts highcharts={Highcharts} className="test-chart" options={{}} {...props} />);
13+
return createWrapper().findByClassName("test-chart");
14+
}
15+
16+
describe("CloudscapeHighcharts: rendering", () => {
17+
test("renders default fallback with highcharts=null", () => {
18+
const wrapper = renderChart({ highcharts: null });
19+
expect(wrapper).not.toBe(null);
20+
expect(wrapper!.findSpinner()).not.toBe(null);
21+
});
22+
23+
test("renders custom fallback with highcharts=null", () => {
24+
const wrapper = renderChart({ highcharts: null, fallback: "Custom fallback" });
25+
expect(wrapper).not.toBe(null);
26+
expect(wrapper!.findSpinner()).toBe(null);
27+
expect(wrapper!.getElement()).toHaveTextContent("Custom fallback");
28+
});
29+
30+
test("renders chart with highcharts=Highcharts", () => {
31+
const wrapper = renderChart({
32+
options: { title: { text: "Chart title" } },
33+
});
34+
expect(wrapper).not.toBe(null);
35+
expect(wrapper!.getElement()).toHaveTextContent("Chart title");
36+
});
37+
});
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { render, waitFor } from "@testing-library/react";
5+
import Highcharts from "highcharts";
6+
import { vi } from "vitest";
7+
8+
import { ComponentWrapper } from "@cloudscape-design/test-utils-core/dom";
9+
10+
import "@cloudscape-design/components/test-utils/dom";
11+
import { CloudscapeHighcharts, CloudscapeHighchartsProps } from "../../../lib/components/core/chart-core";
12+
import testClasses from "../../../lib/components/core/test-classes/styles.selectors";
13+
import tooltipTextClasses from "../../../lib/components/internal/components/popover/test-classes/styles.selectors";
14+
import createWrapper, { ElementWrapper } from "../../../lib/components/test-utils/dom";
15+
16+
class TestWrapper extends ElementWrapper {
17+
findHighchartsTooltip = () => this.findByClassName("highcharts-tooltip");
18+
findTooltip = () => {
19+
const wrapper = this.findByClassName(testClasses.tooltip);
20+
return wrapper ? new TooltipTestWrapper(wrapper.getElement()) : null;
21+
};
22+
}
23+
24+
class TooltipTestWrapper extends ComponentWrapper {
25+
findHeader = () => this.findByClassName(tooltipTextClasses.header);
26+
findBody = () => this.findByClassName(tooltipTextClasses.body);
27+
findFooter = () => this.findByClassName(tooltipTextClasses.footer);
28+
}
29+
30+
function renderChart(props: Partial<CloudscapeHighchartsProps>, Component = CloudscapeHighcharts) {
31+
render(<Component highcharts={Highcharts} className="test-chart" options={{}} {...props} />);
32+
const wrapper = new TestWrapper(createWrapper().findByClassName("test-chart")!.getElement());
33+
return wrapper;
34+
}
35+
36+
const data = [
37+
{ name: "P1", y: 10 },
38+
{ name: "P2", y: 30 },
39+
{ name: "P3", y: 60 },
40+
];
41+
42+
const series: Highcharts.SeriesOptionsType[] = [
43+
{
44+
type: "pie",
45+
name: "Pie series",
46+
data,
47+
},
48+
];
49+
50+
const getChart = () => {
51+
return Highcharts.charts.find((c) => c)!;
52+
};
53+
54+
describe("CloudscapeHighcharts: tooltip", () => {
55+
test("renders highcharts tooltip", () => {
56+
const wrapper = renderChart({
57+
options: { series, tooltip: { enabled: true, formatter: () => "Custom content" } },
58+
});
59+
60+
getChart().series[0].data[0].onMouseOver();
61+
62+
expect(wrapper.findHighchartsTooltip()).not.toBe(null);
63+
expect(wrapper.findHighchartsTooltip()!.getElement().textContent).toBe("Custom content");
64+
});
65+
66+
test("renders tooltip", async () => {
67+
const wrapper = renderChart({
68+
options: { series },
69+
tooltip: { getContent: () => ({ header: "Tooltip title", body: "Tooltip body", footer: "Tooltip footer" }) },
70+
});
71+
72+
getChart().series[0].data[0].onMouseOver();
73+
74+
await waitFor(() => {
75+
expect(wrapper.findTooltip()).not.toBe(null);
76+
expect(wrapper.findTooltip()!.findHeader()!.getElement().textContent).toBe("Tooltip title");
77+
expect(wrapper.findTooltip()!.findBody()!.getElement().textContent).toBe("Tooltip body");
78+
expect(wrapper.findTooltip()!.findFooter()!.getElement().textContent).toBe("Tooltip footer");
79+
});
80+
});
81+
82+
test("provides point for tooltip.getContent", async () => {
83+
const getContent = vi.fn();
84+
renderChart({ options: { series }, tooltip: { getContent } });
85+
86+
for (let i = 0; i < data.length; i++) {
87+
getChart().series[0].data[i].onMouseOver();
88+
89+
await waitFor(() => {
90+
expect(getContent).toHaveBeenCalledWith({ x: i, y: data[i].y });
91+
});
92+
}
93+
});
94+
});

0 commit comments

Comments
 (0)