Cdx 429 add result offset parameter support to js sdk tracker#463
Conversation
…t-to-js-sdk-tracker
There was a problem hiding this comment.
Pull request overview
Adds resultOffset support to the JavaScript SDK tracker to better support infinite-scroll/offset-based result pagination across multiple tracking events, with corresponding TypeScript typing updates and test coverage.
Changes:
- Added
resultOffsetparameter handling to several tracker event payloads (search results loaded, recommendations, browse, generic click, quizzes). - Updated
src/types/tracker.d.tsto exposeresultOffset?: numberon the relevant tracker method parameter types. - Expanded tracker specs to validate
result_offsetinclusion/omission and backend error behavior when combined withresultPage, plus minor test refactors (spread vsObject.assign).
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/types/tracker.d.ts |
Extends Tracker TypeScript declarations to include resultOffset in multiple method parameter shapes. |
src/modules/tracker.js |
Adds result_offset request body support (and validation in quiz methods) for offset-based tracking. |
spec/src/modules/tracker.js |
Adds/updates tests to cover resultOffset behavior and refactors parameter merging to object spread. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @param {string} [parameters.itemName] - Product item name | ||
| * @param {string} [parameters.variationId] - Product item variation unique identifier | ||
| * @param {string} [parameters.section="Products"] - Index section | ||
| * @param {number} [parameters.resultOffset] - Current offset of results, used on scrolling sites. Cannot be used with `resultPage` |
There was a problem hiding this comment.
@Sher-Bakhodirov I think this makes sense. Wdyt?
esezen
left a comment
There was a problem hiding this comment.
PR is looking good overall. I left some comments
| * @param {string} [parameters.itemName] - Product item name | ||
| * @param {string} [parameters.variationId] - Product item variation unique identifier | ||
| * @param {string} [parameters.section="Products"] - Index section | ||
| * @param {number} [parameters.resultOffset] - Current offset of results, used on scrolling sites. Cannot be used with `resultPage` |
There was a problem hiding this comment.
@Sher-Bakhodirov I think this makes sense. Wdyt?
|
|
||
| expect( | ||
| tracker.trackMediaImpressionView( | ||
| Object.assign(requiredParameters, optionalParameters), |
There was a problem hiding this comment.
Object.assign(requiredParameters, optionalParameters) mutates requiredParameters in place, so optional params leaked into tests that should only use the required ones. The change just avoids mutating the shared object. I can revert if you'd rather keep it out of this PR
There was a problem hiding this comment.
Makes sense. We can keep it
| @@ -676,6 +676,7 @@ class Tracker { | |||
| * @param {object[]} parameters.items - List of product item unique identifiers in search results listing | |||
There was a problem hiding this comment.
Not related to this line but can we please add offset to trackSearchResultClickV2 and trackSearchResultClick as well?
There was a problem hiding this comment.
For trackSearchResultClick, it's using a legacy endpoint that doesn't support result_offset. And trackSearchResultClickV2 uses an endpoint that wasn't listed in the ticket, so I think we'd want to verify it supports result_offset before adding it. I can include both if you can confirm
There was a problem hiding this comment.
If V1 doesn't support it, we can skip it. Let's add it to V2. Thank you!
There was a problem hiding this comment.
Code Review
This PR adds resultOffset parameter support across multiple tracker functions and fixes test pollution caused by Object.assign mutating shared requiredParameters. The implementation is largely consistent and well-tested, but there are notable inconsistencies in how resultOffset is written to bodyParams and how input validation is applied across functions.
Inline comments: 7 discussions added
Overall Assessment:
| expect(tracker.trackSearchResultsLoaded(term, parameters)).to.equal(true); | ||
| }); | ||
|
|
||
| it('Should return valid response when resultOffset is passed as an integer', (done) => { |
There was a problem hiding this comment.
Suggestion: Tests for trackSearchResultsLoaded, trackSearchResultClickV2, trackRecommendationView, trackRecommendationClick, trackBrowseResultsLoaded, and trackBrowseResultClick all include a "Should receive error from backend when both resultPage and resultOffset are passed" case — but trackGenericResultClick has no such conflict test. This is probably intentional since trackGenericResultClick has no resultPage concept, but if the backend could still reject some combination, it's worth a comment. The trackGenericResultClick tests also have no "resultOffset is not a number" test unlike trackQuizResultsLoaded/trackQuizResultClick, which is consistent with the missing type validation noted above.
| expect(tracker.trackSearchResultClickV2(term, { ...requiredParameters, ...optionalParameters, ...v2Parameters })).to.equal(true); | ||
| }); | ||
|
|
||
| it('V2 Should return valid response when resultOffset is passed as an integer', (done) => { |
There was a problem hiding this comment.
Suggestion: The trackSearchResultClickV2 tests are prefixed with V2 (e.g. 'V2 Should return valid response when resultOffset is passed as an integer'), but they live inside the trackSearchResultClick describe block alongside the V1 tests. All other resultOffset tests in this PR follow the standard sentence-case naming. Consider using a nested describe('trackSearchResultClickV2') block or at least a consistent naming prefix. This makes test output and debugging easier.
| // Request | ||
| expect(fetchSpy).to.have.been.called; | ||
| expect(requestParams).to.have.property('section').to.equal(requiredParameters.section); | ||
| expect(requestParams).to.have.property('section').to.equal(optionalParameters.section); |
There was a problem hiding this comment.
Important Issue: This is a pre-existing bug fix bundled into the PR — the assertion previously checked requiredParameters.section but should check optionalParameters.section. While the fix is correct, it changes behavior of an existing test and should be called out explicitly in the PR description or as a separate commit to make the history clear. The PR description mentions test cleanup for Object.assign mutation, but this section fix is a distinct correctness fix that should be noted separately.
| }); | ||
|
|
||
| expect(tracker.trackSearchResultsLoaded(term, Object.assign(requiredParameters, optionalParameters))) | ||
| expect(tracker.trackSearchResultsLoaded(term, { ...requiredParameters, ...optionalParameters })) |
There was a problem hiding this comment.
Suggestion: The "omit result_offset when resultOffset is not provided" tests (for all functions) only pass ...requiredParameters without resultOffset and assert the property is absent. Consider also testing the boundary where resultOffset: 0 is passed — since 0 is a valid integer offset but is falsy, and some guard patterns might accidentally filter it out. The isNil helper should handle this correctly, but an explicit test for resultOffset: 0 would confirm the behavior and prevent regression.
esezen
left a comment
There was a problem hiding this comment.
Thanks for making the changes!
Summary
Adds support for the
resultOffsetparameter across the tracker functionsChanges
Added the
resultOffsetparameter to the following tracker functions:trackSearchResultsLoadedtrackBrowseResultsLoadedtrackBrowseResultClicktrackRecommendationViewtrackRecommendationClicktrackGenericResultClickIntentionally Excluded
resultOffsetwas not added to the following functions:trackSearchResultClick— uses the legacy backend endpoint, which does not supportresult_offset.Test Cleanup
The tests previously used the pattern
Object.assign(requiredParameters, optionalParameters), which mutates the originalrequiredParametersobject by merging the optional parameters into it. This caused optional parameters to leak into test cases that were only meant to use the required parameters. Updated these spots to avoid mutating the shared object.