mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
278 lines
7.4 KiB
TypeScript
278 lines
7.4 KiB
TypeScript
import { waitFor } from '@testing-library/react';
|
|
|
|
import { Scope } from '@grafana/data';
|
|
import { config } from '@grafana/runtime';
|
|
import {
|
|
behaviors,
|
|
sceneGraph,
|
|
SceneGridItem,
|
|
SceneGridLayout,
|
|
SceneQueryRunner,
|
|
SceneTimeRange,
|
|
VizPanel,
|
|
} from '@grafana/scenes';
|
|
|
|
import { DashboardControls } from './DashboardControls';
|
|
import { DashboardScene } from './DashboardScene';
|
|
import { ScopeDashboard, ScopesDashboardsScene } from './ScopesDashboardsScene';
|
|
import { ScopesFiltersScene } from './ScopesFiltersScene';
|
|
import { ScopesScene } from './ScopesScene';
|
|
|
|
const dashboardsMocks = {
|
|
dashboard1: {
|
|
uid: 'dashboard1',
|
|
title: 'Dashboard 1',
|
|
url: '/d/dashboard1',
|
|
},
|
|
dashboard2: {
|
|
uid: 'dashboard2',
|
|
title: 'Dashboard 2',
|
|
url: '/d/dashboard2',
|
|
},
|
|
dashboard3: {
|
|
uid: 'dashboard3',
|
|
title: 'Dashboard 3',
|
|
url: '/d/dashboard3',
|
|
},
|
|
};
|
|
|
|
const scopesMocks: Record<
|
|
string,
|
|
Scope & {
|
|
dashboards: ScopeDashboard[];
|
|
}
|
|
> = {
|
|
scope1: {
|
|
metadata: {
|
|
name: 'scope1',
|
|
},
|
|
spec: {
|
|
title: 'Scope 1',
|
|
type: 'Type 1',
|
|
description: 'Description 1',
|
|
category: 'Category 1',
|
|
filters: [
|
|
{ key: 'a-key', operator: 'equals', value: 'a-value' },
|
|
{ key: 'b-key', operator: 'not-equals', value: 'b-value' },
|
|
],
|
|
},
|
|
dashboards: [dashboardsMocks.dashboard1, dashboardsMocks.dashboard2, dashboardsMocks.dashboard3],
|
|
},
|
|
scope2: {
|
|
metadata: {
|
|
name: 'scope2',
|
|
},
|
|
spec: {
|
|
title: 'Scope 2',
|
|
type: 'Type 2',
|
|
description: 'Description 2',
|
|
category: 'Category 2',
|
|
filters: [{ key: 'c-key', operator: 'not-equals', value: 'c-value' }],
|
|
},
|
|
dashboards: [dashboardsMocks.dashboard3],
|
|
},
|
|
scope3: {
|
|
metadata: {
|
|
name: 'scope3',
|
|
},
|
|
spec: {
|
|
title: 'Scope 3',
|
|
type: 'Type 1',
|
|
description: 'Description 3',
|
|
category: 'Category 1',
|
|
filters: [{ key: 'd-key', operator: 'equals', value: 'd-value' }],
|
|
},
|
|
dashboards: [dashboardsMocks.dashboard1, dashboardsMocks.dashboard2],
|
|
},
|
|
};
|
|
|
|
jest.mock('@grafana/runtime', () => ({
|
|
__esModule: true,
|
|
...jest.requireActual('@grafana/runtime'),
|
|
getBackendSrv: () => ({
|
|
get: jest.fn().mockImplementation((url: string) => {
|
|
if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/scopes')) {
|
|
return {
|
|
items: Object.values(scopesMocks).map(({ dashboards: _dashboards, ...scope }) => scope),
|
|
};
|
|
}
|
|
|
|
if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/scopedashboardbindings')) {
|
|
const search = new URLSearchParams(url.split('?').pop() || '');
|
|
const scope = search.get('fieldSelector')?.replace('spec.scope=', '') ?? '';
|
|
|
|
if (scope in scopesMocks) {
|
|
return {
|
|
items: scopesMocks[scope].dashboards.map(({ uid }) => ({
|
|
scope,
|
|
dashboard: uid,
|
|
})),
|
|
};
|
|
}
|
|
|
|
return {
|
|
items: [],
|
|
};
|
|
}
|
|
|
|
if (url.startsWith('/api/dashboards/uid/')) {
|
|
const uid = url.split('/').pop();
|
|
|
|
if (!uid) {
|
|
return {};
|
|
}
|
|
|
|
const dashboard = Object.values(dashboardsMocks).find((dashboard) => dashboard.uid === uid);
|
|
|
|
if (!dashboard) {
|
|
return {};
|
|
}
|
|
|
|
return {
|
|
dashboard: {
|
|
title: dashboard.title,
|
|
uid,
|
|
},
|
|
meta: {
|
|
url: dashboard.url,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {};
|
|
}),
|
|
}),
|
|
}));
|
|
|
|
describe('ScopesScene', () => {
|
|
describe('Feature flag off', () => {
|
|
beforeAll(() => {
|
|
config.featureToggles.scopeFilters = false;
|
|
});
|
|
|
|
it('Does not initialize', () => {
|
|
const dashboardScene = buildTestScene();
|
|
dashboardScene.activate();
|
|
const scopesScene = dashboardScene.state.scopes;
|
|
|
|
expect(scopesScene).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('Feature flag on', () => {
|
|
let dashboardScene: DashboardScene;
|
|
let scopesScene: ScopesScene;
|
|
let filtersScene: ScopesFiltersScene;
|
|
let dashboardsScene: ScopesDashboardsScene;
|
|
let fetchScopesSpy: jest.SpyInstance;
|
|
let fetchDashboardsSpy: jest.SpyInstance;
|
|
|
|
beforeAll(() => {
|
|
config.featureToggles.scopeFilters = true;
|
|
});
|
|
|
|
beforeEach(() => {
|
|
dashboardScene = buildTestScene();
|
|
scopesScene = dashboardScene.state.scopes!;
|
|
filtersScene = scopesScene.state.filters;
|
|
dashboardsScene = scopesScene.state.dashboards;
|
|
fetchScopesSpy = jest.spyOn(filtersScene!, 'fetchScopes');
|
|
fetchDashboardsSpy = jest.spyOn(dashboardsScene!, 'fetchDashboards');
|
|
dashboardScene.activate();
|
|
scopesScene.activate();
|
|
filtersScene.activate();
|
|
dashboardsScene.activate();
|
|
});
|
|
|
|
it('Initializes', () => {
|
|
expect(scopesScene).toBeInstanceOf(ScopesScene);
|
|
expect(filtersScene).toBeInstanceOf(ScopesFiltersScene);
|
|
expect(dashboardsScene).toBeInstanceOf(ScopesDashboardsScene);
|
|
});
|
|
|
|
it('Fetches scopes list', async () => {
|
|
expect(fetchScopesSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it('Fetches dashboards list', () => {
|
|
filtersScene.setScope(scopesMocks.scope1.metadata.name);
|
|
|
|
waitFor(() => {
|
|
expect(fetchDashboardsSpy).toHaveBeenCalled();
|
|
expect(dashboardsScene.state.dashboards).toEqual(scopesMocks.scope1.dashboards);
|
|
});
|
|
|
|
filtersScene.setScope(scopesMocks.scope2.metadata.name);
|
|
|
|
waitFor(() => {
|
|
expect(fetchDashboardsSpy).toHaveBeenCalled();
|
|
expect(dashboardsScene.state.dashboards).toEqual(scopesMocks.scope2.dashboards);
|
|
});
|
|
});
|
|
|
|
it('Enriches data requests', () => {
|
|
const { dashboards: _dashboards, ...scope1 } = scopesMocks.scope1;
|
|
|
|
filtersScene.setScope(scope1.metadata.name);
|
|
|
|
const queryRunner = sceneGraph.findObject(dashboardScene, (o) => o.state.key === 'data-query-runner')!;
|
|
|
|
expect(dashboardScene.enrichDataRequest(queryRunner).scope).toEqual(scope1);
|
|
});
|
|
|
|
it('Toggles expanded state', async () => {
|
|
scopesScene.toggleIsExpanded();
|
|
|
|
expect(scopesScene.state.isExpanded).toEqual(true);
|
|
});
|
|
|
|
it('Enters view mode', async () => {
|
|
dashboardScene.onEnterEditMode();
|
|
|
|
expect(scopesScene.state.isViewing).toEqual(true);
|
|
expect(scopesScene.state.isExpanded).toEqual(false);
|
|
});
|
|
|
|
it('Exits view mode', async () => {
|
|
dashboardScene.onEnterEditMode();
|
|
dashboardScene.exitEditMode({ skipConfirm: true });
|
|
|
|
expect(scopesScene.state.isViewing).toEqual(false);
|
|
expect(scopesScene.state.isExpanded).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
function buildTestScene(overrides: Partial<DashboardScene> = {}) {
|
|
return new DashboardScene({
|
|
title: 'hello',
|
|
uid: 'dash-1',
|
|
description: 'hello description',
|
|
tags: ['tag1', 'tag2'],
|
|
editable: true,
|
|
$timeRange: new SceneTimeRange({
|
|
timeZone: 'browser',
|
|
}),
|
|
controls: new DashboardControls({}),
|
|
$behaviors: [new behaviors.CursorSync({})],
|
|
body: new SceneGridLayout({
|
|
children: [
|
|
new SceneGridItem({
|
|
key: 'griditem-1',
|
|
x: 0,
|
|
y: 0,
|
|
width: 300,
|
|
height: 300,
|
|
body: new VizPanel({
|
|
title: 'Panel A',
|
|
key: 'panel-1',
|
|
pluginId: 'table',
|
|
$data: new SceneQueryRunner({ key: 'data-query-runner', queries: [{ refId: 'A' }] }),
|
|
}),
|
|
}),
|
|
],
|
|
}),
|
|
...overrides,
|
|
});
|
|
}
|