mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
132 lines
3.7 KiB
TypeScript
132 lines
3.7 KiB
TypeScript
import { render, screen } from '@testing-library/react';
|
|
import React from 'react';
|
|
import { act } from 'react-dom/test-utils';
|
|
|
|
import { PluginType, rangeUtil, PluginExtensionLink, PluginExtensionTypes } from '@grafana/data';
|
|
import { usePluginLinkExtensions } from '@grafana/runtime';
|
|
|
|
import { PyroscopeDataSource } from '../datasource';
|
|
import { mockFetchPyroscopeDatasourceSettings } from '../datasource.test';
|
|
|
|
import { Props, PyroscopeQueryLinkExtensions, resetPyroscopeQueryLinkExtensionsFetches } from './QueryLinkExtension';
|
|
|
|
// Constants copied from `QueryLinkExtension.tsx`
|
|
const EXTENSION_POINT_ID = 'plugins/grafana-pyroscope-datasource/query-links';
|
|
|
|
jest.mock('@grafana/runtime', () => ({
|
|
...jest.requireActual('@grafana/runtime'),
|
|
usePluginLinkExtensions: jest.fn(),
|
|
getTemplateSrv: () => {
|
|
return {
|
|
replace: (query: string): string => {
|
|
return query.replace(/\$var/g, 'interpolated');
|
|
},
|
|
};
|
|
},
|
|
}));
|
|
|
|
const usePluginLinkExtensionsMock = jest.mocked(usePluginLinkExtensions);
|
|
|
|
const defaultPyroscopeDataSourceSettings = {
|
|
uid: 'default-pyroscope',
|
|
url: 'http://pyroscope',
|
|
basicAuthUser: 'pyroscope_user',
|
|
};
|
|
|
|
describe('PyroscopeQueryLinkExtensions', () => {
|
|
const EXPECTED_BUTTON_LABEL = 'Profiles App';
|
|
const DEFAULT_EXTENSION_PATH = 'a/mock-path-app/fake-path';
|
|
|
|
function createExtension(overrides?: Partial<PluginExtensionLink>) {
|
|
return {
|
|
...{
|
|
description: 'unremarkable-description',
|
|
extensionPointId: EXTENSION_POINT_ID,
|
|
title: EXPECTED_BUTTON_LABEL,
|
|
path: DEFAULT_EXTENSION_PATH,
|
|
type: PluginExtensionTypes.link,
|
|
category: 'unremarkable-category',
|
|
icon: 'heart',
|
|
onClick() {},
|
|
pluginId: 'mock-path-app',
|
|
id: `${Date.now()}}`,
|
|
},
|
|
...overrides,
|
|
} as PluginExtensionLink;
|
|
}
|
|
|
|
beforeEach(() => {
|
|
resetPyroscopeQueryLinkExtensionsFetches();
|
|
mockFetchPyroscopeDatasourceSettings(defaultPyroscopeDataSourceSettings);
|
|
|
|
usePluginLinkExtensionsMock.mockRestore();
|
|
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [], isLoading: false }); // Unless stated otherwise, no extensions
|
|
});
|
|
|
|
it('should render if extension present', async () => {
|
|
usePluginLinkExtensionsMock.mockReturnValue({ extensions: [createExtension()], isLoading: false }); // Default extension
|
|
|
|
await act(setup);
|
|
expect(await screen.findAllByText(EXPECTED_BUTTON_LABEL)).toBeDefined();
|
|
});
|
|
|
|
it('Should not render if no extension present', async () => {
|
|
await act(setup);
|
|
expect(screen.queryByText(EXPECTED_BUTTON_LABEL)).toBeNull();
|
|
});
|
|
});
|
|
|
|
function setupDs() {
|
|
const ds = new PyroscopeDataSource({
|
|
...defaultPyroscopeDataSourceSettings,
|
|
name: 'test',
|
|
type: PluginType.datasource,
|
|
access: 'proxy',
|
|
id: 1,
|
|
jsonData: {},
|
|
meta: {
|
|
name: '',
|
|
id: '',
|
|
type: PluginType.datasource,
|
|
baseUrl: '',
|
|
info: {
|
|
author: {
|
|
name: '',
|
|
},
|
|
description: '',
|
|
links: [],
|
|
logos: {
|
|
large: '',
|
|
small: '',
|
|
},
|
|
screenshots: [],
|
|
updated: '',
|
|
version: '',
|
|
},
|
|
module: '',
|
|
},
|
|
readOnly: false,
|
|
});
|
|
|
|
return ds;
|
|
}
|
|
|
|
async function setup(options: { props: Partial<Props> } = { props: {} }) {
|
|
const utils = render(
|
|
<PyroscopeQueryLinkExtensions
|
|
query={{
|
|
queryType: 'both',
|
|
labelSelector: '',
|
|
profileTypeId: 'process_cpu:cpu',
|
|
refId: 'A',
|
|
maxNodes: 1000,
|
|
groupBy: [],
|
|
}}
|
|
datasource={setupDs()}
|
|
range={rangeUtil.convertRawToRange({ from: 'now-1h', to: 'now' })}
|
|
{...options.props}
|
|
/>
|
|
);
|
|
return { ...utils };
|
|
}
|