diff --git a/packages/grafana-data/src/text/markdown.test.ts b/packages/grafana-data/src/text/markdown.test.ts
index b9e7052c3ef..20a5bab4611 100644
--- a/packages/grafana-data/src/text/markdown.test.ts
+++ b/packages/grafana-data/src/text/markdown.test.ts
@@ -1,5 +1,4 @@
-import { renderMarkdown } from './markdown';
-import { sanitizeTextPanelContent } from './sanitize';
+import { renderMarkdown, renderTextPanelMarkdown } from './markdown';
describe('Markdown wrapper', () => {
it('should be able to handle undefined value', () => {
@@ -12,12 +11,8 @@ describe('Markdown wrapper', () => {
expect(str).toBe('<script>alert()</script>');
});
- it('should allow whitelisted styles in text panel', () => {
- const html =
- '
';
- const str = sanitizeTextPanelContent(html);
- expect(str).toBe(
- ''
- );
+ it('should sanitize content in text panel by default', () => {
+ const str = renderTextPanelMarkdown('');
+ expect(str).toBe('<script>alert()</script>');
});
});
diff --git a/packages/grafana-data/src/text/sanitize.test.ts b/packages/grafana-data/src/text/sanitize.test.ts
new file mode 100644
index 00000000000..8d9ff47d4d9
--- /dev/null
+++ b/packages/grafana-data/src/text/sanitize.test.ts
@@ -0,0 +1,12 @@
+import { sanitizeTextPanelContent } from './sanitize';
+
+describe('Sanitize wrapper', () => {
+ it('should allow whitelisted styles in text panel', () => {
+ const html =
+ '';
+ const str = sanitizeTextPanelContent(html);
+ expect(str).toBe(
+ ''
+ );
+ });
+});
diff --git a/public/app/plugins/panel/text/TextPanel.test.tsx b/public/app/plugins/panel/text/TextPanel.test.tsx
new file mode 100644
index 00000000000..99a245dff33
--- /dev/null
+++ b/public/app/plugins/panel/text/TextPanel.test.tsx
@@ -0,0 +1,120 @@
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+
+import { dateTime, LoadingState, EventBusSrv } from '@grafana/data';
+
+import { Props, TextPanel } from './TextPanel';
+import { TextMode } from './models.gen';
+
+const replaceVariablesMock = jest.fn();
+const defaultProps: Props = {
+ id: 1,
+ data: {
+ state: LoadingState.Done,
+ series: [
+ {
+ fields: [],
+ length: 0,
+ },
+ ],
+ timeRange: {
+ from: dateTime('2022-01-01T15:55:00Z'),
+ to: dateTime('2022-07-12T15:55:00Z'),
+ raw: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ },
+ },
+ timeRange: {
+ from: dateTime('2022-07-11T15:55:00Z'),
+ to: dateTime('2022-07-12T15:55:00Z'),
+ raw: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ },
+ timeZone: 'utc',
+ transparent: false,
+ width: 120,
+ height: 120,
+ fieldConfig: {
+ defaults: {},
+ overrides: [],
+ },
+ renderCounter: 1,
+ title: 'Test Text Panel',
+ eventBus: new EventBusSrv(),
+ options: { content: '', mode: TextMode.Markdown },
+ onOptionsChange: jest.fn(),
+ onFieldConfigChange: jest.fn(),
+ replaceVariables: replaceVariablesMock,
+ onChangeTimeRange: jest.fn(),
+};
+
+const setup = (props: Props = defaultProps) => {
+ render();
+};
+
+describe('TextPanel', () => {
+ it('should render panel without content', () => {
+ expect(() => setup()).not.toThrow();
+ });
+
+ it('sanitizes content in html mode', () => {
+ const contentTest = '\n';
+ replaceVariablesMock.mockReturnValueOnce(contentTest);
+ const props = Object.assign({}, defaultProps, {
+ options: { content: contentTest, mode: TextMode.HTML },
+ });
+
+ setup(props);
+
+ expect(screen.getByTestId('TextPanel-converted-content').innerHTML).toEqual(
+ '<form>Form tags are sanitized.
</form>\n<script>Script tags are sanitized.</script>'
+ );
+ });
+
+ it('sanitizes content in markdown mode', () => {
+ const contentTest = '\n';
+ replaceVariablesMock.mockReturnValueOnce(contentTest);
+
+ const props = Object.assign({}, defaultProps, {
+ options: { content: contentTest, mode: TextMode.Markdown },
+ });
+
+ setup(props);
+
+ expect(screen.getByTestId('TextPanel-converted-content').innerHTML).toEqual(
+ '<form>Form tags are sanitized.
</form>\n<script>Script tags are sanitized.</script>'
+ );
+ });
+
+ it('converts content to markdown when in markdown mode', async () => {
+ const contentTest = 'We begin by a simple sentence.\n```code block```';
+ replaceVariablesMock.mockReturnValueOnce(contentTest);
+
+ const props = Object.assign({}, defaultProps, {
+ options: { content: contentTest, mode: TextMode.Markdown },
+ });
+
+ setup(props);
+
+ const waited = await screen.getByTestId('TextPanel-converted-content');
+ expect(waited.innerHTML).toEqual('We begin by a simple sentence.\ncode block
\n');
+ });
+
+ it('converts content to html when in html mode', () => {
+ const contentTest = 'We begin by a simple sentence.\n```This is a code block\n```';
+ replaceVariablesMock.mockReturnValueOnce(contentTest);
+ const props = Object.assign({}, defaultProps, {
+ options: { content: contentTest, mode: TextMode.HTML },
+ });
+
+ setup(props);
+
+ expect(screen.getByTestId('TextPanel-converted-content').innerHTML).toEqual(
+ 'We begin by a simple sentence.\n```This is a code block\n```'
+ );
+ });
+});
diff --git a/public/app/plugins/panel/text/TextPanel.tsx b/public/app/plugins/panel/text/TextPanel.tsx
index c30ba779ec9..8494f3a76c8 100644
--- a/public/app/plugins/panel/text/TextPanel.tsx
+++ b/public/app/plugins/panel/text/TextPanel.tsx
@@ -12,7 +12,7 @@ import config from 'app/core/config';
// Types
import { PanelOptions, TextMode } from './models.gen';
-interface Props extends PanelProps {}
+export interface Props extends PanelProps {}
interface State {
html: string;
@@ -90,7 +90,11 @@ export class TextPanel extends PureComponent {
const styles = getStyles();
return (
-
+
);
}