-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'charting/web-components' of https://github.com/microsof…
…t/fluentui into charting/web-components
- Loading branch information
Showing
5 changed files
with
963 additions
and
4 deletions.
There are no files selected for viewing
140 changes: 140 additions & 0 deletions
140
packages/charts/chart-web-components/src/donut-chart/donut-chart.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { test } from '@playwright/test'; | ||
import { expect, fixtureURL } from '../helpers.tests.js'; | ||
import { ChartDataPoint, ChartProps } from './donut-chart.options.js'; | ||
import { teamsDarkTheme } from '@fluentui/tokens'; | ||
|
||
const points: ChartDataPoint[] = [ | ||
{ | ||
legend: 'first', | ||
data: 20000, | ||
}, | ||
{ | ||
legend: 'second', | ||
data: 39000, | ||
}, | ||
]; | ||
|
||
const data: ChartProps = { | ||
chartTitle: 'Donut chart basic example', | ||
chartData: points, | ||
}; | ||
|
||
test.describe('Donut-chart - Basic', () => { | ||
test.beforeEach(async ({ page }) => { | ||
await page.goto(fixtureURL('components-donutchart--basic')); | ||
await page.setContent(/* html */ ` | ||
<div> | ||
<fluent-donut-chart value-inside-donut="39,000" inner-radius="55" data='${JSON.stringify(data)}'> | ||
</fluent-donut-chart> | ||
</div> | ||
`); | ||
await page.waitForFunction(() => customElements.whenDefined('fluent-donut-chart')); | ||
}); | ||
|
||
test('Should render chart properly', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const legends = element.locator('.legend-text'); | ||
await expect(legends.nth(0).getByText('first')).toBeVisible(); | ||
await expect(legends.nth(1).getByText('second')).toBeVisible(); | ||
await expect(element.getByText('39,000')).toBeVisible(); | ||
}); | ||
|
||
test('Should render path with proper attributes and css', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const arcList = element.locator('.arc'); | ||
await expect(arcList).toHaveCount(2); | ||
await expect(arcList.nth(0)).toHaveAttribute('fill', '#637cef'); | ||
await expect(arcList.nth(0)).toHaveAttribute('aria-label', 'first, 20000.'); | ||
await expect(arcList.nth(0)).toHaveAttribute( | ||
'd', | ||
'M-76.547,47.334A90,90,0,0,1,-1.055,-89.994L-1.055,-54.99A55,55,0,0,0,-46.993,28.577Z', | ||
); | ||
await expect(arcList.nth(0)).toHaveCSS('fill', 'rgb(99, 124, 239)'); | ||
await expect(arcList.nth(0)).toHaveCSS('--borderRadiusMedium', '4px'); | ||
|
||
await expect(arcList.nth(1)).toHaveAttribute('fill', '#e3008c'); | ||
await expect(arcList.nth(1)).toHaveAttribute('aria-label', 'second, 39000.'); | ||
await expect(arcList.nth(1)).toHaveAttribute( | ||
'd', | ||
'M1.055,-89.994A90,90,0,1,1,-75.417,49.115L-45.863,30.358A55,55,0,1,0,1.055,-54.99Z', | ||
); | ||
await expect(arcList.nth(1)).toHaveCSS('fill', 'rgb(227, 0, 140)'); | ||
await expect(arcList.nth(1)).toHaveCSS('--borderRadiusMedium', '4px'); | ||
}); | ||
|
||
test('Should render legends data properly', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const legends = element.getByRole('option'); | ||
await expect(legends).toHaveCount(2); | ||
const firstLegend = element.getByRole('option', { name: 'First' }); | ||
const secondLegend = element.getByRole('option', { name: 'Second' }); | ||
await expect(firstLegend).toBeVisible(); | ||
await expect(firstLegend).toHaveText('first'); | ||
await expect(firstLegend).toHaveCSS('--borderRadiusMedium', '4px'); | ||
await expect(secondLegend).toBeVisible(); | ||
await expect(secondLegend).toHaveText('second'); | ||
await expect(secondLegend).toHaveCSS('--borderRadiusMedium', '4px'); | ||
}); | ||
|
||
test('Should update path css values with mouse click event on legend', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const firstPath = element.getByLabel('first,'); | ||
const secondPath = element.getByLabel('second,'); | ||
const firstLegend = element.getByRole('option', { name: 'First' }); | ||
//mouse events | ||
await firstLegend.click(); | ||
await expect(firstPath).toHaveCSS('opacity', '1'); | ||
await expect(secondPath).toHaveCSS('opacity', '0.1'); | ||
await firstLegend.click(); | ||
await expect(firstPath).toHaveCSS('opacity', '1'); | ||
await expect(secondPath).toHaveCSS('opacity', '1'); | ||
}); | ||
|
||
test('Should update path css values with mouse hover event on legend', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const firstPath = element.getByLabel('first,'); | ||
const secondPath = element.getByLabel('second,'); | ||
const firstLegend = element.getByRole('option', { name: 'First' }); | ||
//mouse events | ||
await firstLegend.dispatchEvent('mouseover'); | ||
await expect(firstPath).toHaveCSS('opacity', '1'); | ||
await expect(secondPath).toHaveCSS('opacity', '0.1'); | ||
await firstLegend.dispatchEvent('mouseout'); | ||
await expect(firstPath).toHaveCSS('opacity', '1'); | ||
await expect(secondPath).toHaveCSS('opacity', '1'); | ||
}); | ||
|
||
test('Should show callout with mouse hover event on path', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const firstPath = element.getByLabel('first,'); | ||
const calloutRoot = element.locator('.tooltip'); | ||
await expect(calloutRoot).toHaveCount(0); | ||
await firstPath.dispatchEvent('mouseover'); | ||
await expect(calloutRoot).toHaveCount(1); | ||
await expect(calloutRoot).toHaveCSS('opacity', '1'); | ||
const calloutLegendText = await element.locator('.tooltip-legend-text'); | ||
await expect(calloutLegendText).toHaveText('first'); | ||
const calloutContentY = await element.locator('.tooltip-content-y'); | ||
await expect(calloutContentY).toHaveText('20000'); | ||
await firstPath.dispatchEvent('mouseout'); | ||
await expect(calloutRoot).not.toHaveCSS('opacity', '0'); | ||
}); | ||
|
||
test('Should update callout data when mouse moved from one path to another path', async ({ page }) => { | ||
const element = page.locator('fluent-donut-chart'); | ||
const firstPath = element.getByLabel('first,'); | ||
const calloutRoot = element.locator('.tooltip'); | ||
await expect(calloutRoot).toHaveCount(0); | ||
await firstPath.dispatchEvent('mouseover'); | ||
await expect(calloutRoot).toHaveCSS('opacity', '1'); | ||
const calloutLegendText = await element.locator('.tooltip-legend-text'); | ||
await expect(calloutLegendText).toHaveText('first'); | ||
const calloutContentY = await element.locator('.tooltip-content-y'); | ||
await expect(calloutContentY).toHaveText('20000'); | ||
const secondPath = element.getByLabel('second,'); | ||
await secondPath.dispatchEvent('mouseover'); | ||
await expect(calloutRoot).toHaveCSS('opacity', '1'); | ||
await expect(calloutLegendText).toHaveText('second'); | ||
await expect(calloutContentY).toHaveText('39000'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import qs from 'qs'; | ||
import { expect as baseExpect, type ExpectMatcherState, type Locator } from '@playwright/test'; | ||
|
||
/** | ||
* Returns a formatted URL for a given Storybook fixture. | ||
* | ||
* @param id - the Storybook fixture ID | ||
* @param args - Story args | ||
* @returns - the local URL for the Storybook fixture iframe | ||
*/ | ||
export function fixtureURL(id: string = 'debug--blank', args?: Record<string, any>): string { | ||
const params: Record<string, any> = { id }; | ||
if (args) { | ||
params.args = qs | ||
.stringify(args, { | ||
allowDots: true, | ||
delimiter: ';', | ||
format: 'RFC1738', | ||
encode: false, | ||
}) | ||
.replace(/=/g, ':') | ||
.replace(/\//g, '--'); | ||
} | ||
|
||
const url = qs.stringify(params, { | ||
addQueryPrefix: true, | ||
format: 'RFC1738', | ||
encode: false, | ||
}); | ||
|
||
return url; | ||
} | ||
|
||
/** | ||
* Evaluate whether an element has the given state or not on its `elementInternals` property. | ||
* | ||
* @param locator - The Playwright locator for the element. | ||
* @param state - The name of the state. | ||
* @param expected - Whether the given state is expected to exist. | ||
* @param has - Whether the element is expected to have or not have the given state, defaults to `true`. | ||
*/ | ||
async function toHaveCustomState( | ||
this: ExpectMatcherState, | ||
locator: Locator, | ||
state: string, | ||
options?: { timeout?: number }, | ||
) { | ||
const assertionName = 'toHaveCustomState'; | ||
let pass: boolean; | ||
let matcherResult: any; | ||
const expected: boolean = !this.isNot; | ||
|
||
try { | ||
baseExpect(await locator.evaluate((el, state) => el.matches(`:state(${state})`), state, options)).toEqual(true); | ||
pass = true; | ||
} catch (err: any) { | ||
matcherResult = err.matcherResult; | ||
pass = false; | ||
} | ||
|
||
const message = pass | ||
? () => | ||
this.utils.matcherHint(assertionName, undefined, undefined, { isNot: this.isNot }) + | ||
'\n\n' + | ||
`Locator: ${locator}\n` + | ||
`Expected: ${this.isNot ? 'not' : ''}${this.utils.printExpected(expected)}\n` + | ||
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : '') | ||
: () => | ||
this.utils.matcherHint(assertionName, undefined, undefined, { isNot: this.isNot }) + | ||
'\n\n' + | ||
`Locator: ${locator}\n` + | ||
`Expected: ${this.utils.printExpected(expected)}\n` + | ||
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : ''); | ||
|
||
return { | ||
name: assertionName, | ||
message, | ||
pass, | ||
expected, | ||
actual: matcherResult?.actual, | ||
}; | ||
} | ||
|
||
export const expect = baseExpect.extend({ | ||
toHaveCustomState, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.