refactor(ui): centralize PostHog feature flag reads in ui/lib/feature-flags (#13089)

This commit is contained in:
Alejandro Bailo authored and GitHub committed 2026-10-19 12:27:46 +02:00
1 parent f46b86101a
commit 1783527c11
8 files changed
+199 -39

No files matched your search

@@ -1,49 +1,44 @@
import { renderHook } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
const { useFeatureFlagVariantKeyMock } = vi.hoisted(() => ({
useFeatureFlagVariantKeyMock: vi.fn(),
const { useFeatureFlagVariantMock } = vi.hoisted(() => ({
useFeatureFlagVariantMock: vi.fn(),
}));
vi.mock("posthog-js/react", () => ({
useFeatureFlagVariantKey: useFeatureFlagVariantKeyMock,
vi.mock("@/lib/feature-flags/client", () => ({
useFeatureFlagVariant: useFeatureFlagVariantMock,
}));
import { useSkillLauncherVariant } from "./use-skill-launcher-variant";
describe("useSkillLauncherVariant", () => {
beforeEach(() => {
useFeatureFlagVariantKeyMock.mockReset();
useFeatureFlagVariantMock.mockReset();
});
it("should ask PostHog for the experiment flag", () => {
useFeatureFlagVariantKeyMock.mockReturnValue(undefined);
it("should read the skill launcher flag with card as the fallback", () => {
useFeatureFlagVariantMock.mockReturnValue("card");
renderHook(() => useSkillLauncherVariant());
expect(useFeatureFlagVariantKeyMock).toHaveBeenCalledWith(
expect(useFeatureFlagVariantMock).toHaveBeenCalledWith(
"finding-detail-skill-launcher",
["card", "dropdown"],
"card",
);
});
it("should return the dropdown variant when the flag resolves to it", () => {
useFeatureFlagVariantKeyMock.mockReturnValue("dropdown");
const { result } = renderHook(() => useSkillLauncherVariant());
expect(result.current).toBe("dropdown");
});
it.each([
["dropdown", "dropdown"],
["card", "card"],
["unresolved flag", undefined],
["boolean flag", false],
["unknown variant", "weird"],
])("should fall back to card for %s", (_label, flagValue) => {
useFeatureFlagVariantKeyMock.mockReturnValue(flagValue);
])(
"should return the %s variant the flag module resolves",
(_label, variant) => {
useFeatureFlagVariantMock.mockReturnValue(variant);
const { result } = renderHook(() => useSkillLauncherVariant());
const { result } = renderHook(() => useSkillLauncherVariant());
expect(result.current).toBe("card");
});
expect(result.current).toBe(variant);
},
);
});
@@ -1,20 +1,17 @@
"use client";
import { useFeatureFlagVariantKey } from "posthog-js/react";
import { FEATURE_FLAG, useFeatureFlagVariant } from "@/lib/feature-flags";
import {
SKILL_LAUNCHER_FLAG,
SKILL_LAUNCHER_VARIANT,
type SkillLauncherVariant,
} from "@/types/lighthouse-skills";
// The hook reads the global posthog singleton (posthog-js/react's default
// context), so it needs no provider or init here: the cloud fork initializes
// and identifies the client; OSS builds never resolve the flag and fall back
// to the card control, as do unresolved or unknown variants.
// Unresolved or unknown variants (including OSS builds that never init
// PostHog) fall back to the card control.
export function useSkillLauncherVariant(): SkillLauncherVariant {
const value = useFeatureFlagVariantKey(SKILL_LAUNCHER_FLAG);
return value === SKILL_LAUNCHER_VARIANT.DROPDOWN
? SKILL_LAUNCHER_VARIANT.DROPDOWN
: SKILL_LAUNCHER_VARIANT.CARD;
return useFeatureFlagVariant(
FEATURE_FLAG.SKILL_LAUNCHER,
Object.values(SKILL_LAUNCHER_VARIANT),
SKILL_LAUNCHER_VARIANT.CARD,
);
}