Commit 297ff9a1 by Hugo Häggmark Committed by GitHub

DashboardLinks: Fixes crash when link has no title (#31008)

* DashboardLinks: Fixes crash when link misses title

* Chore: updates after PR comments
parent f43d834a
import React from 'react';
import { render, screen } from '@testing-library/react';
import { DataLinksListItem, DataLinksListItemProps } from './DataLinksListItem';
const baseLink = {
url: '',
title: '',
onBuildUrl: jest.fn(),
onClick: jest.fn(),
};
function setupTestContext(options: Partial<DataLinksListItemProps>) {
const defaults: DataLinksListItemProps = {
index: 0,
link: baseLink,
data: [],
onChange: jest.fn(),
onEdit: jest.fn(),
onRemove: jest.fn(),
suggestions: [],
};
const props = { ...defaults, ...options };
const { rerender } = render(<DataLinksListItem {...props} />);
return { rerender, props };
}
describe('DataLinksListItem', () => {
describe('when link has title', () => {
it('then the link title should be visible', () => {
const link = {
...baseLink,
title: 'Some Data Link Title',
};
setupTestContext({ link });
expect(screen.getByText(/some data link title/i)).toBeInTheDocument();
});
});
describe('when link has url', () => {
it('then the link url should be visible', () => {
const link = {
...baseLink,
url: 'http://localhost:3000',
};
setupTestContext({ link });
expect(screen.getByText(/http:\/\/localhost\:3000/i)).toBeInTheDocument();
expect(screen.getByTitle(/http:\/\/localhost\:3000/i)).toBeInTheDocument();
});
});
describe('when link is missing title', () => {
it('then the link title should be replaced by [Data link title not provided]', () => {
const link = {
...baseLink,
title: (undefined as unknown) as string,
};
setupTestContext({ link });
expect(screen.getByText(/data link title not provided/i)).toBeInTheDocument();
});
});
describe('when link is missing url', () => {
it('then the link url should be replaced by [Data link url not provided]', () => {
const link = {
...baseLink,
url: (undefined as unknown) as string,
};
setupTestContext({ link });
expect(screen.getByText(/data link url not provided/i)).toBeInTheDocument();
expect(screen.getByTitle('')).toBeInTheDocument();
});
});
describe('when link title is empty', () => {
it('then the link title should be replaced by [Data link title not provided]', () => {
const link = {
...baseLink,
title: ' ',
};
setupTestContext({ link });
expect(screen.getByText(/data link title not provided/i)).toBeInTheDocument();
});
});
describe('when link url is empty', () => {
it('then the link url should be replaced by [Data link url not provided]', () => {
const link = {
...baseLink,
url: ' ',
};
setupTestContext({ link });
expect(screen.getByText(/data link url not provided/i)).toBeInTheDocument();
expect(screen.getByTitle('')).toBeInTheDocument();
});
});
});
...@@ -5,7 +5,7 @@ import { stylesFactory, useTheme } from '../../../themes'; ...@@ -5,7 +5,7 @@ import { stylesFactory, useTheme } from '../../../themes';
import { HorizontalGroup, VerticalGroup } from '../../Layout/Layout'; import { HorizontalGroup, VerticalGroup } from '../../Layout/Layout';
import { IconButton } from '../../IconButton/IconButton'; import { IconButton } from '../../IconButton/IconButton';
interface DataLinksListItemProps { export interface DataLinksListItemProps {
index: number; index: number;
link: DataLink; link: DataLink;
data: DataFrame[]; data: DataFrame[];
...@@ -19,24 +19,25 @@ interface DataLinksListItemProps { ...@@ -19,24 +19,25 @@ interface DataLinksListItemProps {
export const DataLinksListItem: FC<DataLinksListItemProps> = ({ link, onEdit, onRemove }) => { export const DataLinksListItem: FC<DataLinksListItemProps> = ({ link, onEdit, onRemove }) => {
const theme = useTheme(); const theme = useTheme();
const styles = getDataLinkListItemStyles(theme); const styles = getDataLinkListItemStyles(theme);
const { title = '', url = '' } = link;
const hasTitle = link.title.trim() !== ''; const hasTitle = title.trim() !== '';
const hasUrl = link.url.trim() !== ''; const hasUrl = url.trim() !== '';
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<VerticalGroup spacing="xs"> <VerticalGroup spacing="xs">
<HorizontalGroup justify="space-between" align="flex-start" width="100%"> <HorizontalGroup justify="space-between" align="flex-start" width="100%">
<div className={cx(styles.title, !hasTitle && styles.notConfigured)}> <div className={cx(styles.title, !hasTitle && styles.notConfigured)}>
{hasTitle ? link.title : 'Data link title not provided'} {hasTitle ? title : 'Data link title not provided'}
</div> </div>
<HorizontalGroup> <HorizontalGroup>
<IconButton name="pen" onClick={onEdit} /> <IconButton name="pen" onClick={onEdit} />
<IconButton name="times" onClick={onRemove} /> <IconButton name="times" onClick={onRemove} />
</HorizontalGroup> </HorizontalGroup>
</HorizontalGroup> </HorizontalGroup>
<div className={cx(styles.url, !hasUrl && styles.notConfigured)} title={link.url}> <div className={cx(styles.url, !hasUrl && styles.notConfigured)} title={url}>
{hasUrl ? link.url : 'Data link url not provided'} {hasUrl ? url : 'Data link url not provided'}
</div> </div>
</VerticalGroup> </VerticalGroup>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment