mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
[Chore] Add unit tests to PanelChrome component (#61695)
* PanelChrome: test loadingState and status * add some tests * fix error-related tests * clean up * fix tests * pass aria-label from PanelChrome to ToolbarButton * add prop comments and clean up
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { screen, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { LoadingState } from '@grafana/data';
|
||||
|
||||
import { PanelChrome, PanelChromeProps } from './PanelChrome';
|
||||
|
||||
const setup = (propOverrides?: Partial<PanelChromeProps>) => {
|
||||
@@ -35,18 +37,50 @@ it('renders an empty panel with padding', () => {
|
||||
expect(screen.getByText("Panel's Content").parentElement).not.toHaveStyle({ padding: '0px' });
|
||||
});
|
||||
|
||||
it('renders panel with a header if prop title', () => {
|
||||
// Check for backwards compatibility
|
||||
it('renders panel header if prop title', () => {
|
||||
setup({ title: 'Test Panel Header' });
|
||||
|
||||
expect(screen.getByTestId('header-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders panel with a header with title in place if prop title', () => {
|
||||
// Check for backwards compatibility
|
||||
it('renders panel with title in place if prop title', () => {
|
||||
setup({ title: 'Test Panel Header' });
|
||||
|
||||
expect(screen.getByText('Test Panel Header')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Check for backwards compatibility
|
||||
it('renders panel with a header if prop leftItems', () => {
|
||||
setup({
|
||||
leftItems: [<div key="left-item-test"> This should be a self-contained node </div>],
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('header-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// todo implement when hoverHeader is implemented
|
||||
it.skip('renders panel without header if no title, no leftItems, and hoverHeader is undefined', () => {
|
||||
setup();
|
||||
|
||||
expect(screen.getByTestId('header-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// todo implement when hoverHeader is implemented
|
||||
it.skip('renders panel with a fixed header if prop hoverHeader is false', () => {
|
||||
setup({ hoverHeader: false });
|
||||
|
||||
expect(screen.getByTestId('header-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// todo implement when hoverHeader is implemented
|
||||
it.skip('renders panel with a hovering header if prop hoverHeader is true', () => {
|
||||
setup({ title: 'Test Panel Header', hoverHeader: true });
|
||||
|
||||
expect(screen.queryByTestId('header-container')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders panel with a header if prop titleItems', () => {
|
||||
setup({
|
||||
titleItems: [<div key="title-item-test"> This should be a self-contained node </div>],
|
||||
@@ -63,11 +97,6 @@ it('renders panel with a header with icons in place if prop titleItems', () => {
|
||||
expect(screen.getByTestId('title-items-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.skip('renders panel with a fixed header if prop hoverHeader is false', () => {
|
||||
// setup({ title: 'Test Panel Header', hoverHeader: false });
|
||||
// expect(screen.getByTestId('header-container')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders panel with a header if prop menu', () => {
|
||||
setup({ menu: <div> Menu </div> });
|
||||
|
||||
@@ -81,8 +110,38 @@ it('renders panel with a show-on-hover menu icon if prop menu', () => {
|
||||
expect(screen.getByTestId('panel-menu-button')).not.toBeVisible();
|
||||
});
|
||||
|
||||
it.skip('renders states in the panel header if any given', () => {});
|
||||
it('renders error status in the panel header if any given', () => {
|
||||
setup({ statusMessage: 'Error test' });
|
||||
|
||||
it.skip('renders leftItems in the panel header if any given when no states prop is given', () => {});
|
||||
expect(screen.getByLabelText('Panel status')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.skip('renders states in the panel header if both leftItems and states are given', () => {});
|
||||
it('does not render error status in the panel header if loadingState is error, but no statusMessage', () => {
|
||||
setup({ loadingState: LoadingState.Error, statusMessage: '' });
|
||||
|
||||
expect(screen.queryByTestId('panel-status')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders loading indicator in the panel header if loadingState is loading', () => {
|
||||
setup({ loadingState: LoadingState.Loading });
|
||||
|
||||
expect(screen.getByLabelText('Panel loading bar')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders loading indicator in the panel header if loadingState is loading regardless of not having a header', () => {
|
||||
setup({ loadingState: LoadingState.Loading, hoverHeader: true });
|
||||
|
||||
expect(screen.getByLabelText('Panel loading bar')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders loading indicator in the panel header if loadingState is loading regardless of having a header', () => {
|
||||
setup({ loadingState: LoadingState.Loading, hoverHeader: false });
|
||||
|
||||
expect(screen.getByLabelText('Panel loading bar')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders streaming indicator in the panel header if loadingState is streaming', () => {
|
||||
setup({ loadingState: LoadingState.Streaming });
|
||||
|
||||
expect(screen.getByTestId('panel-streaming')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -26,10 +26,13 @@ export interface PanelChromeProps {
|
||||
description?: string | (() => string);
|
||||
titleItems?: ReactNode[];
|
||||
menu?: ReactElement | (() => ReactElement);
|
||||
/** dragClass, hoverHeader not yet implemented */
|
||||
dragClass?: string;
|
||||
dragClassCancel?: string;
|
||||
hoverHeader?: boolean;
|
||||
/**
|
||||
* Use only to indicate loading or streaming data in the panel.
|
||||
* Any other values of loadingState are ignored.
|
||||
*/
|
||||
loadingState?: LoadingState;
|
||||
/**
|
||||
* Used to display status message (used for panel errors currently)
|
||||
@@ -39,11 +42,13 @@ export interface PanelChromeProps {
|
||||
* Handle opening error details view (like inspect / error tab)
|
||||
*/
|
||||
statusMessageOnClick?: (e: React.SyntheticEvent) => void;
|
||||
/** @deprecated in favor of props
|
||||
* status for errors and loadingState for loading and streaming
|
||||
/**
|
||||
* @deprecated in favor of props
|
||||
* statusMessage for error messages
|
||||
* and loadingState for loading and streaming data
|
||||
* which will serve the same purpose
|
||||
* of showing/interacting with the panel's data state
|
||||
* */
|
||||
* of showing/interacting with the panel's state
|
||||
*/
|
||||
leftItems?: ReactNode[];
|
||||
}
|
||||
|
||||
@@ -64,14 +69,13 @@ export function PanelChrome({
|
||||
description = '',
|
||||
titleItems = [],
|
||||
menu,
|
||||
// dragClass,
|
||||
dragClass,
|
||||
dragClassCancel,
|
||||
hoverHeader = false,
|
||||
loadingState,
|
||||
statusMessage,
|
||||
statusMessageOnClick,
|
||||
leftItems,
|
||||
dragClass,
|
||||
dragClassCancel,
|
||||
}: PanelChromeProps) {
|
||||
const theme = useTheme2();
|
||||
const styles = useStyles2(getStyles);
|
||||
@@ -108,7 +112,9 @@ export function PanelChrome({
|
||||
return (
|
||||
<div className={styles.container} style={containerStyles} aria-label={ariaLabel}>
|
||||
<div className={styles.loadingBarContainer}>
|
||||
{loadingState === LoadingState.Loading ? <LoadingBar width={'28%'} height={'2px'} /> : null}
|
||||
{loadingState === LoadingState.Loading ? (
|
||||
<LoadingBar width={'28%'} height={'2px'} ariaLabel="Panel loading bar" />
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className={cx(styles.headerContainer, dragClass)} style={headerStyles} data-testid="header-container">
|
||||
@@ -127,7 +133,7 @@ export function PanelChrome({
|
||||
)}
|
||||
|
||||
{loadingState === LoadingState.Streaming && (
|
||||
<div className={styles.item} style={itemStyles}>
|
||||
<div className={styles.item} style={itemStyles} data-testid="panel-streaming">
|
||||
<Tooltip content="Streaming">
|
||||
<Icon name="circle-mono" size="sm" className={styles.streaming} />
|
||||
</Tooltip>
|
||||
@@ -156,6 +162,7 @@ export function PanelChrome({
|
||||
className={cx(styles.errorContainer, dragClassCancel)}
|
||||
message={statusMessage}
|
||||
onClick={statusMessageOnClick}
|
||||
ariaLabel="Panel status"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -229,6 +236,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
},
|
||||
}),
|
||||
loadingBarContainer: css({
|
||||
label: 'panel-loading-bar-container',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
width: '100%',
|
||||
@@ -246,6 +254,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
padding: theme.spacing(0, 0, 0, 1),
|
||||
}),
|
||||
streaming: css({
|
||||
label: 'panel-streaming',
|
||||
marginRight: 0,
|
||||
color: theme.colors.success.text,
|
||||
|
||||
@@ -254,6 +263,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
},
|
||||
}),
|
||||
title: css({
|
||||
label: 'panel-title',
|
||||
marginBottom: 0, // override default h6 margin-bottom
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
@@ -270,6 +280,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
alignItems: 'center',
|
||||
}),
|
||||
menuItem: css({
|
||||
label: 'panel-menu',
|
||||
visibility: 'hidden',
|
||||
border: 'none',
|
||||
}),
|
||||
|
||||
@@ -10,9 +10,10 @@ export interface Props {
|
||||
className?: string;
|
||||
message?: string;
|
||||
onClick?: (e: React.SyntheticEvent) => void;
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
export function PanelStatus({ className, message, onClick }: Props) {
|
||||
export function PanelStatus({ className, message, onClick, ariaLabel = 'status' }: Props) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
@@ -22,6 +23,7 @@ export function PanelStatus({ className, message, onClick }: Props) {
|
||||
variant={'destructive'}
|
||||
icon="exclamation-triangle"
|
||||
tooltip={message || ''}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user