diff --git a/.gitignore b/.gitignore index 799d9521..8c334c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ test # OS X specific files .DS_Store +# Editor specific files +.idea + # Logs logs *.log diff --git a/spec/src/modules/recommendations.js b/spec/src/modules/recommendations.js index 863f68e9..53dfaf70 100644 --- a/spec/src/modules/recommendations.js +++ b/spec/src/modules/recommendations.js @@ -49,6 +49,7 @@ describe(`ConstructorIO - Recommendations${bundledDescriptionSuffix}`, () => { const filteredItemsRecommendationsPodId = 'filtered_items'; const itemId = 'power_drill'; const itemIds = [itemId, 'drill']; + const variationId = 'power_drill_variation'; it('Should return a response with valid itemIds (singular)', (done) => { const { recommendations } = new ConstructorIO({ @@ -99,6 +100,35 @@ describe(`ConstructorIO - Recommendations${bundledDescriptionSuffix}`, () => { }); }); + it('Should return a response with valid variationId', (done) => { + const { recommendations } = new ConstructorIO({ + apiKey: testApiKey, + fetch: fetchSpy, + }); + + recommendations.getRecommendations(podId, { itemIds: itemId, variationId }).then((res) => { + const requestedUrlParams = helpers.extractUrlParamsFromFetch(fetchSpy); + + expect(res).to.have.property('request').to.be.an('object'); + expect(res).to.have.property('response').to.be.an('object'); + expect(res).to.have.property('result_id').to.be.an('string'); + expect(res.request.item_id).to.equal(itemId); + expect(res.response).to.have.property('results').to.be.an('array'); + expect(res.response).to.have.property('pod'); + expect(res.response.pod).to.have.property('id').to.equal(podId); + expect(res.response.pod).to.have.property('display_name'); + expect(fetchSpy).to.have.been.called; + expect(requestedUrlParams).to.have.property('key'); + expect(requestedUrlParams).to.have.property('i'); + expect(requestedUrlParams).to.have.property('s'); + expect(requestedUrlParams).to.have.property('c').to.equal(clientVersion); + expect(requestedUrlParams).to.have.property('item_id').to.equal(itemId); + expect(requestedUrlParams).to.have.property('variation_id').to.equal(variationId); + expect(res.request.variation_id).to.equal(variationId); + done(); + }); + }); + it('Should return a response with valid term for query recommendations strategy pod', (done) => { const term = 'apple'; const { recommendations } = new ConstructorIO({ @@ -462,6 +492,23 @@ describe(`ConstructorIO - Recommendations${bundledDescriptionSuffix}`, () => { recommendations.getRecommendations(podId, { itemIds }); }); + it('Should be rejected when variationId is provided without itemId', () => { + const { recommendations } = new ConstructorIO({ apiKey: testApiKey }); + + return expect(recommendations.getRecommendations(podId, { + variationId, + })).to.eventually.be.rejected; + }); + + it('Should be rejected when variationId is provided with an empty itemIds array', () => { + const { recommendations } = new ConstructorIO({ apiKey: testApiKey }); + + return expect(recommendations.getRecommendations(podId, { + variationId, + itemIds: [], + })).to.eventually.be.rejected; + }); + it('Should be rejected when invalid pod id parameter is provided', () => { const { recommendations } = new ConstructorIO({ apiKey: testApiKey }); diff --git a/src/modules/recommendations.js b/src/modules/recommendations.js index 1ea7af7f..ca839109 100644 --- a/src/modules/recommendations.js +++ b/src/modules/recommendations.js @@ -3,6 +3,7 @@ const EventDispatcher = require('../utils/event-dispatcher'); const helpers = require('../utils/helpers'); // Create URL from supplied parameters +// eslint-disable-next-line complexity function createRecommendationsUrl(podId, parameters, options) { const { apiKey, version, serviceUrl, sessionId, userId, clientId, segments } = options; let queryParams = { c: version }; @@ -30,6 +31,7 @@ function createRecommendationsUrl(podId, parameters, options) { const { numResults, itemIds, + variationId, section, term, filters, @@ -49,6 +51,18 @@ function createRecommendationsUrl(podId, parameters, options) { queryParams.item_id = itemIds; } + if (variationId) { + if (!itemIds || (typeof itemIds === 'string' && !itemIds.trim())) { + throw new Error('itemIds is a required parameter for variationId'); + } + + if (Array.isArray(itemIds) && !itemIds.length) { + throw new Error('At least one itemId is a required parameter for variationId'); + } + + queryParams.variation_id = variationId; + } + // Pull section from parameters if (section) { queryParams.section = section; @@ -116,7 +130,9 @@ class Recommendations { * @description Retrieve recommendation results from Constructor.io API * @param {string} podId - Pod identifier * @param {object} [parameters] - Additional parameters to refine results - * @param {string|array} [parameters.itemIds] - Item ID(s) to retrieve recommendations for (strategy specific) + * @param {string|array} [parameters.itemIds] - Item ID(s) to retrieve recommendations for (strategy specific). + * Required for variationId + * @param {string} [parameters.variationId] - Variation ID to retrieve recommendations for (strategy specific) * @param {number} [parameters.numResults] - The number of results to return * @param {string} [parameters.section] - The section to return results from * @param {string} [parameters.term] - The term to use to refine results (strategy specific) diff --git a/src/types/recommendations.d.ts b/src/types/recommendations.d.ts index 0b63f41b..9d074a80 100644 --- a/src/types/recommendations.d.ts +++ b/src/types/recommendations.d.ts @@ -5,6 +5,7 @@ export default Recommendations; export interface RecommendationsParameters { itemIds?: string | string[]; + variationId?: string; numResults?: number; section?: string; term?: string; @@ -41,6 +42,7 @@ export interface RecommendationsResponse extends Record { export interface RecommendationsRequestType extends Record { num_results: number; item_id: string | string[]; + variation_id: string; filters: { group_id: string; [key: string]: any;