mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-02-04 06:22:59 -05:00
feat: utils/stores unit tests
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import EventEmitter from 'events';
|
||||
import { exportStore, getRequest, postRequest, putRequest, deleteRequest, csrfToken } from '../helpers';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
import { config as mediacmsConfig } from '../settings/config';
|
||||
|
||||
import UrlParse from 'url-parse';
|
||||
|
||||
@@ -39,6 +39,35 @@ function extractPlaylistId() {
|
||||
return playlistId;
|
||||
}
|
||||
|
||||
function extractMediaId() {
|
||||
let result = undefined;
|
||||
|
||||
let urlParams = (function () {
|
||||
let ret = new UrlParse(window.location.href).query;
|
||||
if (!ret) {
|
||||
ret = [];
|
||||
} else {
|
||||
ret = ret.substring(1);
|
||||
ret = ret.split('&');
|
||||
ret = ret.length ? ret.map((v) => v.split('=')).flat() : [];
|
||||
}
|
||||
return ret;
|
||||
})();
|
||||
|
||||
if (urlParams.length) {
|
||||
let i = 0;
|
||||
while (i < urlParams.length) {
|
||||
if ('m' === urlParams[i]) {
|
||||
// NOTE: "m" => media id/token.
|
||||
result = urlParams[i + 1];
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const MediaPageStoreData = {};
|
||||
|
||||
class MediaPageStore extends EventEmitter {
|
||||
@@ -54,8 +83,11 @@ class MediaPageStore extends EventEmitter {
|
||||
this.userList = null;
|
||||
|
||||
MediaPageStoreData[
|
||||
Object.defineProperty(this, 'id', { value: 'MediaPageStoreData_' + Object.keys(MediaPageStoreData).length }).id
|
||||
Object.defineProperty(this, 'id', {
|
||||
value: 'MediaPageStoreData_' + Object.keys(MediaPageStoreData).length,
|
||||
}).id
|
||||
] = {
|
||||
mediaId: extractMediaId(),
|
||||
likedMedia: false,
|
||||
dislikedMedia: false,
|
||||
reported_times: 0,
|
||||
@@ -77,30 +109,7 @@ class MediaPageStore extends EventEmitter {
|
||||
}
|
||||
|
||||
loadData() {
|
||||
if (!MediaPageStoreData[this.id].mediaId) {
|
||||
let urlParams = (function () {
|
||||
let ret = new UrlParse(window.location.href).query;
|
||||
if (!ret) {
|
||||
ret = [];
|
||||
} else {
|
||||
ret = ret.substring(1);
|
||||
ret.split('&');
|
||||
ret = ret.length ? ret.split('=') : [];
|
||||
}
|
||||
return ret;
|
||||
})();
|
||||
|
||||
if (urlParams.length) {
|
||||
let i = 0;
|
||||
while (i < urlParams.length) {
|
||||
if ('m' === urlParams[i]) {
|
||||
// NOTE: "m" => media id/token.
|
||||
MediaPageStoreData[this.id].mediaId = urlParams[i + 1];
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
MediaPageStoreData[this.id].mediaId = MediaPageStoreData[this.id].mediaId ?? extractMediaId();
|
||||
|
||||
if (!MediaPageStoreData[this.id].mediaId) {
|
||||
console.warn('Invalid media id:', MediaPageStoreData[this.id].mediaId);
|
||||
@@ -213,7 +222,9 @@ class MediaPageStore extends EventEmitter {
|
||||
case 'unavailable':
|
||||
MediaPageStoreData[this.id].loadErrorType = response.type;
|
||||
MediaPageStoreData[this.id].loadErrorMessage =
|
||||
void 0 !== response.message ? response.message : "Αn error occurred while loading the media's data";
|
||||
void 0 !== response.message
|
||||
? response.message
|
||||
: "Αn error occurred while loading the media's data";
|
||||
this.emit('loaded_media_error');
|
||||
break;
|
||||
}
|
||||
@@ -273,7 +284,9 @@ class MediaPageStore extends EventEmitter {
|
||||
while (f < resp.data.playlist_media.length) {
|
||||
arr = resp.data.playlist_media[f].url.split('m=');
|
||||
if (2 === arr.length) {
|
||||
MediaPageStoreData[_this.id].playlists[playlistsIndex].media_list.push(arr[1]);
|
||||
MediaPageStoreData[_this.id].playlists[playlistsIndex].media_list.push(
|
||||
arr[1]
|
||||
);
|
||||
}
|
||||
f += 1;
|
||||
}
|
||||
@@ -282,12 +295,12 @@ class MediaPageStore extends EventEmitter {
|
||||
cntr += 1;
|
||||
|
||||
if (cntr === tmp_playlists.length) {
|
||||
this.emit('playlists_load');
|
||||
_this.emit('playlists_load');
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}.bind(this)(i));
|
||||
}).bind(this)(i);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
@@ -429,11 +442,16 @@ class MediaPageStore extends EventEmitter {
|
||||
r = MediaPageStoreData[this.id].playlists || [];
|
||||
break;
|
||||
case 'media-load-error-type':
|
||||
r = void 0 !== MediaPageStoreData[this.id].loadErrorType ? MediaPageStoreData[this.id].loadErrorType : null;
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].loadErrorType
|
||||
? MediaPageStoreData[this.id].loadErrorType
|
||||
: null;
|
||||
break;
|
||||
case 'media-load-error-message':
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].loadErrorMessage ? MediaPageStoreData[this.id].loadErrorMessage : null;
|
||||
void 0 !== MediaPageStoreData[this.id].loadErrorMessage
|
||||
? MediaPageStoreData[this.id].loadErrorMessage
|
||||
: null;
|
||||
break;
|
||||
case 'media-comments':
|
||||
r = MediaPageStoreData[this.id].comments || [];
|
||||
@@ -475,12 +493,14 @@ class MediaPageStore extends EventEmitter {
|
||||
tmp = MediaPageStoreData[this.id].dislikedMedia ? 1 : 0;
|
||||
if (tmp) {
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.dislikes
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.dislikes
|
||||
? MediaPageStoreData[this.id].data.dislikes + tmp
|
||||
: tmp;
|
||||
} else {
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.dislikes
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.dislikes
|
||||
? MediaPageStoreData[this.id].data.dislikes
|
||||
: 'N/A';
|
||||
}
|
||||
@@ -493,7 +513,8 @@ class MediaPageStore extends EventEmitter {
|
||||
break;
|
||||
case 'media-categories':
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.categories_info
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.categories_info
|
||||
? MediaPageStoreData[this.id].data.categories_info
|
||||
: [];
|
||||
break;
|
||||
@@ -505,19 +526,22 @@ class MediaPageStore extends EventEmitter {
|
||||
break;
|
||||
case 'media-type':
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.media_type
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.media_type
|
||||
? MediaPageStoreData[this.id].data.media_type
|
||||
: null;
|
||||
break;
|
||||
case 'media-original-url':
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.original_media_url
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.original_media_url
|
||||
? MediaPageStoreData[this.id].data.original_media_url
|
||||
: null;
|
||||
break;
|
||||
case 'media-thumbnail-url':
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.thumbnail_url
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.thumbnail_url
|
||||
? MediaPageStoreData[this.id].data.thumbnail_url
|
||||
: null;
|
||||
break;
|
||||
@@ -529,7 +553,8 @@ class MediaPageStore extends EventEmitter {
|
||||
break;
|
||||
case 'media-author-thumbnail-url':
|
||||
r =
|
||||
void 0 !== MediaPageStoreData[this.id].data && void 0 !== MediaPageStoreData[this.id].data.author_thumbnail
|
||||
void 0 !== MediaPageStoreData[this.id].data &&
|
||||
void 0 !== MediaPageStoreData[this.id].data.author_thumbnail
|
||||
? this.mediacms_config.site.url +
|
||||
'/' +
|
||||
MediaPageStoreData[this.id].data.author_thumbnail.replace(/^\//g, '')
|
||||
@@ -549,7 +574,9 @@ class MediaPageStore extends EventEmitter {
|
||||
activeItem = 0;
|
||||
i = 0;
|
||||
while (i < this.pagePlaylistData.playlist_media.length) {
|
||||
if (MediaPageStoreData[this.id].mediaId === this.pagePlaylistData.playlist_media[i].friendly_token) {
|
||||
if (
|
||||
MediaPageStoreData[this.id].mediaId === this.pagePlaylistData.playlist_media[i].friendly_token
|
||||
) {
|
||||
activeItem = i;
|
||||
break;
|
||||
}
|
||||
@@ -579,7 +606,9 @@ class MediaPageStore extends EventEmitter {
|
||||
activeItem = 0;
|
||||
i = 0;
|
||||
while (i < this.pagePlaylistData.playlist_media.length) {
|
||||
if (MediaPageStoreData[this.id].mediaId === this.pagePlaylistData.playlist_media[i].friendly_token) {
|
||||
if (
|
||||
MediaPageStoreData[this.id].mediaId === this.pagePlaylistData.playlist_media[i].friendly_token
|
||||
) {
|
||||
activeItem = i;
|
||||
break;
|
||||
}
|
||||
@@ -649,7 +678,10 @@ class MediaPageStore extends EventEmitter {
|
||||
new_playlist_media = [];
|
||||
j = 0;
|
||||
while (j < MediaPageStoreData[this.id].playlists[i].media_list.length) {
|
||||
if (MediaPageStoreData[this.id].mediaId !== MediaPageStoreData[this.id].playlists[i].media_list[j]) {
|
||||
if (
|
||||
MediaPageStoreData[this.id].mediaId !==
|
||||
MediaPageStoreData[this.id].playlists[i].media_list[j]
|
||||
) {
|
||||
new_playlist_media.push(MediaPageStoreData[this.id].playlists[i].media_list[j]);
|
||||
}
|
||||
j += 1;
|
||||
@@ -820,6 +852,13 @@ class MediaPageStore extends EventEmitter {
|
||||
if (response && 204 === response.status) {
|
||||
this.emit('media_delete', MediaPageStoreData[this.id].mediaId);
|
||||
}
|
||||
setTimeout(
|
||||
function (ins) {
|
||||
MediaPageStoreData[ins.id].while.deleteMedia = null;
|
||||
},
|
||||
100,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
removeMediaFail() {
|
||||
@@ -850,7 +889,10 @@ class MediaPageStore extends EventEmitter {
|
||||
let newComments = [];
|
||||
for (k in MediaPageStoreData[this.id].comments) {
|
||||
if (MediaPageStoreData[this.id].comments.hasOwnProperty(k)) {
|
||||
if (MediaPageStoreData[this.id].while.deleteCommentId !== MediaPageStoreData[this.id].comments[k].uid) {
|
||||
if (
|
||||
MediaPageStoreData[this.id].while.deleteCommentId !==
|
||||
MediaPageStoreData[this.id].comments[k].uid
|
||||
) {
|
||||
newComments.push(MediaPageStoreData[this.id].comments[k]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class VideoPlayerStore extends EventEmitter {
|
||||
switch (action.type) {
|
||||
case 'TOGGLE_VIEWER_MODE':
|
||||
_StoreData.inTheaterMode = !_StoreData.inTheaterMode;
|
||||
browserCache.set('in-theater-mode', _StoreData.inTheaterMode);
|
||||
this.emit('changed_viewer_mode');
|
||||
break;
|
||||
case 'SET_VIEWER_MODE':
|
||||
|
||||
385
frontend/tests/tests-constants.ts
Normal file
385
frontend/tests/tests-constants.ts
Normal file
@@ -0,0 +1,385 @@
|
||||
export const sampleGlobalMediaCMS = {
|
||||
profileId: 'john',
|
||||
site: {
|
||||
id: 'my-site',
|
||||
url: 'https://example.com/',
|
||||
api: 'https://example.com/api/',
|
||||
title: 'Example',
|
||||
theme: { mode: 'dark', switch: { enabled: true, position: 'sidebar' } },
|
||||
logo: {
|
||||
lightMode: { img: '/img/light.png', svg: '/img/light.svg' },
|
||||
darkMode: { img: '/img/dark.png', svg: '/img/dark.svg' },
|
||||
},
|
||||
devEnv: false,
|
||||
useRoundedCorners: true,
|
||||
version: '1.0.0',
|
||||
taxonomies: {
|
||||
tags: { enabled: true, title: 'Topic Tags' },
|
||||
categories: { enabled: false, title: 'Kinds' },
|
||||
},
|
||||
pages: {
|
||||
featured: { enabled: true, title: 'Featured picks' },
|
||||
latest: { enabled: true, title: 'Recent uploads' },
|
||||
members: { enabled: true, title: 'People' },
|
||||
recommended: { enabled: false, title: 'You may like' },
|
||||
},
|
||||
userPages: {
|
||||
liked: { enabled: true, title: 'Favorites' },
|
||||
history: { enabled: true, title: 'Watched' },
|
||||
},
|
||||
},
|
||||
url: {
|
||||
home: '/',
|
||||
admin: '/admin',
|
||||
error404: '/404',
|
||||
latestMedia: '/latest',
|
||||
featuredMedia: '/featured',
|
||||
recommendedMedia: '/recommended',
|
||||
signin: '/signin',
|
||||
signout: '/signout',
|
||||
register: '/register',
|
||||
changePassword: '/password',
|
||||
members: '/members',
|
||||
search: '/search',
|
||||
likedMedia: '/liked',
|
||||
history: '/history',
|
||||
addMedia: '/add',
|
||||
editChannel: '/edit/channel',
|
||||
editProfile: '/edit/profile',
|
||||
tags: '/tags',
|
||||
categories: '/categories',
|
||||
manageMedia: '/manage/media',
|
||||
manageUsers: '/manage/users',
|
||||
manageComments: '/manage/comments',
|
||||
},
|
||||
api: {
|
||||
media: 'v1/media/',
|
||||
playlists: 'v1/playlists',
|
||||
members: 'v1/users',
|
||||
liked: 'v1/user/liked',
|
||||
history: 'v1/user/history',
|
||||
tags: 'v1/tags',
|
||||
categories: 'v1/categories',
|
||||
manage_media: 'v1/manage/media',
|
||||
manage_users: 'v1/manage/users',
|
||||
manage_comments: 'v1/manage/comments',
|
||||
search: 'v1/search',
|
||||
actions: 'v1/actions',
|
||||
comments: 'v1/comments',
|
||||
},
|
||||
contents: {
|
||||
header: {
|
||||
right: '',
|
||||
onLogoRight: '',
|
||||
},
|
||||
notifications: {
|
||||
messages: { addToLiked: 'Yay', removeFromLiked: 'Oops', addToDisliked: 'nay', removeFromDisliked: 'ok' },
|
||||
},
|
||||
sidebar: {
|
||||
belowNavMenu: '__belowNavMenu__',
|
||||
belowThemeSwitcher: '__belowThemeSwitcher__',
|
||||
footer: '__footer__',
|
||||
mainMenuExtraItems: [
|
||||
{ text: '__text_1__', link: '__link_1__', icon: '__icon_1__', className: '__className_1__' },
|
||||
],
|
||||
navMenuItems: [
|
||||
{ text: '__text_2__', link: '__link_2__', icon: '__icon_2__', className: '__className_2__' },
|
||||
],
|
||||
},
|
||||
uploader: {
|
||||
belowUploadArea: '__belowUploadArea__',
|
||||
postUploadMessage: '__postUploadMessage__',
|
||||
},
|
||||
},
|
||||
pages: {
|
||||
home: {
|
||||
sections: {
|
||||
latest: { title: 'Latest T' },
|
||||
featured: { title: 'Featured T' },
|
||||
recommended: { title: 'Recommended T' },
|
||||
},
|
||||
},
|
||||
media: { categoriesWithTitle: true, htmlInDescription: true, hideViews: true, related: { initialSize: 5 } },
|
||||
profile: { htmlInDescription: true, includeHistory: true, includeLikedMedia: true },
|
||||
search: { advancedFilters: true },
|
||||
},
|
||||
features: {
|
||||
mediaItem: { hideAuthor: true, hideViews: false, hideDate: true },
|
||||
media: {
|
||||
actions: {
|
||||
like: true,
|
||||
dislike: true,
|
||||
report: true,
|
||||
comment: true,
|
||||
comment_mention: true,
|
||||
download: true,
|
||||
save: true,
|
||||
share: true,
|
||||
},
|
||||
shareOptions: ['embed', 'email'],
|
||||
},
|
||||
playlists: { mediaTypes: ['audio'] },
|
||||
sideBar: { hideHomeLink: false, hideTagsLink: true, hideCategoriesLink: false },
|
||||
embeddedVideo: { initialDimensions: { width: 640, height: 360 } },
|
||||
headerBar: { hideLogin: false, hideRegister: true },
|
||||
},
|
||||
user: {
|
||||
is: { anonymous: false, admin: true },
|
||||
name: ' John ',
|
||||
username: ' john ',
|
||||
thumbnail: ' /img/j.png ',
|
||||
can: {
|
||||
changePassword: true,
|
||||
deleteProfile: true,
|
||||
addComment: true,
|
||||
mentionComment: true,
|
||||
deleteComment: true,
|
||||
editMedia: true,
|
||||
deleteMedia: true,
|
||||
editSubtitle: true,
|
||||
manageMedia: true,
|
||||
manageUsers: true,
|
||||
manageComments: true,
|
||||
contactUser: true,
|
||||
canSeeMembersPage: true,
|
||||
usersNeedsToBeApproved: false,
|
||||
addMedia: true,
|
||||
editProfile: true,
|
||||
readComment: true,
|
||||
},
|
||||
pages: { about: '/u/john/about ', media: '/u/john ', playlists: '/u/john/playlists ' },
|
||||
},
|
||||
};
|
||||
|
||||
export const sampleMediaCMSConfig = {
|
||||
api: {
|
||||
archive: {
|
||||
tags: '',
|
||||
categories: '',
|
||||
},
|
||||
featured: '',
|
||||
manage: {
|
||||
media: '',
|
||||
users: '',
|
||||
comments: '',
|
||||
},
|
||||
media: '',
|
||||
playlists: '/v1/playlists',
|
||||
recommended: '',
|
||||
search: {
|
||||
query: '',
|
||||
titles: './search.html?titles=',
|
||||
tag: '',
|
||||
category: '',
|
||||
},
|
||||
user: {
|
||||
liked: '',
|
||||
history: '',
|
||||
playlists: '/playlists/?author=',
|
||||
},
|
||||
users: '/users',
|
||||
},
|
||||
contents: {
|
||||
header: {
|
||||
right: '',
|
||||
onLogoRight: '',
|
||||
},
|
||||
uploader: {
|
||||
belowUploadArea: '',
|
||||
postUploadMessage: '',
|
||||
},
|
||||
sidebar: {
|
||||
belowNavMenu: '__belowNavMenu__',
|
||||
belowThemeSwitcher: '__belowThemeSwitcher__',
|
||||
footer: '__footer__',
|
||||
mainMenuExtra: {
|
||||
items: [{ text: '__text_1__', link: '__link_1__', icon: '__icon_1__', className: '__className_1__' }],
|
||||
},
|
||||
navMenu: {
|
||||
items: [{ text: '__text_2__', link: '__link_2__', icon: '__icon_2__', className: '__className_2__' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
enabled: {
|
||||
taxonomies: sampleGlobalMediaCMS.site.taxonomies,
|
||||
pages: {
|
||||
featured: { enabled: true, title: 'Featured picks' },
|
||||
latest: { enabled: true, title: 'Recent uploads' },
|
||||
members: { enabled: true, title: 'People' },
|
||||
recommended: { enabled: true, title: 'You may like' },
|
||||
liked: { enabled: true, title: 'Favorites' },
|
||||
history: { enabled: true, title: 'Watched' },
|
||||
},
|
||||
},
|
||||
member: {
|
||||
name: null,
|
||||
username: 'john',
|
||||
thumbnail: null,
|
||||
is: {
|
||||
admin: false,
|
||||
anonymous: false,
|
||||
},
|
||||
can: {
|
||||
addComment: false,
|
||||
addMedia: false,
|
||||
canSeeMembersPage: false,
|
||||
changePassword: false,
|
||||
contactUser: false,
|
||||
deleteComment: false,
|
||||
deleteMedia: false,
|
||||
deleteProfile: false,
|
||||
dislikeMedia: false,
|
||||
downloadMedia: false,
|
||||
editMedia: false,
|
||||
editProfile: false,
|
||||
editSubtitle: false,
|
||||
likeMedia: false,
|
||||
login: false,
|
||||
manageComments: false,
|
||||
manageMedia: false,
|
||||
manageUsers: false,
|
||||
mentionComment: false,
|
||||
readComment: true,
|
||||
register: false,
|
||||
reportMedia: false,
|
||||
saveMedia: true,
|
||||
shareMedia: false,
|
||||
usersNeedsToBeApproved: false,
|
||||
},
|
||||
pages: {
|
||||
home: null,
|
||||
about: null,
|
||||
media: null,
|
||||
playlists: null,
|
||||
},
|
||||
},
|
||||
media: {
|
||||
item: {
|
||||
displayAuthor: false,
|
||||
displayViews: false,
|
||||
displayPublishDate: false,
|
||||
},
|
||||
share: {
|
||||
options: [],
|
||||
},
|
||||
},
|
||||
notifications: {
|
||||
messages: {
|
||||
addToLiked: '',
|
||||
removeFromLiked: '',
|
||||
addToDisliked: '',
|
||||
removeFromDisliked: '',
|
||||
},
|
||||
},
|
||||
options: {
|
||||
pages: {
|
||||
home: {
|
||||
sections: {
|
||||
latest: {
|
||||
title: '',
|
||||
},
|
||||
featured: {
|
||||
title: '',
|
||||
},
|
||||
recommended: {
|
||||
title: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
search: {
|
||||
advancedFilters: false,
|
||||
},
|
||||
media: {
|
||||
categoriesWithTitle: true,
|
||||
htmlInDescription: true,
|
||||
related: { initialSize: 5 },
|
||||
displayViews: true,
|
||||
},
|
||||
profile: {
|
||||
htmlInDescription: false,
|
||||
includeHistory: false,
|
||||
includeLikedMedia: false,
|
||||
},
|
||||
},
|
||||
embedded: {
|
||||
video: {
|
||||
dimensions: {
|
||||
width: 0,
|
||||
widthUnit: 'px',
|
||||
height: 0,
|
||||
heightUnit: 'px',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
playlists: {
|
||||
mediaTypes: [],
|
||||
},
|
||||
sidebar: {
|
||||
hideHomeLink: false,
|
||||
hideTagsLink: false,
|
||||
hideCategoriesLink: false,
|
||||
},
|
||||
site: {
|
||||
api: '',
|
||||
id: '',
|
||||
title: '',
|
||||
url: '',
|
||||
useRoundedCorners: false,
|
||||
version: '',
|
||||
},
|
||||
theme: {
|
||||
logo: {
|
||||
lightMode: { img: '/img/light.png', svg: '/img/light.svg' },
|
||||
darkMode: { img: '/img/dark.png', svg: '/img/dark.svg' },
|
||||
},
|
||||
mode: 'dark',
|
||||
switch: {
|
||||
enabled: true,
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
url: {
|
||||
admin: '',
|
||||
archive: {
|
||||
categories: '',
|
||||
tags: '',
|
||||
},
|
||||
changePassword: '',
|
||||
embed: '',
|
||||
error404: '',
|
||||
featured: '',
|
||||
home: '',
|
||||
latest: '',
|
||||
manage: {
|
||||
comments: '',
|
||||
media: '',
|
||||
users: '',
|
||||
},
|
||||
members: '',
|
||||
profile: {
|
||||
about: '',
|
||||
media: '',
|
||||
playlists: '',
|
||||
shared_by_me: '',
|
||||
shared_with_me: '',
|
||||
},
|
||||
recommended: '',
|
||||
register: '',
|
||||
search: {
|
||||
base: '',
|
||||
category: '',
|
||||
query: '',
|
||||
tag: '',
|
||||
},
|
||||
signin: '',
|
||||
signout: '',
|
||||
user: {
|
||||
addMedia: '',
|
||||
editChannel: '',
|
||||
editProfile: '',
|
||||
history: '',
|
||||
liked: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
739
frontend/tests/utils/stores/MediaPageStore.test.ts
Normal file
739
frontend/tests/utils/stores/MediaPageStore.test.ts
Normal file
@@ -0,0 +1,739 @@
|
||||
import { csrfToken, deleteRequest, getRequest, postRequest, putRequest } from '../../../src/static/js/utils/helpers';
|
||||
|
||||
const MEDIA_ID = 'MEDIA_ID';
|
||||
const PLAYLIST_ID = 'PLAYLIST_ID';
|
||||
|
||||
window.history.pushState({}, '', `/?m=${MEDIA_ID}&pl=${PLAYLIST_ID}`);
|
||||
|
||||
import store from '../../../src/static/js/utils/stores/MediaPageStore';
|
||||
|
||||
import { sampleGlobalMediaCMS, sampleMediaCMSConfig } from '../../tests-constants';
|
||||
|
||||
jest.mock('../../../src/static/js/utils/classes/', () => ({
|
||||
BrowserCache: jest.fn().mockImplementation(() => ({
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
||||
BrowserEvents: jest.fn().mockImplementation(() => ({
|
||||
doc: jest.fn(),
|
||||
win: jest.fn(),
|
||||
})),
|
||||
csrfToken: jest.fn(),
|
||||
deleteRequest: jest.fn(),
|
||||
exportStore: jest.fn((store) => store),
|
||||
getRequest: jest.fn(),
|
||||
postRequest: jest.fn(),
|
||||
putRequest: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('utils/store', () => {
|
||||
describe('MediaPageStore', () => {
|
||||
const handler = store.actions_handler.bind(store);
|
||||
|
||||
const onLoadedViewerPlaylistData = jest.fn();
|
||||
const onLoadedPagePlaylistData = jest.fn();
|
||||
const onLoadedViewerPlaylistError = jest.fn();
|
||||
const onLoadedVideoData = jest.fn();
|
||||
const onLoadedImageData = jest.fn();
|
||||
const onLoadedMediaData = jest.fn();
|
||||
const onLoadedMediaError = jest.fn();
|
||||
const onCommentsLoad = jest.fn();
|
||||
const onUsersLoad = jest.fn();
|
||||
const onPlaylistsLoad = jest.fn();
|
||||
const onLikedMediaFailedRequest = jest.fn();
|
||||
const onLikedMedia = jest.fn();
|
||||
const onDislikedMediaFailedRequest = jest.fn();
|
||||
const onDislikedMedia = jest.fn();
|
||||
const onReportedMedia = jest.fn();
|
||||
const onPlaylistCreationCompleted = jest.fn();
|
||||
const onPlaylistCreationFailed = jest.fn();
|
||||
const onMediaPlaylistAdditionCompleted = jest.fn();
|
||||
const onMediaPlaylistAdditionFailed = jest.fn();
|
||||
const onMediaPlaylistRemovalCompleted = jest.fn();
|
||||
const onMediaPlaylistRemovalFailed = jest.fn();
|
||||
const onCopiedMediaLink = jest.fn();
|
||||
const onCopiedEmbedMediaCode = jest.fn();
|
||||
const onMediaDelete = jest.fn();
|
||||
const onMediaDeleteFail = jest.fn();
|
||||
const onCommentDeleteFail = jest.fn();
|
||||
const onCommentDelete = jest.fn();
|
||||
const onCommentSubmitFail = jest.fn();
|
||||
const onCommentSubmit = jest.fn();
|
||||
|
||||
store.on('loaded_viewer_playlist_data', onLoadedViewerPlaylistData);
|
||||
store.on('loaded_page_playlist_data', onLoadedPagePlaylistData);
|
||||
store.on('loaded_viewer_playlist_error', onLoadedViewerPlaylistError);
|
||||
store.on('loaded_video_data', onLoadedVideoData);
|
||||
store.on('loaded_image_data', onLoadedImageData);
|
||||
store.on('loaded_media_data', onLoadedMediaData);
|
||||
store.on('loaded_media_error', onLoadedMediaError);
|
||||
store.on('comments_load', onCommentsLoad);
|
||||
store.on('users_load', onUsersLoad);
|
||||
store.on('playlists_load', onPlaylistsLoad);
|
||||
store.on('liked_media_failed_request', onLikedMediaFailedRequest);
|
||||
store.on('liked_media', onLikedMedia);
|
||||
store.on('disliked_media_failed_request', onDislikedMediaFailedRequest);
|
||||
store.on('disliked_media', onDislikedMedia);
|
||||
store.on('reported_media', onReportedMedia);
|
||||
store.on('playlist_creation_completed', onPlaylistCreationCompleted);
|
||||
store.on('playlist_creation_failed', onPlaylistCreationFailed);
|
||||
store.on('media_playlist_addition_completed', onMediaPlaylistAdditionCompleted);
|
||||
store.on('media_playlist_addition_failed', onMediaPlaylistAdditionFailed);
|
||||
store.on('media_playlist_removal_completed', onMediaPlaylistRemovalCompleted);
|
||||
store.on('media_playlist_removal_failed', onMediaPlaylistRemovalFailed);
|
||||
store.on('copied_media_link', onCopiedMediaLink);
|
||||
store.on('copied_embed_media_code', onCopiedEmbedMediaCode);
|
||||
store.on('media_delete', onMediaDelete);
|
||||
store.on('media_delete_fail', onMediaDeleteFail);
|
||||
store.on('comment_delete_fail', onCommentDeleteFail);
|
||||
store.on('comment_delete', onCommentDelete);
|
||||
store.on('comment_submit_fail', onCommentSubmitFail);
|
||||
store.on('comment_submit', onCommentSubmit);
|
||||
|
||||
beforeAll(() => {
|
||||
(globalThis as any).window.MediaCMS = {
|
||||
// mediaId: MEDIA_ID, // @note: It doesn't belong in 'sampleGlobalMediaCMS, but it could be used
|
||||
features: sampleGlobalMediaCMS.features,
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
delete (globalThis as any).window.MediaCMS;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('Validate initial values', () => {
|
||||
expect(store.get('users')).toStrictEqual([]);
|
||||
expect(store.get('playlists')).toStrictEqual([]);
|
||||
expect(store.get('media-load-error-type')).toBe(null);
|
||||
expect(store.get('media-load-error-message')).toBe(null);
|
||||
expect(store.get('media-comments')).toStrictEqual([]);
|
||||
expect(store.get('media-data')).toBe(null);
|
||||
expect(store.get('media-id')).toBe(MEDIA_ID);
|
||||
expect(store.get('media-url')).toBe('N/A');
|
||||
expect(store.get('media-edit-subtitle-url')).toBe(null);
|
||||
expect(store.get('media-likes')).toBe('N/A');
|
||||
expect(store.get('media-dislikes')).toBe('N/A');
|
||||
expect(store.get('media-summary')).toBe(null);
|
||||
expect(store.get('media-categories')).toStrictEqual([]);
|
||||
expect(store.get('media-tags')).toStrictEqual([]);
|
||||
expect(store.get('media-type')).toBe(null);
|
||||
expect(store.get('media-original-url')).toBe(null);
|
||||
expect(store.get('media-thumbnail-url')).toBe(null);
|
||||
expect(store.get('user-liked-media')).toBe(false);
|
||||
expect(store.get('user-disliked-media')).toBe(false);
|
||||
expect(store.get('media-author-thumbnail-url')).toBe(null);
|
||||
expect(store.get('playlist-data')).toBe(null);
|
||||
expect(store.get('playlist-id')).toBe(null);
|
||||
expect(store.get('playlist-next-media-url')).toBe(null);
|
||||
expect(store.get('playlist-previous-media-url')).toBe(null);
|
||||
});
|
||||
|
||||
describe('Trigger and validate actions behavior', () => {
|
||||
const MEDIA_DATA = {
|
||||
add_subtitle_url: '/MEDIA_DATA_ADD_SUBTITLE_URL',
|
||||
author_thumbnail: 'MEDIA_DATA_AUTHOR_THUMBNAIL',
|
||||
categories_info: [
|
||||
{ title: 'Art', url: '/search?c=Art' },
|
||||
{ title: 'Documentary', url: '/search?c=Documentary' },
|
||||
],
|
||||
likes: 12,
|
||||
dislikes: 4,
|
||||
media_type: 'video',
|
||||
original_media_url: 'MEDIA_DATA_ORIGINAL_MEDIA_URL',
|
||||
reported_times: 0,
|
||||
summary: 'MEDIA_DATA_SUMMARY',
|
||||
tags_info: [
|
||||
{ title: 'and', url: '/search?t=and' },
|
||||
{ title: 'behavior', url: '/search?t=behavior' },
|
||||
],
|
||||
thumbnail_url: 'MEDIA_DATA_THUMBNAIL_URL',
|
||||
url: '/MEDIA_DATA_URL',
|
||||
};
|
||||
const PLAYLIST_DATA = {
|
||||
playlist_media: [
|
||||
{ friendly_token: `${MEDIA_ID}_2`, url: '/PLAYLIT_MEDIA_URL_2' },
|
||||
{ friendly_token: MEDIA_ID, url: '/PLAYLIT_MEDIA_URL_1' },
|
||||
{ friendly_token: `${MEDIA_ID}_3`, url: '/PLAYLIT_MEDIA_URL_3' },
|
||||
],
|
||||
};
|
||||
const USER_PLAYLIST_DATA = { playlist_media: [{ url: 'm=PLAYLIST_MEDIA_ID' }] };
|
||||
|
||||
test('Action type: "LOAD_MEDIA_DATA"', () => {
|
||||
const MEDIA_API_URL = `${sampleMediaCMSConfig.api.media}/${MEDIA_ID}`;
|
||||
const MEDIA_COMMENTS_API_URL = `${sampleMediaCMSConfig.api.media}/${MEDIA_ID}/comments`;
|
||||
const PLAYLIST_API_URL = `${sampleMediaCMSConfig.api.playlists}/${PLAYLIST_ID}`;
|
||||
const USERS_API_URL = sampleMediaCMSConfig.api.users;
|
||||
const USER_PLAYLISTS_API_URL = `${sampleMediaCMSConfig.api.user.playlists}${sampleMediaCMSConfig.member.username}`;
|
||||
const USER_PLAYLIST_API_URL = `${sampleMediaCMSConfig.site.url}/${'PLAYLIST_API_URL'.replace(/^\//g, '')}`;
|
||||
|
||||
const MEDIA_COMMENTS_RESULTS = ['COMMENT_ID_1'];
|
||||
const USERS_RESULTS = ['USER_ID_1'];
|
||||
const USER_PLAYLISTS_RESULTS = [
|
||||
{
|
||||
url: `/${PLAYLIST_ID}`,
|
||||
user: sampleMediaCMSConfig.member.username,
|
||||
title: 'PLAYLIST_TITLE',
|
||||
description: 'PLAYLIST_DECRIPTION',
|
||||
add_date: 'PLAYLIST_ADD_DATE',
|
||||
api_url: 'PLAYLIST_API_URL',
|
||||
},
|
||||
];
|
||||
|
||||
(getRequest as jest.Mock).mockImplementation((url, _cache, successCallback, _failCallback) => {
|
||||
if (url === PLAYLIST_API_URL) {
|
||||
return successCallback({ data: PLAYLIST_DATA });
|
||||
}
|
||||
|
||||
if (url === USER_PLAYLIST_API_URL) {
|
||||
return successCallback({ data: USER_PLAYLIST_DATA });
|
||||
}
|
||||
|
||||
if (url === MEDIA_API_URL) {
|
||||
return successCallback({ data: MEDIA_DATA });
|
||||
}
|
||||
|
||||
if (url === USERS_API_URL) {
|
||||
return successCallback({ data: { count: USERS_RESULTS.length, results: USERS_RESULTS } });
|
||||
}
|
||||
|
||||
if (url === MEDIA_COMMENTS_API_URL) {
|
||||
return successCallback({
|
||||
data: { count: MEDIA_COMMENTS_RESULTS.length, results: MEDIA_COMMENTS_RESULTS },
|
||||
});
|
||||
}
|
||||
|
||||
if (url === USER_PLAYLISTS_API_URL) {
|
||||
return successCallback({
|
||||
data: { count: USER_PLAYLISTS_RESULTS.length, results: USER_PLAYLISTS_RESULTS },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
handler({ type: 'LOAD_MEDIA_DATA' });
|
||||
|
||||
expect(getRequest).toHaveBeenCalledTimes(6);
|
||||
|
||||
expect(getRequest).toHaveBeenCalledWith(
|
||||
PLAYLIST_API_URL,
|
||||
false,
|
||||
store.playlistDataResponse,
|
||||
store.playlistDataErrorResponse
|
||||
);
|
||||
expect(getRequest).toHaveBeenCalledWith(
|
||||
MEDIA_API_URL,
|
||||
false,
|
||||
store.dataResponse,
|
||||
store.dataErrorResponse
|
||||
);
|
||||
expect(getRequest).toHaveBeenCalledWith(MEDIA_COMMENTS_API_URL, false, store.commentsResponse);
|
||||
expect(getRequest).toHaveBeenCalledWith(USERS_API_URL, false, store.usersResponse);
|
||||
expect(getRequest).toHaveBeenCalledWith(USER_PLAYLISTS_API_URL, false, store.playlistsResponse);
|
||||
expect(getRequest).toHaveBeenCalledWith(USER_PLAYLIST_API_URL, false, expect.any(Function));
|
||||
|
||||
expect(onLoadedViewerPlaylistData).toHaveBeenCalledTimes(1);
|
||||
expect(onLoadedPagePlaylistData).toHaveBeenCalledTimes(1);
|
||||
expect(onLoadedViewerPlaylistError).toHaveBeenCalledTimes(0);
|
||||
expect(onLoadedVideoData).toHaveBeenCalledTimes(1);
|
||||
expect(onLoadedImageData).toHaveBeenCalledTimes(0);
|
||||
expect(onLoadedMediaData).toHaveBeenCalledTimes(1);
|
||||
expect(onLoadedMediaError).toHaveBeenCalledTimes(0);
|
||||
expect(onCommentsLoad).toHaveBeenCalledTimes(1);
|
||||
expect(onUsersLoad).toHaveBeenCalledTimes(1);
|
||||
expect(onPlaylistsLoad).toHaveBeenCalledTimes(1);
|
||||
expect(onLikedMediaFailedRequest).toHaveBeenCalledTimes(0);
|
||||
expect(onLikedMedia).toHaveBeenCalledTimes(0);
|
||||
expect(onDislikedMediaFailedRequest).toHaveBeenCalledTimes(0);
|
||||
expect(onDislikedMedia).toHaveBeenCalledTimes(0);
|
||||
expect(onReportedMedia).toHaveBeenCalledTimes(0);
|
||||
expect(onPlaylistCreationCompleted).toHaveBeenCalledTimes(0);
|
||||
expect(onPlaylistCreationFailed).toHaveBeenCalledTimes(0);
|
||||
expect(onMediaPlaylistAdditionCompleted).toHaveBeenCalledTimes(0);
|
||||
expect(onMediaPlaylistAdditionFailed).toHaveBeenCalledTimes(0);
|
||||
expect(onMediaPlaylistRemovalCompleted).toHaveBeenCalledTimes(0);
|
||||
expect(onMediaPlaylistRemovalFailed).toHaveBeenCalledTimes(0);
|
||||
expect(onCopiedMediaLink).toHaveBeenCalledTimes(0);
|
||||
expect(onCopiedEmbedMediaCode).toHaveBeenCalledTimes(0);
|
||||
expect(onMediaDelete).toHaveBeenCalledTimes(0);
|
||||
expect(onMediaDeleteFail).toHaveBeenCalledTimes(0);
|
||||
expect(onCommentDeleteFail).toHaveBeenCalledTimes(0);
|
||||
expect(onCommentDelete).toHaveBeenCalledTimes(0);
|
||||
expect(onCommentSubmitFail).toHaveBeenCalledTimes(0);
|
||||
expect(onCommentSubmit).toHaveBeenCalledTimes(0);
|
||||
|
||||
expect(store.isVideo()).toBeTruthy();
|
||||
|
||||
expect(store.get('users')).toStrictEqual(USERS_RESULTS);
|
||||
expect(store.get('playlists')).toStrictEqual([
|
||||
{
|
||||
playlist_id: PLAYLIST_ID,
|
||||
title: 'PLAYLIST_TITLE',
|
||||
description: 'PLAYLIST_DECRIPTION',
|
||||
add_date: 'PLAYLIST_ADD_DATE',
|
||||
media_list: ['PLAYLIST_MEDIA_ID'],
|
||||
},
|
||||
]);
|
||||
expect(store.get('media-load-error-type')).toBe(null);
|
||||
expect(store.get('media-load-error-message')).toBe(null);
|
||||
expect(store.get('media-comments')).toStrictEqual(MEDIA_COMMENTS_RESULTS);
|
||||
expect(store.get('media-data')).toBe(MEDIA_DATA);
|
||||
expect(store.get('media-id')).toBe(MEDIA_ID);
|
||||
expect(store.get('media-url')).toBe(MEDIA_DATA.url);
|
||||
expect(store.get('media-edit-subtitle-url')).toBe(MEDIA_DATA.add_subtitle_url);
|
||||
expect(store.get('media-likes')).toBe(MEDIA_DATA.likes);
|
||||
expect(store.get('media-dislikes')).toBe(MEDIA_DATA.dislikes);
|
||||
expect(store.get('media-summary')).toBe(MEDIA_DATA.summary);
|
||||
expect(store.get('media-categories')).toStrictEqual(MEDIA_DATA.categories_info);
|
||||
expect(store.get('media-tags')).toStrictEqual(MEDIA_DATA.tags_info);
|
||||
expect(store.get('media-type')).toBe(MEDIA_DATA.media_type);
|
||||
expect(store.get('media-original-url')).toBe(MEDIA_DATA.original_media_url);
|
||||
expect(store.get('media-thumbnail-url')).toBe(MEDIA_DATA.thumbnail_url);
|
||||
expect(store.get('user-liked-media')).toBe(false);
|
||||
expect(store.get('user-disliked-media')).toBe(false);
|
||||
expect(store.get('media-author-thumbnail-url')).toBe(`/${MEDIA_DATA.author_thumbnail}`);
|
||||
expect(store.get('playlist-data')).toBe(PLAYLIST_DATA);
|
||||
expect(store.get('playlist-id')).toBe(PLAYLIST_ID);
|
||||
expect(store.get('playlist-next-media-url')).toBe(
|
||||
`${PLAYLIST_DATA.playlist_media[2].url}&pl=${PLAYLIST_ID}`
|
||||
);
|
||||
expect(store.get('playlist-previous-media-url')).toBe(
|
||||
`${PLAYLIST_DATA.playlist_media[0].url}&pl=${PLAYLIST_ID}`
|
||||
);
|
||||
});
|
||||
|
||||
test('Action type: "LIKE_MEDIA"', () => {
|
||||
// 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: {} })
|
||||
);
|
||||
|
||||
handler({ type: 'LIKE_MEDIA' });
|
||||
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(postRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.media}/${MEDIA_ID}/actions`,
|
||||
{ type: 'like' },
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
store.likeActionResponse,
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
expect(onLikedMedia).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('media-likes')).toBe(MEDIA_DATA.likes + 1);
|
||||
expect(store.get('media-dislikes')).toBe(MEDIA_DATA.dislikes);
|
||||
expect(store.get('user-liked-media')).toBe(true);
|
||||
expect(store.get('user-disliked-media')).toBe(false);
|
||||
});
|
||||
|
||||
test('Action type: "DISLIKE_MEDIA"', () => {
|
||||
handler({ type: 'DISLIKE_MEDIA' });
|
||||
|
||||
expect(postRequest).toHaveBeenCalledTimes(0);
|
||||
expect(onDislikedMedia).toHaveBeenCalledTimes(0);
|
||||
|
||||
expect(store.get('media-likes')).toBe(MEDIA_DATA.likes + 1);
|
||||
expect(store.get('media-dislikes')).toBe(MEDIA_DATA.dislikes);
|
||||
expect(store.get('user-liked-media')).toBe(true);
|
||||
expect(store.get('user-disliked-media')).toBe(false);
|
||||
});
|
||||
|
||||
test('Action type: "REPORT_MEDIA"', () => {
|
||||
const REPORT_DESCRIPTION = 'REPORT_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: {} })
|
||||
);
|
||||
|
||||
handler({ type: 'REPORT_MEDIA', reportDescription: REPORT_DESCRIPTION });
|
||||
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(postRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.media}/${MEDIA_ID}/actions`,
|
||||
{ type: 'report', extra_info: REPORT_DESCRIPTION },
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
store.reportActionResponse,
|
||||
store.reportActionResponse
|
||||
);
|
||||
|
||||
expect(onReportedMedia).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Action type: "COPY_SHARE_LINK"', () => {
|
||||
document.execCommand = jest.fn(); // @deprecated
|
||||
const inputElement = document.createElement('input');
|
||||
handler({ type: 'COPY_SHARE_LINK', inputElement });
|
||||
expect(onCopiedMediaLink).toHaveBeenCalledTimes(1);
|
||||
expect(document.execCommand).toHaveBeenCalledWith('copy');
|
||||
});
|
||||
|
||||
test('Action type: "COPY_EMBED_MEDIA_CODE"', () => {
|
||||
document.execCommand = jest.fn(); // @deprecated
|
||||
const inputElement = document.createElement('input');
|
||||
handler({ type: 'COPY_EMBED_MEDIA_CODE', inputElement });
|
||||
expect(onCopiedEmbedMediaCode).toHaveBeenCalledTimes(1);
|
||||
expect(document.execCommand).toHaveBeenCalledWith('copy');
|
||||
});
|
||||
|
||||
describe('Action type: "REMOVE_MEDIA"', () => {
|
||||
const mockCSRFtoken = 'test-csrf-token';
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock the CSRF token
|
||||
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
||||
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Verify deleteRequest was called with correct parameters
|
||||
expect(deleteRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.media}/${MEDIA_ID}`,
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
store.removeMediaResponse,
|
||||
store.removeMediaFail
|
||||
);
|
||||
|
||||
// Fast-forward time
|
||||
jest.advanceTimersByTime(100);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
test('Successful', () => {
|
||||
// Mock delete request
|
||||
(deleteRequest as jest.Mock).mockImplementation(
|
||||
(_url, _configData, _sync, successCallback, _failCallback) => successCallback({ status: 204 })
|
||||
);
|
||||
|
||||
handler({ type: 'REMOVE_MEDIA' });
|
||||
|
||||
expect(onMediaDelete).toHaveBeenCalledTimes(1);
|
||||
expect(onMediaDelete).toHaveBeenCalledWith(MEDIA_ID);
|
||||
});
|
||||
|
||||
test('Failed', () => {
|
||||
// Mock delete request
|
||||
(deleteRequest as jest.Mock).mockImplementation(
|
||||
(_url, _configData, _sync, _successCallback, failCallback) => failCallback({})
|
||||
);
|
||||
|
||||
handler({ type: 'REMOVE_MEDIA' });
|
||||
|
||||
expect(onMediaDeleteFail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Action type: "SUBMIT_COMMENT"', () => {
|
||||
const COMMENT_TEXT = 'COMMENT_TEXT';
|
||||
const COMMENT_UID = 'COMMENT_UID';
|
||||
|
||||
const mockCSRFtoken = 'test-csrf-token';
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock the CSRF token
|
||||
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
||||
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(postRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.media}/${MEDIA_ID}/comments`,
|
||||
{ text: COMMENT_TEXT },
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
store.submitCommentResponse,
|
||||
store.submitCommentFail
|
||||
);
|
||||
|
||||
// Fast-forward time
|
||||
jest.advanceTimersByTime(100);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
test('Successful', () => {
|
||||
// Mock post request
|
||||
(postRequest as jest.Mock).mockImplementation(
|
||||
(_url, _postData, _configData, _sync, successCallback, _failCallback) =>
|
||||
successCallback({ data: { uid: COMMENT_UID }, status: 201 })
|
||||
);
|
||||
|
||||
handler({ type: 'SUBMIT_COMMENT', commentText: COMMENT_TEXT });
|
||||
|
||||
expect(onCommentSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onCommentSubmit).toHaveBeenCalledWith(COMMENT_UID);
|
||||
});
|
||||
|
||||
test('Failed', () => {
|
||||
// Mock post request
|
||||
(postRequest as jest.Mock).mockImplementation(
|
||||
(_url, _postData, _configData, _sync, _successCallback, failCallback) => failCallback()
|
||||
);
|
||||
|
||||
handler({ type: 'SUBMIT_COMMENT', commentText: COMMENT_TEXT });
|
||||
|
||||
expect(onCommentSubmitFail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Action type: "DELETE_COMMENT"', () => {
|
||||
const COMMENT_ID = 'COMMENT_ID';
|
||||
|
||||
const mockCSRFtoken = 'test-csrf-token';
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock the CSRF token
|
||||
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
||||
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Verify deleteRequest was called with correct parameters
|
||||
expect(deleteRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.media}/${MEDIA_ID}/comments/${COMMENT_ID}`,
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
store.removeCommentResponse,
|
||||
store.removeCommentFail
|
||||
);
|
||||
|
||||
// Fast-forward time
|
||||
jest.advanceTimersByTime(100);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
test('Successful', () => {
|
||||
// Mock delete request
|
||||
(deleteRequest as jest.Mock).mockImplementation(
|
||||
(_url, _configData, _sync, successCallback, _failCallback) => successCallback({ status: 204 })
|
||||
);
|
||||
|
||||
handler({ type: 'DELETE_COMMENT', commentId: COMMENT_ID });
|
||||
|
||||
expect(onCommentDelete).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Failed', () => {
|
||||
// Mock delete request
|
||||
(deleteRequest as jest.Mock).mockImplementation(
|
||||
(_url, _configData, _sync, _successCallback, failCallback) => failCallback()
|
||||
);
|
||||
|
||||
handler({ type: 'DELETE_COMMENT', commentId: COMMENT_ID });
|
||||
|
||||
expect(onCommentDeleteFail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Action type: "CREATE_PLAYLIST"', () => {
|
||||
const NEW_PLAYLIST_DATA = {
|
||||
title: 'NEW_PLAYLIST_DATA_TITLE',
|
||||
description: 'NEW_PLAYLIST_DATA_DESCRIPTION',
|
||||
};
|
||||
|
||||
const mockCSRFtoken = 'test-csrf-token';
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock the CSRF token
|
||||
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(postRequest).toHaveBeenCalledWith(
|
||||
sampleMediaCMSConfig.api.playlists,
|
||||
NEW_PLAYLIST_DATA,
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
expect.any(Function),
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
test('Successful', () => {
|
||||
const NEW_PLAYLIST_RESPONSE_DATA = { uid: 'COMMENT_UID' };
|
||||
|
||||
// Mock post request
|
||||
(postRequest as jest.Mock).mockImplementation(
|
||||
(_url, _postData, _configData, _sync, successCallback, _failCallback) =>
|
||||
successCallback({ data: NEW_PLAYLIST_RESPONSE_DATA, status: 201 })
|
||||
);
|
||||
|
||||
handler({ type: 'CREATE_PLAYLIST', playlist_data: NEW_PLAYLIST_DATA });
|
||||
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(postRequest).toHaveBeenCalledWith(
|
||||
sampleMediaCMSConfig.api.playlists,
|
||||
NEW_PLAYLIST_DATA,
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
expect.any(Function),
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
expect(onPlaylistCreationCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(onPlaylistCreationCompleted).toHaveBeenCalledWith(NEW_PLAYLIST_RESPONSE_DATA);
|
||||
});
|
||||
|
||||
test('Failed', () => {
|
||||
// Mock post request
|
||||
(postRequest as jest.Mock).mockImplementation(
|
||||
(_url, _postData, _configData, _sync, _successCallback, failCallback) => failCallback()
|
||||
);
|
||||
|
||||
handler({ type: 'CREATE_PLAYLIST', playlist_data: NEW_PLAYLIST_DATA });
|
||||
|
||||
expect(onPlaylistCreationFailed).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Action type: "ADD_MEDIA_TO_PLAYLIST"', () => {
|
||||
const NEW_PLAYLIST_MEDIA_ID = 'NEW_PLAYLIST_MEDIA_ID';
|
||||
const mockCSRFtoken = 'test-csrf-token';
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock the CSRF token
|
||||
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(putRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.playlists}/${PLAYLIST_ID}`,
|
||||
{ type: 'add', media_friendly_token: NEW_PLAYLIST_MEDIA_ID },
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
expect.any(Function),
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
test('Successful', () => {
|
||||
// Mock put request
|
||||
(putRequest as jest.Mock).mockImplementation(
|
||||
(_url, _putData, _configData, _sync, successCallback, _failCallback) =>
|
||||
successCallback({ data: {} })
|
||||
);
|
||||
|
||||
handler({
|
||||
type: 'ADD_MEDIA_TO_PLAYLIST',
|
||||
playlist_id: PLAYLIST_ID,
|
||||
media_id: NEW_PLAYLIST_MEDIA_ID,
|
||||
});
|
||||
|
||||
expect(onMediaPlaylistAdditionCompleted).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Failed', () => {
|
||||
// Mock put request
|
||||
(putRequest as jest.Mock).mockImplementation(
|
||||
(_url, _putData, _configData, _sync, _successCallback, failCallback) => failCallback()
|
||||
);
|
||||
|
||||
handler({
|
||||
type: 'ADD_MEDIA_TO_PLAYLIST',
|
||||
playlist_id: PLAYLIST_ID,
|
||||
media_id: NEW_PLAYLIST_MEDIA_ID,
|
||||
});
|
||||
|
||||
expect(onMediaPlaylistAdditionFailed).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Action type: "REMOVE_MEDIA_FROM_PLAYLIST"', () => {
|
||||
// Mock the CSRF token
|
||||
const mockCSRFtoken = 'test-csrf-token';
|
||||
(csrfToken as jest.Mock).mockReturnValue(mockCSRFtoken);
|
||||
|
||||
afterEach(() => {
|
||||
// Verify postRequest was called with correct parameters
|
||||
expect(putRequest).toHaveBeenCalledWith(
|
||||
`${sampleMediaCMSConfig.api.playlists}/${PLAYLIST_ID}`,
|
||||
{ type: 'remove', media_friendly_token: MEDIA_ID },
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
expect.any(Function),
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
test('Successful', () => {
|
||||
// Mock put request
|
||||
(putRequest as jest.Mock).mockImplementation(
|
||||
(_url, _putData, _configData, _sync, successCallback, _failCallback) =>
|
||||
successCallback({ data: {} })
|
||||
);
|
||||
|
||||
handler({ type: 'REMOVE_MEDIA_FROM_PLAYLIST', playlist_id: PLAYLIST_ID, media_id: MEDIA_ID });
|
||||
|
||||
expect(onMediaPlaylistRemovalCompleted).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Failed', () => {
|
||||
// Mock put request
|
||||
(putRequest as jest.Mock).mockImplementation(
|
||||
(_url, _putData, _configData, _sync, _successCallback, failCallback) => failCallback()
|
||||
);
|
||||
|
||||
handler({ type: 'REMOVE_MEDIA_FROM_PLAYLIST', playlist_id: PLAYLIST_ID, media_id: MEDIA_ID });
|
||||
|
||||
expect(onMediaPlaylistRemovalFailed).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
test('Action type: "APPEND_NEW_PLAYLIST"', () => {
|
||||
const NEW_USER_PLAYLIST = {
|
||||
add_date: 'PLAYLIST_ADD_DATE_2',
|
||||
description: 'PLAYLIST_DECRIPTION_2',
|
||||
media_list: ['PLAYLIST_MEDIA_ID'],
|
||||
playlist_id: 'PLAYLIST_ID',
|
||||
title: 'PLAYLIST_TITLE_2',
|
||||
};
|
||||
|
||||
handler({ type: 'APPEND_NEW_PLAYLIST', playlist_data: NEW_USER_PLAYLIST });
|
||||
|
||||
expect(onPlaylistsLoad).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('playlists')).toStrictEqual([
|
||||
{
|
||||
add_date: 'PLAYLIST_ADD_DATE',
|
||||
description: 'PLAYLIST_DECRIPTION',
|
||||
media_list: ['PLAYLIST_MEDIA_ID'],
|
||||
playlist_id: PLAYLIST_ID,
|
||||
title: 'PLAYLIST_TITLE',
|
||||
},
|
||||
NEW_USER_PLAYLIST,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
162
frontend/tests/utils/stores/PageStore.test.ts
Normal file
162
frontend/tests/utils/stores/PageStore.test.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { BrowserCache } from '../../../src/static/js/utils/classes';
|
||||
import store from '../../../src/static/js/utils/stores/PageStore';
|
||||
|
||||
import { sampleMediaCMSConfig } from '../../tests-constants';
|
||||
|
||||
jest.mock('../../../src/static/js/utils/classes/', () => ({
|
||||
BrowserCache: jest.fn().mockImplementation(() => ({
|
||||
get: (key: string) => (key === 'media-auto-play' ? false : undefined),
|
||||
set: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
||||
BrowserEvents: jest.fn().mockImplementation(() => ({
|
||||
doc: jest.fn(),
|
||||
win: jest.fn(),
|
||||
})),
|
||||
exportStore: jest.fn((store) => store),
|
||||
}));
|
||||
|
||||
describe('utils/store', () => {
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('PageStore', () => {
|
||||
const handler = store.actions_handler.bind(store);
|
||||
|
||||
const onInit = jest.fn();
|
||||
const onToggleAutoPlay = jest.fn();
|
||||
const onAddNotification = jest.fn();
|
||||
|
||||
store.on('page_init', onInit);
|
||||
store.on('switched_media_auto_play', onToggleAutoPlay);
|
||||
store.on('added_notification', onAddNotification);
|
||||
|
||||
test('Validate initial values', () => {
|
||||
// BrowserCache mock
|
||||
expect(store.get('browser-cache').get('media-auto-play')).toBe(false);
|
||||
expect(store.get('browser-cache').get('ANY')).toBe(undefined);
|
||||
|
||||
// Autoplay media files
|
||||
expect(store.get('media-auto-play')).toBe(false);
|
||||
|
||||
// Configuration
|
||||
expect(store.get('config-contents')).toStrictEqual(sampleMediaCMSConfig.contents);
|
||||
expect(store.get('config-enabled')).toStrictEqual(sampleMediaCMSConfig.enabled);
|
||||
expect(store.get('config-media-item')).toStrictEqual(sampleMediaCMSConfig.media.item);
|
||||
expect(store.get('config-options')).toStrictEqual(sampleMediaCMSConfig.options);
|
||||
expect(store.get('config-site')).toStrictEqual(sampleMediaCMSConfig.site);
|
||||
|
||||
// Playlists API path
|
||||
expect(store.get('api-playlists')).toStrictEqual(sampleMediaCMSConfig.api.playlists);
|
||||
|
||||
// Notifications
|
||||
expect(store.get('notifications')).toStrictEqual([]);
|
||||
expect(store.get('notifications-size')).toBe(0);
|
||||
|
||||
expect(store.get('current-page')).toBe(undefined);
|
||||
});
|
||||
|
||||
test('Trigger and validate browser events behavior', () => {
|
||||
const docVisChange = jest.fn();
|
||||
const winScroll = jest.fn();
|
||||
const winResize = jest.fn();
|
||||
|
||||
store.on('document_visibility_change', docVisChange);
|
||||
store.on('window_scroll', winScroll);
|
||||
store.on('window_resize', winResize);
|
||||
|
||||
store.onDocumentVisibilityChange();
|
||||
store.onWindowScroll();
|
||||
store.onWindowResize();
|
||||
|
||||
expect(docVisChange).toHaveBeenCalled();
|
||||
expect(winScroll).toHaveBeenCalled();
|
||||
expect(winResize).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('Trigger and validate actions behavior', () => {
|
||||
test('Action type: "INIT_PAGE"', () => {
|
||||
handler({ type: 'INIT_PAGE', page: 'home' });
|
||||
expect(onInit).toHaveBeenCalledTimes(1);
|
||||
expect(store.get('current-page')).toBe('home');
|
||||
|
||||
handler({ type: 'INIT_PAGE', page: 'about' });
|
||||
expect(onInit).toHaveBeenCalledTimes(2);
|
||||
expect(store.get('current-page')).toBe('about');
|
||||
|
||||
handler({ type: 'INIT_PAGE', page: 'profile' });
|
||||
expect(onInit).toHaveBeenCalledTimes(3);
|
||||
expect(store.get('current-page')).toBe('profile');
|
||||
|
||||
expect(onInit).toHaveBeenCalledWith();
|
||||
|
||||
expect(onToggleAutoPlay).toHaveBeenCalledTimes(0);
|
||||
expect(onAddNotification).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('Action type: "TOGGLE_AUTO_PLAY"', () => {
|
||||
const browserCacheInstance = (BrowserCache as jest.Mock).mock.results[0].value;
|
||||
const browserCacheSetSpy = browserCacheInstance.set;
|
||||
|
||||
const initialValue = store.get('media-auto-play');
|
||||
|
||||
handler({ type: 'TOGGLE_AUTO_PLAY' });
|
||||
|
||||
expect(onToggleAutoPlay).toHaveBeenCalledWith();
|
||||
expect(onToggleAutoPlay).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('media-auto-play')).toBe(!initialValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('media-auto-play', !initialValue);
|
||||
|
||||
browserCacheSetSpy.mockRestore();
|
||||
});
|
||||
|
||||
test('Action type: "ADD_NOTIFICATION"', () => {
|
||||
const notificationMsg1 = 'NOTIFICATION_MSG_1';
|
||||
const notificationMsg2 = 'NOTIFICATION_MSG_2';
|
||||
const invalidNotification = 44;
|
||||
|
||||
// Add notification
|
||||
handler({ type: 'ADD_NOTIFICATION', notification: notificationMsg1 });
|
||||
expect(onAddNotification).toHaveBeenCalledWith();
|
||||
expect(onAddNotification).toHaveBeenCalledTimes(1);
|
||||
expect(store.get('notifications-size')).toBe(1);
|
||||
|
||||
const currentNotifications = store.get('notifications');
|
||||
expect(currentNotifications.length).toBe(1);
|
||||
expect(typeof currentNotifications[0][0]).toBe('string');
|
||||
expect(currentNotifications[0][1]).toBe(notificationMsg1);
|
||||
|
||||
expect(store.get('notifications-size')).toBe(0);
|
||||
expect(store.get('notifications')).toStrictEqual([]);
|
||||
|
||||
// Add another notification
|
||||
handler({ type: 'ADD_NOTIFICATION', notification: notificationMsg2 });
|
||||
|
||||
expect(onAddNotification).toHaveBeenCalledWith();
|
||||
expect(onAddNotification).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(store.get('notifications-size')).toBe(1);
|
||||
expect(store.get('notifications')[0][1]).toBe(notificationMsg2);
|
||||
|
||||
expect(store.get('notifications-size')).toBe(0);
|
||||
expect(store.get('notifications')).toStrictEqual([]);
|
||||
|
||||
// Add invalid notification
|
||||
handler({ type: 'ADD_NOTIFICATION', notification: invalidNotification });
|
||||
expect(onAddNotification).toHaveBeenCalledWith();
|
||||
expect(onAddNotification).toHaveBeenCalledTimes(3);
|
||||
|
||||
expect(store.get('notifications-size')).toBe(0);
|
||||
expect(store.get('notifications')).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
390
frontend/tests/utils/stores/PlaylistPageStore.test.ts
Normal file
390
frontend/tests/utils/stores/PlaylistPageStore.test.ts
Normal file
@@ -0,0 +1,390 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
83
frontend/tests/utils/stores/PlaylistViewStore.test.ts
Normal file
83
frontend/tests/utils/stores/PlaylistViewStore.test.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { BrowserCache } from '../../../src/static/js/utils/classes/';
|
||||
import store from '../../../src/static/js/utils/stores/PlaylistViewStore';
|
||||
|
||||
jest.mock('../../../src/static/js/utils/classes/', () => ({
|
||||
BrowserCache: jest.fn().mockImplementation(() => ({
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
||||
BrowserEvents: jest.fn().mockImplementation(() => ({
|
||||
doc: jest.fn(),
|
||||
win: jest.fn(),
|
||||
})),
|
||||
exportStore: jest.fn((store) => store),
|
||||
}));
|
||||
|
||||
describe('utils/store', () => {
|
||||
describe('PlaylistViewStore', () => {
|
||||
const browserCacheInstance = (BrowserCache as jest.Mock).mock.results[0].value;
|
||||
const browserCacheSetSpy = browserCacheInstance.set;
|
||||
|
||||
const handler = store.actions_handler.bind(store);
|
||||
|
||||
const onLoopRepeatUpdated = jest.fn();
|
||||
const onShuffleUpdated = jest.fn();
|
||||
const onSavedUpdated = jest.fn();
|
||||
|
||||
store.on('loop-repeat-updated', onLoopRepeatUpdated);
|
||||
store.on('shuffle-updated', onShuffleUpdated);
|
||||
store.on('saved-updated', onSavedUpdated);
|
||||
|
||||
test('Validate initial values', () => {
|
||||
expect(store.get('INVALID_TYPE')).toBe(null);
|
||||
expect(store.get('logged-in-user-playlist')).toBe(false);
|
||||
expect(store.get('enabled-loop')).toBe(undefined);
|
||||
expect(store.get('enabled-shuffle')).toBe(undefined);
|
||||
expect(store.get('saved-playlist')).toBe(false);
|
||||
});
|
||||
|
||||
describe('Trigger and validate actions behavior', () => {
|
||||
// @todo: Revisit the behavior of this action
|
||||
test('Action type: "TOGGLE_LOOP"', () => {
|
||||
handler({ type: 'TOGGLE_LOOP' });
|
||||
|
||||
expect(onLoopRepeatUpdated).toHaveBeenCalledTimes(1);
|
||||
expect(onLoopRepeatUpdated).toHaveBeenCalledWith();
|
||||
|
||||
expect(store.get('enabled-loop')).toBe(undefined);
|
||||
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('loopPlaylist[null]', true);
|
||||
});
|
||||
|
||||
// @todo: Revisit the behavior of this action
|
||||
test('Action type: "TOGGLE_SHUFFLE"', () => {
|
||||
handler({ type: 'TOGGLE_SHUFFLE' });
|
||||
|
||||
expect(onShuffleUpdated).toHaveBeenCalledTimes(1);
|
||||
expect(onShuffleUpdated).toHaveBeenCalledWith();
|
||||
|
||||
expect(store.get('enabled-shuffle')).toBe(undefined);
|
||||
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('shufflePlaylist[null]', true);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
168
frontend/tests/utils/stores/ProfilePageStore.test.ts
Normal file
168
frontend/tests/utils/stores/ProfilePageStore.test.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import { getRequest, deleteRequest, csrfToken } from '../../../src/static/js/utils/helpers';
|
||||
import store from '../../../src/static/js/utils/stores/ProfilePageStore';
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => ({
|
||||
...jest.requireActual('../../tests-constants').sampleMediaCMSConfig,
|
||||
api: { ...jest.requireActual('../../tests-constants').sampleMediaCMSConfig.api, users: '' },
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
||||
getRequest: jest.fn(),
|
||||
deleteRequest: jest.fn(),
|
||||
csrfToken: jest.fn(),
|
||||
exportStore: jest.fn((store) => store),
|
||||
}));
|
||||
|
||||
describe('utils/store', () => {
|
||||
const mockAuthorData = { username: 'testuser', name: 'Test User' };
|
||||
|
||||
beforeAll(() => {
|
||||
(globalThis as any).window.MediaCMS = { profileId: mockAuthorData.username };
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
delete (globalThis as any).window.MediaCMS;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('ProfilePageStore', () => {
|
||||
const handler = store.actions_handler.bind(store);
|
||||
|
||||
const onProfileDelete = jest.fn();
|
||||
const onProfileDeleteFail = jest.fn();
|
||||
const onLoadAuthorData = jest.fn();
|
||||
|
||||
beforeAll(() => {
|
||||
store.on('profile_delete', onProfileDelete);
|
||||
store.on('profile_delete_fail', onProfileDeleteFail);
|
||||
store.on('load-author-data', onLoadAuthorData);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset store state
|
||||
store.authorData = null;
|
||||
store.removingProfile = false;
|
||||
store.authorQuery = undefined;
|
||||
});
|
||||
|
||||
describe('Trigger and validate actions behavior', () => {
|
||||
test('Action type: "REMOVE_PROFILE" - successful deletion', async () => {
|
||||
// Set up author data
|
||||
store.authorData = mockAuthorData;
|
||||
|
||||
// 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) => successCallback({ status: 204 })
|
||||
);
|
||||
|
||||
handler({ type: 'REMOVE_PROFILE' });
|
||||
|
||||
// Verify deleteRequest was called with correct parameters
|
||||
expect(deleteRequest).toHaveBeenCalledWith(
|
||||
'/testuser', // API URL constructed from config + username
|
||||
{ headers: { 'X-CSRFToken': mockCSRFtoken } },
|
||||
false,
|
||||
store.removeProfileResponse,
|
||||
store.removeProfileFail
|
||||
);
|
||||
|
||||
// Verify event was emitted
|
||||
expect(onProfileDelete).toHaveBeenCalledWith(mockAuthorData.username);
|
||||
expect(onProfileDelete).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Action type: "REMOVE_PROFILE" - deletion failure', async () => {
|
||||
// Set up author data
|
||||
store.authorData = mockAuthorData;
|
||||
|
||||
// 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.call(store)
|
||||
);
|
||||
|
||||
handler({ type: 'REMOVE_PROFILE' });
|
||||
|
||||
// Wait for the setTimeout in removeProfileFail
|
||||
await new Promise((resolve) => setTimeout(resolve, 150));
|
||||
|
||||
// Verify event was emitted
|
||||
expect(onProfileDeleteFail).toHaveBeenCalledWith(mockAuthorData.username);
|
||||
expect(onProfileDeleteFail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('Action type: "REMOVE_PROFILE" - prevents duplicate calls while removing', () => {
|
||||
// Set up author data
|
||||
store.authorData = mockAuthorData;
|
||||
|
||||
handler({ type: 'REMOVE_PROFILE' });
|
||||
expect(deleteRequest).toHaveBeenCalledTimes(1);
|
||||
|
||||
store.removingProfile = true;
|
||||
handler({ type: 'REMOVE_PROFILE' });
|
||||
expect(deleteRequest).toHaveBeenCalledTimes(1);
|
||||
|
||||
store.removingProfile = false;
|
||||
handler({ type: 'REMOVE_PROFILE' });
|
||||
expect(deleteRequest).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('Action type: "LOAD_AUTHOR_DATA"', async () => {
|
||||
(getRequest as jest.Mock).mockImplementation((_url, _cache, successCallback, _failCallback) =>
|
||||
successCallback({ data: mockAuthorData })
|
||||
);
|
||||
|
||||
handler({ type: 'LOAD_AUTHOR_DATA' });
|
||||
|
||||
// Verify getRequest was called with correct parameters
|
||||
expect(getRequest).toHaveBeenCalledWith('/testuser', false, store.onDataLoad, store.onDataLoadFail);
|
||||
|
||||
// Verify event was emitted
|
||||
expect(onLoadAuthorData).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Verify author data was processed correctly
|
||||
expect(store.get('author-data')).toStrictEqual(mockAuthorData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Getter methods', () => {
|
||||
test('Validate initial values', () => {
|
||||
expect(store.get('INVALID_TYPE')).toBe(undefined);
|
||||
expect(store.get('author-data')).toBe(null);
|
||||
expect(store.get('author-query')).toBe(null);
|
||||
});
|
||||
|
||||
test('get("author-data") returns authorData', () => {
|
||||
store.authorData = mockAuthorData;
|
||||
expect(store.get('author-data')).toBe(mockAuthorData);
|
||||
});
|
||||
|
||||
test('get("author-query") - without "aq" parameter in URL', () => {
|
||||
window.history.pushState({}, '', '/path');
|
||||
expect(store.get('author-query')).toBe(null);
|
||||
});
|
||||
|
||||
test('get("author-query") - with "aq" parameter in URL', () => {
|
||||
window.history.pushState({}, '', '/path?aq=AUTHOR_QUERY');
|
||||
expect(store.get('author-query')).toBe('AUTHOR_QUERY');
|
||||
});
|
||||
|
||||
test('get("author-query") - empty search string', () => {
|
||||
window.history.pushState({}, '', '/path?aq');
|
||||
expect(store.get('author-query')).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
64
frontend/tests/utils/stores/SearchFieldStore.test.ts
Normal file
64
frontend/tests/utils/stores/SearchFieldStore.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
const urlParams = { q: 'search_query', c: 'category_1', t: 'tag_1' };
|
||||
window.history.pushState({}, '', `/?q=${urlParams.q}&c=${urlParams.c}&t=${urlParams.t}`);
|
||||
|
||||
import store from '../../../src/static/js/utils/stores/SearchFieldStore';
|
||||
import { getRequest } from '../../../src/static/js/utils/helpers';
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
||||
exportStore: jest.fn((store) => store),
|
||||
getRequest: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('utils/store', () => {
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('SearchFieldStore', () => {
|
||||
const handler = store.actions_handler.bind(store);
|
||||
|
||||
const onLoadPredictions = jest.fn();
|
||||
|
||||
store.on('load_predictions', onLoadPredictions);
|
||||
|
||||
test('Validate initial values based on URL params', async () => {
|
||||
expect(store.get('INVALID_TYPE')).toBe(null);
|
||||
expect(store.get('search-query')).toBe(urlParams.q);
|
||||
expect(store.get('search-categories')).toBe(urlParams.c);
|
||||
expect(store.get('search-tags')).toBe(urlParams.t);
|
||||
});
|
||||
|
||||
test('Action type: "Action type: "TOGGLE_VIEWER_MODE"', async () => {
|
||||
const predictionsQuery_1 = 'predictions_query_1';
|
||||
const predictionsQuery_2 = 'predictions_query_2';
|
||||
|
||||
const response_1 = { data: [{ title: 'Prediction 1' }, { title: 'Prediction 2' }] };
|
||||
const response_2 = { data: [{ title: 'Prediction 3' }, { title: 'Prediction 4' }] };
|
||||
|
||||
(getRequest as jest.Mock)
|
||||
.mockImplementationOnce((_url, _cache, successCallback, _failCallback) => successCallback(response_1))
|
||||
.mockImplementationOnce((_url, _cache, successCallback, _failCallback) => successCallback(response_2));
|
||||
|
||||
handler({ type: 'REQUEST_PREDICTIONS', query: predictionsQuery_1 });
|
||||
handler({ type: 'REQUEST_PREDICTIONS', query: predictionsQuery_2 });
|
||||
|
||||
expect(onLoadPredictions).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(onLoadPredictions).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
predictionsQuery_1,
|
||||
response_1.data.map(({ title }) => title)
|
||||
);
|
||||
|
||||
expect(onLoadPredictions).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
predictionsQuery_2,
|
||||
response_2.data.map(({ title }) => title)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
147
frontend/tests/utils/stores/VideoViewerStore.test.ts
Normal file
147
frontend/tests/utils/stores/VideoViewerStore.test.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { BrowserCache } from '../../../src/static/js/utils/classes/';
|
||||
import store from '../../../src/static/js/utils/stores/VideoViewerStore';
|
||||
|
||||
jest.mock('../../../src/static/js/utils/classes/', () => ({
|
||||
BrowserCache: jest.fn().mockImplementation(() => ({
|
||||
get: (key: string) => {
|
||||
let result: any = undefined;
|
||||
switch (key) {
|
||||
case 'player-volume':
|
||||
result = 0.6;
|
||||
break;
|
||||
case 'player-sound-muted':
|
||||
result = false;
|
||||
break;
|
||||
case 'in-theater-mode':
|
||||
result = true;
|
||||
break;
|
||||
case 'video-quality':
|
||||
result = 720;
|
||||
break;
|
||||
case 'video-playback-speed':
|
||||
result = 2;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
set: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/settings/config', () => ({
|
||||
config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig),
|
||||
}));
|
||||
|
||||
jest.mock('../../../src/static/js/utils/helpers', () => ({
|
||||
BrowserEvents: jest.fn().mockImplementation(() => ({
|
||||
doc: jest.fn(),
|
||||
win: jest.fn(),
|
||||
})),
|
||||
exportStore: jest.fn((store) => store),
|
||||
}));
|
||||
|
||||
describe('utils/store', () => {
|
||||
describe('VideoViewerStore', () => {
|
||||
const browserCacheInstance = (BrowserCache as jest.Mock).mock.results[0].value;
|
||||
const browserCacheSetSpy = browserCacheInstance.set;
|
||||
|
||||
const handler = store.actions_handler.bind(store);
|
||||
|
||||
const onChangedViewerMode = jest.fn();
|
||||
const onChangedPlayerVolume = jest.fn();
|
||||
const onChangedPlayerSoundMuted = jest.fn();
|
||||
const onChangedVideoQuality = jest.fn();
|
||||
const onChangedVideoPlaybackSpeed = jest.fn();
|
||||
|
||||
store.on('changed_viewer_mode', onChangedViewerMode);
|
||||
store.on('changed_player_volume', onChangedPlayerVolume);
|
||||
store.on('changed_player_sound_muted', onChangedPlayerSoundMuted);
|
||||
store.on('changed_video_quality', onChangedVideoQuality);
|
||||
store.on('changed_video_playback_speed', onChangedVideoPlaybackSpeed);
|
||||
|
||||
test('Validate initial values', () => {
|
||||
expect(store.get('player-volume')).toBe(0.6);
|
||||
expect(store.get('player-sound-muted')).toBe(false);
|
||||
expect(store.get('in-theater-mode')).toBe(true);
|
||||
expect(store.get('video-data')).toBe(undefined); // @todo: Revisit this behavior
|
||||
expect(store.get('video-quality')).toBe(720);
|
||||
expect(store.get('video-playback-speed')).toBe(2);
|
||||
});
|
||||
|
||||
describe('Trigger and validate actions behavior', () => {
|
||||
test('Action type: "TOGGLE_VIEWER_MODE"', () => {
|
||||
const initialValue = store.get('in-theater-mode');
|
||||
|
||||
handler({ type: 'TOGGLE_VIEWER_MODE' });
|
||||
|
||||
expect(onChangedViewerMode).toHaveBeenCalledWith();
|
||||
expect(onChangedViewerMode).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('in-theater-mode')).toBe(!initialValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('in-theater-mode', !initialValue);
|
||||
});
|
||||
|
||||
test('Action type: "SET_VIEWER_MODE"', () => {
|
||||
const initialValue = store.get('in-theater-mode');
|
||||
const newValue = !initialValue;
|
||||
|
||||
handler({ type: 'SET_VIEWER_MODE', inTheaterMode: newValue });
|
||||
|
||||
expect(onChangedViewerMode).toHaveBeenCalledWith();
|
||||
expect(onChangedViewerMode).toHaveBeenCalledTimes(2); // The first time called by 'TOGGLE_VIEWER_MODE' action.
|
||||
|
||||
expect(store.get('in-theater-mode')).toBe(newValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('in-theater-mode', newValue);
|
||||
});
|
||||
|
||||
test('Action type: "SET_PLAYER_VOLUME"', () => {
|
||||
const newValue = 0.3;
|
||||
|
||||
handler({ type: 'SET_PLAYER_VOLUME', playerVolume: newValue });
|
||||
|
||||
expect(onChangedPlayerVolume).toHaveBeenCalledWith();
|
||||
expect(onChangedPlayerVolume).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('player-volume')).toBe(newValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('player-volume', newValue);
|
||||
});
|
||||
|
||||
test('Action type: "SET_PLAYER_SOUND_MUTED"', () => {
|
||||
const initialValue = store.get('player-sound-muted');
|
||||
const newValue = !initialValue;
|
||||
|
||||
handler({ type: 'SET_PLAYER_SOUND_MUTED', playerSoundMuted: newValue });
|
||||
|
||||
expect(onChangedPlayerSoundMuted).toHaveBeenCalledWith();
|
||||
expect(onChangedPlayerSoundMuted).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('player-sound-muted')).toBe(newValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('player-sound-muted', newValue);
|
||||
});
|
||||
|
||||
test('Action type: "SET_VIDEO_QUALITY"', () => {
|
||||
const newValue = 1080;
|
||||
|
||||
handler({ type: 'SET_VIDEO_QUALITY', quality: newValue });
|
||||
|
||||
expect(onChangedVideoQuality).toHaveBeenCalledWith();
|
||||
expect(onChangedVideoQuality).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('video-quality')).toBe(newValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('video-quality', newValue);
|
||||
});
|
||||
|
||||
test('Action type: "SET_VIDEO_PLAYBACK_SPEED"', () => {
|
||||
const newValue = 1.5;
|
||||
|
||||
handler({ type: 'SET_VIDEO_PLAYBACK_SPEED', playbackSpeed: newValue });
|
||||
|
||||
expect(onChangedVideoPlaybackSpeed).toHaveBeenCalledWith();
|
||||
expect(onChangedVideoPlaybackSpeed).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(store.get('video-playback-speed')).toBe(newValue);
|
||||
expect(browserCacheSetSpy).toHaveBeenCalledWith('video-playback-speed', newValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user