Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ export interface GrowthBook {
getFeatureValue(this: GrowthBook, featureKey: string, defaultValue: unknown, ...rest: unknown[]): unknown;
}

// We only depend on the surface we wrap; constructor args are irrelevant here.
export type GrowthBookClass = new (...args: unknown[]) => GrowthBook;
// We only depend on the surface we wrap, so accept any class whose prototype matches.
export type GrowthBookClass = { prototype: GrowthBook };
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { getCurrentScope } from '@sentry/core/browser';
import { afterEach, describe, expect, it } from 'vitest';
import { growthbookIntegration } from '../../../../src/integrations/featureFlags/growthbook';

describe('growthbookIntegration', () => {
afterEach(() => {
getCurrentScope().clear();
});

it('accepts a precisely-typed GrowthBook class without a cast and captures boolean evaluations', () => {
class MockGrowthBook {
public constructor(_options?: { apiHost: string }) {}

public isOn(_key: string): boolean {
return true;
}

public getFeatureValue(_key: string, _defaultValue: unknown): unknown {
return false;
}
}

const integration = growthbookIntegration({
growthbookClass: MockGrowthBook,
});
integration.setupOnce?.();

const growthbook = new MockGrowthBook();
growthbook.isOn('my-feature');
growthbook.getFeatureValue('my-other-feature', true);

expect(getCurrentScope().getScopeData().contexts.flags?.values).toEqual([
{ flag: 'my-feature', result: true },
{ flag: 'my-other-feature', result: false },
]);
});
});
4 changes: 2 additions & 2 deletions packages/core/src/integrations/featureFlags/growthbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface GrowthBookLike {
getFeatureValue(this: GrowthBookLike, featureKey: string, defaultValue: unknown, ...rest: unknown[]): unknown;
}

export type GrowthBookClassLike = new (...args: unknown[]) => GrowthBookLike;
export type GrowthBookClassLike = { prototype: GrowthBookLike };

/**
* Sentry integration for capturing feature flag evaluations from GrowthBook.
Expand All @@ -40,7 +40,7 @@ export const growthbookIntegration: IntegrationFn = defineIntegration(
name: 'GrowthBook' as const,

setupOnce() {
const proto = growthbookClass.prototype as GrowthBookLike;
const proto = growthbookClass.prototype;

// Type guard and wrap isOn
if (typeof proto.isOn === 'function') {
Expand Down