Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
plugins
/
components
/
File Content:
AppRootPage.test.tsx
import { act, render, screen } from '@testing-library/react'; import React, { Component } from 'react'; import { Provider } from 'react-redux'; import { Route, Router } from 'react-router-dom'; import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock'; import { AppPlugin, PluginType, AppRootProps, NavModelItem, PluginIncludeType, OrgRole } from '@grafana/data'; import { getMockPlugin } from '@grafana/data/test/__mocks__/pluginMocks'; import { locationService, setEchoSrv } from '@grafana/runtime'; import { GrafanaContext } from 'app/core/context/GrafanaContext'; import { GrafanaRoute } from 'app/core/navigation/GrafanaRoute'; import { RouteDescriptor } from 'app/core/navigation/types'; import { contextSrv } from 'app/core/services/context_srv'; import { Echo } from 'app/core/services/echo/Echo'; import { configureStore } from 'app/store/configureStore'; import { getPluginSettings } from '../pluginSettings'; import { importAppPlugin } from '../plugin_loader'; import AppRootPage from './AppRootPage'; jest.mock('../pluginSettings', () => ({ getPluginSettings: jest.fn(), })); jest.mock('../plugin_loader', () => ({ importAppPlugin: jest.fn(), })); jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), config: { featureToggles: { accessControlOnCall: true, }, theme2: { breakpoints: { values: { sm: 576, md: 768, lg: 992, xl: 1200, }, }, }, }, })); const importAppPluginMock = importAppPlugin as jest.Mock< ReturnType<typeof importAppPlugin>, Parameters<typeof importAppPlugin> >; const getPluginSettingsMock = getPluginSettings as jest.Mock< ReturnType<typeof getPluginSettings>, Parameters<typeof getPluginSettings> >; class RootComponent extends Component<AppRootProps> { static timesRendered = 0; render() { RootComponent.timesRendered += 1; return <p>my great component</p>; } } async function renderUnderRouter(page = '') { const appPluginNavItem: NavModelItem = { text: 'App', id: 'plugin-page-app', url: '/a/plugin-page-app', children: [ { text: 'Page 1', url: '/a/plugin-page-app/page-1', }, { text: 'Page 2', url: '/a/plugin-page-app/page-2', }, ], }; const appsSection = { text: 'apps', id: 'apps', children: [appPluginNavItem], }; appPluginNavItem.parentItem = appsSection; const pagePath = page ? `/${page}` : ''; const store = configureStore(); const route = { component: () => <AppRootPage pluginId="my-awesome-plugin" pluginNavSection={appsSection} />, } as unknown as RouteDescriptor; await act(async () => { locationService.push(`/a/my-awesome-plugin${pagePath}`); }); render( <Router history={locationService.getHistory()}> <Provider store={store}> <GrafanaContext.Provider value={getGrafanaContextMock()}> <Route path={`/a/:pluginId${pagePath}`} exact render={(props) => <GrafanaRoute {...props} route={route} />} /> </GrafanaContext.Provider> </Provider> </Router> ); } describe('AppRootPage', () => { beforeEach(() => { jest.resetAllMocks(); setEchoSrv(new Echo()); }); const pluginMeta = getMockPlugin({ id: 'my-awesome-plugin', type: PluginType.app, enabled: true, }); it("should show a not found page if the plugin settings can't load", async () => { jest.spyOn(console, 'error').mockImplementation(); getPluginSettingsMock.mockRejectedValue(new Error('Unknown Plugin')); // Renders once for the first time await act(async () => { await renderUnderRouter(); }); expect(await screen.findByText('App not found')).toBeVisible(); }); it('should not render the component if we are not under a plugin path', async () => { getPluginSettingsMock.mockResolvedValue(pluginMeta); const plugin = new AppPlugin(); plugin.meta = pluginMeta; plugin.root = RootComponent; importAppPluginMock.mockResolvedValue(plugin); // Renders once for the first time await renderUnderRouter(); expect(await screen.findByText('my great component')).toBeVisible(); expect(RootComponent.timesRendered).toEqual(1); // Does not render again when navigating to a non-plugin path await act(async () => { locationService.push('/foo'); }); expect(RootComponent.timesRendered).toEqual(1); // Renders it again when navigating back to a plugin path await act(async () => { locationService.push('/a/my-awesome-plugin'); }); expect(RootComponent.timesRendered).toEqual(2); }); describe('When accessing using different roles', () => { beforeEach(() => { const pluginMetaWithIncludes = getMockPlugin({ id: 'my-awesome-plugin', type: PluginType.app, enabled: true, includes: [ { type: PluginIncludeType.page, name: 'Awesome page 1', path: '/a/my-awesome-plugin/viewer-page', role: 'Viewer', }, { type: PluginIncludeType.page, name: 'Awesome page 2', path: '/a/my-awesome-plugin/editor-page', role: 'Editor', }, { type: PluginIncludeType.page, name: 'Awesome page 2', path: '/a/my-awesome-plugin/admin-page', role: 'Admin', }, { type: PluginIncludeType.page, name: 'Awesome page with mistake', path: '/a/my-awesome-plugin/mistake-page', role: 'NotExistingRole', }, { type: PluginIncludeType.page, name: 'Awesome page 2', path: '/a/my-awesome-plugin/page-without-role', }, { type: PluginIncludeType.page, name: 'Awesome page 3', path: '/a/my-awesome-plugin/page-with-action-no-role', action: 'grafana-awesomeapp.user-settings:read', }, { type: PluginIncludeType.page, name: 'Awesome page 4', path: '/a/my-awesome-plugin/page-with-action-and-role', role: 'Viewer', action: 'grafana-awesomeapp.user-settings:read', }, ], }); getPluginSettingsMock.mockResolvedValue(pluginMetaWithIncludes); const plugin = new AppPlugin(); plugin.meta = pluginMetaWithIncludes; plugin.root = RootComponent; importAppPluginMock.mockResolvedValue(plugin); }); it('an User should not be able to see page with not existing role', async () => { contextSrv.user.orgRole = OrgRole.Editor; await renderUnderRouter('mistake-page'); expect(await screen.findByText('Access denied')).toBeVisible(); }); it('a None role user should only have access to pages with actions defined or undefined', async () => { contextSrv.user.orgRole = OrgRole.None; // has access to a plugin entry page by default await renderUnderRouter(''); expect(await screen.findByText('my great component')).toBeVisible(); // does not have access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // does not have access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // has access to a page without roles await renderUnderRouter('page-without-role'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to Viewer page await renderUnderRouter('viewer-page'); expect(await screen.findByText('Access denied')).toBeVisible(); contextSrv.user.permissions = { 'grafana-awesomeapp.user-settings:read': true, }; // has access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('my great component')).toBeVisible(); }); it('a Viewer should only have access to pages with "Viewer" roles', async () => { contextSrv.user.orgRole = OrgRole.Viewer; contextSrv.user.permissions = {}; // Viewer has access to a plugin entry page by default await renderUnderRouter(''); expect(await screen.findByText('my great component')).toBeVisible(); // Viewer does not have access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // Viewer does not have access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // Viewer has access to a page without roles await renderUnderRouter('page-without-role'); expect(await screen.findByText('my great component')).toBeVisible(); // Viewer has access to Viewer page await renderUnderRouter('viewer-page'); expect(await screen.findByText('my great component')).toBeVisible(); // Viewer does not have access to Editor page await renderUnderRouter('editor-page'); expect(await screen.findByText('Access denied')).toBeVisible(); // Viewer does not have access to a Admin page await renderUnderRouter('admin-page'); expect(await screen.findByText('Access denied')).toBeVisible(); }); it('an Editor should have access to pages with both "Viewer" and "Editor" roles', async () => { contextSrv.user.orgRole = OrgRole.Editor; contextSrv.isEditor = true; contextSrv.user.permissions = {}; // does not have access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // does not have access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // has access to a plugin entry page by default await renderUnderRouter(''); expect(await screen.findByText('my great component')).toBeVisible(); // has access to a page without roles await renderUnderRouter('page-without-role'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to Viewer page await renderUnderRouter('viewer-page'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to Editor page await renderUnderRouter('editor-page'); expect(await screen.findByText('my great component')).toBeVisible(); // does not have access to a Admin page await renderUnderRouter('admin-page'); expect(await screen.findByText('Access denied')).toBeVisible(); contextSrv.user.permissions = { 'grafana-awesomeapp.user-settings:read': true, }; // has access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('my great component')).toBeVisible(); }); it('an Admin should have access to pages with both "Viewer" and "Editor" roles', async () => { contextSrv.user.orgRole = OrgRole.Admin; contextSrv.user.permissions = {}; // does not have access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // does not have access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // has access to a plugin entry page by default await renderUnderRouter(''); expect(await screen.findByText('my great component')).toBeVisible(); // has access to a page without roles await renderUnderRouter('page-without-role'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to Viewer page await renderUnderRouter('viewer-page'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to Editor page await renderUnderRouter('editor-page'); expect(await screen.findByText('my great component')).toBeVisible(); // has access to a Admin page await renderUnderRouter('admin-page'); expect(await screen.findByText('my great component')).toBeVisible(); }); it('a Grafana Admin should be able to see any page without action specifier', async () => { contextSrv.isGrafanaAdmin = true; // Viewer has access to a plugin entry page await renderUnderRouter(''); expect(await screen.findByText('my great component')).toBeVisible(); // Viewer does not have access to a page with an action but no role await renderUnderRouter('page-with-action-no-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // Viewer does not have access to a page with an action and role await renderUnderRouter('page-with-action-and-role'); expect(await screen.findByText('Access denied')).toBeVisible(); // Admin has access to a page without roles await renderUnderRouter('page-without-role'); expect(await screen.findByText('my great component')).toBeVisible(); // Admin has access to Viewer page await renderUnderRouter('viewer-page'); expect(await screen.findByText('my great component')).toBeVisible(); // Admin has access to Editor page await renderUnderRouter('editor-page'); expect(await screen.findByText('my great component')).toBeVisible(); // Admin has access to a Admin page await renderUnderRouter('admin-page'); expect(await screen.findByText('my great component')).toBeVisible(); }); }); });
Edit
Rename
Chmod
Delete
FILE
FOLDER
INFO
Name
Size
Permission
Action
AppRootPage.test.tsx
14538 bytes
0644
AppRootPage.tsx
7213 bytes
0644
PluginPageContext.tsx
649 bytes
0644
PluginStateInfo.tsx
1207 bytes
0644
PluginsErrorsInfo.tsx
2667 bytes
0644
N4ST4R_ID | Naxtarrr