|
| 1 | +import type { ClientOptions, UserContext } from '@growthbook/growthbook'; |
| 2 | +import { GrowthBookClient } from '@growthbook/growthbook'; |
1 | 3 | import { _INTERNAL_FLAG_BUFFER_SIZE as FLAG_BUFFER_SIZE } from '@sentry/core'; |
2 | 4 | import * as Sentry from '@sentry/node'; |
3 | 5 | import { loggingTransport } from '@sentry-internal/node-integration-tests'; |
4 | 6 |
|
5 | | -// Minimal GrowthBook-like class that matches the real API for testing |
6 | | -// This is necessary since we don't want to add @growthbook/growthbook as a dependency |
7 | | -// just for integration tests, but we want to test the actual integration behavior |
8 | | -class GrowthBookLike { |
9 | | - private _features: Record<string, { value: unknown }> = {}; |
| 7 | +// Wrapper class to instantiate GrowthBookClient |
| 8 | +class GrowthBookWrapper { |
| 9 | + private _gbClient: GrowthBookClient; |
| 10 | + private _userContext: UserContext = { attributes: { id: 'test-user-123' } }; |
10 | 11 |
|
11 | | - public isOn(featureKey: string): boolean { |
12 | | - const feature = this._features[featureKey]; |
13 | | - return feature ? !!feature.value : false; |
| 12 | + public constructor(..._args: unknown[]) { |
| 13 | + // Create GrowthBookClient with proper configuration |
| 14 | + const clientOptions: ClientOptions = { |
| 15 | + apiHost: 'https://cdn.growthbook.io', |
| 16 | + clientKey: 'sdk-abc123' |
| 17 | + }; |
| 18 | + this._gbClient = new GrowthBookClient(clientOptions); |
| 19 | + |
| 20 | + // Create features for testing |
| 21 | + const features = this._createTestFeatures(); |
| 22 | + |
| 23 | + this._gbClient.initSync({ |
| 24 | + payload: { features } |
| 25 | + }); |
14 | 26 | } |
15 | 27 |
|
16 | | - public getFeatureValue(featureKey: string, defaultValue: unknown): unknown { |
17 | | - const feature = this._features[featureKey]; |
18 | | - return feature ? feature.value : defaultValue; |
| 28 | + public isOn(featureKey: string, ..._rest: unknown[]): boolean { |
| 29 | + return this._gbClient.isOn(featureKey, this._userContext); |
19 | 30 | } |
20 | 31 |
|
21 | | - // Helper method to set feature values for testing |
22 | | - public setFeature(featureKey: string, value: unknown): void { |
23 | | - this._features[featureKey] = { value }; |
| 32 | + public getFeatureValue(featureKey: string, defaultValue: unknown, ..._rest: unknown[]): unknown { |
| 33 | + return this._gbClient.getFeatureValue(featureKey, defaultValue as boolean | string | number, this._userContext); |
| 34 | + } |
| 35 | + |
| 36 | + private _createTestFeatures(): Record<string, { defaultValue: unknown }> { |
| 37 | + const features: Record<string, { defaultValue: unknown }> = {}; |
| 38 | + |
| 39 | + // Fill buffer with flags 1-100 (all false by default) |
| 40 | + for (let i = 1; i <= FLAG_BUFFER_SIZE; i++) { |
| 41 | + features[`feat${i}`] = { defaultValue: false }; |
| 42 | + } |
| 43 | + |
| 44 | + // Add feat101 (true), which should evict feat1 |
| 45 | + features[`feat${FLAG_BUFFER_SIZE + 1}`] = { defaultValue: true }; |
| 46 | + |
| 47 | + // Update feat3 to true, which should move it to the end |
| 48 | + features['feat3'] = { defaultValue: true }; |
| 49 | + |
| 50 | + // Test features with boolean values (should be captured) |
| 51 | + features['bool-feat'] = { defaultValue: true }; |
| 52 | + |
| 53 | + // Test features with non-boolean values (should NOT be captured) |
| 54 | + features['string-feat'] = { defaultValue: 'hello' }; |
| 55 | + features['number-feat'] = { defaultValue: 42 }; |
| 56 | + |
| 57 | + return features; |
24 | 58 | } |
25 | 59 | } |
26 | 60 |
|
27 | 61 | Sentry.init({ |
28 | 62 | dsn: 'https://public@dsn.ingest.sentry.io/1337', |
29 | 63 | sampleRate: 1.0, |
30 | 64 | transport: loggingTransport, |
31 | | - integrations: [Sentry.growthbookIntegration({ growthbookClass: GrowthBookLike })], |
| 65 | + integrations: [Sentry.growthbookIntegration({ growthbookClass: GrowthBookWrapper })], |
32 | 66 | }); |
33 | 67 |
|
34 | | -const gb = new GrowthBookLike(); |
| 68 | +// Create GrowthBookWrapper instance |
| 69 | +const gb = new GrowthBookWrapper(); |
35 | 70 |
|
36 | 71 | // Fill buffer with flags 1-100 (all false by default) |
37 | 72 | for (let i = 1; i <= FLAG_BUFFER_SIZE; i++) { |
38 | 73 | gb.isOn(`feat${i}`); |
39 | 74 | } |
40 | 75 |
|
41 | 76 | // Add feat101 (true), which should evict feat1 |
42 | | -gb.setFeature(`feat${FLAG_BUFFER_SIZE + 1}`, true); |
43 | 77 | gb.isOn(`feat${FLAG_BUFFER_SIZE + 1}`); |
44 | 78 |
|
45 | 79 | // Update feat3 to true, which should move it to the end |
46 | | -gb.setFeature('feat3', true); |
47 | 80 | gb.isOn('feat3'); |
48 | 81 |
|
49 | 82 | // Test getFeatureValue with boolean values (should be captured) |
50 | | -gb.setFeature('bool-feat', true); |
51 | 83 | gb.getFeatureValue('bool-feat', false); |
52 | 84 |
|
53 | 85 | // Test getFeatureValue with non-boolean values (should NOT be captured) |
54 | | -gb.setFeature('string-feat', 'hello'); |
55 | 86 | gb.getFeatureValue('string-feat', 'default'); |
56 | | -gb.setFeature('number-feat', 42); |
57 | 87 | gb.getFeatureValue('number-feat', 0); |
58 | 88 |
|
59 | 89 | throw new Error('Test error'); |
0 commit comments