completion

This commit is contained in:
2025-08-06 13:49:11 +08:00
commit c2d7317897
684 changed files with 92987 additions and 0 deletions

View File

@@ -0,0 +1,339 @@
/* global describe: true, test:true, expect:true */
import { playlists as playlistsReducer, initialState } from '~/reducers/playlists';
import {
GET_PLAYLISTS,
GET_PLAYLISTS_SUCCESS,
GET_PLAYLISTS_ERROR,
GET_PLAYLIST_CONTENT,
GET_PLAYLIST_CONTENT_SUCCESS,
GET_PLAYLIST_CONTENT_ERROR,
LOGOUT_SUCCESS,
CREATE_DYNAMIC_PLAYLIST_SUCCESS,
GET_DYNAMIC_PLAYLISTS_SUCCESS,
UPLOAD_ITEM_STARTED,
UPLOAD_ITEMS_SUCCESS,
UPLOAD_ITEMS_ERROR,
PLAYLIST_PROCESSING_STARTED,
PLAYLIST_PROCESSING_DONE,
UPLOAD_SUCCESS,
UPLOAD_ALL_CANCELLED,
} from '~/store/actionTypes';
import Factory from 'helper/factories/api';
describe('playlists reducer', () => {
test('CASE 1: should return initial state', () => {
expect(playlistsReducer(undefined, { type: 'Default' }))
.toEqual(initialState);
});
test('CASE 2: should return state with meta set to loading when type is GET_PLAYLISTS', () => {
const playlists = [{ id: 1 }, { id: 2 }];
const expectedState = { ...initialState, meta: { ...initialState.meta, loading: false } };
const stateResult = playlistsReducer(initialState, {
type: GET_PLAYLISTS, payload: { playlists },
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 3a: should return state with playlist content merged with dynamic playlist when type is GET_PLAYLISTS_SUCCESS', () => {
const playlists = Factory.buildList('Playlist', 6);
const googleId = 'someone@gmail.com';
const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
const statePlaylists = playlists.map((item) => ({ ...item, slides: [{ url: 'url' }] }));
const originalState = {
...initialState, playlists: statePlaylists, dynamicPlaylists,
};
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLISTS_SUCCESS, payload: { playlists },
});
expect(stateResult.playlists).toEqual(expect.arrayContaining([expect.objectContaining({
name: expect.any(String),
googleId: expect.any(String),
status: expect.any(String),
slides: expect.any(Array),
dynamicPlaylistName: expect.any(String),
lastSynced: expect.any(String),
})]));
});
test('CASE 3b: should return state with playlist content merged with dynamic playlist when type is GET_PLAYLISTS_SUCCESS', () => {
const playlists = Factory.buildList('Playlist', 1);
const googleId = 'someone@gmail.com';
const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
const originalState = { ...initialState, dynamicPlaylists };
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLISTS_SUCCESS, payload: { playlists },
});
expect(stateResult.playlists).toEqual(expect.arrayContaining([expect.objectContaining({
name: expect.any(String),
googleId: expect.any(String),
status: expect.any(String),
dynamicPlaylistName: expect.any(String),
lastSynced: expect.any(String),
googleCollectionType: expect.any(String),
})]));
});
test('CASE 3c: should return state with playlist content merged with dynamic playlist when type is GET_PLAYLISTS_SUCCESS', () => {
const playlists = Factory.buildList('Playlist', 1);
const googleId = 'someone@gmail.com';
const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
const statePlaylists = playlists.map((item) => ({ ...item, slides: [{ url: 'url' }] }));
const originalState = {
...initialState, playlists: statePlaylists, dynamicPlaylists,
};
const count = Math.floor((Math.random() * 500) + 1);
const thumbs = [0, 1, 2].map(item => ({ src: `https://loremflickr.com/1024/768/cats?asdf=${item}`, rotation: 0, orientation: 1 }));
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLISTS_SUCCESS, payload: { playlists: [{ ...playlists[0], count, thumbs }] },
});
// The count and thumbs properties should be overridden by the new playlists data
expect(stateResult.playlists[0].count).toEqual(count);
expect(stateResult.playlists[0].thumbs).toEqual(thumbs);
});
test('CASE 4: should return state with error when type is GET_PLAYLISTS_ERROR', () => {
const error = new Error('getPlaylistError');
const expectedState = { ...initialState, meta: { ...initialState.meta, error } };
const stateResult = playlistsReducer(initialState, {
type: GET_PLAYLISTS_ERROR, payload: { error },
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 5: should return state with meta set to loading when type is GET_PLAYLIST_CONTENT', () => {
const playlists = [
{ id: 1 },
{ id: 2 },
];
const originalState = { ...initialState, playlists };
const payload = { playlistId: 1 };
const expectedState = {
...initialState,
playlists: [{
id: 1,
meta: { error: '', loading: true },
},
{ id: 2 }],
meta: { error: '', loading: false, uploading: false },
};
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLIST_CONTENT, payload,
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 6a: should return state with playlist content set when type is GET_PLAYLIST_CONTENT_SUCCESS', () => {
const playlists = [
{ id: 1 },
];
const originalState = { ...initialState, playlists };
const payload = {
playlistId: 1,
playlist: { name: 'PL one', slides: [] },
offset: 0,
};
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLIST_CONTENT_SUCCESS, payload,
});
expect(stateResult.playlists[0]).toHaveProperty('name', payload.playlist.name);
expect(stateResult.playlists[0]).toHaveProperty('slides');
// expect(stateResult.playlists[0]).toHaveProperty('thumbs');
});
test('CASE 6b: GET_PLAYLIST_CONTENT_SUCCESS should combine playlist slides if offset is > 0', () => {
const initialSlides = ['a', 'b', 'c'];
const nextSlides = ['d', 'e', 'f'];
const playlists = [
{
id: 1, slides: initialSlides, pictureCount: 6, offset: 3,
},
];
const originalState = { ...initialState, playlists };
const payload = {
playlistId: 1,
playlist: {
name: 'PL one',
slides: nextSlides,
offset: 5,
pictureCount: 6,
},
startOffset: 3,
endOffset: 6,
};
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLIST_CONTENT_SUCCESS, payload,
});
expect(stateResult.playlists[0]).toHaveProperty('slides', [...initialSlides, ...nextSlides]);
});
test('CASE 7: should return state error when type is GET_PLAYLIST_CONTENT_ERROR', () => {
const playlists = [
{ id: 1, meta: { error: '', loading: true } },
{ id: 2, meta: { error: '', loading: false } },
];
const originalState = { ...initialState, playlists };
// console.log({ originalState: JSON.stringify(originalState) });
const error = new Error('getPlaylistError');
const payload = {
playlistId: 1,
error,
};
const expectedState = {
...initialState,
playlists: [{
id: 1,
meta: { error, loading: false },
},
{ id: 2, meta: { error: '', loading: false } }],
meta: { error: '', loading: false, uploading: false },
};
const stateResult = playlistsReducer(originalState, {
type: GET_PLAYLIST_CONTENT_ERROR, payload,
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 9: should empty the state on LOGOUT_SUCCESS', () => {
const existingState = [{ id: 1 }, { id: 2 }];
expect(playlistsReducer(existingState, { type: LOGOUT_SUCCESS }))
.toEqual(initialState);
});
test('CASE 10: should current state on CREATE_DYNAMIC_PLAYLIST_SUCCESS', () => {
const existingState = [{ id: 1 }, { id: 2 }];
expect(playlistsReducer(existingState, { type: CREATE_DYNAMIC_PLAYLIST_SUCCESS }))
.toEqual(existingState);
});
test('CASE 11: should return state with dynamicPlaylist set when type is GET_DYNAMIC_PLAYLISTS_SUCCESS', () => {
const playlists = Factory.buildList('Playlist', 6);
const googleId = 'someone@gmail.com';
const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
const originalState = { ...initialState, playlists };
const stateResult = playlistsReducer(originalState, {
type: GET_DYNAMIC_PLAYLISTS_SUCCESS, payload: { google: dynamicPlaylists },
});
expect(stateResult.playlists).toEqual(expect.arrayContaining([expect.objectContaining({
name: expect.any(String),
googleId: expect.any(String),
status: expect.any(String),
dynamicPlaylistName: expect.any(String),
lastSynced: expect.any(String),
})]));
expect(stateResult.dynamicPlaylists).toEqual(dynamicPlaylists);
});
test('CASE 12: should return state with upload state set when type is UPLOAD_ITEM_STARTED', () => {
const expectedState = { ...initialState, meta: { ...initialState.meta, uploading: true } };
const stateResult = playlistsReducer(initialState, {
type: UPLOAD_ITEM_STARTED,
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 13: should return state with upload state set when type is UPLOAD_ITEMS_SUCCESS or UPLOAD_ITEMS_ERROR', () => {
const expectedState = { ...initialState, meta: { ...initialState.meta, uploading: false } };
const stateResult = playlistsReducer(initialState, {
type: UPLOAD_ITEMS_SUCCESS,
});
expect(stateResult).toEqual(expectedState);
const expectedState2 = { ...initialState, meta: { ...initialState.meta, uploading: false } };
const stateResult2 = playlistsReducer(initialState, {
type: UPLOAD_ITEMS_ERROR,
});
expect(stateResult2).toEqual(expectedState2);
});
test('CASE 14: should return state with trackerId set when type is PLAYLIST_PROCESSING_STARTED', () => {
const playlists = [
{ id: 1, meta: { error: '', loading: true } },
{ id: 2, meta: { error: '', loading: false } },
{ id: 3, meta: { error: '', loading: true } },
];
const originalState = { ...initialState, playlists };
const playlistsWithTracker = [
{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', loading: true } },
{ id: 2, meta: { error: '', loading: false } },
{ id: 3, trackerId: '5b0e992791ed43ca79928eed54ca0b4f', meta: { error: '', loading: true } },
];
const expectedState = { ...originalState, playlists: playlistsWithTracker };
const stateResult = playlistsReducer(originalState, {
type: PLAYLIST_PROCESSING_STARTED,
payload: {
data: [
{ receiver: '1', trackerId: 'a74d2e06f17e2893017431375b416b76' },
{ receiver: '3', trackerId: '5b0e992791ed43ca79928eed54ca0b4f' },
],
},
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 15: should return state without trackerId set when type is PLAYLIST_PROCESSING_DONE', () => {
const playlists = [
{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', loading: true } },
{ id: 2, meta: { error: '', loading: false } },
{ id: 3, trackerId: '5b0e992791ed43ca79928eed54ca0b4f', meta: { error: '', loading: true } },
];
const originalState = { ...initialState, playlists };
const playlistsWithTracker = [
{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', loading: true } },
{ id: 2, meta: { error: '', loading: false } },
{ id: 3, meta: { error: '', loading: true } },
];
const expectedState = { ...originalState, playlists: playlistsWithTracker };
const stateResult = playlistsReducer(originalState, {
type: PLAYLIST_PROCESSING_DONE,
payload: {
playlistId: 3, trackerId: '5b0e992791ed43ca79928eed54ca0b4f',
},
});
expect(stateResult).toEqual(expectedState);
});
test('CASE 16: should return state with meta.uploading set to false when type is UPLOAD_SUCCESS', () => {
const playlists = [
{ id: 1, meta: { error: '', uploading: true } },
{ id: 2, meta: { error: '', uploading: false } },
{ id: 3, meta: { error: '', uploading: true } },
];
const originalState = { ...initialState, playlists };
const stateResult = playlistsReducer(originalState, {
type: UPLOAD_SUCCESS,
});
stateResult.playlists.forEach((item) => {
expect(item.meta).toHaveProperty('uploading', false);
});
});
test('CASE 17: should return state with no trackerId and meta.uploading set to false when type is UPLOAD_ITEMS_ERROR or UPLOAD_ALL_CANCELLED', () => {
const playlists = [
{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', uploading: true } },
{ id: 2, meta: { error: '', uploading: false } },
{ id: 3, meta: { error: '', uploading: true } },
];
const originalState = { ...initialState, playlists };
const stateResult = playlistsReducer(originalState, {
type: UPLOAD_ALL_CANCELLED,
});
stateResult.playlists.forEach((item) => {
expect(item.meta).toHaveProperty('uploading', false);
expect(item).not.toHaveProperty('trackerId');
});
});
});