fix: regenerate E2E screenshots for 2-tier feature system
- Rewrote screenshot-feature-flags.ts: removed stale 'unstable' tier references (relay-members, identity-archive), updated close button selector to settings-back-to-app - Deleted all old screenshots + feature-flags-tour/ artifacts - Regenerated 13 fresh screenshots matching current UI - Added Experiments nav group to SettingsView (was defined but missing from settingsNavGroups) - Registered test in playwright.config.ts smoke project Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@@ -35,6 +35,7 @@ export default defineConfig({
|
||||
"**/workflows.spec.ts",
|
||||
"**/identity-archive.spec.ts",
|
||||
"**/identity-archive-hide.spec.ts",
|
||||
"**/screenshot-feature-flags.ts",
|
||||
],
|
||||
use: {
|
||||
...devices["Desktop Chrome"],
|
||||
|
||||
@@ -25,9 +25,7 @@ function FeatureRow({ feature }: { feature: FeatureDefinition }) {
|
||||
}
|
||||
|
||||
export function ExperimentalFeaturesCard() {
|
||||
const previewFeatures = desktopFeatures.filter(
|
||||
(f) => f.tier === "preview",
|
||||
);
|
||||
const previewFeatures = desktopFeatures.filter((f) => f.tier === "preview");
|
||||
|
||||
return (
|
||||
<section className="min-w-0" data-testid="settings-experimental">
|
||||
|
||||
@@ -64,6 +64,10 @@ const settingsNavGroups: Array<{
|
||||
label: "App",
|
||||
sections: ["agents", "compute", "mobile", "updates", "doctor"],
|
||||
},
|
||||
{
|
||||
label: "Experiments",
|
||||
sections: ["experimental"],
|
||||
},
|
||||
];
|
||||
|
||||
function SettingsSectionButton({
|
||||
@@ -127,7 +131,10 @@ export function SettingsView({
|
||||
// Feature gate check
|
||||
if (s.featureGate) {
|
||||
const feature = getFeature(s.featureGate);
|
||||
if (feature && !resolveEnabled(feature.tier, feature.id, featureState)) {
|
||||
if (
|
||||
feature &&
|
||||
!resolveEnabled(feature.tier, feature.id, featureState)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ describe("resolveEnabled", () => {
|
||||
describe("stable tier", () => {
|
||||
it("always returns true regardless of overrides", () => {
|
||||
assert.equal(resolveEnabled("stable", "channels", {}), true);
|
||||
assert.equal(resolveEnabled("stable", "channels", { channels: false }), true);
|
||||
assert.equal(
|
||||
resolveEnabled("stable", "channels", { channels: false }),
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ const srcRoot = path.resolve(
|
||||
"src",
|
||||
);
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const repoRoot = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"..",
|
||||
);
|
||||
|
||||
export function resolve(specifier, context, nextResolve) {
|
||||
if (specifier === "@features-manifest") {
|
||||
|
||||
@@ -9,20 +9,23 @@ test.beforeEach(async ({ page }) => {
|
||||
await installMockBridge(page);
|
||||
});
|
||||
|
||||
// Helper: enable a feature via settings, then close settings
|
||||
async function enableFeature(page: import("@playwright/test").Page, featureId: string) {
|
||||
// Helper: enable a preview feature via settings, then close settings
|
||||
async function enableFeature(
|
||||
page: import("@playwright/test").Page,
|
||||
featureId: string,
|
||||
) {
|
||||
await openSettings(page);
|
||||
await page.getByTestId("settings-nav-experimental").click();
|
||||
await expect(page.getByTestId("settings-experimental")).toBeVisible();
|
||||
await page.getByTestId(`feature-toggle-${featureId}`).click();
|
||||
await page.waitForTimeout(200);
|
||||
await page.getByTestId("settings-close").click();
|
||||
await page.getByTestId("settings-back-to-app").click();
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
// --- Stable features (settings panels) ---
|
||||
// --- Stable features (settings panels, always visible) ---
|
||||
|
||||
test("screenshot: Settings → Agents (managed-agents, stable)", async ({ page }) => {
|
||||
test("screenshot: Settings → Agents (stable)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page, "agents");
|
||||
await page.waitForTimeout(500);
|
||||
@@ -30,24 +33,28 @@ test("screenshot: Settings → Agents (managed-agents, stable)", async ({ page }
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-agents.png" });
|
||||
});
|
||||
|
||||
test("screenshot: Settings → Templates (channel-templates, stable)", async ({ page }) => {
|
||||
test("screenshot: Settings → Templates (stable)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page, "channel-templates");
|
||||
await page.waitForTimeout(500);
|
||||
const view = page.getByTestId("settings-view");
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-templates.png" });
|
||||
await view.screenshot({
|
||||
path: "tests/e2e/screenshots/settings-templates.png",
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Settings → Custom Emoji (custom-emoji, stable)", async ({ page }) => {
|
||||
test("screenshot: Settings → Custom Emoji (stable)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page);
|
||||
await page.getByTestId("settings-nav-custom-emoji").click();
|
||||
await page.waitForTimeout(500);
|
||||
const view = page.getByTestId("settings-view");
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-custom-emoji.png" });
|
||||
await view.screenshot({
|
||||
path: "tests/e2e/screenshots/settings-custom-emoji.png",
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Settings → Doctor (doctor, stable)", async ({ page }) => {
|
||||
test("screenshot: Settings → Doctor (stable)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page, "doctor");
|
||||
await page.waitForTimeout(500);
|
||||
@@ -55,64 +62,84 @@ test("screenshot: Settings → Doctor (doctor, stable)", async ({ page }) => {
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-doctor.png" });
|
||||
});
|
||||
|
||||
// --- Preview features (navigated into their views) ---
|
||||
// --- Preview features (opt-in via Experiments) ---
|
||||
|
||||
test("screenshot: Workflows view (workflows, preview)", async ({ page }) => {
|
||||
test("screenshot: Workflows view (preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "workflows");
|
||||
await page.getByTestId("open-workflows-view").click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: "tests/e2e/screenshots/view-workflows.png", fullPage: false });
|
||||
await page.screenshot({
|
||||
path: "tests/e2e/screenshots/view-workflows.png",
|
||||
fullPage: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Projects view (projects, preview)", async ({ page }) => {
|
||||
test("screenshot: Projects view (preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "projects");
|
||||
await page.getByTestId("open-projects-view").click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: "tests/e2e/screenshots/view-projects.png", fullPage: false });
|
||||
await page.screenshot({
|
||||
path: "tests/e2e/screenshots/view-projects.png",
|
||||
fullPage: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Pulse view (pulse, preview)", async ({ page }) => {
|
||||
test("screenshot: Pulse view (preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "pulse");
|
||||
await page.getByTestId("open-pulse-view").click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: "tests/e2e/screenshots/view-pulse.png", fullPage: false });
|
||||
await page.screenshot({
|
||||
path: "tests/e2e/screenshots/view-pulse.png",
|
||||
fullPage: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Forum with active thread (forum, preview)", async ({ page }) => {
|
||||
test("screenshot: Forum post list (preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "forum");
|
||||
// Navigate directly into the forum channel and open a thread
|
||||
await page.goto(`/#/channels/${WATERCOLOR_CHANNEL_ID}/posts/${FORUM_POST_ID}`);
|
||||
await page.goto(`/#/channels/${WATERCOLOR_CHANNEL_ID}`);
|
||||
await expect(
|
||||
page.getByText("Release checklist: async feedback thread."),
|
||||
).toBeVisible();
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({
|
||||
path: "tests/e2e/screenshots/view-forum-posts.png",
|
||||
fullPage: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Forum with active thread (preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "forum");
|
||||
await page.goto(
|
||||
`/#/channels/${WATERCOLOR_CHANNEL_ID}/posts/${FORUM_POST_ID}`,
|
||||
);
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("watercooler");
|
||||
await page.waitForTimeout(600);
|
||||
await page.screenshot({ path: "tests/e2e/screenshots/view-forum-thread.png", fullPage: false });
|
||||
await page.screenshot({
|
||||
path: "tests/e2e/screenshots/view-forum-thread.png",
|
||||
fullPage: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Forum post list (forum, preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "forum");
|
||||
// Navigate to the forum channel post list
|
||||
await page.goto(`/#/channels/${WATERCOLOR_CHANNEL_ID}`);
|
||||
await expect(page.getByText("Release checklist: async feedback thread.")).toBeVisible();
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: "tests/e2e/screenshots/view-forum-posts.png", fullPage: false });
|
||||
});
|
||||
|
||||
test("screenshot: Huddles in channel header (huddles, preview)", async ({ page }) => {
|
||||
test("screenshot: Huddles in channel header (preview)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await enableFeature(page, "huddles");
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: "tests/e2e/screenshots/view-huddles.png", fullPage: false });
|
||||
await page.screenshot({
|
||||
path: "tests/e2e/screenshots/view-huddles.png",
|
||||
fullPage: false,
|
||||
});
|
||||
});
|
||||
|
||||
// --- Unstable features (settings panels after enabling) ---
|
||||
|
||||
test("screenshot: Settings → Compute (mesh-compute, unstable)", async ({ page }) => {
|
||||
test("screenshot: Settings → Compute (preview, after enabling)", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page);
|
||||
await page.getByTestId("settings-nav-experimental").click();
|
||||
@@ -124,31 +151,21 @@ test("screenshot: Settings → Compute (mesh-compute, unstable)", async ({ page
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-compute.png" });
|
||||
});
|
||||
|
||||
test("screenshot: Settings → Relay Members (relay-members, unstable)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page);
|
||||
await page.getByTestId("settings-nav-experimental").click();
|
||||
await page.getByTestId("feature-toggle-relay-members").click();
|
||||
await page.waitForTimeout(300);
|
||||
await page.getByTestId("settings-nav-relay-members").click();
|
||||
await page.waitForTimeout(500);
|
||||
const view = page.getByTestId("settings-view");
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-relay-members.png" });
|
||||
});
|
||||
// --- Experiments panel ---
|
||||
|
||||
// --- Settings → Preview & Unstable panel ---
|
||||
|
||||
test("screenshot: Settings → Preview & Unstable (default)", async ({ page }) => {
|
||||
test("screenshot: Settings → Experiments (default)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page);
|
||||
await page.getByTestId("settings-nav-experimental").click();
|
||||
await expect(page.getByTestId("settings-experimental")).toBeVisible();
|
||||
await page.waitForTimeout(500);
|
||||
const view = page.getByTestId("settings-view");
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-preview-unstable-default.png" });
|
||||
await view.screenshot({
|
||||
path: "tests/e2e/screenshots/settings-experiments-default.png",
|
||||
});
|
||||
});
|
||||
|
||||
test("screenshot: Settings → Preview & Unstable (all on)", async ({ page }) => {
|
||||
test("screenshot: Settings → Experiments (all on)", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await openSettings(page);
|
||||
await page.getByTestId("settings-nav-experimental").click();
|
||||
@@ -159,9 +176,9 @@ test("screenshot: Settings → Preview & Unstable (all on)", async ({ page }) =>
|
||||
await page.getByTestId("feature-toggle-forum").click();
|
||||
await page.getByTestId("feature-toggle-huddles").click();
|
||||
await page.getByTestId("feature-toggle-mesh-compute").click();
|
||||
await page.getByTestId("feature-toggle-identity-archive").click();
|
||||
await page.getByTestId("feature-toggle-relay-members").click();
|
||||
await page.waitForTimeout(500);
|
||||
const view = page.getByTestId("settings-view");
|
||||
await view.screenshot({ path: "tests/e2e/screenshots/settings-preview-unstable-all-on.png" });
|
||||
await view.screenshot({
|
||||
path: "tests/e2e/screenshots/settings-experiments-all-on.png",
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |