From 147a7a4ad4f8ed2b66b55bfa111cab3942981cf0 Mon Sep 17 00:00:00 2001 From: Aleksei Pavlov Date: Fri, 7 Aug 2026 12:38:21 +0200 Subject: [PATCH] [CDX-501] Add support for refined filters as top level URL parameters in browse results --- spec/src/modules/browse.js | 53 ++++++++++++++++++++++++++++++++++++++ src/modules/browse.js | 12 +++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/spec/src/modules/browse.js b/spec/src/modules/browse.js index 6c282457..85a86bb3 100644 --- a/spec/src/modules/browse.js +++ b/spec/src/modules/browse.js @@ -565,6 +565,59 @@ describe('ConstructorIO - Browse', () => { }); }); + it('Should send refined filters supplied within the qs param as a top level url parameter', (done) => { + const qsParam = { refined_filters: { group_id: 'BrandXY' } }; + const { browse } = new ConstructorIO({ + apiKey: testApiKey, + fetch: fetchSpy, + }); + + browse.getBrowseResults(filterName, filterValue, { qsParam }).then((res) => { + const requestedUrlParams = helpers.extractUrlParamsFromFetch(fetchSpy); + + expect(res).to.have.property('request').to.be.an('object'); + expect(requestedUrlParams).to.have.property('refined_filters'); + expect(requestedUrlParams.refined_filters).to.have.property('group_id').to.equal('BrandXY'); + expect(requestedUrlParams).to.not.have.property('qs'); + expect(res.request.refined_filters).to.deep.equal(qsParam.refined_filters); + done(); + }); + }); + + it('Should retain the remaining qs param values when sending refined filters as a top level url parameter', (done) => { + const qsParam = { + num_results_per_page: '10', + refined_filters: { group_id: 'BrandXY' }, + }; + const { browse } = new ConstructorIO({ + apiKey: testApiKey, + fetch: fetchSpy, + }); + + browse.getBrowseResults(filterName, filterValue, { qsParam }).then((res) => { + const requestedUrlParams = helpers.extractUrlParamsFromFetch(fetchSpy); + + expect(requestedUrlParams.refined_filters).to.have.property('group_id').to.equal('BrandXY'); + expect(JSON.parse(requestedUrlParams.qs)).to.deep.equal({ num_results_per_page: '10' }); + expect(res.request.num_results_per_page).to.equal(10); + expect(res.request.refined_filters).to.deep.equal(qsParam.refined_filters); + done(); + }); + }); + + it('Should not mutate the supplied qs param when sending refined filters as a top level url parameter', (done) => { + const qsParam = { refined_filters: { group_id: 'BrandXY' } }; + const { browse } = new ConstructorIO({ + apiKey: testApiKey, + fetch: fetchSpy, + }); + + browse.getBrowseResults(filterName, filterValue, { qsParam }).then(() => { + expect(qsParam).to.deep.equal({ refined_filters: { group_id: 'BrandXY' } }); + done(); + }); + }); + it('Should properly encode path parameters', (done) => { const specialCharacters = '+[]&'; const filterNameSpecialCharacters = `name ${specialCharacters}`; diff --git a/src/modules/browse.js b/src/modules/browse.js index c1ee4991..151bf8c7 100644 --- a/src/modules/browse.js +++ b/src/modules/browse.js @@ -108,9 +108,17 @@ function createQueryParams(parameters, userParameters, options) { queryParams.pre_filter_expression = JSON.stringify(preFilterExpression); } - // Pull qs param from parameters + // Pull qs param from parameters - refined filters are sent as a top level parameter if (qsParam) { - queryParams.qs = JSON.stringify(qsParam); + const { refined_filters: refinedFilters, ...remainingQsParam } = qsParam; + + if (refinedFilters) { + queryParams.refined_filters = refinedFilters; + } + + if (Object.keys(remainingQsParam).length) { + queryParams.qs = JSON.stringify(remainingQsParam); + } } }