/* 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'); }); }); });