diff --git a/library/src/main/java/io/constructor/core/ConstructorIo.kt b/library/src/main/java/io/constructor/core/ConstructorIo.kt index 5e14cf25..fb846e23 100755 --- a/library/src/main/java/io/constructor/core/ConstructorIo.kt +++ b/library/src/main/java/io/constructor/core/ConstructorIo.kt @@ -200,7 +200,9 @@ object ConstructorIo { groupIdFilter: String? = null, preFilterExpression: String? = null, sectionFacets: Map>>>? = null, - fmtOptions: Map? = null + fmtOptions: Map? = null, + slCampaignId: String? = null, + slCampaignOwner: String? = null ): ArrayList> { val encodedParams: ArrayList> = arrayListOf() @@ -263,6 +265,8 @@ object ConstructorIo { } } showHiddenFacets?.let { encodedParams.add(Constants.QueryConstants.FMT_OPTIONS.format(Constants.QueryConstants.SHOW_HIDDEN_FACETS).urlEncode() to showHiddenFacets.toString().urlEncode()) } + slCampaignId?.let { encodedParams.add("sl_campaign_id".urlEncode() to it.urlEncode()) } + slCampaignOwner?.let { encodedParams.add("sl_campaign_owner".urlEncode() to it.urlEncode()) } groupsSortBy?.let { encodedParams.add(Constants.QueryConstants.FMT_OPTIONS.format(Constants.QueryConstants.GROUPS_SORT_BY).urlEncode() to groupsSortBy.urlEncode()) } groupsSortOrder?.let { encodedParams.add(Constants.QueryConstants.FMT_OPTIONS.format(Constants.QueryConstants.GROUPS_SORT_ORDER).urlEncode() to groupsSortOrder.urlEncode()) } resultId?.let { encodedParams.add(Constants.QueryConstants.RESULT_ID.urlEncode() to it.urlEncode()) } @@ -1442,6 +1446,7 @@ object ConstructorIo { } /** + * @deprecated Prefer [trackSearchResultsLoaded] with an array of [TrackingItem] in place of an array of strings for customerIds. * Tracks search results loaded (a.k.a. search results viewed) events. * * Example: @@ -1454,17 +1459,37 @@ object ConstructorIo { * @param analyticsTags Additional analytics tags to pass */ fun trackSearchResultsLoaded(term: String, resultCount: Int, customerIds: Array? = null, analyticsTags: Map? = null) { - var completable = trackSearchResultsLoadedInternal(term, resultCount, customerIds, analyticsTags) - disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { - t -> e("Search Results Loaded error: ${t.message}") - })) + var completable = trackSearchResultsLoadedInternal(term, resultCount, customerIds = customerIds, analyticsTags = analyticsTags) + disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Search Results Loaded error: ${t.message}") })) + } + + /** + * Tracks search results loaded (a.k.a. search results viewed) events. + * + * Example: + * ``` + * ConstructorIo.trackSearchResultsLoaded("tooth", 789, arrayOf(TrackingItem("1234", "2345", "camp1234", "owner-A")) + * ``` + * @param term the term that results are displayed for, i.e. "Pumpkin" + * @param resultCount the number of results for that term + * @param items the list of items shown + * @param analyticsTags Additional analytics tags to pass + */ + fun trackSearchResultsLoaded(term: String, resultCount: Int, items: Array, analyticsTags: Map? = null) { + var completable = trackSearchResultsLoadedInternal(term, resultCount, items = items, analyticsTags = analyticsTags) + disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Search Results Loaded error: ${t.message}") })) } - internal fun trackSearchResultsLoadedInternal(term: String, resultCount: Int, customerIds: Array? = null, analyticsTags: Map? = null): Completable { + + internal fun trackSearchResultsLoadedInternal(term: String, resultCount: Int, customerIds: Array? = null, items: Array? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) - val items = customerIds?.map{ item -> TrackingItem(item, null)} + val itemsList: List? = when { + items != null -> items.toList() + customerIds != null -> customerIds.map { id -> TrackingItem(id, null, null, null) } + else -> null + } val searchResultLoadRequestBody = SearchResultLoadRequestBody( term, - items, + itemsList, resultCount, "Not Available", BuildConfig.CLIENT_VERSION, @@ -1497,7 +1522,7 @@ object ConstructorIo { * @param searchTerm the term that results are displayed for, i.e. "Pumpkin" * @param sectionName the section that the results came from, i.e. "Products" * @param resultID the result ID of the search response that the click came from - */ + */ fun trackSearchResultClick(itemName: String, customerId: String, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, resultID: String? = null) { var completable = trackSearchResultClickInternal(itemName, customerId, null, searchTerm, sectionName, resultID) @@ -1527,9 +1552,9 @@ object ConstructorIo { })) } - internal fun trackSearchResultClickInternal(itemName: String, customerId: String, variationId: String?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, resultID: String? = null): Completable { + internal fun trackSearchResultClickInternal(itemName: String, customerId: String, variationId: String?, searchTerm: String = Constants.QueryConstants.TERM_UNKNOWN, sectionName: String? = null, resultID: String? = null, slCampaignId: String? = null, slCampaignOwner: String? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) - val encodedParams: ArrayList> = getEncodedParams(resultId = resultID) + val encodedParams: ArrayList> = getEncodedParams(resultId = resultID, slCampaignId = slCampaignId, slCampaignOwner = slCampaignOwner) val sName = sectionName ?: preferenceHelper.defaultItemSection return dataManager.trackSearchResultClick(itemName, customerId, variationId, searchTerm, arrayOf( Constants.QueryConstants.SECTION to sName @@ -1622,7 +1647,7 @@ object ConstructorIo { * @param revenue the revenue of the purchase event * @param orderID the identifier of the order * @param analyticsTags Additional analytics tags to pass - */ + */ fun trackPurchase(customerIds: Array, revenue: Double?, orderID: String, sectionName: String? = null, analyticsTags: Map? = null) { val items = customerIds.map { item -> PurchaseItem(item) } var completable = trackPurchaseInternal(items.toTypedArray(), revenue, orderID, sectionName, analyticsTags) @@ -1677,6 +1702,7 @@ object ConstructorIo { } /** + * @deprecated Prefer [trackBrowseResultsLoaded] with an array of [TrackingItem] in place of an array of strings for itemIds. * Tracks browse result loaded (a.k.a. browse results viewed) events. * * Example: @@ -1690,10 +1716,26 @@ object ConstructorIo { * @param analyticsTags Additional analytics tags to pass */ fun trackBrowseResultsLoaded(filterName: String, filterValue: String, itemIds: Array, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { - var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, itemIds, resultCount, sectionName, url, analyticsTags) - disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { - t -> e("Browse Results Loaded error: ${t.message}") - })) + var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, itemIds = itemIds, resultCount = resultCount, sectionName = sectionName, url = url, analyticsTags = analyticsTags) + disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Results Loaded error: ${t.message}") })) + } + + /** + * Tracks browse result loaded (a.k.a. browse results viewed) events. + * + * Example: + * ``` + * ConstructorIo.trackBrowseResultsLoaded("Category", "Snacks", arrayOf(TrackingItem("1234", "2345", "camp1234", "owner-A")), 674) + * ``` + * @param filterName the name of the primary filter, i.e. "Aisle" + * @param filterValue the value of the primary filter, i.e. "Produce" + * @param items the list of the displayed items + * @param resultCount the number of results for that filter name/value pair + * @param analyticsTags Additional analytics tags to pass + */ + fun trackBrowseResultsLoaded(filterName: String, filterValue: String, items: Array, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { + var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, items = items, resultCount = resultCount, sectionName = sectionName, url = url, analyticsTags = analyticsTags) + disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Results Loaded error: ${t.message}") })) } /** @@ -1709,20 +1751,24 @@ object ConstructorIo { * @param analyticsTags Additional analytics tags to pass */ fun trackBrowseResultsLoaded(filterName: String, filterValue: String, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null) { - var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, null, resultCount, sectionName, url, analyticsTags) + var completable = trackBrowseResultsLoadedInternal(filterName, filterValue, null, null, resultCount, sectionName, url, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Results Loaded error: ${t.message}") })) } - internal fun trackBrowseResultsLoadedInternal(filterName: String, filterValue: String, itemIds: Array? = null, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { + internal fun trackBrowseResultsLoadedInternal(filterName: String, filterValue: String, itemIds: Array? = null, items: Array? = null, resultCount: Int, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection - val items = itemIds?.map{ item -> TrackingItem(item, null)} + val itemsList: List? = when { + items != null -> items.toList() + itemIds != null -> itemIds.map { id -> TrackingItem(id, null, null, null) } + else -> null + } val browseResultLoadRequestBody = BrowseResultLoadRequestBody( filterName, filterValue, - items, + itemsList, resultCount, url, BuildConfig.CLIENT_VERSION, @@ -1757,9 +1803,11 @@ object ConstructorIo { * @param sectionName the section that the results came from, i.e. "Products" * @param resultID the result ID of the browse response that the selection came from * @param analyticsTags Additional analytics tags to pass + * @param slCampaignId The campaign id of the clicked item + * @param slCampaignOwner The campaign owner of the clicked item */ - fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null) { - var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, null, resultPositionOnPage, sectionName, resultID, analyticsTags) + fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null, slCampaignId: String? = null, slCampaignOwner: String? = null) { + var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, null, resultPositionOnPage, sectionName, resultID, slCampaignId, slCampaignOwner, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Result Click error: ${t.message}") })) @@ -1780,15 +1828,17 @@ object ConstructorIo { * @param sectionName the section that the results came from, i.e. "Products" * @param resultID the result ID of the browse response that the selection came from * @param analyticsTags Additional analytics tags to pass + * @param slCampaignId The campaign id of the clicked item + * @param slCampaignOwner The campaign owner of the clicked item */ - fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, variationId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null) { - var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, variationId, resultPositionOnPage, sectionName, resultID, analyticsTags) + fun trackBrowseResultClick(filterName: String, filterValue: String, customerId: String, variationId: String, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null, slCampaignId: String? = null, slCampaignOwner: String? = null) { + var completable = trackBrowseResultClickInternal(filterName, filterValue, customerId, variationId, resultPositionOnPage, sectionName, resultID, slCampaignId, slCampaignOwner, analyticsTags) disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { t -> e("Browse Result Click error: ${t.message}") })) } - internal fun trackBrowseResultClickInternal(filterName: String, filterValue: String, customerId: String, variationId: String? = null, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, analyticsTags: Map? = null): Completable { + internal fun trackBrowseResultClickInternal(filterName: String, filterValue: String, customerId: String, variationId: String? = null, resultPositionOnPage: Int, sectionName: String? = null, resultID: String? = null, slCampaignId: String? = null, slCampaignOwner: String? = null, analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection val browseResultClickRequestBody = BrowseResultClickRequestBody( @@ -1808,6 +1858,8 @@ object ConstructorIo { section, System.currentTimeMillis(), resultID, + slCampaignId, + slCampaignOwner, ) return dataManager.trackBrowseResultClick( @@ -2110,7 +2162,7 @@ object ConstructorIo { internal fun trackRecommendationResultsViewInternal(podId: String, itemIds: Array? = null, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map? = null): Completable { preferenceHelper.getSessionId(sessionIncrementHandler) val section = sectionName ?: preferenceHelper.defaultItemSection - val items = itemIds?.map{ item -> TrackingItem(item, null)} + val items = itemIds?.map{ item -> TrackingItem(item, null, null, null)} val recommendationResultViewRequestBody = RecommendationResultViewRequestBody( podId, items, diff --git a/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt b/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt index 86c0de62..cefbdcce 100644 --- a/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt +++ b/library/src/main/java/io/constructor/data/model/browse/BrowseResultClickRequestBody.kt @@ -26,4 +26,6 @@ data class BrowseResultClickRequestBody( @Json(name= "section") val section: String?, @Json(name= "_dt") val _dt: Long?, @Json(name= "result_id") val resultId: String?, + @Json(name = "sl_campaign_id") val slCampaignId: String?, + @Json(name = "sl_campaign_owner") val slCampaignOwner: String?, ) : Serializable diff --git a/library/src/main/java/io/constructor/data/model/common/TrackingItem.kt b/library/src/main/java/io/constructor/data/model/common/TrackingItem.kt index 44766cf4..23d14b1d 100644 --- a/library/src/main/java/io/constructor/data/model/common/TrackingItem.kt +++ b/library/src/main/java/io/constructor/data/model/common/TrackingItem.kt @@ -11,4 +11,6 @@ import java.io.Serializable data class TrackingItem( @Json(name = "item_id") val itemId: String?, @Json(name = "variation_id") val variationId: String?, + @Json(name = "sl_campaign_id") val slCampaignId: String?, + @Json(name = "sl_campaign_owner") val slCampaignOwner: String?, ) : Serializable diff --git a/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt b/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt index 89cf9df1..8e864163 100644 --- a/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorIoIntegrationTest.kt @@ -5,6 +5,7 @@ import io.constructor.data.builder.* import io.constructor.data.local.PreferencesHelper import io.constructor.data.memory.ConfigMemoryHolder import io.constructor.data.model.common.VariationsMap +import io.constructor.data.model.common.TrackingItem import io.constructor.data.model.purchase.PurchaseItem import io.constructor.test.createTestDataManager import io.constructor.util.RxSchedulersOverrideRule @@ -29,6 +30,8 @@ class ConstructorIoIntegrationTest { private val preferencesHelper = mockk() private val configMemoryHolder = mockk() private val timeBetweenTests = 2000.toLong() + private val testCampaignId = "cmp123" + private val testCampaignOwner = "desktop" @Before fun setup() { @@ -973,6 +976,22 @@ class ConstructorIoIntegrationTest { Thread.sleep(timeBetweenTests) } + @Test + fun trackSearchResultClickWithCampaignParamsAgainstRealResponse() { + val observer = constructorIo.trackSearchResultClickInternal( + "Boneless Pork Shoulder Roast", + "prrst_shldr_bls", + null, + "pork", + null, + null, + testCampaignId, + testCampaignOwner + ).test() + observer.assertComplete() + Thread.sleep(timeBetweenTests) + } + @Test fun trackSearchResultsLoadedAgainstRealResponse() { val observer = constructorIo.trackSearchResultsLoadedInternal("titanic", 10, arrayOf("123", "234")).test() @@ -980,6 +999,17 @@ class ConstructorIoIntegrationTest { Thread.sleep(timeBetweenTests) } + @Test + fun trackSearchResultsLoadedWithCampaignParamsAgainstRealResponse() { + val items = arrayOf( + TrackingItem("123", null, testCampaignId, testCampaignOwner), + TrackingItem("234", null, testCampaignId, testCampaignOwner), + ) + val observer = constructorIo.trackSearchResultsLoadedInternal("titanic", 10, items = items).test() + observer.assertComplete() + Thread.sleep(timeBetweenTests) + } + @Test fun trackConversionAgainstRealResponse() { val observer = constructorIo.trackConversionInternal( @@ -1034,7 +1064,18 @@ class ConstructorIoIntegrationTest { @Test fun trackBrowseResultsLoadedAgainstRealResponse() { - val observer = constructorIo.trackBrowseResultsLoadedInternal("group_ids", "544", arrayOf("123", "234"), 10).test() + val observer = constructorIo.trackBrowseResultsLoadedInternal("group_ids", "544", arrayOf("123", "234"), null, 10).test() + observer.assertComplete() + Thread.sleep(timeBetweenTests) + } + + @Test + fun trackBrowseResultsLoadedWithCampaignParamsAgainstRealResponse() { + val items = arrayOf( + TrackingItem("123", null, testCampaignId, testCampaignOwner), + TrackingItem("234", null, testCampaignId, testCampaignOwner), + ) + val observer = constructorIo.trackBrowseResultsLoadedInternal("group_ids", "544", items = items, resultCount = 10).test() observer.assertComplete() Thread.sleep(timeBetweenTests) } @@ -1057,6 +1098,23 @@ class ConstructorIoIntegrationTest { Thread.sleep(timeBetweenTests) } + @Test + fun trackBrowseResultClickWithCampaignParamsAgainstRealResponse() { + val observer = constructorIo.trackBrowseResultClickInternal( + "group_ids", + "544", + "prrst_shldr_bls", + null, + 5, + "Products", + null, + testCampaignId, + testCampaignOwner + ).test() + observer.assertComplete() + Thread.sleep(timeBetweenTests) + } + @Test fun trackItemDetailLoadedAgainstRealResponse() { val observer = constructorIo.trackItemDetailLoadedInternal("Pencil", "1234").test() diff --git a/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt b/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt index 4511f9e5..517244ef 100755 --- a/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt +++ b/library/src/test/java/io/constructor/core/ConstructorIoTrackingTest.kt @@ -5,6 +5,7 @@ import io.constructor.data.local.PreferencesHelper import io.constructor.data.memory.ConfigMemoryHolder import io.constructor.data.model.common.ResultGroup import io.constructor.data.model.purchase.PurchaseItem +import io.constructor.data.model.common.TrackingItem import io.constructor.test.createTestDataManager import io.constructor.util.RxSchedulersOverrideRule import io.mockk.every @@ -370,6 +371,23 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackSearchResultLoadedWithCampaignItemsArray() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val items = arrayOf( + TrackingItem("123", "RED", "cmp123", "ownerA"), + TrackingItem("234", null, "cmp456", "ownerB") + ) + val observer = ConstructorIo.trackSearchResultsLoadedInternal("titanic", 10, null, items).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + assert(requestBody["items"]!!.contains("sl_campaign_owner:ownerA")) + assert(requestBody["items"]!!.contains("sl_campaign_id:cmp123")) + assertEquals("POST", request.method) + } + @Test fun trackSearchResultLoadedWithCustomerIDs() { val mockResponse = MockResponse().setResponseCode(204) @@ -437,6 +455,26 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackSearchResultClickWithCampaignParams() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackSearchResultClickInternal( + "Fancy Item", + "123", + null, + "titanic", + "Products", + "abc", + "cmp123", + "ownerA" + ).test() + observer.assertComplete() + val request = mockServer.takeRequest() + assert(request.path!!.contains("sl_campaign_id=cmp123")) + assert(request.path!!.contains("sl_campaign_owner=ownerA")) + } + @Test fun trackSearchResultClickWithVariationId() { val mockResponse = MockResponse().setResponseCode(204) @@ -737,7 +775,7 @@ class ConstructorIoTrackingTest { fun trackBrowseResultLoaded() { val mockResponse = MockResponse().setResponseCode(204) mockServer.enqueue(mockResponse) - val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, 10).test() + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, null, 10).test() observer.assertComplete() val request = mockServer.takeRequest() val requestBody = getRequestBody(request) @@ -750,11 +788,28 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackBrowseResultLoadedWithCampaignItemsArray() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val items = arrayOf( + TrackingItem("123", null, "cmp123", "ownerA"), + TrackingItem("234", null, "cmp456", "ownerB") + ) + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, items, 10).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + assert(requestBody["items"]!!.contains("sl_campaign_owner:ownerA")) + assert(requestBody["items"]!!.contains("sl_campaign_id:cmp123")) + assertEquals("POST", request.method) + } + @Test fun trackBrowseResultLoadedWithAnalyticsTags() { val mockResponse = MockResponse().setResponseCode(204) mockServer.enqueue(mockResponse) - val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, 10, null, analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, null,10, null, analyticsTags = mapOf("test" to "test1", "appVersion" to "150")).test() observer.assertComplete() val request = mockServer.takeRequest() val requestBody = getRequestBody(request) @@ -773,7 +828,7 @@ class ConstructorIoTrackingTest { val mockResponse = MockResponse().setResponseCode(204) mockServer.enqueue(mockResponse) val items = arrayOf("123", "234"); - val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", items, 10).test() + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", items, null, 10).test() observer.assertComplete() val request = mockServer.takeRequest() val requestBody = getRequestBody(request) @@ -790,7 +845,7 @@ class ConstructorIoTrackingTest { fun trackBrowseResultLoaded500() { val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") mockServer.enqueue(mockResponse) - val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, 10).test() + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, null,10).test() observer.assertError { true } val request = mockServer.takeRequest() val requestBody = getRequestBody(request) @@ -807,7 +862,7 @@ class ConstructorIoTrackingTest { val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") mockResponse.throttleBody(0, 5, TimeUnit.SECONDS) mockServer.enqueue(mockResponse) - val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, 10).test() + val observer = ConstructorIo.trackBrowseResultsLoadedInternal("group_id", "Movies", null, null,10).test() observer.assertError(SocketTimeoutException::class.java) val request = mockServer.takeRequest(10, TimeUnit.SECONDS) assertEquals(null, request) @@ -832,6 +887,28 @@ class ConstructorIoTrackingTest { assert(request.path!!.startsWith(path)) } + @Test + fun trackBrowseResultClickWithCampaignParams() { + val mockResponse = MockResponse().setResponseCode(204) + mockServer.enqueue(mockResponse) + val observer = ConstructorIo.trackBrowseResultClickInternal( + "group_id", + "Movies", + "123", + null, + 4, + "Products", + "xyz", + "cmp123", + "ownerA" + ).test() + observer.assertComplete() + val request = mockServer.takeRequest() + val requestBody = getRequestBody(request) + assertEquals("cmp123", requestBody["sl_campaign_id"]) + assertEquals("ownerA", requestBody["sl_campaign_owner"]) + } + @Test fun trackBrowseResultClickWithAnalyticsTags() { val mockResponse = MockResponse().setResponseCode(204)