grafana_bak/public/app/features/playlist/PlaylistSrv.test.ts
2025-04-01 10:38:02 +09:00

167 lines
4.5 KiB
TypeScript

import { Store } from 'redux';
import configureMockStore from 'redux-mock-store';
import { locationService } from '@grafana/runtime';
import { setStore } from 'app/store/store';
import { DashboardQueryResult } from '../search/service/types';
import { PlaylistSrv } from './PlaylistSrv';
import { Playlist, PlaylistItem } from './types';
jest.mock('./api', () => ({
getPlaylistAPI: () => ({
getPlaylist: jest.fn().mockReturnValue({
interval: '1s',
uid: 'xyz',
name: 'The display',
items: [
{ type: 'dashboard_by_uid', value: 'aaa' },
{ type: 'dashboard_by_uid', value: 'bbb' },
],
} as Playlist),
}),
loadDashboards: (items: PlaylistItem[]) => {
return Promise.resolve(
items.map((v) => ({
...v, // same item with dashboard URLs filled in
dashboards: [{ url: `/url/to/${v.value}` } as unknown as DashboardQueryResult],
}))
);
},
}));
const mockStore = configureMockStore();
setStore(
mockStore({
location: {},
}) as Store
);
function createPlaylistSrv(): PlaylistSrv {
locationService.push('/playlists/foo');
return new PlaylistSrv();
}
const mockWindowLocation = (): [jest.Mock, () => void] => {
const oldLocation = window.location;
const hrefMock = jest.fn();
// JSDom defines window in a way that you cannot tamper with location so this seems to be the only way to change it.
// https://github.com/facebook/jest/issues/5124#issuecomment-446659510
//@ts-ignore
delete window.location;
window.location = {} as Location;
// Only mocking href as that is all this test needs, but otherwise there is lots of things missing, so keep that
// in mind if this is reused.
Object.defineProperty(window.location, 'href', {
set: hrefMock,
get: hrefMock,
});
const unmock = () => {
window.location = oldLocation;
};
return [hrefMock, unmock];
};
describe('PlaylistSrv', () => {
let srv: PlaylistSrv;
let hrefMock: jest.Mock;
let unmockLocation: () => void;
const initialUrl = 'http://localhost/playlist';
beforeEach(() => {
jest.clearAllMocks();
srv = createPlaylistSrv();
[hrefMock, unmockLocation] = mockWindowLocation();
// This will be cached in the srv when start() is called
hrefMock.mockReturnValue(initialUrl);
});
afterEach(() => {
unmockLocation();
});
it('runs all dashboards in cycle and reloads page after 3 cycles', async () => {
await srv.start('foo');
for (let i = 0; i < 6; i++) {
srv.next();
}
expect(hrefMock).toHaveBeenCalledTimes(2);
expect(hrefMock).toHaveBeenLastCalledWith(initialUrl);
});
it('keeps the refresh counter value after restarting', async () => {
await srv.start('foo');
// 1 complete loop
for (let i = 0; i < 3; i++) {
srv.next();
}
srv.stop();
await srv.start('foo');
// Another 2 loops
for (let i = 0; i < 4; i++) {
srv.next();
}
expect(hrefMock).toHaveBeenCalledTimes(3);
expect(hrefMock).toHaveBeenLastCalledWith(initialUrl);
});
it('Should stop playlist when navigating away', async () => {
await srv.start('foo');
locationService.push('/datasources');
expect(srv.state.isPlaying).toBe(false);
});
it('storeUpdated should not stop playlist when navigating to next dashboard', async () => {
await srv.start('foo');
// eslint-disable-next-line
expect((srv as any).validPlaylistUrl).toBe('/url/to/aaa');
srv.next();
// eslint-disable-next-line
expect((srv as any).validPlaylistUrl).toBe('/url/to/bbb');
expect(srv.state.isPlaying).toBe(true);
});
it('should replace playlist start page in history when starting playlist', async () => {
// Start at playlists page
locationService.push('/playlists');
// Navigate to playlist start page
locationService.push('/playlists/play/foo');
// Start the playlist
await srv.start('foo');
// Get history entries
const history = locationService.getHistory();
const entries = (history as unknown as { entries: Location[] }).entries;
// The current entry should be the first dashboard
expect(entries[entries.length - 1].pathname).toBe('/url/to/aaa');
// The previous entry should be the playlists page, not the start page
expect(entries[entries.length - 2].pathname).toBe('/playlists');
// Verify the start page (/playlists/play/foo) is not in history
const hasStartPage = entries.some((entry: { pathname: string }) => entry.pathname === '/playlists/play/foo');
expect(hasStartPage).toBe(false);
});
});