test(e2e): derive preview-feature list from features.json

Both the screenshot 'all on' test and the bridge mock seed were
hand-maintaining a parallel array of preview feature ids. tier
transitions (e.g. promoting huddles to stable) required updating
two places that the type system couldn't help us with.

Add tests/helpers/features.ts as a single source of truth that
imports /features.json directly and filters tier === 'preview'.
The 'all on' test now loops over PREVIEW_FEATURE_IDS, and bridge.ts
re-uses the same constant for its localStorage seeding.

12/12 screenshot-feature-flags tests pass locally.

Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w
2026-06-08 13:02:59 -07:00
committed by Taylor Ho
parent 0c5c43d591
commit 0ca05eddc5
3 changed files with 32 additions and 8 deletions
@@ -1,6 +1,7 @@
import { expect, test } from "@playwright/test";
import { installMockBridge } from "../helpers/bridge";
import { openSettings } from "../helpers/settings";
import { PREVIEW_FEATURE_IDS } from "../helpers/features";
const WATERCOLOR_CHANNEL_ID = "a27e1ee9-76a6-5bdf-a5d5-1d85610dad11";
const FORUM_POST_ID = "mock-forum-release-thread";
@@ -155,10 +156,9 @@ test("screenshot: Settings → Experiments (all on)", async ({ page }) => {
await openSettings(page);
await page.getByTestId("settings-nav-experimental").click();
await expect(page.getByTestId("settings-experimental")).toBeVisible();
await page.getByTestId("feature-toggle-workflows").click();
await page.getByTestId("feature-toggle-projects").click();
await page.getByTestId("feature-toggle-pulse").click();
await page.getByTestId("feature-toggle-forum").click();
for (const id of PREVIEW_FEATURE_IDS) {
await page.getByTestId(`feature-toggle-${id}`).click();
}
await page.waitForTimeout(500);
const view = page.getByTestId("settings-view");
await view.screenshot({
+1 -4
View File
@@ -1,4 +1,5 @@
import type { Page } from "@playwright/test";
import { PREVIEW_FEATURE_IDS } from "./features";
export const TEST_IDENTITIES = {
tyler: {
@@ -111,10 +112,6 @@ type BridgeOptions = {
const ONBOARDING_COMPLETION_STORAGE_KEY_PREFIX =
"sprout-onboarding-complete.v1:";
const FEATURE_OVERRIDES_STORAGE_KEY = "sprout-feature-overrides-v1";
// Keep in sync with `tier: "preview"` entries in `/features.json`. E2E
// tests opt into all preview features by default so gated UI is reachable
// without clicking through Settings → Experiments on every spec.
const PREVIEW_FEATURE_IDS = ["workflows", "projects", "pulse", "forum"];
const DEFAULT_MOCK_PUBKEY = "deadbeef".repeat(8);
const DEFAULT_RELAY_WS_URL = "ws://localhost:3000";
+27
View File
@@ -0,0 +1,27 @@
// Single source of truth for E2E tests: derive the preview-feature list from
// /features.json so we don't have to hand-maintain a parallel array.
//
// Tier transitions (preview → stable, or new preview features added) are
// picked up automatically by every test that imports from here.
import featuresManifest from "../../../features.json" with { type: "json" };
interface FeatureDefinition {
id: string;
name: string;
description: string;
tier: "stable" | "preview";
platforms?: string[];
}
interface FeaturesManifest {
version: number;
features: FeatureDefinition[];
}
const manifest = featuresManifest as FeaturesManifest;
/** IDs of every preview-tier feature on desktop. */
export const PREVIEW_FEATURE_IDS: string[] = manifest.features
.filter((f) => f.tier === "preview")
.filter((f) => !f.platforms || f.platforms.includes("desktop"))
.map((f) => f.id);