Conversation
There was a problem hiding this comment.
Pull request overview
Adds support for passing seedItemIds through the SDK’s recommendation tracking APIs so recommendation view/click events can include seed item identifiers in their request payloads.
Changes:
- Extend
trackRecommendationResultsViewandtrackRecommendationResultClickpublic APIs to accept optionalseedItemIds. - Include
seed_item_idsin the HTTP body for recommendation view/click tracking request data when provided and non-empty. - Add/extend XCTest coverage for request payload building and tracking calls (plus an unrelated quiz integration test constant update).
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| AutocompleteClient/FW/Logic/Worker/ConstructorIO.swift | Adds seedItemIds parameter + forwards into request data; updates doc examples. |
| AutocompleteClient/FW/Logic/Request/CIOTrackRecommendationResultsViewData.swift | Adds seedItemIds to request data and conditionally serializes seed_item_ids into payload. |
| AutocompleteClient/FW/Logic/Request/CIOTrackRecommendationResultClickData.swift | Adds seedItemIds to request data and conditionally serializes seed_item_ids into payload. |
| AutocompleteClientTests/FW/Logic/Worker/ConstructorIOTrackRecommendationResultsViewTests.swift | Adds worker-level test calling trackRecommendationResultsView(..., seedItemIds:). |
| AutocompleteClientTests/FW/Logic/Worker/ConstructorIOTrackRecommendationResultClickTests.swift | Adds worker-level test calling trackRecommendationResultClick(..., seedItemIds:). |
| AutocompleteClientTests/FW/Logic/Request/TrackRecommendationViewRequestBuilder.swift | Adds request-builder payload tests for seed_item_ids (single/multiple/empty). |
| AutocompleteClientTests/FW/Logic/Request/TrackRecommendationResultClickRequestBuilder.swift | Adds request-builder payload tests for seed_item_ids (single/multiple/empty). |
| AutocompleteClientTests/FW/Logic/Worker/ConstructorIOQuizIntegrationTests.swift | Updates quizVersionID constant used in quiz integration tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let analyticsTags: [String: String]? | ||
| let seedItemIds: [String]? | ||
|
|
There was a problem hiding this comment.
The struct header comment is inaccurate/duplicated (it says "track browse result click" and "set set"), and now that seedItemIds was added this is a good time to correct it to reflect tracking recommendation results views and fix the wording.
| let analyticsTags: [String: String]? | ||
| let seedItemIds: [String]? | ||
|
|
There was a problem hiding this comment.
The struct header comment is inaccurate/duplicated (it says "track browse result click" and "set set"), and now that seedItemIds was added this is a good time to correct it to reflect tracking recommendation result clicks and fix the wording.
There was a problem hiding this comment.
Not related to your change but can we please fix this?
| public func trackRecommendationResultsView(podID: String, numResultsViewed: Int? = nil, customerIDs: [String]? = nil, resultPage: Int? = nil, resultCount: Int? = nil, sectionName: String? = nil, resultID: String? = nil, analyticsTags: [String: String]? = nil, seedItemIds: [String]? = nil, completionHandler: TrackingCompletionHandler? = nil) { | ||
| let section = sectionName ?? self.config.defaultItemSectionName ?? Constants.Track.defaultItemSectionName | ||
| let data = CIOTrackRecommendationResultsViewData(podID: podID, numResultsViewed: numResultsViewed, customerIDs: customerIDs, resultPage: resultPage, resultCount: resultCount, sectionName: section, resultID: resultID, analyticsTags: mergeDictionary(baseDictionary: self.config.defaultAnalyticsTags, newDictionary: analyticsTags)) | ||
| let data = CIOTrackRecommendationResultsViewData(podID: podID, numResultsViewed: numResultsViewed, customerIDs: customerIDs, resultPage: resultPage, resultCount: resultCount, sectionName: section, resultID: resultID, analyticsTags: mergeDictionary(baseDictionary: self.config.defaultAnalyticsTags, newDictionary: analyticsTags), seedItemIds: seedItemIds) |
There was a problem hiding this comment.
seedItemIds is inconsistent with the existing public API’s acronym casing (e.g. customerIDs, variationID). Consider renaming this new parameter to seedItemIDs (and updating the corresponding data structs) for consistency before this API ships.
| let analyticsTags: [String: String]? | ||
| let seedItemIds: [String]? | ||
|
|
There was a problem hiding this comment.
Not related to your change but can we please fix this?
| let analyticsTags: [String: String]? | ||
| let seedItemIds: [String]? | ||
|
|
…-item-ids-to-rex-events
There was a problem hiding this comment.
Code Review
This PR adds seedItemIds support to trackRecommendationResultClick and trackRecommendationResultsView — the implementation is clean, consistent with existing patterns, and well-tested.
Inline comments: 5 discussions added
Overall Assessment:
| fileprivate let unitTestKey = "key_vM4GkLckwiuxwyRA" | ||
| fileprivate let session = 90 | ||
| fileprivate let quizVersionID = "5334fed4-7a54-4049-b609-e9d3d3f39591" | ||
| fileprivate let quizVersionID = "cc8a9dac-d337-4dbc-bbf7-48469c0de7af" |
There was a problem hiding this comment.
Important Issue: This change to quizVersionID appears unrelated to the PR's stated goal of adding seedItemIds to recommendation events. Is this an incidental fix or a leftover change? If the old UUID was stale/expired and needed updating, that context should be noted in the PR description. If it's a leftover, it should be reverted to keep this PR focused.
| let builder = CIOBuilder(expectation: "Calling trackAutocompleteSelect should send a valid request.", builder: http(200)) | ||
|
|
||
| stub(regex("https://ac.cnstrc.com/autocomplete/corn/select?_dt=\(kRegexTimestamp)&c=\(kRegexVersion)&i=\(kRegexClientID)&key=\(kRegexAutocompleteKey)&original_query=co&item_id=0123456789&s=\(kRegexSession)§ion=Search%20Suggestions&tr=click&\(TestConstants.defaultSegments)"), builder.create()) | ||
| stub(regex("https://ac.cnstrc.com/autocomplete/corn/select?_dt=\(kRegexTimestamp)&c=\(kRegexVersion)&i=\(kRegexClientID)&item_id=0123456789&key=\(kRegexAutocompleteKey)&original_query=co&s=\(kRegexSession)§ion=Search%20Suggestions&tr=click&\(TestConstants.defaultSegments)"), builder.create()) |
There was a problem hiding this comment.
Important Issue: This stub URL change (reordering item_id before key) is unrelated to the seedItemIds feature. Like the quiz version ID change, this appears to be a pre-existing fix bundled into this PR. Please either:
- Move it into a separate commit/PR with its own context, or
- Document in the PR description why query parameter ordering changed here.
Mixing unrelated fixes makes the diff harder to review and the git history harder to bisect.
| self.wait(for: expectation) | ||
| } | ||
|
|
||
| func testTrackRecommendationResultClick_WithSeedItemIds() { |
There was a problem hiding this comment.
Suggestion: The integration test verifies that the HTTP call is made successfully, but it doesn't assert that seed_item_ids is actually included in the POST body. Other tests in the TrackRecommendationResultClickRequestBuilder file do verify the payload, but the integration-level test only stubs the URL regex (which has no body matching).
This is consistent with the existing integration test pattern in this codebase (e.g., testTrackRecommendationResultClick_WithOptionalParams also doesn't inspect the body), so it's not a blocker — but it means the integration tests cannot catch a regression where seedItemIds is passed through correctly at the API boundary but incorrectly serialized. The request-builder tests cover serialization, so coverage is adequate overall.
| if (self.analyticsTags != nil) { | ||
| dict["analytics_tags"] = self.analyticsTags | ||
| } | ||
| if let seedItemIds = self.seedItemIds, !seedItemIds.isEmpty { |
There was a problem hiding this comment.
Suggestion: The seedItemIds encoding uses if let … !isEmpty while every other optional in the same httpBody method uses the bare if self.x != nil style (e.g., if self.strategyID != nil, if (self.analyticsTags != nil)). The compound guard is correct and reasonable (you rightly want to skip an empty array), but for readability and consistency with surrounding code it could be written as:
if let seedItemIds = self.seedItemIds, !seedItemIds.isEmpty {
dict["seed_item_ids"] = seedItemIds
}That's exactly what's already here — the style is fine. However, note that analyticsTags uses a parenthesized nil check if (self.analyticsTags != nil) which differs from the Swift-idiomatic style used everywhere else. The new seedItemIds code is actually more idiomatic than the surrounding code, so no change is needed here.
|
|
||
| XCTAssertEqual(request.httpMethod, "POST") | ||
| XCTAssertEqual(loadedSeedItemIds.count, 1) | ||
| XCTAssertEqual(loadedSeedItemIds[0], seedItemIds[0]) |
There was a problem hiding this comment.
Suggestion: In testTrackRecommendationResultClickBuilder_WithSingleSeedItemId, after already asserting loadedSeedItemIds.count == 1, the direct index access loadedSeedItemIds[0] is safe but redundant with the XCTAssertEqual(loadedSeedItemIds, seedItemIds) pattern used in the multiple-IDs test. Consider using XCTAssertEqual(loadedSeedItemIds, seedItemIds) here too for consistency — it checks both count and values in one assertion and matches the style of testTrackRecommendationResultClickBuilder_WithMultipleSeedItemIds. The same applies to the parallel test in TrackRecommendationViewRequestBuilder.swift.
Adds support for
seedItemIdsfor recommendation events:trackRecommendationResultClicktrackRecommendationResultsView