Skip to content

Commit

Permalink
Write tests for search-store (#286)
Browse files Browse the repository at this point in the history
Add initial query values

Handle media reset on query change only in `search` page

Update src/utils/prepare-search-query-params.js

Co-authored-by: sarayourfriend <24264157+sarayourfriend@users.noreply.github.com>
obulat and sarayourfriend authored Oct 13, 2021

Partially verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
1 parent 7d517f9 commit 3967fc1
Showing 6 changed files with 314 additions and 377 deletions.
1 change: 0 additions & 1 deletion src/components/ContentReport/ContentReportForm.vue
Original file line number Diff line number Diff line change
@@ -144,7 +144,6 @@ export default {
} else if (this.selectedReason === 'dmca') {
this.selectedCopyright = true
} else {
console.log('sending content report')
this.sendContentReport()
}
},
1 change: 1 addition & 0 deletions src/constants/mutation-types.js
Original file line number Diff line number Diff line change
@@ -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'
198 changes: 50 additions & 148 deletions src/store-modules/search-store.js
Original file line number Diff line number Diff line change
@@ -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,30 +138,19 @@ const actions = (AudioService, ImageService) => ({
})

commit(SET_IMAGE, { image: {} })
return ImageService.getMediaDetail(params)
await services[IMAGE].getMediaDetail(params)
.then(({ data }) => {
commit(SET_IMAGE, { image: data })
})
.catch((error) => {
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 {
5 changes: 4 additions & 1 deletion src/store/index.js
Original file line number Diff line number Diff line change
@@ -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 }) {
3 changes: 3 additions & 0 deletions src/utils/prepare-search-query-params.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export default function prepareSearchQueryParams(searchParams) {
if (typeof searchParams.mediaType !== 'undefined') {
delete searchParams.mediaType
}
const params = {
...searchParams,
}
Loading

0 comments on commit 3967fc1

Please sign in to comment.