diff --git a/packages/react-charting/docs/TestPlans/VerticalStackedBarChart/ComponentTests.md b/packages/react-charting/docs/TestPlans/VerticalStackedBarChart/ComponentTests.md
new file mode 100644
index 00000000000000..92d269c99e870d
--- /dev/null
+++ b/packages/react-charting/docs/TestPlans/VerticalStackedBarChart/ComponentTests.md
@@ -0,0 +1,73 @@
+**Vertical Stacked Bar Chart – Component test plan**
+
+**Sub-components: Bar, Line, Legends, Callout, Labels**
+
+1. **Bar: Bar data, Bar color (single/multiple), bar label**
+1. **Line: show/hide line, highlight data points on line and show callout**
+1. **Legends: show/hide legends, highlight the corresponding bar/line on legend hover**
+1. **Callout: Default/custom callout**
+1. **Labels: x-Axis labels default/rotated**
+
+| **Test steps** | **Validation** | **Tool used** |
+| :---------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------: | :-----------: |
+| Test 1: [Snapshot testing] | | |
+| - With only data prop, numerical data on x-axis. | Renders VerticalStackedBar chart correctly | RTL |
+| - With HideLegend prop set to “true” | Should hide legends | Enzyme |
+| - With HideTooltip prop set to “true” | Should hide the tooltip in chart | Enzyme |
+| - With EnabledLegendsWrapLines set to “true” | Should enable the legends to wrap lines if there is not enough space to show all legends on a single line | Enzyme |
+| - With ShowXAxisLablesTooltip set to “true” | Should truncate x axis labels and show tooltip on x axis labels | Enzyme |
+| - With WrapXAxisLables set to “true” | Should wrap x axis label values | Enzyme |
+| - With isCalloutForStack set to “true” | Should render callout for stack properly | Enzyme |
+| - With yAxisTickFormat set to “%d” |
Should render the y-axis ticks in the format specified
| Enzyme |
+| - With hideLabels set to “true” | Should hide bar labels | Enzyme |
+| Test 2: Basic props testing | | |
+| - HideLegend prop set to “true” | Should not mount legend when hideLegend is true | Enzyme |
+| - HideLegend prop set to “false” | Should mount legend when hideLegend is false | Enzyme |
+| - HideTooltip prop set to “true” | Should not mount callout when hideTootip is true | Enzyme |
+| - HideTooltip prop set to “false” | Should mount callout when hideTootip is false | Enzyme |
+| - onRenderCalloutPerStack prop is not given | Should not render onRenderCalloutPerStack | Enzyme |
+| - onRenderCalloutPerDataPoint is given | Should render onRenderCalloutPerDataPoint | Enzyme |
+| - onRenderCalloutPerDataPoint is not given | Should not render onRenderCalloutPerDataPoint | Enzyme |
+| - onRenderCalloutPerDataPoint is given | Should render onRenderCalloutPerDataPoint | Enzyme |
+| Test 3: Render calling with respective to props | | |
+| - No prop changes: Mount VerticalStackedBar chart and then set the same props again | Render function should have been called twice | Enzyme |
+| - Prop changes: Mount VerticalStackedBar chart and then set some other prop | Render function should have been called twice | Enzyme |
+| Test 4: Mouse events | | |
+| - Mouse over on a bar | Should render callout correctly on mouseover | Enzyme |
+| - Mouse move from one bar to other bar | Should render callout correctly on mouse move | Enzyme |
+| - Mouse over on a bar with customized callout | Should render customized callout on mouseover | Enzyme |
+| - Customized callout per stack on mouse over | Should render customized callout per stack correctly on mouseover | Enzyme |
+| - Customized callout on a bar from one bar to other bar | Should render customized callout for stack on mouseover | Enzyme |
+| Test 5: [Sub-Component]: Line | | |
+| - Specify line data | Should render line with the data provided | RTL |
+| Test 6: [Sub-Component]: Bar | | |
+| - Specify bar color | Should render bar with the specified color | RTL |
+| - Specify separate bars in a single bar | Should render stacked bar with specified data | RTL |
+| - setMinimumBarHeight to “x” | Should render bars properly, bars below this height will be displayed at this height | RTL |
+| - set barWidth to “x” | Should render bars with specified bar width | RTL |
+| - set barGapMax to “x” | Should render bars with specified bar gap | RTL |
+| - set barCornerRadius | Should render top bar with specified bar corner radius | RTL |
+| Test 7: [Sub-Component]: Legends | | |
+| - Hide legends | Should not show any rendered legends | RTL |
+| - Hover mouse over line legends | Should reduce the opacity of the other lines/bars | RTL |
+| - Hover mouse over bar legends | Should reduce the opacity of the other lines/bars | RTL |
+| - Mouse move from one Legend to another Legend | Should reset the opacity of the lines on mouse leave a bar legend | RTL |
+| - Single mouse click on bar legends | Should select legend on single mouse click on respective legend | RTL |
+| - Double mouse click on bar legends | Should deselect legend on double mouse click on respective legend | RTL |
+| - Single mouse click on line legends | Should select legend on single mouse click on respective legend | RTL |
+| - Double mouse click on line legends | Should deselect legend on double mouse click on respective legend | RTL |
+| Test 8: [Sub-Component]: Callout | | |
+| - Hover mouse over a bar | Should call the handler on mouse over bar | RTL |
+| - Hover mouse over a bar to display callout | Should show the default callout over that bar | RTL |
+| - Hover mouse over a stacked bar | Should show the default stacked call out | RTL |
+| - Hover mouse over the line | Should show the default callout over that line | RTL |
+| - Specify custom callout and hover mouse over a bar | Should show the custom callout over that bar | RTL |
+| - Specify custom callout and hover mouse over the line | Should show the custom callout over that line | RTL |
+| - Mouse click on bar | Should call the handler on mouse click on the bar | RTL |
+| Test 9: [Sub-Component]: x-axis labels | | |
+| - Truncate x-axis labels | Should show the x-axis labels tooltip when hovered | RTL |
+| - Rotate x-axis labels | Should rotate the x-axis labels by 45 degrees | RTL |
+| Test 10: [Sub-Component]: Screen resolution | | |
+| - Increase the screen resolution (zoom in) | Should remain unchanged on zoom in | RTL |
+| - Decrease the screen resolution (zoom out) | Should remain unchanged on zoom out | RTL |
+| Test 11: Theme changed to Dark Theme | Should reflect theme change | RTL |
diff --git a/packages/react-charting/src/components/VerticalStackedBarChart/VerticalStackedBarChartRTL.test.tsx b/packages/react-charting/src/components/VerticalStackedBarChart/VerticalStackedBarChartRTL.test.tsx
index caae9733cb38e9..fd6b98cd2dc4e7 100644
--- a/packages/react-charting/src/components/VerticalStackedBarChart/VerticalStackedBarChartRTL.test.tsx
+++ b/packages/react-charting/src/components/VerticalStackedBarChart/VerticalStackedBarChartRTL.test.tsx
@@ -1,22 +1,493 @@
+import { render, screen, fireEvent, act } from '@testing-library/react';
+import { chartPoints } from './VerticalStackedBarChart.test';
import * as React from 'react';
-import { queryAllByAttribute, render, waitFor } from '@testing-library/react';
-import { emptyChartPoints, chartPoints } from './VerticalStackedBarChart.test';
-import { VerticalStackedBarChart } from './index';
+import { DarkTheme } from '@fluentui/theme-samples';
+import { ThemeProvider } from '@fluentui/react';
+import { DefaultPalette } from '@fluentui/react/lib/Styling';
+import { IVSChartDataPoint } from '../../index';
+import { VerticalStackedBarChart } from './VerticalStackedBarChart';
+import { getByClass, getById, testWithWait, testWithoutWait } from '../../utilities/TestUtility.test';
+import { VerticalStackedBarChartBase } from './VerticalStackedBarChart.base';
+
+const firstChartPoints: IVSChartDataPoint[] = [
+ { legend: 'Metadata1', data: 2, color: DefaultPalette.blue },
+ { legend: 'Metadata2', data: 0.5, color: DefaultPalette.blueMid },
+ { legend: 'Metadata3', data: 0, color: DefaultPalette.blueLight },
+];
+
+const secondChartPoints: IVSChartDataPoint[] = [
+ { legend: 'Metadata1', data: 30, color: DefaultPalette.blue },
+ { legend: 'Metadata2', data: 3, color: DefaultPalette.blueMid },
+ { legend: 'Metadata3', data: 40, color: DefaultPalette.blueLight },
+];
+
+const thirdChartPoints: IVSChartDataPoint[] = [
+ { legend: 'Metadata1', data: 10, color: DefaultPalette.blue },
+ { legend: 'Metadata2', data: 60, color: DefaultPalette.blueMid },
+ { legend: 'Metadata3', data: 30, color: DefaultPalette.blueLight },
+];
+
+const simplePoints = [
+ {
+ chartData: firstChartPoints,
+ xAxisPoint: 'January',
+ lineData: [{ y: 42, legend: 'Supported Builds', color: DefaultPalette.magentaLight }],
+ },
+ {
+ chartData: secondChartPoints,
+ xAxisPoint: 'February',
+ lineData: [{ y: 41, legend: 'Supported Builds', color: DefaultPalette.magentaLight }],
+ },
+ {
+ chartData: thirdChartPoints,
+ xAxisPoint: 'March',
+ lineData: [{ y: 100, legend: 'Supported Builds', color: DefaultPalette.magentaLight }],
+ },
+];
+
+const simplePointsWithLine = [
+ {
+ chartData: firstChartPoints,
+ xAxisPoint: 20,
+ lineData: [{ y: 42, legend: 'Supported Builds', color: DefaultPalette.magentaLight }],
+ },
+];
+
+const simpleChartPoints: IVSChartDataPoint[] = [
+ { legend: 'Metadata1', data: 2, color: DefaultPalette.blue },
+ { legend: 'Metadata2', data: 0.5, color: DefaultPalette.blueMid },
+];
+
+const simplePointsWithoutLine = [
+ {
+ chartData: simpleChartPoints,
+ xAxisPoint: 20,
+ },
+];
+
+const maxBarGap = 5;
describe('Vertical stacked bar chart rendering', () => {
- test('Should re-render the Vertical stacked bar chart with data', async () => {
- // Arrange
- const { container, rerender } = render();
- const getById = queryAllByAttribute.bind(null, 'id');
- // Assert
- expect(container).toMatchSnapshot();
- expect(getById(container, /_VSBC_empty/i)).toHaveLength(1);
- // Act
- rerender();
- await waitFor(() => {
+ testWithoutWait(
+ 'Should render the vertical stacked bar chart with numeric x-axis data',
+ VerticalStackedBarChart,
+ { data: chartPoints },
+ container => {
// Assert
expect(container).toMatchSnapshot();
- expect(getById(container, /_VSBC_empty/i)).toHaveLength(0);
+ },
+ );
+});
+
+describe('Vertical stacked bar chart - Subcomponent Line', () => {
+ testWithoutWait(
+ 'Should render line with the data provided',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ // Assert
+ const lines = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'line');
+ expect(lines).toBeDefined();
+ },
+ );
+});
+
+describe('Vertical stacked bar chart - Subcomponent bar', () => {
+ testWithWait(
+ 'Should set minimum bar height',
+ VerticalStackedBarChart,
+ { data: simplePoints, barMinimumHeight: 100 },
+ container => {
+ // Legends have 'rect' as a part of their classname
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ // Assert
+ expect(bars[0].getAttribute('height')).toEqual('100');
+ },
+ );
+
+ testWithWait(
+ 'Should render the bar with the given width',
+ VerticalStackedBarChart,
+ { data: simplePointsWithLine, barWidth: 100 },
+ container => {
+ // Assert
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ expect(bars).toHaveLength(2);
+ expect(bars[0].getAttribute('width')).toEqual('100');
+ expect(bars[1].getAttribute('width')).toEqual('100');
+ },
+ );
+
+ testWithWait(
+ 'Should render the bar with the given maximum bar gap',
+ VerticalStackedBarChart,
+ { data: simplePointsWithoutLine, barGapMax: maxBarGap },
+ container => {
+ // Assert
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ expect(bars).toHaveLength(2);
+ const firstBarYvalue = Number(bars[1].getAttribute('y'));
+ const firstBarHeight = Number(bars[1].getAttribute('height'));
+ const secondBarYvalue = Number(bars[0].getAttribute('y'));
+ expect(firstBarYvalue! + firstBarHeight + maxBarGap).toEqual(secondBarYvalue!);
+ },
+ );
+
+ testWithWait(
+ 'Should render the bar with the given bar corner radius',
+ VerticalStackedBarChart,
+ { data: simplePointsWithoutLine, barCornerRadius: 6 },
+ container => {
+ // Assert
+ const legend = screen.queryByText('a 6 6');
+ expect(legend).toBeDefined();
+ },
+ );
+
+ testWithWait(
+ 'Should render the bar with the specified color',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ // Assert
+ expect(bars[0].getAttribute('fill')).toEqual(DefaultPalette.blue);
+ expect(bars[1].getAttribute('fill')).toEqual(DefaultPalette.blueMid);
+ },
+ );
+
+ testWithWait(
+ 'Should render the stacked bar with the specified data',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ // Assert
+ expect(bars).toHaveLength(8);
+ },
+ );
+});
+
+describe('Vertical stacked bar chart - Subcomponent Legends', () => {
+ testWithoutWait(
+ 'Should not show any rendered legends when hideLegend is true',
+ VerticalStackedBarChart,
+ { data: simplePoints, hideLegend: true },
+ container => {
+ // Assert
+ // Legends have 'rect' as a part of their classname
+ expect(getByClass(container, /rect/i)).toHaveLength(0);
+ },
+ );
+
+ testWithWait(
+ 'Should reduce the opacity of the other bars/lines on mouse over a line legend',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ const line = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'line');
+ const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button');
+ fireEvent.mouseOver(legends[0]);
+ // Assert
+ expect(line[8].getAttribute('opacity')).toEqual('1');
+ expect(bars[0]).toHaveStyle('opacity: 0.1');
+ expect(bars[1]).toHaveStyle('opacity: 0.1');
+ expect(bars[2]).toHaveStyle('opacity: 0.1');
+ expect(bars[3]).toHaveStyle('opacity: 0.1');
+ expect(bars[4]).toHaveStyle('opacity: 0.1');
+ expect(bars[5]).toHaveStyle('opacity: 0.1');
+ expect(bars[6]).toHaveStyle('opacity: 0.1');
+ expect(bars[7]).toHaveStyle('opacity: 0.1');
+ },
+ );
+
+ testWithWait(
+ 'Should reduce the opacity of the other bars/lines on mouse over a bar legend',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ // Arrange
+ const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button');
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ const line = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'line');
+ fireEvent.mouseOver(legends![1]);
+
+ // Assert
+ expect(line[8].getAttribute('opacity')).toEqual('0.1');
+ expect(bars[1]).not.toHaveAttribute('opacity');
+ expect(bars[1]).toHaveStyle('opacity: 0.1');
+ expect(bars[3]).toHaveStyle('opacity: 0.1');
+ expect(bars[4]).toHaveStyle('opacity: 0.1');
+ expect(bars[6]).toHaveStyle('opacity: 0.1');
+ expect(bars[7]).toHaveStyle('opacity: 0.1');
+ },
+ );
+
+ testWithWait(
+ 'Should reset the opacity of the lines on mouse leave a bar legend',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ // Arrange
+ const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button');
+ fireEvent.mouseOver(legends![1]);
+ fireEvent.mouseLeave(legends![1]);
+ const line = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'line');
+ // Assert
+ expect(line[8].getAttribute('opacity')).toEqual('1');
+ },
+ );
+
+ testWithWait(
+ 'Should select legend on single mouse click on legends',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button');
+ fireEvent.click(legends![1]);
+ const legendsAfterClickEvent = screen.getAllByText(
+ (content, element) => element!.tagName.toLowerCase() === 'button',
+ );
+ // Assert
+ expect(legendsAfterClickEvent[0]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[1]).toHaveAttribute('aria-selected', 'true');
+ expect(legendsAfterClickEvent[2]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[3]).toHaveAttribute('aria-selected', 'false');
+ },
+ );
+
+ testWithWait(
+ 'Should deselect legend on double mouse click on legends',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button');
+ fireEvent.click(legends![1]);
+ fireEvent.click(legends![1]);
+ const legendsAfterClickEvent = screen.getAllByText(
+ (content, element) => element!.tagName.toLowerCase() === 'button',
+ );
+ // Assert
+ expect(legendsAfterClickEvent[0]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[1]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[2]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[3]).toHaveAttribute('aria-selected', 'false');
+ },
+ );
+
+ testWithWait(
+ 'Should select line legend on single mouse click on line legends',
+ VerticalStackedBarChart,
+ { data: simplePoints },
+ container => {
+ const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button');
+ fireEvent.click(legends![0]);
+ const legendsAfterClickEvent = screen.getAllByText(
+ (content, element) => element!.tagName.toLowerCase() === 'button',
+ );
+ // Assert
+ expect(legendsAfterClickEvent[0]).toHaveAttribute('aria-selected', 'true');
+ expect(legendsAfterClickEvent[1]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[2]).toHaveAttribute('aria-selected', 'false');
+ expect(legendsAfterClickEvent[3]).toHaveAttribute('aria-selected', 'false');
+ },
+ );
+});
+
+describe('Vertical stacked bar chart - Subcomponent callout', () => {
+ testWithWait(
+ 'Should call the handler on mouse over bar and on mouse leave from bar',
+ VerticalStackedBarChart,
+ { data: simplePoints, calloutProps: { doNotLayer: true } },
+ container => {
+ // eslint-disable-next-line
+ const handleMouseOver = jest.spyOn(VerticalStackedBarChartBase.prototype as any, '_onStackHover');
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ // Assert
+ expect(bars).toHaveLength(8);
+ fireEvent.mouseOver(bars[0]);
+ expect(handleMouseOver).toHaveBeenCalled();
+ },
+ );
+
+ testWithWait(
+ 'Should show the callout over the bar on mouse over',
+ VerticalStackedBarChart,
+ { data: simplePoints, calloutProps: { doNotLayer: true } },
+ container => {
+ // Arrange
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ fireEvent.mouseOver(bars[2]);
+ // Assert
+ expect(getById(container, /toolTipcallout/i)).toBeDefined();
+ },
+ );
+
+ testWithWait(
+ 'Should show the stacked callout over the bar on mouse over',
+ VerticalStackedBarChart,
+ { data: simplePoints, calloutProps: { doNotLayer: true } },
+ container => {
+ // Arrange
+ const bars = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'rect');
+ expect(bars).toHaveLength(8);
+ fireEvent.mouseOver(bars[2]);
+ // Assert
+ expect(getByClass(container, /calloutlegendText/i)).toBeDefined();
+ expect(getByClass(container, /calloutlegendText/i)).toHaveLength(4);
+ },
+ );
+
+ testWithWait(
+ 'Should show the callout over the line on mouse over',
+ VerticalStackedBarChart,
+ { data: simplePoints, calloutProps: { doNotLayer: true } },
+ container => {
+ const lines = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'line');
+ fireEvent.mouseOver(lines[0]);
+ // Assert
+ expect(getById(container, /toolTipcallout/i)).toBeDefined();
+ },
+ );
+
+ testWithWait(
+ 'Should show the custom callout over the bar on mouse over',
+ VerticalStackedBarChart,
+ {
+ data: simplePoints,
+ calloutProps: { doNotLayer: true },
+ onRenderCalloutPerDataPoint: (props: IVSChartDataPoint) =>
+ props ? (
+
+
+`;
+
+exports[`Vertical stacked bar chart - Screen resolution Should remain unchanged on zoom out 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Vertical stacked bar chart - Theme Should reflect theme change 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
-exports[`Vertical stacked bar chart rendering Should re-render the Vertical stacked bar chart with data 2`] = `
+exports[`Vertical stacked bar chart rendering Should render the vertical stacked bar chart with numeric x-axis data 1`] = `