it('does not fetch featured themes if includeFeaturedThemes is false', async () => { const collections = []; const featuredExtensions = createAddonsApiResult([fakeAddon]); mockSearchApi .expects('search') .returns(Promise.resolve(featuredExtensions)); const popularAddons = createAddonsApiResult([fakeAddon]); mockSearchApi.expects('search').returns(Promise.resolve(popularAddons)); const trendingExtensions = createAddonsApiResult([fakeAddon]); mockSearchApi.expects('search').returns(Promise.resolve(popularAddons)); _fetchHomeAddons({ collectionsToFetch: [], includeFeaturedThemes: false, }); const loadAction = loadHomeAddons({ collections, shelves: { featuredExtensions, featuredThemes: null, popularAddons, trendingExtensions, }, }); const expectedAction = await sagaTester.waitFor(loadAction.type); mockSearchApi.verify(); expect(expectedAction).toEqual(loadAction); });
it('does not display a collection shelf if there is no collection in state', () => { const { store } = dispatchClientMetadata(); const addons = [{ ...fakeAddon, slug: 'addon' }]; const collections = [null, null, null]; const featuredExtensions = createAddonsApiResult(addons); const featuredThemes = createAddonsApiResult([]); const popularExtensions = createAddonsApiResult(addons); store.dispatch( loadHomeAddons({ collections, featuredExtensions, featuredThemes, popularExtensions, }), ); const root = render({ store }); const shelves = root.find(LandingAddonsCard); const collectionShelves = shelves.find('.Home-FeaturedCollection'); expect(collectionShelves).toHaveLength(0); });
const _loadHomeAddons = ({ store, collections = [], shelves = {} }) => { store.dispatch( loadHomeAddons({ collections, shelves, }), ); };
async (status) => { const error = createApiError({ response: { status } }); const firstCollectionSlug = 'collection-slug'; const firstCollectionUserId = 'user-id-or-name'; mockCollectionsApi .expects('getCollectionAddons') .returns(Promise.reject(error)); const collections = [null]; const featuredExtensions = createAddonsApiResult([fakeAddon]); mockSearchApi .expects('search') .returns(Promise.resolve(featuredExtensions)); const popularAddons = createAddonsApiResult([fakeAddon]); mockSearchApi.expects('search').returns(Promise.resolve(popularAddons)); const trendingExtensions = createAddonsApiResult([fakeAddon]); mockSearchApi.expects('search').returns(Promise.resolve(popularAddons)); _fetchHomeAddons({ collectionsToFetch: [ { slug: firstCollectionSlug, userId: firstCollectionUserId }, ], includeFeaturedThemes: false, }); const loadAction = loadHomeAddons({ collections, shelves: { featuredExtensions, featuredThemes: null, popularAddons, trendingExtensions, }, }); const expectedAction = await sagaTester.waitFor(loadAction.type); expect(expectedAction).toEqual(loadAction); },
it('does not fetch the add-ons when results are already loaded', () => { const { store } = dispatchClientMetadata(); const addons = [{ ...fakeAddon, slug: 'addon' }]; const collectionAddons = createFakeCollectionAddons(); const collections = [ createFakeCollectionAddonsListResponse({ addons: collectionAddons }), ]; const featuredExtensions = createAddonsApiResult(addons); const popularExtensions = createAddonsApiResult(addons); store.dispatch( loadHomeAddons({ collections, featuredExtensions, featuredThemes: null, popularExtensions, }), ); const fakeDispatch = sinon.stub(store, 'dispatch'); const root = render({ includeFeaturedThemes: false, store }); sinon.assert.callCount(fakeDispatch, 1); sinon.assert.calledWith(fakeDispatch, setViewContext(VIEW_CONTEXT_HOME)); const firstCollectionShelf = root.find('.Home-FeaturedCollection'); expect(firstCollectionShelf).toHaveProp('loading', false); expect(firstCollectionShelf).toHaveProp( 'addons', collectionAddons.map((addon) => createInternalAddon(addon.addon)), ); const featuredExtensionsShelf = root.find('.Home-FeaturedExtensions'); expect(featuredExtensionsShelf).toHaveProp('loading', false); expect(featuredExtensionsShelf).toHaveProp( 'addons', addons.map((addon) => createInternalAddon(addon)), ); });
export function* fetchHomeAddons({ payload: { collectionsToFetch, errorHandlerId, includeFeaturedThemes }, }: FetchHomeAddonsAction): Generator<any, any, any> { const errorHandler = createErrorHandler(errorHandlerId); yield put(errorHandler.createClearingAction()); const state = yield select(getState); const collections = []; for (const collection of collectionsToFetch) { try { const params: GetCollectionAddonsParams = { api: state.api, slug: collection.slug, username: collection.username, }; const result = yield call(getCollectionAddons, params); collections.push(result); } catch (error) { log.warn( oneLine`Home collection: ${collection.username}/${collection.slug} failed to load: ${error}`, ); if (error.response && [401, 404].includes(error.response.status)) { // The collection was not found or is marked private. collections.push(null); } else { yield put(errorHandler.createErrorAction(error)); return; } } } const featuredSearchFilters = { featured: true, page_size: LANDING_PAGE_EXTENSION_COUNT, sort: SEARCH_SORT_RANDOM, }; const featuredExtensionsParams: SearchParams = { api: state.api, filters: { addonType: ADDON_TYPE_EXTENSION, ...featuredSearchFilters, }, }; const featuredThemesParams: SearchParams = { api: state.api, filters: { addonType: getAddonTypeFilter(ADDON_TYPE_THEME), ...featuredSearchFilters, page_size: LANDING_PAGE_THEME_COUNT, }, }; const popularExtensionsParams: SearchParams = { api: state.api, filters: { addonType: ADDON_TYPE_EXTENSION, page_size: LANDING_PAGE_EXTENSION_COUNT, sort: SEARCH_SORT_POPULAR, }, }; let homeAddons = {}; try { homeAddons = yield all({ featuredExtensions: call(searchApi, featuredExtensionsParams), featuredThemes: includeFeaturedThemes ? call(searchApi, featuredThemesParams) : null, popularExtensions: call(searchApi, popularExtensionsParams), }); } catch (error) { log.warn(`Home add-ons failed to load: ${error}`); yield put(errorHandler.createErrorAction(error)); return; } yield put( loadHomeAddons({ collections, featuredExtensions: homeAddons.featuredExtensions, featuredThemes: homeAddons.featuredThemes, popularExtensions: homeAddons.popularExtensions, }), ); }
it('calls the API to fetch the add-ons to display on home', async () => { const state = sagaTester.getState(); const firstCollectionSlug = 'collection-slug'; const firstCollectionUserId = 123; const secondCollectionSlug = 'collection-slug-2'; const secondCollectionUserId = 456; const baseArgs = { api: state.api }; const firstCollection = createFakeCollectionAddonsListResponse(); const secondCollection = createFakeCollectionAddonsListResponse(); mockCollectionsApi .expects('getCollectionAddons') .withArgs({ ...baseArgs, slug: firstCollectionSlug, userId: firstCollectionUserId, }) .returns(Promise.resolve(firstCollection)); mockCollectionsApi .expects('getCollectionAddons') .withArgs({ ...baseArgs, slug: secondCollectionSlug, userId: secondCollectionUserId, }) .returns(Promise.resolve(secondCollection)); const collections = [firstCollection, secondCollection]; const featuredExtensions = createAddonsApiResult([fakeAddon]); mockSearchApi .expects('search') .withArgs({ ...baseArgs, filters: { page_size: String(LANDING_PAGE_EXTENSION_COUNT), addonType: ADDON_TYPE_EXTENSION, featured: true, sort: SEARCH_SORT_RANDOM, }, }) .returns(Promise.resolve(featuredExtensions)); const featuredThemes = createAddonsApiResult([fakeTheme]); mockSearchApi .expects('search') .withArgs({ ...baseArgs, filters: { page_size: String(LANDING_PAGE_THEME_COUNT), addonType: getAddonTypeFilter(ADDON_TYPE_THEME), featured: true, sort: SEARCH_SORT_RANDOM, }, }) .returns(Promise.resolve(featuredThemes)); const popularAddons = createAddonsApiResult([fakeAddon]); mockSearchApi .expects('search') .withArgs({ ...baseArgs, filters: { page_size: String(LANDING_PAGE_EXTENSION_COUNT), addonType: getAddonTypeFilter(ADDON_TYPE_THEME), sort: SEARCH_SORT_POPULAR, }, }) .returns(Promise.resolve(featuredExtensions)); const trendingExtensions = createAddonsApiResult([fakeAddon]); mockSearchApi .expects('search') .withArgs({ ...baseArgs, filters: { page_size: String(LANDING_PAGE_EXTENSION_COUNT), addonType: ADDON_TYPE_EXTENSION, sort: SEARCH_SORT_TRENDING, }, }) .returns(Promise.resolve(featuredExtensions)); _fetchHomeAddons({ collectionsToFetch: [ { slug: firstCollectionSlug, userId: firstCollectionUserId }, { slug: secondCollectionSlug, userId: secondCollectionUserId }, ], includeFeaturedThemes: true, }); const loadAction = loadHomeAddons({ collections, shelves: { featuredExtensions, featuredThemes, popularAddons, trendingExtensions, }, }); const expectedAction = await sagaTester.waitFor(loadAction.type); mockCollectionsApi.verify(); mockSearchApi.verify(); expect(expectedAction).toEqual(loadAction); });