Skip to content

Commit 03437b1

Browse files
committed
Use actual growthbook instance for testing
1 parent 9fbd558 commit 03437b1

File tree

3 files changed

+87
-42
lines changed

3 files changed

+87
-42
lines changed

dev-packages/node-integration-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@anthropic-ai/sdk": "0.63.0",
2727
"@aws-sdk/client-s3": "^3.552.0",
2828
"@google/genai": "^1.20.0",
29+
"@growthbook/growthbook": "^1.6.1",
2930
"@hapi/hapi": "^21.3.10",
3031
"@hono/node-server": "^1.19.4",
3132
"@nestjs/common": "11.1.3",
Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,89 @@
1+
import type { ClientOptions, UserContext } from '@growthbook/growthbook';
2+
import { GrowthBookClient } from '@growthbook/growthbook';
13
import { _INTERNAL_FLAG_BUFFER_SIZE as FLAG_BUFFER_SIZE } from '@sentry/core';
24
import * as Sentry from '@sentry/node';
35
import { loggingTransport } from '@sentry-internal/node-integration-tests';
46

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' } };
1011

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+
});
1426
}
1527

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);
1930
}
2031

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;
2458
}
2559
}
2660

2761
Sentry.init({
2862
dsn: 'https://[email protected]/1337',
2963
sampleRate: 1.0,
3064
transport: loggingTransport,
31-
integrations: [Sentry.growthbookIntegration({ growthbookClass: GrowthBookLike })],
65+
integrations: [Sentry.growthbookIntegration({ growthbookClass: GrowthBookWrapper })],
3266
});
3367

34-
const gb = new GrowthBookLike();
68+
// Create GrowthBookWrapper instance
69+
const gb = new GrowthBookWrapper();
3570

3671
// Fill buffer with flags 1-100 (all false by default)
3772
for (let i = 1; i <= FLAG_BUFFER_SIZE; i++) {
3873
gb.isOn(`feat${i}`);
3974
}
4075

4176
// Add feat101 (true), which should evict feat1
42-
gb.setFeature(`feat${FLAG_BUFFER_SIZE + 1}`, true);
4377
gb.isOn(`feat${FLAG_BUFFER_SIZE + 1}`);
4478

4579
// Update feat3 to true, which should move it to the end
46-
gb.setFeature('feat3', true);
4780
gb.isOn('feat3');
4881

4982
// Test getFeatureValue with boolean values (should be captured)
50-
gb.setFeature('bool-feat', true);
5183
gb.getFeatureValue('bool-feat', false);
5284

5385
// Test getFeatureValue with non-boolean values (should NOT be captured)
54-
gb.setFeature('string-feat', 'hello');
5586
gb.getFeatureValue('string-feat', 'default');
56-
gb.setFeature('number-feat', 42);
5787
gb.getFeatureValue('number-feat', 0);
5888

5989
throw new Error('Test error');
Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,56 @@
1+
import type { ClientOptions, InitSyncOptions, UserContext } from '@growthbook/growthbook';
2+
import { GrowthBookClient } from '@growthbook/growthbook';
13
import * as Sentry from '@sentry/node';
24
import { loggingTransport } from '@sentry-internal/node-integration-tests';
35

4-
// Minimal GrowthBook-like class that matches the real API for testing
5-
class GrowthBookLike {
6-
private _features: Record<string, { value: unknown }> = {};
6+
// Wrapper class to instantiate GrowthBookClient
7+
class GrowthBookWrapper {
8+
private _gbClient: GrowthBookClient;
9+
private _userContext: UserContext = { attributes: { id: 'test-user-123' } };
710

8-
public isOn(featureKey: string): boolean {
9-
const feature = this._features[featureKey];
10-
return feature ? !!feature.value : false;
11+
public constructor(..._args: unknown[]) {
12+
// Create GrowthBookClient and initialize it synchronously with payload
13+
const clientOptions: ClientOptions = {
14+
apiHost: 'https://cdn.growthbook.io',
15+
clientKey: 'sdk-abc123'
16+
};
17+
this._gbClient = new GrowthBookClient(clientOptions);
18+
19+
// Create test features
20+
const features = {
21+
'feat1': { defaultValue: true },
22+
'feat2': { defaultValue: false },
23+
'bool-feat': { defaultValue: true },
24+
'string-feat': { defaultValue: 'hello' }
25+
};
26+
27+
// Initialize synchronously with payload
28+
const initOptions: InitSyncOptions = {
29+
payload: { features }
30+
};
31+
32+
this._gbClient.initSync(initOptions);
1133
}
1234

13-
public getFeatureValue(featureKey: string, defaultValue: unknown): unknown {
14-
const feature = this._features[featureKey];
15-
return feature ? feature.value : defaultValue;
35+
public isOn(featureKey: string, ..._rest: unknown[]): boolean {
36+
return this._gbClient.isOn(featureKey, this._userContext);
1637
}
1738

18-
// Helper method to set feature values for testing
19-
public setFeature(featureKey: string, value: unknown): void {
20-
this._features[featureKey] = { value };
39+
public getFeatureValue(featureKey: string, defaultValue: unknown, ..._rest: unknown[]): unknown {
40+
return this._gbClient.getFeatureValue(featureKey, defaultValue as boolean | string | number, this._userContext);
2141
}
2242
}
2343

44+
const gb = new GrowthBookWrapper();
45+
2446
Sentry.init({
2547
dsn: 'https://[email protected]/1337',
2648
sampleRate: 1.0,
2749
tracesSampleRate: 1.0,
2850
transport: loggingTransport,
29-
integrations: [Sentry.growthbookIntegration({ growthbookClass: GrowthBookLike })],
51+
integrations: [Sentry.growthbookIntegration({ growthbookClass: GrowthBookWrapper })],
3052
});
3153

32-
const gb = new GrowthBookLike();
33-
34-
// Set up feature flags
35-
gb.setFeature('feat1', true);
36-
gb.setFeature('feat2', false);
37-
gb.setFeature('bool-feat', true);
38-
3954
Sentry.startSpan({ name: 'test-span', op: 'function' }, () => {
4055
// Evaluate feature flags during the span
4156
gb.isOn('feat1');
@@ -45,6 +60,5 @@ Sentry.startSpan({ name: 'test-span', op: 'function' }, () => {
4560
gb.getFeatureValue('bool-feat', false);
4661

4762
// Test getFeatureValue with non-boolean values (should NOT be captured)
48-
gb.setFeature('string-feat', 'hello');
4963
gb.getFeatureValue('string-feat', 'default');
5064
});

0 commit comments

Comments
 (0)