diff --git a/src/components/ContentReport/ContentReportForm.vue b/src/components/ContentReport/ContentReportForm.vue index a97f373ad8d..fd0a6721faa 100644 --- a/src/components/ContentReport/ContentReportForm.vue +++ b/src/components/ContentReport/ContentReportForm.vue @@ -144,7 +144,6 @@ export default { } else if (this.selectedReason === 'dmca') { this.selectedCopyright = true } else { - console.log('sending content report') this.sendContentReport() } }, diff --git a/src/constants/mutation-types.js b/src/constants/mutation-types.js index 9c30c052b77..fbf349e83bc 100644 --- a/src/constants/mutation-types.js +++ b/src/constants/mutation-types.js @@ -36,3 +36,4 @@ export const SET_SEARCH_TYPE = 'SET_SEARCH_TYPE' export const UPDATE_FILTERS = 'UPDATE_FILTERS' export const SET_ACTIVE_MEDIA_ITEM = 'SET_ACTIVE_MEDIA_ITEM' export const UNSET_ACTIVE_MEDIA_ITEM = 'UNSET_ACTIVE_MEDIA_ITEM' +export const RESET_MEDIA = 'RESET_MEDIA' diff --git a/src/store-modules/search-store.js b/src/store-modules/search-store.js index 5e9bd04e896..78002c8fc60 100644 --- a/src/store-modules/search-store.js +++ b/src/store-modules/search-store.js @@ -1,22 +1,21 @@ -import isEmpty from 'lodash.isempty' import findIndex from 'lodash.findindex' import prepareSearchQueryParams from '~/utils/prepare-search-query-params' import decodeMediaData from '~/utils/decode-media-data' import { - FETCH_MEDIA, FETCH_AUDIO, FETCH_IMAGE, - FETCH_COLLECTION_IMAGES, - HANDLE_NO_MEDIA, + FETCH_MEDIA, HANDLE_MEDIA_ERROR, - UPDATE_SEARCH_TYPE, + HANDLE_NO_MEDIA, SET_SEARCH_TYPE_FROM_URL, + UPDATE_SEARCH_TYPE, } from '~/constants/action-types' import { FETCH_END_MEDIA, FETCH_MEDIA_ERROR, FETCH_START_MEDIA, MEDIA_NOT_FOUND, + RESET_MEDIA, SET_AUDIO, SET_IMAGE, SET_IMAGE_PAGE, @@ -26,8 +25,8 @@ import { UPDATE_FILTERS, } from '~/constants/mutation-types' import { - SEND_SEARCH_QUERY_EVENT, SEND_RESULT_CLICKED_EVENT, + SEND_SEARCH_QUERY_EVENT, } from '~/constants/usage-data-analytics-types' import { queryStringToSearchType } from '~/utils/search-query-transform' import { ALL_MEDIA, AUDIO, IMAGE } from '~/constants/media' @@ -38,77 +37,6 @@ import { USAGE_DATA } from '~/constants/store-modules' // ? window.location.pathname // : '/search' -/** - * hides the search results in case the user is performing a new search. - * This prevents results from a previous search from showing while the - * new search results are still loading - */ -const hideSearchResultsOnNewSearch = (commit, pageNumber) => { - if (!pageNumber) { - commit(SET_MEDIA, { mediaType: IMAGE, media: [] }) - commit(SET_MEDIA, { mediaType: AUDIO, media: [] }) - } -} - -const allKeysUndefinedExcept = (value, keyName) => { - const keys = Object.keys(value) - return keys.reduce((matchedUndefinedCriteria, key) => { - const shouldBeUndefined = key !== keyName - const isUndefined = isEmpty(value[key]) - - return matchedUndefinedCriteria && shouldBeUndefined === isUndefined - }, true) -} - -const fetchCollectionImages = (commit, params, imageService) => { - hideSearchResultsOnNewSearch(commit, params.page) - - const queryParams = { - q: params.q, - provider: params.provider, - searchBy: params.searchBy, - } - // the provider collection API doesn't support the `q` parameter. - // so if the `q`, or any other search filter is provided, and - // since the `provider` parameter is passed, we can just call the search API instead - const searchMethod = allKeysUndefinedExcept(queryParams, 'provider') - ? imageService.getProviderCollection - : imageService.search - const newParams = { ...params, source: params.provider } - delete newParams.provider - return searchMethod(prepareSearchQueryParams(newParams)) -} - -/** - * With the API response: set loading to false, set the - * store `images` or `audios` property to the result, - * and handle possible errors - * @param {import('vuex').Commit} commit - * @param {import('vuex').Dispatch} dispatch - * @param {import('../store/types').MediaResult} data - * @param {Object} params - * @param {'image'|'audio'} params.mediaType - * @param {boolean} params.shouldPersistMedia - * @param {number} params.page - */ -const handleSearchResponse = async ( - commit, - dispatch, - data, - { mediaType, shouldPersistMedia, page } -) => { - commit(FETCH_END_MEDIA, { mediaType }) - commit(SET_MEDIA, { - mediaType, - media: data.results, - mediaCount: data.result_count, - pageCount: data.page_count, - shouldPersistMedia: shouldPersistMedia, - page: page, - }) - return dispatch(HANDLE_NO_MEDIA, mediaType) -} - /** * @type {{ audios: import('../store/types').AudioDetail[], * audiosCount: number, audioPage:number, @@ -143,12 +71,8 @@ const state = { query: {}, } -/** - * @param {Object} AudioService - * @param {Object} ImageService - */ -const actions = (AudioService, ImageService) => ({ - [FETCH_MEDIA]({ commit, dispatch, rootState }, params) { +const actions = (services) => ({ + async [FETCH_MEDIA]({ commit, dispatch, rootState }, params) { // does not send event if user is paginating for more results const { page, mediaType, q } = params if (!page) { @@ -159,40 +83,42 @@ const actions = (AudioService, ImageService) => ({ } commit(FETCH_START_MEDIA, { mediaType }) - hideSearchResultsOnNewSearch(commit, page) + if (!params.page) { + commit(RESET_MEDIA, { mediaType }) + } const queryParams = prepareSearchQueryParams(params) - let service - if (mediaType === IMAGE) { - service = ImageService - } else if (mediaType === AUDIO) { - service = AudioService - } else { + if (!Object.keys(services).includes(mediaType)) { throw new Error(`Cannot fetch unknown media type "${mediaType}"`) } - return service + await services[mediaType] .search(queryParams) - .then( - async ({ data }) => - await handleSearchResponse(commit, dispatch, data, params) - ) + .then(({ data }) => { + commit(FETCH_END_MEDIA, { mediaType }) + const mediaCount = data.result_count + commit(SET_MEDIA, { + mediaType, + media: data.results, + mediaCount, + pageCount: data.page_count, + shouldPersistMedia: params.shouldPersistMedia, + page: page, + }) + dispatch(HANDLE_NO_MEDIA, { mediaType, mediaCount }) + }) .catch((error) => { dispatch(HANDLE_MEDIA_ERROR, { mediaType, error }) }) }, - // eslint-disable-next-line no-unused-vars - [FETCH_AUDIO]({ commit, dispatch, state, rootState }, params) { + async [FETCH_AUDIO]({ commit, dispatch, state, rootState }, params) { dispatch(`${USAGE_DATA}/${SEND_RESULT_CLICKED_EVENT}`, { query: state.query.q, resultUuid: params.id, resultRank: findIndex(state.audios, (img) => img.id === params.id), - sessionId: rootState.usageSessionId, + sessionId: rootState.user.usageSessionId, }) - - commit(FETCH_START_MEDIA, { mediaType: AUDIO }) commit(SET_AUDIO, { audio: {} }) - return AudioService.getMediaDetail(params) + await services[AUDIO].getMediaDetail(params) .then(({ data }) => { - commit(FETCH_END_MEDIA, { mediaType: AUDIO }) commit(SET_AUDIO, { audio: data }) }) .catch((error) => { @@ -203,8 +129,7 @@ const actions = (AudioService, ImageService) => ({ } }) }, - // eslint-disable-next-line no-unused-vars - [FETCH_IMAGE]({ commit, dispatch, state, rootState }, params) { + async [FETCH_IMAGE]({ commit, dispatch, state, rootState }, params) { dispatch(`${USAGE_DATA}/${SEND_RESULT_CLICKED_EVENT}`, { query: state.query.q, resultUuid: params.id, @@ -213,7 +138,7 @@ const actions = (AudioService, ImageService) => ({ }) commit(SET_IMAGE, { image: {} }) - return ImageService.getMediaDetail(params) + await services[IMAGE].getMediaDetail(params) .then(({ data }) => { commit(SET_IMAGE, { image: data }) }) @@ -221,22 +146,11 @@ const actions = (AudioService, ImageService) => ({ if (error.response && error.response.status === 404) { commit(MEDIA_NOT_FOUND, { mediaType: IMAGE }) } else { - throw new Error(`Error fetching the image: ${error}`) + throw new Error(`Error fetching the image: ${error.message}`) } }) }, - [FETCH_COLLECTION_IMAGES]({ commit, dispatch }, params) { - commit(FETCH_START_MEDIA, { mediaType: IMAGE }) - return fetchCollectionImages(commit, params, ImageService) - .then( - async ({ data }) => - await handleSearchResponse(commit, dispatch, data, params) - ) - .catch((error) => { - dispatch(HANDLE_MEDIA_ERROR, { mediaType: IMAGE, error }) - }) - }, - [HANDLE_MEDIA_ERROR]({ commit }, { mediaType, error }) { + async [HANDLE_MEDIA_ERROR]({ commit }, { mediaType, error }) { let errorMessage if (error.response) { errorMessage = @@ -266,41 +180,21 @@ const actions = (AudioService, ImageService) => ({ }, }) -function setQuery(_state, params) { - const query = Object.assign({}, _state.query, params.query) - _state.query = query - _state.images = [] - - // if (params.shouldNavigate === true) { - // redirect({ path, query }) - // } -} - -/* eslint no-param-reassign: ["error", { "props": false }] */ const mutations = { [FETCH_START_MEDIA](_state, { mediaType }) { - if (mediaType === IMAGE) { - _state.isFetching.images = true - _state.isFetchingError.images = false - } else if (mediaType === AUDIO) { - _state.isFetching.audios = true - _state.isFetchingError.audios = false - } + const mediaPlural = `${mediaType}s` + _state.isFetching[mediaPlural] = true + _state.isFetchingError[mediaPlural] = false }, [FETCH_END_MEDIA](_state, { mediaType }) { - mediaType === IMAGE - ? (_state.isFetching.images = false) - : (_state.isFetching.audios = false) + const mediaPlural = `${mediaType}s` + _state.isFetching[mediaPlural] = false }, [FETCH_MEDIA_ERROR](_state, params) { const { mediaType, errorMessage } = params - if (mediaType === IMAGE) { - _state.isFetchingError.images = true - _state.isFetching.images = false - } else if (mediaType === AUDIO) { - _state.isFetchingError.audios = true - _state.isFetching.audios = false - } + const mediaPlural = `${mediaType}s` + _state.isFetching[mediaPlural] = false + _state.isFetchingError[mediaPlural] = true _state.errorMessage = errorMessage }, [SET_AUDIO](_state, params) { @@ -335,14 +229,22 @@ const mutations = { _state.pageCount[mediaPlural] = pageCount }, [SET_QUERY](_state, params) { - setQuery(_state, params) + _state.query = Object.assign({}, _state.query, params.query) + _state.images = [] }, - [MEDIA_NOT_FOUND](params) { + [MEDIA_NOT_FOUND](_state, params) { throw new Error(`Media of type ${params.mediaType} not found`) }, [SET_SEARCH_TYPE](_state, params) { _state.searchType = params.searchType }, + [RESET_MEDIA](_state, params) { + const { mediaType } = params + _state[`${mediaType}s`] = [] + _state[`${mediaType}sCount`] = 0 + _state[`${mediaType}Page`] = undefined + _state.pageCount[`${mediaType}s`] = 0 + }, } export default { diff --git a/src/store/index.js b/src/store/index.js index 7ed7cc0a12a..635dd5c8c76 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -4,9 +4,12 @@ import SearchStore from '~/store-modules/search-store' import FilterStore from '~/store-modules/filter-store' import { FETCH_MEDIA_PROVIDERS } from '~/constants/action-types' import { PROVIDER } from '~/constants/store-modules' +import { AUDIO, IMAGE } from '~/constants/media' + +const mediaServices = { [AUDIO]: AudioService, [IMAGE]: ImageService } export const actions = Object.assign( - SearchStore.actions(AudioService, ImageService), + SearchStore.actions(mediaServices), FilterStore.actions, { async nuxtServerInit({ dispatch }) { diff --git a/src/utils/prepare-search-query-params.js b/src/utils/prepare-search-query-params.js index 077197aef53..fcad6ed511a 100644 --- a/src/utils/prepare-search-query-params.js +++ b/src/utils/prepare-search-query-params.js @@ -1,4 +1,7 @@ export default function prepareSearchQueryParams(searchParams) { + if (typeof searchParams.mediaType !== 'undefined') { + delete searchParams.mediaType + } const params = { ...searchParams, } diff --git a/test/unit/specs/store/search-store.spec.js b/test/unit/specs/store/search-store.spec.js index 2adda542b53..ae0959f2489 100644 --- a/test/unit/specs/store/search-store.spec.js +++ b/test/unit/specs/store/search-store.spec.js @@ -1,20 +1,28 @@ import store from '~/store-modules/search-store' import { + FETCH_END_MEDIA, + FETCH_MEDIA_ERROR, + FETCH_START_MEDIA, + MEDIA_NOT_FOUND, + RESET_MEDIA, + SET_AUDIO, SET_IMAGE, SET_IMAGE_PAGE, SET_MEDIA, SET_QUERY, - MEDIA_NOT_FOUND, - FETCH_START_MEDIA, - FETCH_END_MEDIA, - FETCH_MEDIA_ERROR, + SET_SEARCH_TYPE, + UPDATE_FILTERS, } from '~/constants/mutation-types' import { + FETCH_AUDIO, FETCH_IMAGE, - FETCH_COLLECTION_IMAGES, FETCH_MEDIA, + HANDLE_MEDIA_ERROR, + HANDLE_NO_MEDIA, + SET_SEARCH_TYPE_FROM_URL, + UPDATE_SEARCH_TYPE, } from '~/constants/action-types' -import { IMAGE } from '~/constants/media' +import { ALL_MEDIA, AUDIO, IMAGE } from '~/constants/media' import { SEND_RESULT_CLICKED_EVENT, SEND_SEARCH_QUERY_EVENT, @@ -78,6 +86,13 @@ describe('Search Store', () => { expect(state.errorMessage).toBe('error') }) + it('SET_AUDIO updates state', () => { + const params = { audio: { title: 'Foo', creator: 'bar', tags: [] } } + mutations[SET_AUDIO](state, params) + + expect(state.audio).toEqual(params.audio) + }) + it('SET_IMAGE updates state', () => { const params = { image: { title: 'Foo', creator: 'bar', tags: [] } } mutations[SET_IMAGE](state, params) @@ -155,11 +170,42 @@ describe('Search Store', () => { expect(state.query.q).toBe('bar') expect(state.images).toEqual([]) }) + + it('MEDIA_NOT_FOUND throws an error', () => { + expect(() => + mutations[MEDIA_NOT_FOUND](state, { mediaType: AUDIO }) + ).toThrow('Media of type audio not found') + }) + + it('SET_SEARCH_TYPE updates the state', () => { + state.searchType = IMAGE + mutations[SET_SEARCH_TYPE](state, { searchType: AUDIO }) + expect(state.searchType).toEqual(AUDIO) + }) + + it('RESET_MEDIA resets the media type state', () => { + state = { + images: [{ id: 'image1' }, { id: 'image2' }], + imagePage: 2, + imagesCount: 200, + pageCount: { + images: 2, + }, + } + + mutations[RESET_MEDIA](state, { mediaType: IMAGE }) + expect(state.images).toStrictEqual([]) + expect(state.imagesCount).toEqual(0) + expect(state.imagePage).toBe(undefined) + expect(state.pageCount.images).toEqual(0) + }) }) describe('actions', () => { const searchData = { results: ['foo'], result_count: 1 } + const audioDetailData = 'audioDetails' const imageDetailData = 'imageDetails' + let services = null let audioServiceMock = null let imageServiceMock = null let commit = null @@ -183,12 +229,14 @@ describe('Search Store', () => { Promise.resolve({ data: searchData }) ), getMediaDetail: jest.fn(() => - Promise.resolve({ data: imageDetailData }) + Promise.resolve({ data: audioDetailData }) ), } + services = { [AUDIO]: audioServiceMock, [IMAGE]: imageServiceMock } commit = jest.fn() dispatch = jest.fn() state = { + audios: [{ id: 'foo' }, { id: 'bar' }, { id: 'zeta' }], images: [{ id: 'foo' }, { id: 'bar' }, { id: 'zeta' }], query: { q: 'foo query' }, } @@ -196,42 +244,47 @@ describe('Search Store', () => { store.rootState = rootState }) - it('FETCH_MEDIA on success', (done) => { + it('FETCH_MEDIA throws an error on unknown media type', async () => { + const action = store.actions(services)[FETCH_MEDIA] + const params = { + mediaType: 'unknown', + page: 1, + } + await expect(action({ commit, dispatch, state }, params)).rejects.toThrow( + 'Cannot fetch unknown media type "unknown"' + ) + }) + + it('FETCH_MEDIA on success', async () => { const params = { q: 'foo', page: 1, shouldPersistMedia: false, mediaType: IMAGE, } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_MEDIA - ] - action({ commit, dispatch, state }, params).then(() => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) - expect(commit).toBeCalledWith(FETCH_END_MEDIA, { mediaType: IMAGE }) - - expect(commit).toBeCalledWith(SET_MEDIA, { - media: searchData.results, - mediaCount: searchData.result_count, - shouldPersistMedia: params.shouldPersistMedia, - page: params.page, - mediaType: IMAGE, - }) - - expect(imageServiceMock.search).toBeCalledWith(params) - - done() + const action = store.actions(services)[FETCH_MEDIA] + await action({ commit, dispatch, state }, params) + expect(commit).toHaveBeenCalledWith(FETCH_START_MEDIA, { + mediaType: IMAGE, + }) + expect(commit).toHaveBeenCalledWith(FETCH_END_MEDIA, { mediaType: IMAGE }) + + expect(commit).toHaveBeenCalledWith(SET_MEDIA, { + media: searchData.results, + mediaCount: searchData.result_count, + shouldPersistMedia: params.shouldPersistMedia, + page: params.page, + mediaType: IMAGE, }) + expect(services[IMAGE].search).toHaveBeenCalledWith(params) }) - it('FETCH_MEDIA dispatches SEND_SEARCH_QUERY_EVENT', () => { + it('FETCH_MEDIA dispatches SEND_SEARCH_QUERY_EVENT', async () => { const params = { q: 'foo', shouldPersistMedia: false, mediaType: IMAGE } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_MEDIA - ] - action({ commit, dispatch, state, rootState }, params) + const action = store.actions(services)[FETCH_MEDIA] + await action({ commit, dispatch, state, rootState }, params) - expect(dispatch).toHaveBeenLastCalledWith( + expect(dispatch).toHaveBeenCalledWith( `${USAGE_DATA}/${SEND_SEARCH_QUERY_EVENT}`, { query: params.q, @@ -240,234 +293,140 @@ describe('Search Store', () => { ) }) - it('does not dispatch SEND_SEARCH_QUERY_EVENT if page param is available', () => { + it('does not dispatch SEND_SEARCH_QUERY_EVENT if page param is available', async () => { const params = { q: 'foo', page: 1, shouldPersistMedia: false, mediaType: IMAGE, } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_MEDIA - ] - action({ commit, dispatch, state }, params) + const action = store.actions(services)[FETCH_MEDIA] + await action({ commit, dispatch, state }, params) - expect(dispatch).not.toHaveBeenLastCalledWith('SEND_SEARCH_QUERY_EVENT', { + expect(dispatch).not.toHaveBeenCalledWith('SEND_SEARCH_QUERY_EVENT', { query: params.q, sessionId: state.usageSessionId, }) }) - it('FETCH_COLLECTION_IMAGES on success', (done) => { - const params = { - provider: 'met', - page: 1, - shouldPersistMedia: false, - mediaType: IMAGE, + it('FETCH_MEDIA on error', async () => { + const mediaType = IMAGE + services[IMAGE] = { + search: jest.fn(() => Promise.reject('error')), } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_COLLECTION_IMAGES - ] - action({ commit, dispatch }, params).then(() => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) - expect(commit).toBeCalledWith(FETCH_END_MEDIA, { mediaType: IMAGE }) - - expect(commit).toBeCalledWith(SET_MEDIA, { - media: searchData.results, - mediaCount: searchData.result_count, - shouldPersistMedia: params.shouldPersistMedia, - page: params.page, - mediaType: IMAGE, - }) - - const newParams = { ...params, source: params.provider } - delete newParams.provider - expect(imageServiceMock.getProviderCollection).toBeCalledWith(newParams) - done() - }) - }) - - it('FETCH_COLLECTION_IMAGES calls search API if q param exist', (done) => { const params = { - q: 'nature', - provider: 'met', + q: 'foo', page: 1, shouldPersistMedia: false, - mediaType: IMAGE, + mediaType, } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_COLLECTION_IMAGES - ] - action({ commit, dispatch }, params).then(() => { - const newParams = { ...params, source: params.provider } - delete newParams.provider - expect(imageServiceMock.search).toBeCalledWith(newParams) - - done() + const action = store.actions(services)[FETCH_MEDIA] + await action({ commit, dispatch, state }, params) + await expect(services[IMAGE].search).rejects.toEqual('error') + + expect(commit).toHaveBeenCalledWith(FETCH_START_MEDIA, { mediaType }) + expect(dispatch).toHaveBeenCalledWith('HANDLE_MEDIA_ERROR', { + error: 'error', + mediaType, }) }) - it('FETCH_COLLECTION_IMAGES calls getProviderCollection API if li param exist', (done) => { + it('FETCH_MEDIA resets images if page is not defined', async () => { + const mediaType = IMAGE const params = { - li: 'by', - provider: 'met', - page: 1, + q: 'foo', + page: undefined, shouldPersistMedia: false, - mediaType: IMAGE, + mediaType, } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_COLLECTION_IMAGES - ] - action({ commit, dispatch }, params).then(() => { - const newParams = { ...params, source: params.provider } - delete newParams.provider - expect(imageServiceMock.getProviderCollection).toBeCalledWith(newParams) - - done() - }) - }) + const action = store.actions(services)[FETCH_MEDIA] + await action({ commit, dispatch, state, rootState }, params) - it('FETCH_COLLECTION_IMAGES calls getProviderCollection API if lt param exist', (done) => { - const params = { - lt: 'commercial', - provider: 'met', - page: 1, - shouldPersistMedia: false, - mediaType: IMAGE, - } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_COLLECTION_IMAGES - ] - action({ commit, dispatch }, params).then(() => { - const newParams = { ...params, source: params.provider } - delete newParams.provider - expect(imageServiceMock.getProviderCollection).toBeCalledWith(newParams) - - done() - }) + expect(commit).toHaveBeenCalledWith(FETCH_START_MEDIA, { mediaType }) + expect(commit).toHaveBeenCalledWith(RESET_MEDIA, { mediaType }) + expect(commit).toHaveBeenCalledWith(FETCH_END_MEDIA, { mediaType }) }) - it('FETCH_COLLECTION_IMAGES calls search API if q param exist', (done) => { + it('FETCH_MEDIA does not reset images if page is defined', async () => { + const mediaType = IMAGE const params = { - q: 'nature', - provider: 'met', + q: 'foo', page: 1, shouldPersistMedia: false, - mediaType: IMAGE, + mediaType, } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_COLLECTION_IMAGES - ] - action({ commit, dispatch }, params).then(() => { - const newParams = { ...params, source: params.provider } - delete newParams.provider - expect(imageServiceMock.search).toBeCalledWith(newParams) - - done() - }) + const action = store.actions(services)[FETCH_MEDIA] + await action({ commit, dispatch, state }, params) + + expect(commit).not.toHaveBeenCalledWith(RESET_MEDIA, { mediaType }) }) - it('FETCH_MEDIA on error', (done) => { - const failedMock = { - search: jest.fn(() => Promise.reject('error')), - } - const params = { - q: 'foo', - page: 1, - shouldPersistMedia: false, - mediaType: IMAGE, - } - const action = store.actions(failedMock, failedMock)[FETCH_MEDIA] - action({ commit, dispatch, state }, params).catch((error) => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) - expect(dispatch).toBeCalledWith('HANDLE_IMAGE_ERROR', error) - }) - done() + it('FETCH_AUDIO on success', async () => { + const params = { id: 'foo' } + const action = store.actions(services)[FETCH_AUDIO] + await action({ commit, dispatch, state, rootState }, params) + expect(commit).toHaveBeenCalledWith(SET_AUDIO, { audio: {} }) + expect(commit).toHaveBeenCalledWith(SET_AUDIO, { audio: audioDetailData }) + expect(audioServiceMock.getMediaDetail).toHaveBeenCalledWith(params) }) - it('FETCH_COLLECTION_IMAGES on error', (done) => { - const failedMock = { - getProviderCollection: jest.fn(() => Promise.reject('error')), - search: jest.fn(() => Promise.reject('error')), - } - const params = { - q: 'foo', - page: 1, - shouldPersistMedia: false, - mediaType: IMAGE, - } - const action = store.actions(failedMock, failedMock)[ - FETCH_COLLECTION_IMAGES - ] - action({ commit, dispatch }, params).catch((error) => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) - expect(dispatch).toBeCalledWith('HANDLE_IMAGE_ERROR', error) - }) - done() + it('FETCH_AUDIO dispatches SEND_RESULT_CLICKED_EVENT', () => { + const params = { id: 'foo' } + const action = store.actions(services)[FETCH_AUDIO] + action({ commit, dispatch, state, rootState }, params) + + expect(dispatch).toHaveBeenLastCalledWith( + `${USAGE_DATA}/${SEND_RESULT_CLICKED_EVENT}`, + { + query: state.query.q, + resultUuid: 'foo', + resultRank: 0, + sessionId: rootState.user.usageSessionId, + } + ) }) - it('FETCH_MEDIA resets images if page is not defined', (done) => { - const params = { - q: 'foo', - page: undefined, - shouldPersistMedia: false, - mediaType: IMAGE, + it('FETCH_AUDIO on error', async () => { + services[AUDIO] = { + getMediaDetail: jest.fn(() => Promise.reject('error')), } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_MEDIA - ] - action({ commit, dispatch, state, rootState }, params).then(() => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { - mediaType: IMAGE, - }) - - expect(commit).toBeCalledWith(FETCH_END_MEDIA, { - mediaType: IMAGE, - }) - - expect(commit).toBeCalledWith(SET_MEDIA, { - media: [], - mediaType: IMAGE, - }) - done() + const params = { id: 'foo' } + const action = store.actions(services)[FETCH_AUDIO] + await action({ commit, dispatch, state, rootState }, params) + await expect(services[AUDIO].getMediaDetail).rejects.toEqual('error') + + expect(dispatch).toHaveBeenLastCalledWith('HANDLE_MEDIA_ERROR', { + error: 'error', + mediaType: 'audio', }) }) - it('FETCH_MEDIA does not reset images if page is defined', (done) => { - const params = { - q: 'foo', - page: 1, - shouldPersistMedia: false, - mediaType: IMAGE, + it('FETCH_AUDIO on 404 doesnt break and commits MEDIA_NOT_FOUND', async () => { + const mediaType = AUDIO + services[AUDIO] = { + getMediaDetail: jest.fn(() => + Promise.reject({ response: { status: 404 } }) + ), } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_MEDIA - ] - action({ commit, dispatch, state }, params).then(() => { - expect(commit).not.toBeCalledWith(SET_MEDIA, { media: [] }) - done() - }) + const params = { id: 'foo' } + const action = store.actions(services)[FETCH_AUDIO] + await action({ commit, dispatch, state, rootState }, params) + expect(commit).toHaveBeenCalledWith(MEDIA_NOT_FOUND, { mediaType }) }) - it('FETCH_IMAGE on success', (done) => { + it('FETCH_IMAGE on success', async () => { const params = { id: 'foo' } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_IMAGE - ] - action({ commit, dispatch, state, rootState }, params).then(() => { - expect(commit).toBeCalledWith(SET_IMAGE, { image: {} }) - expect(commit).toBeCalledWith(SET_IMAGE, { image: imageDetailData }) - expect(imageServiceMock.getMediaDetail).toBeCalledWith(params) - - done() - }) + const action = store.actions(services)[FETCH_IMAGE] + await action({ commit, dispatch, state, rootState }, params) + expect(commit).toHaveBeenCalledWith(SET_IMAGE, { image: {} }) + expect(commit).toHaveBeenCalledWith(SET_IMAGE, { image: imageDetailData }) + + expect(imageServiceMock.getMediaDetail).toHaveBeenCalledWith(params) }) it('FETCH_IMAGE dispatches SEND_RESULT_CLICKED_EVENT', () => { const params = { id: 'foo' } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_IMAGE - ] + const action = store.actions(services)[FETCH_IMAGE] action({ commit, dispatch, state, rootState }, params) expect(dispatch).toHaveBeenLastCalledWith( @@ -481,32 +440,102 @@ describe('Search Store', () => { ) }) - it('FETCH_IMAGE on error', (done) => { - const failedMock = { - getMediaDetail: jest.fn(() => Promise.reject('error')), + it('FETCH_IMAGE on error', async () => { + services[IMAGE] = { + getMediaDetail: jest.fn(() => + Promise.reject(new Error('Server error')) + ), } const params = { id: 'foo' } - const action = store.actions(failedMock, failedMock)[FETCH_IMAGE] - action({ commit, dispatch, state, rootState }, params).catch((error) => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) - expect(dispatch).toBeCalledWith('HANDLE_IMAGE_ERROR', error) - }) - done() + const action = store.actions(services)[FETCH_IMAGE] + await expect( + action({ commit, dispatch, state, rootState }, params) + ).rejects.toThrow('Error fetching the image: Server error') }) - it('FETCH_IMAGE on 404 doesnt break and commits MEDIA_NOT_FOUND', (done) => { - const failedMock = { + it('FETCH_IMAGE on 404 doesnt break and commits MEDIA_NOT_FOUND', async () => { + const mediaType = IMAGE + services[IMAGE] = { getMediaDetail: jest.fn(() => Promise.reject({ response: { status: 404 } }) ), } const params = { id: 'foo' } - const action = store.actions(failedMock, failedMock)[FETCH_IMAGE] - action({ commit, dispatch, state, rootState }, params).then(() => { - expect(commit).toBeCalledWith(MEDIA_NOT_FOUND, { mediaType: IMAGE }) + const action = store.actions(services)[FETCH_IMAGE] + await action({ commit, dispatch, state, rootState }, params) + expect(commit).toHaveBeenCalledWith(MEDIA_NOT_FOUND, { mediaType }) + }) + + it('HANDLE_MEDIA_ERROR handles 500 error', () => { + const action = store.actions(services)[HANDLE_MEDIA_ERROR] + const error = { response: { status: 500, message: 'Server error' } } + + action({ commit }, { mediaType: AUDIO, error }) + expect(commit).toHaveBeenCalledWith(FETCH_MEDIA_ERROR, { + errorMessage: 'There was a problem with our servers', + mediaType: AUDIO, + }) + }) + + it('HANDLE_MEDIA_ERROR handles a 403 error', () => { + const action = store.actions(services)[HANDLE_MEDIA_ERROR] + const error = { response: { status: 403, message: 'Server error' } } + + action({ commit }, { mediaType: AUDIO, error }) + expect(commit).toHaveBeenCalledWith(FETCH_MEDIA_ERROR, { + errorMessage: error.response.message, + mediaType: AUDIO, + }) + }) + + it('HANDLE_MEDIA_ERROR throws a new error on error when server did not respond', async () => { + const action = store.actions(services)[HANDLE_MEDIA_ERROR] + const error = new Error('Server did not respond') + await expect( + action({ commit }, { mediaType: AUDIO, error }) + ).rejects.toThrow(error.message) + }) + + it('HANDLE_NO_MEDIA throws an error when media count is 0', async () => { + const action = store.actions(services)[HANDLE_NO_MEDIA] + await action({ commit }, { mediaCount: 0, mediaType: IMAGE }) + expect(commit).toHaveBeenLastCalledWith(FETCH_MEDIA_ERROR, { + errorMessage: 'No image found for this query', + }) + }) + + it('HANDLE_NO_MEDIA does not throw an error when media count is not 0', () => { + const action = store.actions(services)[HANDLE_NO_MEDIA] + action({ commit }, { mediaCount: 1, mediaType: IMAGE }) + expect(commit.mock.calls.length).toEqual(0) + }) + + it('SET_SEARCH_TYPE_FROM_URL sets search type to image', () => { + const action = store.actions(services)[SET_SEARCH_TYPE_FROM_URL] + action({ commit }, { url: '/search/image?q=cat&source=met' }) + expect(commit).toHaveBeenCalledWith(SET_SEARCH_TYPE, { + searchType: IMAGE, + }) + expect(commit).toHaveBeenCalledWith(UPDATE_FILTERS) + }) + + it('SET_SEARCH_TYPE_FROM_URL sets search type to ALL_MEDIA if URL param is not set', () => { + const action = store.actions(services)[SET_SEARCH_TYPE_FROM_URL] + action({ commit }, { url: '/search/?q=cat&source=met' }) + expect(commit).toHaveBeenCalledWith(SET_SEARCH_TYPE, { + searchType: ALL_MEDIA, + }) + expect(commit).toHaveBeenCalledWith(UPDATE_FILTERS) + }) + + it('UPDATE_SEARCH_TYPE sets search type to ALL_MEDIA if URL param is not set', () => { + const action = store.actions(services)[UPDATE_SEARCH_TYPE] - done() + action({ commit }, { searchType: ALL_MEDIA }) + expect(commit).toHaveBeenCalledWith(SET_SEARCH_TYPE, { + searchType: ALL_MEDIA, }) + expect(commit).toHaveBeenCalledWith(UPDATE_FILTERS) }) }) })