123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- import { render, RenderResult, waitFor, within } from '@testing-library/react';
- import userEvent from '@testing-library/user-event';
- import React from 'react';
- import { Provider } from 'react-redux';
- import { Router } from 'react-router-dom';
- import { PluginType } from '@grafana/data';
- import { locationService } from '@grafana/runtime';
- import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
- import { configureStore } from 'app/store/configureStore';
- import { getCatalogPluginMock, getPluginsStateMock } from '../__mocks__';
- import { fetchRemotePlugins } from '../state/actions';
- import { PluginAdminRoutes, CatalogPlugin, ReducerState, RequestStatus } from '../types';
- import BrowsePage from './Browse';
- jest.mock('@grafana/runtime', () => {
- const original = jest.requireActual('@grafana/runtime');
- const mockedRuntime = { ...original };
- mockedRuntime.config.bootData.user.isGrafanaAdmin = true;
- mockedRuntime.config.buildInfo.version = 'v8.1.0';
- return mockedRuntime;
- });
- const renderBrowse = (
- path = '/plugins',
- plugins: CatalogPlugin[] = [],
- pluginsStateOverride?: ReducerState
- ): RenderResult => {
- const store = configureStore({ plugins: pluginsStateOverride || getPluginsStateMock(plugins) });
- locationService.push(path);
- const props = getRouteComponentProps({
- route: { routeName: PluginAdminRoutes.Home } as any,
- });
- return render(
- <Provider store={store}>
- <Router history={locationService.getHistory()}>
- <BrowsePage {...props} />
- </Router>
- </Provider>
- );
- };
- describe('Browse list of plugins', () => {
- describe('when filtering', () => {
- it('should list installed plugins by default', async () => {
- const { queryByText } = renderBrowse('/plugins', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-4', name: 'Plugin 4', isInstalled: false }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 1')).toBeInTheDocument());
- expect(queryByText('Plugin 1')).toBeInTheDocument();
- expect(queryByText('Plugin 2')).toBeInTheDocument();
- expect(queryByText('Plugin 3')).toBeInTheDocument();
- expect(queryByText('Plugin 4')).toBeNull();
- });
- it('should list all plugins (except core plugins) when filtering by all', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&filterByType=all', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', isInstalled: false }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-4', name: 'Plugin 4', isInstalled: true, isCore: true }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 1')).toBeInTheDocument());
- expect(queryByText('Plugin 2')).toBeInTheDocument();
- expect(queryByText('Plugin 3')).toBeInTheDocument();
- // Core plugins should not be listed
- expect(queryByText('Plugin 4')).not.toBeInTheDocument();
- });
- it('should list installed plugins (including core plugins) when filtering by installed', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=installed', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', isInstalled: false }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-4', name: 'Plugin 4', isInstalled: true, isCore: true }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 1')).toBeInTheDocument());
- expect(queryByText('Plugin 3')).toBeInTheDocument();
- expect(queryByText('Plugin 4')).toBeInTheDocument();
- // Not showing not installed plugins
- expect(queryByText('Plugin 2')).not.toBeInTheDocument();
- });
- it('should list all plugins (including disabled plugins) when filtering by all', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&filterByType=all', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', isInstalled: false }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-4', name: 'Plugin 4', isInstalled: true, isDisabled: true }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 1')).toBeInTheDocument());
- expect(queryByText('Plugin 2')).toBeInTheDocument();
- expect(queryByText('Plugin 3')).toBeInTheDocument();
- expect(queryByText('Plugin 4')).toBeInTheDocument();
- });
- it('should list installed plugins (including disabled plugins) when filtering by installed', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=installed', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', isInstalled: false }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-4', name: 'Plugin 4', isInstalled: true, isDisabled: true }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 1')).toBeInTheDocument());
- expect(queryByText('Plugin 3')).toBeInTheDocument();
- expect(queryByText('Plugin 4')).toBeInTheDocument();
- // Not showing not installed plugins
- expect(queryByText('Plugin 2')).not.toBeInTheDocument();
- });
- it('should list enterprise plugins when querying for them', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&q=wavefront', [
- getCatalogPluginMock({ id: 'wavefront', name: 'Wavefront', isInstalled: true, isEnterprise: true }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', isInstalled: true, isCore: true }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', isInstalled: true }),
- ]);
- await waitFor(() => expect(queryByText('Wavefront')).toBeInTheDocument());
- // Should not show plugins that don't match the query
- expect(queryByText('Plugin 2')).not.toBeInTheDocument();
- expect(queryByText('Plugin 3')).not.toBeInTheDocument();
- });
- it('should list only datasource plugins when filtering by datasource', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&filterByType=datasource', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', type: PluginType.app }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', type: PluginType.datasource }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', type: PluginType.panel }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 2')).toBeInTheDocument());
- // Other plugin types shouldn't be shown
- expect(queryByText('Plugin 1')).not.toBeInTheDocument();
- expect(queryByText('Plugin 3')).not.toBeInTheDocument();
- });
- it('should list only panel plugins when filtering by panel', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&filterByType=panel', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', type: PluginType.app }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', type: PluginType.datasource }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', type: PluginType.panel }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 3')).toBeInTheDocument());
- // Other plugin types shouldn't be shown
- expect(queryByText('Plugin 1')).not.toBeInTheDocument();
- expect(queryByText('Plugin 2')).not.toBeInTheDocument();
- });
- it('should list only app plugins when filtering by app', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&filterByType=app', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', type: PluginType.app }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2', type: PluginType.datasource }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3', type: PluginType.panel }),
- ]);
- await waitFor(() => expect(queryByText('Plugin 1')).toBeInTheDocument());
- // Other plugin types shouldn't be shown
- expect(queryByText('Plugin 2')).not.toBeInTheDocument();
- expect(queryByText('Plugin 3')).not.toBeInTheDocument();
- });
- });
- describe('when searching', () => {
- it('should only list plugins matching search', async () => {
- const { queryByText } = renderBrowse('/plugins?filterBy=all&q=zabbix', [
- getCatalogPluginMock({ id: 'zabbix', name: 'Zabbix' }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2' }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3' }),
- ]);
- await waitFor(() => expect(queryByText('Zabbix')).toBeInTheDocument());
- // Other plugin types shouldn't be shown
- expect(queryByText('Plugin 2')).not.toBeInTheDocument();
- expect(queryByText('Plugin 3')).not.toBeInTheDocument();
- });
- });
- describe('when sorting', () => {
- it('should sort plugins by name in ascending alphabetical order', async () => {
- const { findByTestId } = renderBrowse('/plugins?filterBy=all', [
- getCatalogPluginMock({ id: 'wavefront', name: 'Wavefront' }),
- getCatalogPluginMock({ id: 'redis-application', name: 'Redis Application' }),
- getCatalogPluginMock({ id: 'zabbix', name: 'Zabbix' }),
- getCatalogPluginMock({ id: 'diagram', name: 'Diagram' }),
- getCatalogPluginMock({ id: 'acesvg', name: 'ACE.SVG' }),
- ]);
- const pluginList = await findByTestId('plugin-list');
- const pluginHeadings = within(pluginList).queryAllByRole('heading');
- expect(pluginHeadings.map((heading) => heading.innerHTML)).toStrictEqual([
- 'ACE.SVG',
- 'Diagram',
- 'Redis Application',
- 'Wavefront',
- 'Zabbix',
- ]);
- });
- it('should sort plugins by name in descending alphabetical order', async () => {
- const { findByTestId } = renderBrowse('/plugins?filterBy=all&sortBy=nameDesc', [
- getCatalogPluginMock({ id: 'wavefront', name: 'Wavefront' }),
- getCatalogPluginMock({ id: 'redis-application', name: 'Redis Application' }),
- getCatalogPluginMock({ id: 'zabbix', name: 'Zabbix' }),
- getCatalogPluginMock({ id: 'diagram', name: 'Diagram' }),
- getCatalogPluginMock({ id: 'acesvg', name: 'ACE.SVG' }),
- ]);
- const pluginList = await findByTestId('plugin-list');
- const pluginHeadings = within(pluginList).queryAllByRole('heading');
- expect(pluginHeadings.map((heading) => heading.innerHTML)).toStrictEqual([
- 'Zabbix',
- 'Wavefront',
- 'Redis Application',
- 'Diagram',
- 'ACE.SVG',
- ]);
- });
- it('should sort plugins by date in ascending updated order', async () => {
- const { findByTestId } = renderBrowse('/plugins?filterBy=all&sortBy=updated', [
- getCatalogPluginMock({ id: '1', name: 'Wavefront', updatedAt: '2021-04-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '2', name: 'Redis Application', updatedAt: '2021-02-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '3', name: 'Zabbix', updatedAt: '2021-01-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '4', name: 'Diagram', updatedAt: '2021-05-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '5', name: 'ACE.SVG', updatedAt: '2021-02-01T00:00:00.000Z' }),
- ]);
- const pluginList = await findByTestId('plugin-list');
- const pluginHeadings = within(pluginList).queryAllByRole('heading');
- expect(pluginHeadings.map((heading) => heading.innerHTML)).toStrictEqual([
- 'Diagram',
- 'Wavefront',
- 'Redis Application',
- 'ACE.SVG',
- 'Zabbix',
- ]);
- });
- it('should sort plugins by date in ascending published order', async () => {
- const { findByTestId } = renderBrowse('/plugins?filterBy=all&sortBy=published', [
- getCatalogPluginMock({ id: '1', name: 'Wavefront', publishedAt: '2021-04-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '2', name: 'Redis Application', publishedAt: '2021-02-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '3', name: 'Zabbix', publishedAt: '2021-01-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '4', name: 'Diagram', publishedAt: '2021-05-01T00:00:00.000Z' }),
- getCatalogPluginMock({ id: '5', name: 'ACE.SVG', publishedAt: '2021-02-01T00:00:00.000Z' }),
- ]);
- const pluginList = await findByTestId('plugin-list');
- const pluginHeadings = within(pluginList).queryAllByRole('heading');
- expect(pluginHeadings.map((heading) => heading.innerHTML)).toStrictEqual([
- 'Diagram',
- 'Wavefront',
- 'Redis Application',
- 'ACE.SVG',
- 'Zabbix',
- ]);
- });
- it('should sort plugins by number of downloads in ascending order', async () => {
- const { findByTestId } = renderBrowse('/plugins?filterBy=all&sortBy=downloads', [
- getCatalogPluginMock({ id: '1', name: 'Wavefront', downloads: 30 }),
- getCatalogPluginMock({ id: '2', name: 'Redis Application', downloads: 10 }),
- getCatalogPluginMock({ id: '3', name: 'Zabbix', downloads: 50 }),
- getCatalogPluginMock({ id: '4', name: 'Diagram', downloads: 20 }),
- getCatalogPluginMock({ id: '5', name: 'ACE.SVG', downloads: 40 }),
- ]);
- const pluginList = await findByTestId('plugin-list');
- const pluginHeadings = within(pluginList).queryAllByRole('heading');
- expect(pluginHeadings.map((heading) => heading.innerHTML)).toStrictEqual([
- 'Zabbix',
- 'ACE.SVG',
- 'Wavefront',
- 'Diagram',
- 'Redis Application',
- ]);
- });
- });
- describe('when GCOM api is not available', () => {
- it('should disable the All / Installed filter', async () => {
- const plugins = [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 2', isInstalled: true }),
- getCatalogPluginMock({ id: 'plugin-4', name: 'Plugin 3', isInstalled: true }),
- ];
- const state = getPluginsStateMock(plugins);
- // Mock the store like if the remote plugins request was rejected
- const stateOverride = {
- ...state,
- requests: {
- ...state.requests,
- [fetchRemotePlugins.typePrefix]: {
- status: RequestStatus.Rejected,
- },
- },
- };
- // The radio input for the filters should be disabled
- const { getByRole } = renderBrowse('/plugins', [], stateOverride);
- await waitFor(() => expect(getByRole('radio', { name: 'Installed' })).toBeDisabled());
- });
- });
- it('should be possible to switch between display modes', async () => {
- const { findByTestId, getByRole, getByTitle, queryByText } = renderBrowse('/plugins?filterBy=all', [
- getCatalogPluginMock({ id: 'plugin-1', name: 'Plugin 1' }),
- getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2' }),
- getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3' }),
- ]);
- await findByTestId('plugin-list');
- const listOptionTitle = 'Display plugins in list';
- const gridOptionTitle = 'Display plugins in a grid layout';
- const listOption = getByRole('radio', { name: listOptionTitle });
- const listOptionLabel = getByTitle(listOptionTitle);
- const gridOption = getByRole('radio', { name: gridOptionTitle });
- const gridOptionLabel = getByTitle(gridOptionTitle);
- // All options should be visible
- expect(listOptionLabel).toBeVisible();
- expect(gridOptionLabel).toBeVisible();
- // The default display mode should be "grid"
- expect(gridOption).toBeChecked();
- expect(listOption).not.toBeChecked();
- // Switch to "list" view
- await userEvent.click(listOption);
- expect(gridOption).not.toBeChecked();
- expect(listOption).toBeChecked();
- // All plugins are still visible
- expect(queryByText('Plugin 1')).toBeInTheDocument();
- expect(queryByText('Plugin 2')).toBeInTheDocument();
- expect(queryByText('Plugin 3')).toBeInTheDocument();
- });
- });
|