diff --git a/packages/client/src/builders/recommendation/products/index.ts b/packages/client/src/builders/recommendation/products/index.ts index a972588..908d435 100644 --- a/packages/client/src/builders/recommendation/products/index.ts +++ b/packages/client/src/builders/recommendation/products/index.ts @@ -13,4 +13,5 @@ export * from './purchasedWithMultipleProductsBuilder'; export * from './purchasedWithProductBuilder'; export * from './searchTermBasedProductRecommendationBuilder'; export * from './sortProductsBuilder'; -export * from './similarProductsProductBuilder'; \ No newline at end of file +export * from './similarProductsProductBuilder'; +export * from './popularityMultiplierBuilder'; \ No newline at end of file diff --git a/packages/client/src/builders/recommendation/products/popularProductsBuilder.ts b/packages/client/src/builders/recommendation/products/popularProductsBuilder.ts index 62fd211..316972a 100644 --- a/packages/client/src/builders/recommendation/products/popularProductsBuilder.ts +++ b/packages/client/src/builders/recommendation/products/popularProductsBuilder.ts @@ -1,11 +1,13 @@ import { Settings } from '../../../builders/settings'; import { PopularProductsRequest } from '../../../models/data-contracts'; +import { PopularityMultiplierBuilder } from './popularityMultiplierBuilder'; import { ProductSettingsRecommendationBuilder } from './productSettingsRecommendationBuilder'; import { ProductsRecommendationBuilder } from './productsRecommendationBuilder'; export class PopularProductsBuilder extends ProductSettingsRecommendationBuilder implements ProductsRecommendationBuilder { private since: number = 0; private basedOnSelection: 'MostPurchased' | 'MostViewed' = 'MostPurchased'; + private popularityMultiplierBuilder: PopularityMultiplierBuilder = new PopularityMultiplierBuilder(); constructor( settings: Settings) { @@ -24,6 +26,12 @@ export class PopularProductsBuilder extends ProductSettingsRecommendationBuilder return this; } + public setPopularityMultiplier(popularityMultiplierBuilder: (popularityMultiplierBuilder: PopularityMultiplierBuilder) => void) { + popularityMultiplierBuilder(this.popularityMultiplierBuilder); + + return this; + } + public build() { const request: PopularProductsRequest = { $type: 'Relewise.Client.Requests.Recommendations.PopularProductsRequest, Relewise.Client', @@ -31,6 +39,7 @@ export class PopularProductsBuilder extends ProductSettingsRecommendationBuilder settings: this.recommendationSettings, basedOn: this.basedOnSelection, sinceMinutesAgo: this.since, + popularityMultiplier: this.popularityMultiplierBuilder.build(), }; return request; diff --git a/packages/client/src/builders/recommendation/products/popularityMultiplierBuilder.ts b/packages/client/src/builders/recommendation/products/popularityMultiplierBuilder.ts new file mode 100644 index 0000000..951838d --- /dev/null +++ b/packages/client/src/builders/recommendation/products/popularityMultiplierBuilder.ts @@ -0,0 +1,19 @@ +import { DataKeyPopularityMultiplierSelector, PopularityMultiplierSelector } from '../../../models/data-contracts'; + +export class PopularityMultiplierBuilder { + private popularityMultiplierSelector: PopularityMultiplierSelector | null = null; + + public setDataKeyPopularityMultiplierSelector(selector: { key?: string | null }): this { + const dataKeyPopularityMultiplierSelector: DataKeyPopularityMultiplierSelector = { + $type: 'Relewise.Client.Requests.PopularityMultiplierSelectors.DataKeyPopularityMultiplierSelector, Relewise.Client', + ...selector, + } + + this.popularityMultiplierSelector = dataKeyPopularityMultiplierSelector; + return this; + } + + build(): PopularityMultiplierSelector | null { + return this.popularityMultiplierSelector; + } +} \ No newline at end of file diff --git a/packages/client/tests/integration-tests/productRecommendations.integration.test.ts b/packages/client/tests/integration-tests/productRecommendations.integration.test.ts index a58fc3c..75115fe 100644 --- a/packages/client/tests/integration-tests/productRecommendations.integration.test.ts +++ b/packages/client/tests/integration-tests/productRecommendations.integration.test.ts @@ -1,4 +1,4 @@ -import { DataValueFactory, ProductRecommendationResponse, ProductsViewedAfterViewingProductBuilder, PurchasedWithProductBuilder, Recommender, UserFactory } from '../../src'; +import { DataValueFactory, PopularProductsBuilder, ProductRecommendationResponse, ProductsViewedAfterViewingProductBuilder, PurchasedWithProductBuilder, Recommender, UserFactory } from '../../src'; import { test, expect } from '@jest/globals' const { npm_config_API_KEY: API_KEY, npm_config_DATASET_ID: DATASET_ID, npm_config_SERVER_URL: SERVER_URL } = process.env; @@ -14,7 +14,7 @@ const settings = { test('PurchasedWithProduct', async() => { - const result: ProductRecommendationResponse | undefined = await recommender.recommendPurchasedWithProduct(new PurchasedWithProductBuilder(settings).product({productId: '1'}).build()); + const result: ProductRecommendationResponse | undefined = await recommender.recommendPurchasedWithProduct(new PurchasedWithProductBuilder(settings).product({ productId: '1' }).build()); expect(result).not.toBe(undefined); expect(result!.recommendations?.length).toBeGreaterThan(0); @@ -22,7 +22,7 @@ test('PurchasedWithProduct', async() => { test('ProductsViewedAfterViewingProduct', async() => { - const result: ProductRecommendationResponse | undefined = await recommender.recommendProductsViewedAfterViewingProduct(new ProductsViewedAfterViewingProductBuilder(settings).product({productId: '1'}).build()); + const result: ProductRecommendationResponse | undefined = await recommender.recommendProductsViewedAfterViewingProduct(new ProductsViewedAfterViewingProductBuilder(settings).product({ productId: '1' }).build()); expect(result).not.toBe(undefined); expect(result!.recommendations?.length).toBeGreaterThan(0); @@ -36,18 +36,29 @@ test('ProductsViewedAfterViewingProduct with all conditions', async() => { displayedAtLocation: 'integration test Conditions', user: UserFactory.anonymous(), }) - .product({productId: '1'}) + .product({ productId: '1' }) .filters(f => f .addProductDataFilter('ShortDescription', b => b .addContainsCondition(DataValueFactory.stringCollection(['d']), 'Any') .addContainsCondition(DataValueFactory.booleanCollection([true]), 'Any') .addContainsCondition(DataValueFactory.doubleCollection([1]), 'Any') - .addContainsCondition(DataValueFactory.multilingual([{language: 'en-us', value: 'd'}]), 'Any') - .addContainsCondition(DataValueFactory.multiCurrency([{currency: 'USD', amount: 1}]), 'Any'), + .addContainsCondition(DataValueFactory.multilingual([{ language: 'en-us', value: 'd' }]), 'Any') + .addContainsCondition(DataValueFactory.multiCurrency([{ currency: 'USD', amount: 1 }]), 'Any'), )); const result: ProductRecommendationResponse | undefined = await recommender.recommendProductsViewedAfterViewingProduct(recommendationBuilder.build()); expect(result).not.toBe(undefined); expect(result!.recommendations?.length).toEqual(0); +}); + +test('ProductsViewedAfterViewingProduct with all conditions', async() => { + + const recommendationBuilder = new PopularProductsBuilder(settings) + .setPopularityMultiplier(pm => pm.setDataKeyPopularityMultiplierSelector({ key: 'some-data-key' })); + + const result: ProductRecommendationResponse | undefined = await recommender.recommendPopularProducts(recommendationBuilder.build()); + + expect(result).not.toBe(undefined); + expect(result!.recommendations?.length).toBeGreaterThan(0); }); \ No newline at end of file diff --git a/packages/client/tests/unit-tests/builders/recommendation/popularProductsBuilder.unit.test.ts b/packages/client/tests/unit-tests/builders/recommendation/popularProductsBuilder.unit.test.ts new file mode 100644 index 0000000..c568eb1 --- /dev/null +++ b/packages/client/tests/unit-tests/builders/recommendation/popularProductsBuilder.unit.test.ts @@ -0,0 +1,23 @@ +import { UserFactory } from '../../../../src/factory'; +import { test, expect } from '@jest/globals' +import { PopularProductsRequest } from '../../../../src/models/data-contracts'; +import { PopularProductsBuilder } from '../../../../src'; + +function baseBuilder() { + return new PopularProductsBuilder({ + language: 'da-DK', + currency: 'DKK', + displayedAtLocation: 'unit test', + user: UserFactory.anonymous(), + }); +}; + +test('setPopularityMultiplier', () => { + const key: string = 'data-key'; + + const subject: PopularProductsRequest = baseBuilder() + .setPopularityMultiplier(pm => pm.setDataKeyPopularityMultiplierSelector({ key: key })) + .build(); + + expect(subject.popularityMultiplier?.key).toBe(key); +});