mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-02-04 06:22:59 -05:00
391 lines
16 KiB
TypeScript
391 lines
16 KiB
TypeScript
import {
|
|
publishedOnDate,
|
|
getRequest,
|
|
postRequest,
|
|
deleteRequest,
|
|
csrfToken,
|
|
} from '../../../src/static/js/utils/helpers';
|
|
import store from '../../../src/static/js/utils/stores/PlaylistPageStore';
|
|
|
|
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
|
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
|
}));
|
|
|
|
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
|
publishedOnDate: jest.fn(),
|
|
exportStore: jest.fn((store) => store),
|
|
getRequest: jest.fn(),
|
|
postRequest: jest.fn(),
|
|
deleteRequest: jest.fn(),
|
|
csrfToken: jest.fn(),
|
|
}));
|
|
|
|
describe('utils/store', () => {
|
|
beforeAll(() => {
|
|
(globalThis as any).window.MediaCMS = { playlistId: null };
|
|
});
|
|
|
|
afterAll(() => {
|
|
delete (globalThis as any).window.MediaCMS;
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('PlaylistPageStore', () => {
|
|
const handler = store.actions_handler.bind(store);
|
|
|
|
const onLoadedPlaylistData = jest.fn();
|
|
const onLoadedPlaylistEerror = jest.fn();
|
|
const onLoadedMediaError = jest.fn();
|
|
const onPlaylistUpdateCompleted = jest.fn();
|
|
const onPlaylistUpdateFailed = jest.fn();
|
|
const onPlaylistRemovalCompleted = jest.fn();
|
|
const onPlaylistRemovalFailed = jest.fn();
|
|
const onSavedUpdated = jest.fn();
|
|
const onReorderedMediaInPlaylist = jest.fn();
|
|
const onRemovedMediaFromPlaylist = jest.fn();
|
|
|
|
store.on('loaded_playlist_data', onLoadedPlaylistData);
|
|
store.on('loaded_playlist_error', onLoadedPlaylistEerror);
|
|
store.on('loaded_media_error', onLoadedMediaError); // @todo: It doesn't get called
|
|
store.on('playlist_update_completed', onPlaylistUpdateCompleted);
|
|
store.on('playlist_update_failed', onPlaylistUpdateFailed);
|
|
store.on('playlist_removal_completed', onPlaylistRemovalCompleted);
|
|
store.on('playlist_removal_failed', onPlaylistRemovalFailed);
|
|
store.on('saved-updated', onSavedUpdated);
|
|
store.on('reordered_media_in_playlist', onReorderedMediaInPlaylist);
|
|
store.on('removed_media_from_playlist', onRemovedMediaFromPlaylist);
|
|
|
|
test('Validate initial values', () => {
|
|
expect(store.get('INVALID_TYPE')).toBe(null);
|
|
expect(store.get('playlistId')).toBe(null);
|
|
expect(store.get('logged-in-user-playlist')).toBe(false);
|
|
expect(store.get('playlist-media')).toStrictEqual([]);
|
|
expect(store.get('visibility')).toBe('public');
|
|
expect(store.get('visibility-icon')).toBe(null);
|
|
// // expect(store.get('total-items')).toBe(0); // @todo: It throws error
|
|
expect(store.get('views-count')).toBe('N/A');
|
|
expect(store.get('title')).toBe(null);
|
|
expect(store.get('edit-link')).toBe('#');
|
|
expect(store.get('thumb')).toBe(null);
|
|
expect(store.get('description')).toBe(null);
|
|
expect(store.get('author-username')).toBe(null);
|
|
expect(store.get('author-name')).toBe(null);
|
|
expect(store.get('author-link')).toBe(null);
|
|
expect(store.get('author-thumb')).toBe(null);
|
|
expect(store.get('saved-playlist')).toBe(false);
|
|
expect(store.get('date-label')).toBe(null);
|
|
});
|
|
|
|
describe('Trigger and validate actions behavior', () => {
|
|
test('Action type: "LOAD_PLAYLIST_DATA" - failed', () => {
|
|
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
const loadDataSpy = jest.spyOn(store, 'loadData');
|
|
|
|
handler({ type: 'LOAD_PLAYLIST_DATA' });
|
|
|
|
expect(loadDataSpy).toHaveBeenCalledTimes(1);
|
|
expect(loadDataSpy).toHaveReturnedWith(false);
|
|
|
|
expect(warnSpy).toHaveBeenCalledTimes(1);
|
|
expect(warnSpy).toHaveBeenCalledWith('Invalid playlist id:', '');
|
|
|
|
expect(store.get('playlistId')).toBe(null);
|
|
|
|
loadDataSpy.mockRestore();
|
|
warnSpy.mockRestore();
|
|
});
|
|
|
|
test('Action type: "LOAD_PLAYLIST_DATA" - completed successful', () => {
|
|
const playlistId = 'PLAYLIST_ID_1';
|
|
window.history.pushState({}, '', `/playlists/${playlistId}`);
|
|
|
|
// Mock get request
|
|
const mockGetRequestResponse = {
|
|
data: {
|
|
add_date: Date.now(),
|
|
description: 'DESCRIPTION',
|
|
playlist_media: [],
|
|
title: 'TITLE',
|
|
user: 'USER',
|
|
user_thumbnail_url: 'USER_THUMB_URL',
|
|
},
|
|
};
|
|
|
|
(getRequest as jest.Mock).mockImplementation((_url, _cache, successCallback, _failCallback) =>
|
|
successCallback(mockGetRequestResponse)
|
|
);
|
|
|
|
const loadDataSpy = jest.spyOn(store, 'loadData');
|
|
const dataResponseSpy = jest.spyOn(store, 'dataResponse');
|
|
|
|
handler({ type: 'LOAD_PLAYLIST_DATA' });
|
|
|
|
expect(store.get('playlistId')).toBe(playlistId);
|
|
expect(store.get('author-name')).toBe(mockGetRequestResponse.data.user);
|
|
expect(store.get('author-link')).toBe(`/user/${mockGetRequestResponse.data.user}`);
|
|
expect(store.get('author-thumb')).toBe(`/${mockGetRequestResponse.data.user_thumbnail_url}`);
|
|
|
|
expect(store.get('date-label')).toBe('Created on undefined');
|
|
expect(publishedOnDate).toHaveBeenCalledWith(new Date(mockGetRequestResponse.data.add_date), 3);
|
|
|
|
expect(loadDataSpy).toHaveBeenCalledTimes(1);
|
|
expect(loadDataSpy).toHaveReturnedWith(undefined);
|
|
|
|
expect(dataResponseSpy).toHaveBeenCalledTimes(1);
|
|
expect(dataResponseSpy).toHaveBeenCalledWith(mockGetRequestResponse);
|
|
|
|
// Verify getRequest was called with correct parameters
|
|
expect(getRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
false,
|
|
store.dataResponse,
|
|
store.dataErrorResponse
|
|
);
|
|
|
|
expect(onLoadedPlaylistData).toHaveBeenCalledTimes(1);
|
|
expect(onLoadedPlaylistData).toHaveBeenCalledWith();
|
|
|
|
loadDataSpy.mockRestore();
|
|
dataResponseSpy.mockRestore();
|
|
});
|
|
|
|
test('Action type: "LOAD_PLAYLIST_DATA" - completed with error', () => {
|
|
const playlistId = 'PLAYLIST_ID_2';
|
|
window.history.pushState({}, '', `/playlists/${playlistId}`);
|
|
|
|
// Mock get request
|
|
const mockGetRequestResponse = { type: 'private' };
|
|
(getRequest as jest.Mock).mockImplementation((_url, _cache, _successCallback, failCallback) =>
|
|
failCallback(mockGetRequestResponse)
|
|
);
|
|
|
|
const loadDataSpy = jest.spyOn(store, 'loadData');
|
|
const dataErrorResponseSpy = jest.spyOn(store, 'dataErrorResponse');
|
|
|
|
handler({ type: 'LOAD_PLAYLIST_DATA' });
|
|
|
|
expect(store.get('playlistId')).toBe(playlistId);
|
|
|
|
expect(loadDataSpy).toHaveBeenCalledTimes(1);
|
|
expect(loadDataSpy).toHaveReturnedWith(undefined);
|
|
|
|
expect(dataErrorResponseSpy).toHaveBeenCalledTimes(1);
|
|
expect(dataErrorResponseSpy).toHaveBeenCalledWith(mockGetRequestResponse);
|
|
|
|
// Verify getRequest was called with correct parameters
|
|
expect(getRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
false,
|
|
store.dataResponse,
|
|
store.dataErrorResponse
|
|
);
|
|
|
|
expect(onLoadedPlaylistEerror).toHaveBeenCalledTimes(1);
|
|
expect(onLoadedPlaylistEerror).toHaveBeenCalledWith();
|
|
|
|
loadDataSpy.mockRestore();
|
|
dataErrorResponseSpy.mockRestore();
|
|
});
|
|
|
|
test('Action type: "TOGGLE_SAVE"', () => {
|
|
const initialValue = store.get('saved-playlist');
|
|
|
|
handler({ type: 'TOGGLE_SAVE' });
|
|
|
|
expect(onSavedUpdated).toHaveBeenCalledTimes(1);
|
|
expect(onSavedUpdated).toHaveBeenCalledWith();
|
|
|
|
expect(store.get('saved-playlist')).toBe(!initialValue);
|
|
});
|
|
|
|
test('Action type: "UPDATE_PLAYLIST" - failed', () => {
|
|
// Mock (updated) playlist data
|
|
const mockPlaylistData = { title: 'PLAYLIST_TITLE', description: 'PLAYLIST_DESCRIPTION' };
|
|
|
|
// Mock the CSRF token
|
|
const mockCSRFtoken = 'test-csrf-token';
|
|
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
|
|
|
// Mock post request
|
|
(postRequest as jest.Mock).mockImplementation(
|
|
(_url, _postData, _configData, _sync, _successCallback, failCallback) => failCallback()
|
|
);
|
|
|
|
const initialStoreData = {
|
|
title: store.get('title'),
|
|
description: store.get('description'),
|
|
};
|
|
|
|
expect(store.get('title')).toBe(initialStoreData.title);
|
|
expect(store.get('description')).toBe(initialStoreData.description);
|
|
|
|
handler({ type: 'UPDATE_PLAYLIST', playlist_data: mockPlaylistData });
|
|
|
|
expect(store.get('title')).toBe(initialStoreData.title);
|
|
expect(store.get('description')).toBe(initialStoreData.description);
|
|
|
|
// Verify postRequest was called with correct parameters
|
|
expect(postRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
mockPlaylistData,
|
|
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
|
false,
|
|
store.onPlaylistUpdateCompleted,
|
|
store.onPlaylistUpdateFailed
|
|
);
|
|
|
|
expect(onPlaylistUpdateFailed).toHaveBeenCalledWith();
|
|
});
|
|
|
|
test('Action type: "UPDATE_PLAYLIST" - successful', () => {
|
|
// Mock (updated) playlist data
|
|
const mockPlaylistData = { title: 'PLAYLIST_TITLE', description: 'PLAYLIST_DESCRIPTION' };
|
|
|
|
// Mock the CSRF token
|
|
const mockCSRFtoken = 'test-csrf-token';
|
|
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
|
|
|
// Mock post request
|
|
(postRequest as jest.Mock).mockImplementation(
|
|
(_url, _postData, _configData, _sync, successCallback, _failCallback) =>
|
|
successCallback({ data: mockPlaylistData })
|
|
);
|
|
|
|
const initialStoreData = {
|
|
title: store.get('title'),
|
|
description: store.get('description'),
|
|
};
|
|
|
|
expect(store.get('title')).toBe(initialStoreData.title);
|
|
expect(store.get('description')).toBe(initialStoreData.description);
|
|
|
|
handler({ type: 'UPDATE_PLAYLIST', playlist_data: mockPlaylistData });
|
|
|
|
expect(store.get('title')).toBe(mockPlaylistData.title);
|
|
expect(store.get('description')).toBe(mockPlaylistData.description);
|
|
|
|
// Verify postRequest was called with correct parameters
|
|
expect(postRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
mockPlaylistData,
|
|
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
|
false,
|
|
store.onPlaylistUpdateCompleted,
|
|
store.onPlaylistUpdateFailed
|
|
);
|
|
|
|
expect(onPlaylistUpdateCompleted).toHaveBeenCalledWith(mockPlaylistData);
|
|
});
|
|
|
|
test('Action type: "REMOVE_PLAYLIST" - failed', () => {
|
|
// Mock the CSRF token
|
|
const mockCSRFtoken = 'test-csrf-token';
|
|
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
|
|
|
// Mock delete request
|
|
(deleteRequest as jest.Mock).mockImplementation(
|
|
(_url, _config, _sync, _successCallback, failCallback) => failCallback()
|
|
);
|
|
|
|
handler({ type: 'REMOVE_PLAYLIST' });
|
|
|
|
// Verify deleteRequest was called with correct parameters
|
|
expect(deleteRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
|
false,
|
|
store.onPlaylistRemovalCompleted,
|
|
store.onPlaylistRemovalFailed
|
|
);
|
|
|
|
expect(onPlaylistRemovalFailed).toHaveBeenCalledWith();
|
|
});
|
|
|
|
test('Action type: "REMOVE_PLAYLIST" - completed successful', () => {
|
|
// Mock the CSRF token
|
|
const mockCSRFtoken = 'test-csrf-token';
|
|
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
|
|
|
// Mock delete request
|
|
const deleteRequestResponse = { status: 204 };
|
|
(deleteRequest as jest.Mock).mockImplementation(
|
|
(_url, _config, _sync, successCallback, _failCallback) => successCallback(deleteRequestResponse)
|
|
);
|
|
|
|
handler({ type: 'REMOVE_PLAYLIST' });
|
|
|
|
// Verify deleteRequest was called with correct parameters
|
|
expect(deleteRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
|
false,
|
|
store.onPlaylistRemovalCompleted,
|
|
store.onPlaylistRemovalFailed
|
|
);
|
|
|
|
expect(onPlaylistRemovalCompleted).toHaveBeenCalledWith(deleteRequestResponse);
|
|
});
|
|
|
|
test('Action type: "REMOVE_PLAYLIST" - completed with invalid status code', () => {
|
|
// Mock the CSRF token
|
|
const mockCSRFtoken = 'test-csrf-token';
|
|
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
|
|
|
// Mock delete request
|
|
const deleteRequestResponse = { status: 403 };
|
|
(deleteRequest as jest.Mock).mockImplementation(
|
|
(_url, _config, _sync, successCallback, _failCallback) => successCallback(deleteRequestResponse)
|
|
);
|
|
|
|
handler({ type: 'REMOVE_PLAYLIST' });
|
|
|
|
// Verify deleteRequest was called with correct parameters
|
|
expect(deleteRequest).toHaveBeenCalledWith(
|
|
store.playlistAPIUrl,
|
|
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
|
false,
|
|
store.onPlaylistRemovalCompleted,
|
|
store.onPlaylistRemovalFailed
|
|
);
|
|
|
|
expect(onPlaylistRemovalFailed).toHaveBeenCalledWith();
|
|
});
|
|
|
|
test('Action type: "PLAYLIST_MEDIA_REORDERED"', () => {
|
|
// Mock playlist media data
|
|
const mockPlaylistMedia = [
|
|
{ thumbnail_url: 'THUMB_URL_1', url: '?id=MEDIA_ID_1' },
|
|
{ thumbnail_url: 'THUMB_URL_2', url: '?id=MEDIA_ID_2' },
|
|
];
|
|
|
|
handler({ type: 'PLAYLIST_MEDIA_REORDERED', playlist_media: mockPlaylistMedia });
|
|
|
|
expect(onReorderedMediaInPlaylist).toHaveBeenCalledWith();
|
|
|
|
expect(store.get('playlist-media')).toStrictEqual(mockPlaylistMedia);
|
|
expect(store.get('thumb')).toBe(mockPlaylistMedia[0].thumbnail_url);
|
|
expect(store.get('total-items')).toBe(mockPlaylistMedia.length);
|
|
});
|
|
|
|
test('Action type: "MEDIA_REMOVED_FROM_PLAYLIST"', () => {
|
|
// Mock playlist media data
|
|
const mockPlaylistMedia = [
|
|
{ thumbnail_url: 'THUMB_URL_1', url: '?id=MEDIA_ID_1' },
|
|
{ thumbnail_url: 'THUMB_URL_2', url: '?id=MEDIA_ID_2' },
|
|
];
|
|
|
|
handler({ type: 'PLAYLIST_MEDIA_REORDERED', playlist_media: mockPlaylistMedia });
|
|
|
|
handler({ type: 'MEDIA_REMOVED_FROM_PLAYLIST', media_id: 'MEDIA_ID_2' });
|
|
|
|
expect(store.get('playlist-media')).toStrictEqual([mockPlaylistMedia[0]]);
|
|
expect(store.get('thumb')).toBe(mockPlaylistMedia[0].thumbnail_url);
|
|
expect(store.get('total-items')).toBe(mockPlaylistMedia.length - 1);
|
|
});
|
|
});
|
|
});
|
|
});
|