import { render as RTLRender } from '@testing-library/react'; import * as React from 'react'; import { TestProvider } from 'test/helpers/TestProvider'; import { SceneTimeRange, behaviors } from '@grafana/scenes'; import { DashboardCursorSync } from '@grafana/schema'; import { DashboardControls } from '../scene/DashboardControls'; import { DashboardScene } from '../scene/DashboardScene'; import { activateFullSceneTree } from '../utils/test-utils'; import { DashboardLinksEditView } from './DashboardLinksEditView'; import { NEW_LINK } from './links/utils'; function render(component: React.ReactNode) { return RTLRender({component}); } describe('DashboardLinksEditView', () => { describe('Url state', () => { let settings: DashboardLinksEditView; beforeEach(async () => { const result = await buildTestScene(); settings = result.settings; }); it('should return the correct urlKey', () => { expect(settings.getUrlKey()).toBe('links'); }); }); describe('Dashboard updates', () => { let dashboard: DashboardScene; let settings: DashboardLinksEditView; beforeEach(async () => { const result = await buildTestScene(); dashboard = result.dashboard; settings = result.settings; }); it('should have isDirty false', () => { expect(dashboard.state.isDirty).toBeFalsy(); }); it('should update dashboard state when adding a link', () => { settings.onNewLink(); expect(dashboard.state.links[0]).toEqual(NEW_LINK); }); it('should update dashboard state when deleting a link', () => { dashboard.setState({ links: [NEW_LINK] }); settings.onDelete(0); expect(dashboard.state.links).toEqual([]); }); it('should update dashboard state when duplicating a link', () => { dashboard.setState({ links: [NEW_LINK] }); settings.onDuplicate(NEW_LINK); expect(dashboard.state.links).toEqual([NEW_LINK, NEW_LINK]); }); it('should update dashboard state when reordering a link', () => { dashboard.setState({ links: [ { ...NEW_LINK, title: 'link-1' }, { ...NEW_LINK, title: 'link-2' }, ], }); settings.onOrderChange(0, 1); expect(dashboard.state.links).toEqual([ { ...NEW_LINK, title: 'link-2' }, { ...NEW_LINK, title: 'link-1' }, ]); }); it('should update dashboard state when editing a link', () => { dashboard.setState({ links: [{ ...NEW_LINK, title: 'old title' }] }); settings.setState({ editIndex: 0 }); settings.onUpdateLink({ ...NEW_LINK, title: 'new title' }); expect(dashboard.state.links[0].title).toEqual('new title'); }); }); describe('Edit a link', () => { let dashboard: DashboardScene; let settings: DashboardLinksEditView; beforeEach(async () => { const result = await buildTestScene(); dashboard = result.dashboard; settings = result.settings; }); it('should set editIndex when editing a link', () => { dashboard.setState({ links: [{ ...NEW_LINK, title: 'old title' }] }); settings.onEdit(0); expect(settings.state.editIndex).toEqual(0); }); it('should set editIndex when editing a link that does not exist', () => { dashboard.setState({ links: [{ ...NEW_LINK, title: 'old title' }] }); settings.onEdit(1); expect(settings.state.editIndex).toBe(1); }); it('should update dashboard state when editing a link', () => { dashboard.setState({ links: [{ ...NEW_LINK, title: 'old title' }] }); settings.setState({ editIndex: 0 }); settings.onUpdateLink({ ...NEW_LINK, title: 'new title' }); expect(dashboard.state.links[0].title).toEqual('new title'); }); it('should update dashboard state when going back', () => { settings.setState({ editIndex: 0 }); settings.onGoBack(); expect(settings.state.editIndex).toBeUndefined(); }); }); describe('Render the views', () => { let dashboard: DashboardScene; let settings: DashboardLinksEditView; beforeEach(async () => { const result = await buildTestScene(); dashboard = result.dashboard; settings = result.settings; }); it('should render with no errors', () => { expect(() => render()).not.toThrow(); }); it('should render the empty state when no links', () => { dashboard.setState({ links: [] }); const { getByText } = render(); expect(getByText('Add dashboard link')).toBeInTheDocument(); }); it('should render the empty state when no links', () => { dashboard.setState({ links: [] }); const { getByText } = render(); expect(getByText('Add dashboard link')).toBeInTheDocument(); }); it('should render the list of link when there are links', () => { dashboard.setState({ links: [ { ...NEW_LINK, title: 'link-1' }, { ...NEW_LINK, title: 'link-2' }, ], }); const { getByText } = render(); expect(getByText('link-1')).toBeInTheDocument(); expect(getByText('link-2')).toBeInTheDocument(); expect(getByText('New link')).toBeInTheDocument(); }); it('should render the list of link when the editing link does not exist', () => { dashboard.setState({ links: [ { ...NEW_LINK, title: 'link-1' }, { ...NEW_LINK, title: 'link-2' }, ], }); settings.setState({ editIndex: 2 }); const { getByText } = render(); expect(getByText('link-1')).toBeInTheDocument(); expect(getByText('link-2')).toBeInTheDocument(); expect(getByText('New link')).toBeInTheDocument(); }); it('should render the link form when the editing link does exist', () => { dashboard.setState({ links: [ { ...NEW_LINK, title: 'link-1' }, { ...NEW_LINK, title: 'link-2' }, ], }); settings.setState({ editIndex: 1 }); const { getByText } = render(); expect(getByText('Edit link')).toBeInTheDocument(); expect(getByText('Back to list')).toBeInTheDocument(); }); }); }); async function buildTestScene() { const settings = new DashboardLinksEditView({}); const dashboard = new DashboardScene({ $timeRange: new SceneTimeRange({}), $behaviors: [new behaviors.CursorSync({ sync: DashboardCursorSync.Off })], controls: new DashboardControls({}), title: 'hello', uid: 'dash-1', meta: { canEdit: true, }, editview: settings, }); activateFullSceneTree(dashboard); await new Promise((r) => setTimeout(r, 1)); dashboard.onEnterEditMode(); settings.activate(); return { dashboard, settings }; }