Skip to content

feat: Add generic useABTest hook for A/B testing#25541

Merged
bfullam merged 6 commits intomainfrom
ab-testing
Feb 16, 2026
Merged

feat: Add generic useABTest hook for A/B testing#25541
bfullam merged 6 commits intomainfrom
ab-testing

Conversation

@bfullam
Copy link
Contributor

@bfullam bfullam commented Feb 2, 2026

Description

Adds a useABTest hook that provides a simple, type-safe interface for A/B testing using LaunchDarkly feature flags. The hook reads the assigned variant from RemoteFeatureFlagController (which handles bucketing via SHA256 hash of metametricsId + flagName) and maps it to variant data defined by the caller.

Why: We need a standardized, reusable pattern for running A/B tests without requiring per-test boilerplate or Segment schema changes for each experiment.

What's included:

  • Generic useABTest hook with TypeScript support
  • Handles both object format { name } from controller and legacy string format
  • Comprehensive unit tests (26 test cases)
  • Documentation covering LD setup, analytics integration, and bucketing explanation

Changelog

CHANGELOG entry: null

Related issues

Fixes: N/A - Infrastructure for future A/B testing

Manual testing steps

  1. Hook returns correct variant when flag is set: Configure LD to return { name: "treatment" } → hook returns treatment variant data, isActive is true
  2. Hook falls back to control when flag is not set: No LD flag configured → hook returns control variant data, isActive is false
  3. Analytics tracking includes ab_tests property: With active test, SWAP_PAGE_VIEWED event includes ab_tests: { select_amount_text: "treatment" }

Screenshots/Recordings

Before

N/A - New feature

After

N/A - No UI changes; hook is internal infrastructure. First experiment (select amount text) requires LD flag to be configured to observe behavior difference.

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Low Risk
New hook + docs/tests with no changes to existing runtime flows unless adopted by callers; primary risk is incorrect variant selection/activation logic when teams start using it.

Overview
Adds a new generic useABTest React hook that maps a remote feature-flag value to locally-defined variant data, exposing { variant, variantName, isActive } with a guaranteed control fallback and protection against prototype-key matches.

The hook supports both the controller’s { name } A/B-test object format and a legacy string flag value format, is exported via app/hooks/index.ts, and is backed by extensive unit tests plus a new docs/ab-testing.md guide covering LaunchDarkly configuration and analytics tracking conventions.

Written by Cursor Bugbot for commit 561734a. This will update automatically on new commits. Configure here.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2026

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@github-actions github-actions bot added the size-L label Feb 3, 2026
@bfullam bfullam changed the title Ab testing feat: Add generic useABTest hook for A/B testing Feb 3, 2026
@bfullam bfullam added the team-swaps-and-bridge Swaps and Bridge team label Feb 3, 2026
@bfullam bfullam marked this pull request as ready for review February 3, 2026 15:16
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🔍 Smart E2E Test Selection

  • Selected E2E tags: None (no tests recommended)
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: low
  • AI Confidence: 95%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR introduces a new A/B testing framework consisting of:

  1. New useABTest hook (app/hooks/useABTest.ts) - A generic React hook for A/B testing that reads feature flags from the RemoteFeatureFlagController and maps them to variant data
  2. Unit tests (app/hooks/useABTest.test.ts) - Comprehensive test coverage with 465 lines of tests
  3. Hooks index (app/hooks/index.ts) - Centralized exports for hooks
  4. Documentation (docs/ab-testing.md) - Framework documentation

Why no E2E tests are needed:

  • All files are new additions - no existing code is modified
  • The useABTest hook is not used anywhere in the application yet (verified via grep search - only found in its own files)
  • No UI components are affected by these changes
  • No existing user flows or E2E test scenarios could be impacted
  • The hook relies on existing stable infrastructure (selectRemoteFeatureFlags selector from app/selectors/featureFlagController)
  • The comprehensive unit tests (465 lines) provide adequate validation for this infrastructure code

This is purely additive infrastructure code that enables future A/B testing capabilities but doesn't change any current app behavior.

Performance Test Selection:
No performance tests needed. This PR adds a new useABTest hook that is not yet used anywhere in the application. The hook is a simple wrapper around existing Redux selectors (selectRemoteFeatureFlags) with minimal logic - just reading a flag value and mapping it to variant data. There are no UI rendering changes, no data loading changes, no list rendering, and no impact on app startup or critical user flows. The hook's performance characteristics are trivial (single useSelector call with simple object lookup).

View GitHub Actions results

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 6, 2026

**Parameters:**

- `flagKey` - The feature flag key in LaunchDarkly (camelCase, e.g., `'buttonColorTest'`)
- `variants` - Object mapping variant names to their data. **Must include a `control` key** which is used as the fallback when the flag is not set or invalid.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: wonder if it makes sense that the hook takes an optional default variant value?
In case there are cases where the default value is "treatment" instead of "control" ?

Copy link
Contributor

@sahar-fehri sahar-fehri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bfullam bfullam added this pull request to the merge queue Feb 16, 2026
Merged via the queue into main with commit 140386f Feb 16, 2026
89 of 97 checks passed
@bfullam bfullam deleted the ab-testing branch February 16, 2026 10:12
@github-actions github-actions bot locked and limited conversation to collaborators Feb 16, 2026
@metamaskbot metamaskbot added the release-7.67.0 Issue or pull request that will be included in release 7.67.0 label Feb 16, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.67.0 Issue or pull request that will be included in release 7.67.0 size-L team-swaps-and-bridge Swaps and Bridge team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants