Skip to content

Commit 90e4730

Browse files
abbaseyaclaude
andcommitted
fix(context): forward all BucketingAttributes to ExperienceManager
Context.runExperience and Context.runExperiences rebuilt a fresh attributes object with only four hardcoded keys (visitorProperties, locationProperties, updateVisitorProperties, environment) before forwarding to ExperienceManager.selectVariation/selectVariations. This silently dropped every other BucketingAttributes field — enableTracking, forceVariationId, ignoreLocationProperties, typeCasting, experienceKeys — so callers opting out of tracking, forcing a variation, or ignoring location targeting were silently ignored. DataManager._getBucketingByField destructures these by name with enableTracking defaulting to `true`, which is how the opt-out was being lost. Switch to spread-then-override so all caller-supplied attributes pass through while still applying the two transforms Context must do: merging visitorProperties via getVisitorProperties() and defaulting environment to the Context's own environment. Add tests covering forwarding of enableTracking, forceVariationId, ignoreLocationProperties, and updateVisitorProperties through both runExperience and runExperiences. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d4e3ef4 commit 90e4730

2 files changed

Lines changed: 74 additions & 4 deletions

File tree

packages/js-sdk/src/context.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,8 @@ export class Context implements ContextInterface {
136136
this._visitorId,
137137
experienceKey,
138138
{
139+
...attributes,
139140
visitorProperties, // represents audiences
140-
locationProperties: attributes?.locationProperties, // represents site_area/locations
141-
updateVisitorProperties: attributes?.updateVisitorProperties,
142141
environment: attributes?.environment || this._environment
143142
}
144143
);
@@ -190,9 +189,8 @@ export class Context implements ContextInterface {
190189
const bucketedVariations = this._experienceManager.selectVariations(
191190
this._visitorId,
192191
{
192+
...attributes,
193193
visitorProperties, // represents audiences
194-
locationProperties: attributes?.locationProperties, // represents site_area/locations
195-
updateVisitorProperties: attributes?.updateVisitorProperties,
196194
environment: attributes?.environment || this._environment
197195
}
198196
);

packages/js-sdk/tests/context.tests.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,78 @@ describe('Context tests', function () {
179179
done
180180
);
181181
});
182+
it('Should forward BucketingAttributes (enableTracking, forceVariationId, ignoreLocationProperties) through runExperience', function () {
183+
const experienceKey = 'test-experience-ab-fullstack-2';
184+
const originalSelectVariation =
185+
experienceManager.selectVariation.bind(experienceManager);
186+
let capturedAttributes;
187+
experienceManager.selectVariation = function (
188+
capturedVisitorId,
189+
capturedExperienceKey,
190+
attributes
191+
) {
192+
capturedAttributes = attributes;
193+
return originalSelectVariation(
194+
capturedVisitorId,
195+
capturedExperienceKey,
196+
attributes
197+
);
198+
};
199+
try {
200+
context.runExperience(experienceKey, {
201+
locationProperties: {url: 'https://convert.com/'},
202+
visitorProperties: {varName3: 'something'},
203+
enableTracking: false,
204+
forceVariationId: '100299461',
205+
ignoreLocationProperties: true,
206+
updateVisitorProperties: true
207+
});
208+
expect(capturedAttributes).to.include({
209+
enableTracking: false,
210+
forceVariationId: '100299461',
211+
ignoreLocationProperties: true,
212+
updateVisitorProperties: true
213+
});
214+
expect(capturedAttributes.locationProperties).to.deep.equal({
215+
url: 'https://convert.com/'
216+
});
217+
} finally {
218+
experienceManager.selectVariation = originalSelectVariation;
219+
}
220+
});
221+
it('Should forward BucketingAttributes (enableTracking, forceVariationId, ignoreLocationProperties) through runExperiences', function () {
222+
const originalSelectVariations =
223+
experienceManager.selectVariations.bind(experienceManager);
224+
let capturedAttributes;
225+
experienceManager.selectVariations = function (
226+
capturedVisitorId,
227+
attributes
228+
) {
229+
capturedAttributes = attributes;
230+
return originalSelectVariations(capturedVisitorId, attributes);
231+
};
232+
try {
233+
context.runExperiences({
234+
locationProperties: {url: 'https://convert.com/'},
235+
visitorProperties: {varName3: 'something'},
236+
enableTracking: false,
237+
forceVariationId: '100299461',
238+
ignoreLocationProperties: true,
239+
updateVisitorProperties: true
240+
});
241+
expect(capturedAttributes).to.include({
242+
enableTracking: false,
243+
forceVariationId: '100299461',
244+
ignoreLocationProperties: true,
245+
updateVisitorProperties: true
246+
});
247+
expect(capturedAttributes.locationProperties).to.deep.equal({
248+
url: 'https://convert.com/'
249+
});
250+
} finally {
251+
experienceManager.selectVariations = originalSelectVariations;
252+
}
253+
});
182254
it('Shoud successfully get a single feature and its status', function (done) {
183255
this.timeout(test_timeout);
184256
getSingleFeatureWithStatus(

0 commit comments

Comments
 (0)