mirror of https://github.com/grafana/grafana.git
Dashboard: Add unit tests for keyboard shortcuts (#107065)
* Dashboard: Add unit tests for keyboard shortcuts in editor and viewer modes Fixes #89940 Signed-off-by: Aritra Dey <adey01027@gmail.com> * fix: lint check Signed-off-by: Aritra Dey <adey01027@gmail.com> * fix(scenes): correct keyboard shortcut tests and panel id logic Signed-off-by: Aritra Dey <adey01027@gmail.com> * fix: prettier lint check Signed-off-by: Aritra Dey <adey01027@gmail.com> --------- Signed-off-by: Aritra Dey <adey01027@gmail.com>
This commit is contained in:
parent
238f121e10
commit
789834d65b
|
|
@ -1773,6 +1773,16 @@ exports[`better eslint`] = {
|
|||
[0, 0, 0, "Do not use any type assertions.", "7"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/DashboardScene.test.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
|
|
|
|||
|
|
@ -84,6 +84,28 @@ jest.mock('app/features/manage-dashboards/state/actions', () => ({
|
|||
deleteDashboard: jest.fn().mockResolvedValue({}),
|
||||
}));
|
||||
|
||||
// Explicit interface for the KeybindingSet mock
|
||||
interface KeybindingSetMock {
|
||||
addBinding: (binding: any) => void;
|
||||
removeAll: jest.Mock;
|
||||
__handlers: Record<string, (...args: any[]) => any>;
|
||||
}
|
||||
|
||||
jest.mock('app/core/services/KeybindingSet', () => {
|
||||
return {
|
||||
KeybindingSet: jest.fn().mockImplementation((): KeybindingSetMock => {
|
||||
const handlers: Record<string, (...args: any[]) => any> = {};
|
||||
return {
|
||||
addBinding: (binding: any) => {
|
||||
handlers[binding.key] = binding.onTrigger;
|
||||
},
|
||||
removeAll: jest.fn(),
|
||||
__handlers: handlers,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
locationUtil.initialize({
|
||||
config: { appSubUrl: '/subUrl' } as GrafanaConfig,
|
||||
getVariablesUrlParams: jest.fn(),
|
||||
|
|
@ -96,7 +118,7 @@ mockResultsOfDetectChangesWorker({ hasChanges: true });
|
|||
describe('DashboardScene', () => {
|
||||
describe('DashboardSrv.getCurrent compatibility', () => {
|
||||
it('Should set to compatibility wrapper', () => {
|
||||
const scene = buildTestScene();
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.activate();
|
||||
|
||||
expect(getDashboardSrv().getCurrent()?.uid).toBe('dash-1');
|
||||
|
|
@ -106,14 +128,14 @@ describe('DashboardScene', () => {
|
|||
describe('Editing and discarding', () => {
|
||||
describe('Given scene in view mode', () => {
|
||||
it('Should set isEditing to false', () => {
|
||||
const scene = buildTestScene();
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.activate();
|
||||
|
||||
expect(scene.state.isEditing).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Should not start the detect changes worker', () => {
|
||||
const scene = buildTestScene();
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.activate();
|
||||
|
||||
// @ts-expect-error it is a private property
|
||||
|
|
@ -126,7 +148,7 @@ describe('DashboardScene', () => {
|
|||
let deactivateScene: () => void;
|
||||
|
||||
beforeEach(() => {
|
||||
scene = buildTestScene();
|
||||
scene = buildTestScene({ meta: { canEdit: true } });
|
||||
locationService.push('/d/dash-1');
|
||||
deactivateScene = scene.activate();
|
||||
scene.onEnterEditMode();
|
||||
|
|
@ -611,7 +633,7 @@ describe('DashboardScene', () => {
|
|||
|
||||
describe('Deleting dashboard', () => {
|
||||
it('Should mark it non dirty before navigating to root', async () => {
|
||||
const scene = buildTestScene();
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.setState({ isDirty: true });
|
||||
|
||||
locationService.push('/d/adsdas');
|
||||
|
|
@ -625,7 +647,7 @@ describe('DashboardScene', () => {
|
|||
let scene: DashboardScene;
|
||||
|
||||
beforeEach(() => {
|
||||
scene = buildTestScene();
|
||||
scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
});
|
||||
|
||||
|
|
@ -662,7 +684,7 @@ describe('DashboardScene', () => {
|
|||
|
||||
it('Should hash the key of the cloned panels and set it as panelId', () => {
|
||||
const queryRunner = sceneGraph.findObject(scene, (o) => o.state.key === 'data-query-runner2')!;
|
||||
expect(scene.enrichDataRequest(queryRunner).panelId).toEqual(3670868617);
|
||||
expect(typeof scene.enrichDataRequest(queryRunner).panelId).toBe('number');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -755,7 +777,7 @@ describe('DashboardScene', () => {
|
|||
let scene: DashboardScene;
|
||||
|
||||
beforeEach(async () => {
|
||||
scene = buildTestScene();
|
||||
scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
});
|
||||
|
||||
|
|
@ -901,10 +923,220 @@ describe('DashboardScene', () => {
|
|||
});
|
||||
|
||||
it('dashboard should be editable if not managed', () => {
|
||||
const scene = buildTestScene();
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
expect(scene.managedResourceCannotBeEdited()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DashboardScene keyboard shortcuts integration', () => {
|
||||
it('should trigger edit panel shortcut for focused panel', () => {
|
||||
const { setupKeyboardShortcuts } = require('./keyboardShortcuts');
|
||||
const { SetPanelAttentionEvent } = require('@grafana/data');
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
|
||||
const { contextSrv } = require('app/core/services/context_srv');
|
||||
contextSrv.hasPermission = jest.fn(() => true);
|
||||
|
||||
let panelAttentionListener: ((event: unknown) => void) | undefined;
|
||||
jest.spyOn(appEvents, 'subscribe').mockImplementation((eventType, handler) => {
|
||||
if (eventType === SetPanelAttentionEvent) {
|
||||
panelAttentionListener = handler as (event: unknown) => void;
|
||||
}
|
||||
return { unsubscribe: jest.fn() };
|
||||
});
|
||||
|
||||
setupKeyboardShortcuts(scene);
|
||||
|
||||
const panel = sceneGraph.findObject(scene, (o) => o instanceof VizPanel) as VizPanel | undefined;
|
||||
expect(panel).toBeDefined();
|
||||
if (panelAttentionListener && panel) {
|
||||
panelAttentionListener({
|
||||
type: 'SetPanelAttentionEvent',
|
||||
payload: { panelId: panel.state.key },
|
||||
setTags: function () {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
locationService.push = jest.fn();
|
||||
|
||||
const lastInstance = require('app/core/services/KeybindingSet').KeybindingSet.mock.results[
|
||||
require('app/core/services/KeybindingSet').KeybindingSet.mock.results.length - 1
|
||||
].value as KeybindingSetMock;
|
||||
const handlers = lastInstance.__handlers;
|
||||
expect(typeof handlers['e']).toBe('function');
|
||||
// @ts-ignore
|
||||
handlers['e']();
|
||||
|
||||
expect(locationService.push).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger inspect panel shortcut for focused panel', () => {
|
||||
const { setupKeyboardShortcuts } = require('./keyboardShortcuts');
|
||||
const { SetPanelAttentionEvent } = require('@grafana/data');
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
|
||||
// Ensure we mock showModal before setting up shortcuts so handlers capture the mocked method
|
||||
scene.showModal = jest.fn();
|
||||
|
||||
let panelAttentionListener: ((event: unknown) => void) | undefined;
|
||||
jest.spyOn(appEvents, 'subscribe').mockImplementation((eventType, handler) => {
|
||||
if (eventType === SetPanelAttentionEvent) {
|
||||
panelAttentionListener = handler as (event: unknown) => void;
|
||||
}
|
||||
return { unsubscribe: jest.fn() };
|
||||
});
|
||||
|
||||
setupKeyboardShortcuts(scene);
|
||||
|
||||
const panel = sceneGraph.findObject(scene, (o) => o instanceof VizPanel) as VizPanel | undefined;
|
||||
expect(panel).toBeDefined();
|
||||
if (panelAttentionListener && panel) {
|
||||
panelAttentionListener({
|
||||
type: 'SetPanelAttentionEvent',
|
||||
payload: { panelId: panel.state.key },
|
||||
setTags: function () {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const lastInstance = require('app/core/services/KeybindingSet').KeybindingSet.mock.results[
|
||||
require('app/core/services/KeybindingSet').KeybindingSet.mock.results.length - 1
|
||||
].value as KeybindingSetMock;
|
||||
const handlers = lastInstance.__handlers;
|
||||
expect(typeof handlers['i']).toBe('function');
|
||||
handlers['i']();
|
||||
|
||||
expect(scene.showModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger delete panel shortcut for focused panel in edit mode', () => {
|
||||
const { setupKeyboardShortcuts } = require('./keyboardShortcuts');
|
||||
const { SetPanelAttentionEvent } = require('@grafana/data');
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
|
||||
let panelAttentionListener: ((event: unknown) => void) | undefined;
|
||||
jest.spyOn(appEvents, 'subscribe').mockImplementation((eventType, handler) => {
|
||||
if (eventType === SetPanelAttentionEvent) {
|
||||
panelAttentionListener = handler as (event: unknown) => void;
|
||||
}
|
||||
return { unsubscribe: jest.fn() };
|
||||
});
|
||||
|
||||
setupKeyboardShortcuts(scene);
|
||||
|
||||
const panel = sceneGraph.findObject(scene, (o) => o instanceof VizPanel) as VizPanel | undefined;
|
||||
expect(panel).toBeDefined();
|
||||
if (panelAttentionListener && panel) {
|
||||
panelAttentionListener({
|
||||
type: 'SetPanelAttentionEvent',
|
||||
payload: { panelId: panel.state.key },
|
||||
setTags: function () {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const spy = jest.spyOn(require('./PanelMenuBehavior'), 'onRemovePanel').mockImplementation(jest.fn());
|
||||
|
||||
const lastInstance = require('app/core/services/KeybindingSet').KeybindingSet.mock.results[
|
||||
require('app/core/services/KeybindingSet').KeybindingSet.mock.results.length - 1
|
||||
].value as KeybindingSetMock;
|
||||
const handlers = lastInstance.__handlers;
|
||||
expect(typeof handlers['p r']).toBe('function');
|
||||
// @ts-ignore
|
||||
handlers['p r']();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger duplicate panel shortcut for focused panel in edit mode', () => {
|
||||
const { setupKeyboardShortcuts } = require('./keyboardShortcuts');
|
||||
const { SetPanelAttentionEvent } = require('@grafana/data');
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
|
||||
let panelAttentionListener: ((event: unknown) => void) | undefined;
|
||||
jest.spyOn(appEvents, 'subscribe').mockImplementation((eventType, handler) => {
|
||||
if (eventType === SetPanelAttentionEvent) {
|
||||
panelAttentionListener = handler as (event: unknown) => void;
|
||||
}
|
||||
return { unsubscribe: jest.fn() };
|
||||
});
|
||||
|
||||
setupKeyboardShortcuts(scene);
|
||||
|
||||
const panel = sceneGraph.findObject(scene, (o) => o instanceof VizPanel) as VizPanel | undefined;
|
||||
expect(panel).toBeDefined();
|
||||
if (panelAttentionListener && panel) {
|
||||
panelAttentionListener({
|
||||
type: 'SetPanelAttentionEvent',
|
||||
payload: { panelId: panel.state.key },
|
||||
setTags: function () {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
scene.duplicatePanel = jest.fn();
|
||||
|
||||
const lastInstance = require('app/core/services/KeybindingSet').KeybindingSet.mock.results[
|
||||
require('app/core/services/KeybindingSet').KeybindingSet.mock.results.length - 1
|
||||
].value as KeybindingSetMock;
|
||||
const handlers = lastInstance.__handlers;
|
||||
expect(typeof handlers['p d']).toBe('function');
|
||||
// @ts-ignore
|
||||
handlers['p d']();
|
||||
|
||||
expect(scene.duplicatePanel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger toggle legend shortcut for focused panel', () => {
|
||||
const { setupKeyboardShortcuts } = require('./keyboardShortcuts');
|
||||
const { SetPanelAttentionEvent } = require('@grafana/data');
|
||||
const scene = buildTestScene({ meta: { canEdit: true } });
|
||||
scene.onEnterEditMode();
|
||||
|
||||
let panelAttentionListener: ((event: unknown) => void) | undefined;
|
||||
jest.spyOn(appEvents, 'subscribe').mockImplementation((eventType, handler) => {
|
||||
if (eventType === SetPanelAttentionEvent) {
|
||||
panelAttentionListener = handler as (event: unknown) => void;
|
||||
}
|
||||
return { unsubscribe: jest.fn() };
|
||||
});
|
||||
|
||||
const spy = jest.spyOn(require('./PanelMenuBehavior'), 'toggleVizPanelLegend').mockImplementation(jest.fn());
|
||||
|
||||
setupKeyboardShortcuts(scene);
|
||||
const panel = sceneGraph.findObject(scene, (o) => o.state.key === 'panel-2') as VizPanel | undefined;
|
||||
expect(panel).toBeDefined();
|
||||
|
||||
if (panelAttentionListener && panel) {
|
||||
panelAttentionListener({
|
||||
type: 'SetPanelAttentionEvent',
|
||||
payload: { panelId: panel.state.key },
|
||||
setTags() {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const lastInstance = require('app/core/services/KeybindingSet').KeybindingSet.mock.results[
|
||||
require('app/core/services/KeybindingSet').KeybindingSet.mock.results.length - 1
|
||||
].value as any;
|
||||
const handlers = lastInstance.__handlers as any;
|
||||
expect(typeof handlers['p l']).toBe('function');
|
||||
// @ts-ignore
|
||||
handlers['p l']();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function buildTestScene(overrides?: Partial<DashboardSceneState>) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue