mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DataSourceSettings: use details from HealthCheckResult (#32759)
* add custom HealthCheckError * allow details from HealthCheckResult to be passed in the error * pass in details.message from testing status into Alert component * add chance * add aria label to read only message * update tests and add error message tests * extract HealthCheckResultDetails type out and add comment * extract TestingStatus interface out * remove chance from test * remove chance
This commit is contained in:
@@ -1,85 +1,142 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { DataSourceSettingsPage, Props } from './DataSourceSettingsPage';
|
||||
import { DataSourceConstructor, DataSourcePlugin, DataSourceSettings, NavModel } from '@grafana/data';
|
||||
import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
|
||||
import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
|
||||
import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
|
||||
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
|
||||
import { cleanUpAction } from 'app/core/actions/cleanUp';
|
||||
import { screen, render } from '@testing-library/react';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { PluginState } from '@grafana/data';
|
||||
|
||||
const pluginMock = new DataSourcePlugin({} as DataSourceConstructor<any>);
|
||||
|
||||
jest.mock('app/features/plugins/plugin_loader', () => {
|
||||
return {
|
||||
importDataSourcePlugin: () => Promise.resolve(pluginMock),
|
||||
};
|
||||
const getMockNode = () => ({
|
||||
text: 'text',
|
||||
subTitle: 'subtitle',
|
||||
icon: 'icon',
|
||||
});
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
...getRouteComponentProps(),
|
||||
navModel: {} as NavModel,
|
||||
dataSource: getMockDataSource(),
|
||||
dataSourceMeta: getMockPlugin(),
|
||||
dataSourceId: 1,
|
||||
deleteDataSource: jest.fn(),
|
||||
loadDataSource: jest.fn(),
|
||||
setDataSourceName,
|
||||
updateDataSource: jest.fn(),
|
||||
initDataSourceSettings: jest.fn(),
|
||||
testDataSource: jest.fn(),
|
||||
setIsDefault,
|
||||
dataSourceLoaded,
|
||||
cleanUpAction,
|
||||
page: null,
|
||||
plugin: null,
|
||||
loadError: null,
|
||||
testingStatus: {},
|
||||
...propOverrides,
|
||||
};
|
||||
|
||||
return shallow(<DataSourceSettingsPage {...props} />);
|
||||
};
|
||||
const getProps = (): Props => ({
|
||||
...getRouteComponentProps(),
|
||||
navModel: {
|
||||
node: getMockNode(),
|
||||
main: getMockNode(),
|
||||
},
|
||||
dataSource: getMockDataSource(),
|
||||
dataSourceMeta: getMockPlugin(),
|
||||
dataSourceId: 1,
|
||||
deleteDataSource: jest.fn(),
|
||||
loadDataSource: jest.fn(),
|
||||
setDataSourceName,
|
||||
updateDataSource: jest.fn(),
|
||||
initDataSourceSettings: jest.fn(),
|
||||
testDataSource: jest.fn(),
|
||||
setIsDefault,
|
||||
dataSourceLoaded,
|
||||
cleanUpAction,
|
||||
page: null,
|
||||
plugin: null,
|
||||
loadError: null,
|
||||
testingStatus: {},
|
||||
});
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
it('should not render loading when props are ready', () => {
|
||||
render(<DataSourceSettingsPage {...getProps()} />);
|
||||
|
||||
expect(screen.queryByText('Loading ...')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render loader', () => {
|
||||
const wrapper = setup({
|
||||
dataSource: {} as DataSourceSettings,
|
||||
plugin: pluginMock,
|
||||
});
|
||||
it('should render loading if datasource is not ready', () => {
|
||||
const mockProps = getProps();
|
||||
mockProps.dataSource.id = 0;
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(screen.getByText('Loading ...')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render beta info text', () => {
|
||||
const wrapper = setup({
|
||||
dataSourceMeta: { ...getMockPlugin(), state: 'beta' },
|
||||
});
|
||||
it('should render beta info text if plugin state is beta', () => {
|
||||
const mockProps = getProps();
|
||||
mockProps.dataSourceMeta.state = PluginState.beta;
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(
|
||||
screen.getByTitle('Beta Plugin: There could be bugs and minor breaking changes to this plugin')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render alpha info text', () => {
|
||||
const wrapper = setup({
|
||||
dataSourceMeta: { ...getMockPlugin(), state: 'alpha' },
|
||||
plugin: pluginMock,
|
||||
});
|
||||
it('should render alpha info text if plugin state is alpha', () => {
|
||||
const mockProps = getProps();
|
||||
mockProps.dataSourceMeta.state = PluginState.alpha;
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(
|
||||
screen.getByTitle('Alpha Plugin: This plugin is a work in progress and updates may include breaking changes')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render is ready only message', () => {
|
||||
const wrapper = setup({
|
||||
dataSource: { ...getMockDataSource(), readOnly: true },
|
||||
plugin: pluginMock,
|
||||
});
|
||||
it('should not render is ready only message is readOnly is false', () => {
|
||||
const mockProps = getProps();
|
||||
mockProps.dataSource.readOnly = false;
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(screen.queryByLabelText(selectors.pages.DataSource.readOnly)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render is ready only message is readOnly is true', () => {
|
||||
const mockProps = getProps();
|
||||
mockProps.dataSource.readOnly = true;
|
||||
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(screen.getByLabelText(selectors.pages.DataSource.readOnly)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render error message with detailed message', () => {
|
||||
const mockProps = {
|
||||
...getProps(),
|
||||
testingStatus: {
|
||||
message: 'message',
|
||||
status: 'error',
|
||||
details: { message: 'detailed message' },
|
||||
},
|
||||
};
|
||||
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(screen.getByText(mockProps.testingStatus.message)).toBeInTheDocument();
|
||||
expect(screen.getByText(mockProps.testingStatus.details.message)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render error message with empty details', () => {
|
||||
const mockProps = {
|
||||
...getProps(),
|
||||
testingStatus: {
|
||||
message: 'message',
|
||||
status: 'error',
|
||||
details: {},
|
||||
},
|
||||
};
|
||||
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(screen.getByText(mockProps.testingStatus.message)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render error message without details', () => {
|
||||
const mockProps = {
|
||||
...getProps(),
|
||||
testingStatus: {
|
||||
message: 'message',
|
||||
status: 'error',
|
||||
},
|
||||
};
|
||||
|
||||
render(<DataSourceSettingsPage {...mockProps} />);
|
||||
|
||||
expect(screen.getByText(mockProps.testingStatus.message)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -127,7 +127,7 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
|
||||
renderIsReadOnlyMessage() {
|
||||
return (
|
||||
<InfoBox severity="info">
|
||||
<InfoBox aria-label={selectors.pages.DataSource.readOnly} severity="info">
|
||||
This data source was added by config and cannot be modified using the UI. Please contact your server admin to
|
||||
update this data source.
|
||||
</InfoBox>
|
||||
@@ -234,12 +234,14 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
)}
|
||||
|
||||
<div className="gf-form-group">
|
||||
{testingStatus && testingStatus.message && (
|
||||
{testingStatus?.message && (
|
||||
<Alert
|
||||
severity={testingStatus.status === 'error' ? 'error' : 'success'}
|
||||
title={testingStatus.message}
|
||||
aria-label={selectors.pages.DataSource.alert}
|
||||
/>
|
||||
>
|
||||
{testingStatus.details?.message ?? null}
|
||||
</Alert>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,439 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render alpha info text 1`] = `
|
||||
<Page
|
||||
navModel={Object {}}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div>
|
||||
<form
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<label
|
||||
className="gf-form-label width-10"
|
||||
>
|
||||
Plugin state
|
||||
</label>
|
||||
<label
|
||||
className="gf-form-label gf-form-label--transparent"
|
||||
>
|
||||
<PluginStateinfo
|
||||
state="alpha"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<CloudInfoBox
|
||||
dataSource={
|
||||
Object {
|
||||
"access": "",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"id": 13,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"authType": "credentials",
|
||||
"defaultRegion": "eu-west-2",
|
||||
},
|
||||
"name": "gdev-cloudwatch",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonFields": Object {},
|
||||
"type": "cloudwatch",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
|
||||
"typeName": "Cloudwatch",
|
||||
"url": "",
|
||||
"user": "",
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<BasicSettings
|
||||
dataSourceName="gdev-cloudwatch"
|
||||
isDefault={false}
|
||||
onDefaultChange={[Function]}
|
||||
onNameChange={[Function]}
|
||||
/>
|
||||
<PluginSettings
|
||||
dataSource={
|
||||
Object {
|
||||
"access": "",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"id": 13,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"authType": "credentials",
|
||||
"defaultRegion": "eu-west-2",
|
||||
},
|
||||
"name": "gdev-cloudwatch",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonFields": Object {},
|
||||
"type": "cloudwatch",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
|
||||
"typeName": "Cloudwatch",
|
||||
"url": "",
|
||||
"user": "",
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
dataSourceMeta={
|
||||
Object {
|
||||
"baseUrl": "path/to/plugin",
|
||||
"defaultNavUrl": "some/url",
|
||||
"enabled": false,
|
||||
"hasUpdate": false,
|
||||
"id": "1",
|
||||
"info": Object {
|
||||
"author": Object {
|
||||
"name": "Grafana Labs",
|
||||
"url": "url/to/GrafanaLabs",
|
||||
},
|
||||
"description": "pretty decent plugin",
|
||||
"links": Array [
|
||||
Object {
|
||||
"name": "project",
|
||||
"url": "one link",
|
||||
},
|
||||
],
|
||||
"logos": Object {
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"name": "test",
|
||||
"path": "screenshot",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
"latestVersion": "1",
|
||||
"module": "path/to/module",
|
||||
"name": "pretty cool plugin 1",
|
||||
"pinned": false,
|
||||
"state": "alpha",
|
||||
"type": "panel",
|
||||
}
|
||||
}
|
||||
onModelChange={[Function]}
|
||||
plugin={
|
||||
DataSourcePlugin {
|
||||
"DataSourceClass": Object {},
|
||||
"components": Object {},
|
||||
"meta": Object {},
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
/>
|
||||
<ButtonRow
|
||||
isReadOnly={false}
|
||||
onDelete={[Function]}
|
||||
onSubmit={[Function]}
|
||||
onTest={[Function]}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render beta info text 1`] = `
|
||||
<Page
|
||||
navModel={Object {}}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div>
|
||||
<form
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<div
|
||||
className="gf-form"
|
||||
>
|
||||
<label
|
||||
className="gf-form-label width-10"
|
||||
>
|
||||
Plugin state
|
||||
</label>
|
||||
<label
|
||||
className="gf-form-label gf-form-label--transparent"
|
||||
>
|
||||
<PluginStateinfo
|
||||
state="beta"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<CloudInfoBox
|
||||
dataSource={
|
||||
Object {
|
||||
"access": "",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"id": 13,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"authType": "credentials",
|
||||
"defaultRegion": "eu-west-2",
|
||||
},
|
||||
"name": "gdev-cloudwatch",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonFields": Object {},
|
||||
"type": "cloudwatch",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
|
||||
"typeName": "Cloudwatch",
|
||||
"url": "",
|
||||
"user": "",
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<BasicSettings
|
||||
dataSourceName="gdev-cloudwatch"
|
||||
isDefault={false}
|
||||
onDefaultChange={[Function]}
|
||||
onNameChange={[Function]}
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
/>
|
||||
<ButtonRow
|
||||
isReadOnly={false}
|
||||
onDelete={[Function]}
|
||||
onSubmit={[Function]}
|
||||
onTest={[Function]}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Page
|
||||
navModel={Object {}}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div>
|
||||
<form
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<CloudInfoBox
|
||||
dataSource={
|
||||
Object {
|
||||
"access": "",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"id": 13,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"authType": "credentials",
|
||||
"defaultRegion": "eu-west-2",
|
||||
},
|
||||
"name": "gdev-cloudwatch",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": false,
|
||||
"secureJsonFields": Object {},
|
||||
"type": "cloudwatch",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
|
||||
"typeName": "Cloudwatch",
|
||||
"url": "",
|
||||
"user": "",
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<BasicSettings
|
||||
dataSourceName="gdev-cloudwatch"
|
||||
isDefault={false}
|
||||
onDefaultChange={[Function]}
|
||||
onNameChange={[Function]}
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
/>
|
||||
<ButtonRow
|
||||
isReadOnly={false}
|
||||
onDelete={[Function]}
|
||||
onSubmit={[Function]}
|
||||
onTest={[Function]}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render is ready only message 1`] = `
|
||||
<Page
|
||||
navModel={Object {}}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div>
|
||||
<form
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<InfoBox
|
||||
severity="info"
|
||||
>
|
||||
This data source was added by config and cannot be modified using the UI. Please contact your server admin to update this data source.
|
||||
</InfoBox>
|
||||
<CloudInfoBox
|
||||
dataSource={
|
||||
Object {
|
||||
"access": "",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"id": 13,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"authType": "credentials",
|
||||
"defaultRegion": "eu-west-2",
|
||||
},
|
||||
"name": "gdev-cloudwatch",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": true,
|
||||
"secureJsonFields": Object {},
|
||||
"type": "cloudwatch",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
|
||||
"typeName": "Cloudwatch",
|
||||
"url": "",
|
||||
"user": "",
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<BasicSettings
|
||||
dataSourceName="gdev-cloudwatch"
|
||||
isDefault={false}
|
||||
onDefaultChange={[Function]}
|
||||
onNameChange={[Function]}
|
||||
/>
|
||||
<PluginSettings
|
||||
dataSource={
|
||||
Object {
|
||||
"access": "",
|
||||
"basicAuth": false,
|
||||
"basicAuthPassword": "",
|
||||
"basicAuthUser": "",
|
||||
"database": "",
|
||||
"id": 13,
|
||||
"isDefault": false,
|
||||
"jsonData": Object {
|
||||
"authType": "credentials",
|
||||
"defaultRegion": "eu-west-2",
|
||||
},
|
||||
"name": "gdev-cloudwatch",
|
||||
"orgId": 1,
|
||||
"password": "",
|
||||
"readOnly": true,
|
||||
"secureJsonFields": Object {},
|
||||
"type": "cloudwatch",
|
||||
"typeLogoUrl": "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
|
||||
"typeName": "Cloudwatch",
|
||||
"url": "",
|
||||
"user": "",
|
||||
"withCredentials": false,
|
||||
}
|
||||
}
|
||||
dataSourceMeta={
|
||||
Object {
|
||||
"baseUrl": "path/to/plugin",
|
||||
"defaultNavUrl": "some/url",
|
||||
"enabled": false,
|
||||
"hasUpdate": false,
|
||||
"id": "1",
|
||||
"info": Object {
|
||||
"author": Object {
|
||||
"name": "Grafana Labs",
|
||||
"url": "url/to/GrafanaLabs",
|
||||
},
|
||||
"description": "pretty decent plugin",
|
||||
"links": Array [
|
||||
Object {
|
||||
"name": "project",
|
||||
"url": "one link",
|
||||
},
|
||||
],
|
||||
"logos": Object {
|
||||
"large": "large/logo",
|
||||
"small": "small/logo",
|
||||
},
|
||||
"screenshots": Array [
|
||||
Object {
|
||||
"name": "test",
|
||||
"path": "screenshot",
|
||||
},
|
||||
],
|
||||
"updated": "2018-09-26",
|
||||
"version": "1",
|
||||
},
|
||||
"latestVersion": "1",
|
||||
"module": "path/to/module",
|
||||
"name": "pretty cool plugin 1",
|
||||
"pinned": false,
|
||||
"type": "panel",
|
||||
}
|
||||
}
|
||||
onModelChange={[Function]}
|
||||
plugin={
|
||||
DataSourcePlugin {
|
||||
"DataSourceClass": Object {},
|
||||
"components": Object {},
|
||||
"meta": Object {},
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="gf-form-group"
|
||||
/>
|
||||
<ButtonRow
|
||||
isReadOnly={true}
|
||||
onDelete={[Function]}
|
||||
onSubmit={[Function]}
|
||||
onTest={[Function]}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render loader 1`] = `
|
||||
<Page
|
||||
navModel={Object {}}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
</Page>
|
||||
`;
|
||||
Reference in New Issue
Block a user