Files
supabase/apps/studio/components/interfaces/ProjectHome/Home.utils.test.ts
T
Pamela ChiaandAli Waseem 578a73f966 feat(studio): connectSection experiment — replace Getting Started with Connect section (#43629)
## Summary

Re-ports PR #43119 against the current `ProjectHome` codebase (the
original PR targeted `HomeNew/` which was removed during the `homeNew`
graduation in #43437). Also unifies the `connectSheet` and
`connectSection` feature flags into a single `connectSection` flag — the
`connectSheet` flag is removed entirely, so both the ConnectSheet
(header) and ConnectSection (homepage row) are controlled by one
experiment.

- Adds `connectSection` PostHog experiment flag that controls two
things:
1. Swaps the Getting Started section for a Connect section on the
project homepage for new projects (< 10 days old)
2. Swaps the legacy Connect dialog for the new ConnectSheet panel in the
header
- **Control** (`getting-started`): existing Getting Started section +
legacy Connect dialog in header
- **Treatment** (`connect`): new 4-tile Connect section + ConnectSheet
in header
- `undefined` (loading): neither section renders, avoiding flash
- Tiles filtered by the same `useIsFeatureEnabled` flags as ConnectSheet
(`show_app_frameworks`, `show_mobile_frameworks`, `show_orms`)
- Connect tile clicks tracked via `home_connect_action_clicked`; section
render tracked via `home_connect_section_exposed`; sheet opens tracked
via `connect_sheet_opened` with source attribution (`header_button` or
`connect_section`)

## Changes

- `packages/common/telemetry-constants.ts` — new
`home_connect_section_exposed`, `home_connect_action_clicked`, and
`connect_sheet_opened` event types
- `ConnectSheet/ConnectSheet.tsx` — read `connectTab` query param and
sync to active mode on open; `handleModeChange` keeps param in sync on
tab switch; fire `connect_sheet_opened` event with source attribution on
open
- `ConnectButton/ConnectButton.tsx` — set `connectSource=header_button`
query param on click
- `ProjectHome/ConnectSection.tsx` — new component (4-tile connect
card); set `connectSource=connect_section` on tile click
- `ProjectHome/Home.tsx` — experiment flag wiring
- `LayoutHeader/LayoutHeader.tsx` — read `connectSection` flag instead
of `connectSheet` to toggle ConnectSheet vs legacy Connect dialog

## Test plan

To test on the Vercel preview, set `connectSection=connect` to 100% in
PostHog (or override via cookie `ph_override_connectSection=connect`).
No separate `connectSheet` flag is needed — `connectSection` controls
both features.
- [x] Treatment (`connect` variant) — "Get connected" section renders on
new project, Getting Started hidden
- [x] Control (`getting-started`) — Getting Started renders, Connect
section hidden
- [x] Mature project (> 10 days) — neither section regardless of flag
- [x] Clicking each tile opens ConnectSheet on the correct tab
(Framework / Direct / ORM / MCP)
- [x] Switching tabs inside sheet updates `connectTab` URL param
- [x] Closing sheet clears `connectTab` param
- [x] Direct URL deep-link (`?showConnect=true&connectTab=orm`) opens
sheet on correct tab
- [x] Dark mode — background gradient renders correctly
- [x] Light mode — background switches to light gradient
- [x] Responsive layout — 4 cols (xl), 2×2 (md), stacked (mobile)
- [x] Telemetry — `home_connect_section_exposed` fires once on load;
`home_connect_action_clicked` fires with correct `mode`
- [x] Treatment — header Connect button opens ConnectSheet (not legacy
Connect dialog)
- [x] Control — header Connect button opens legacy Connect dialog (not
ConnectSheet)
- [x] Telemetry — clicking a ConnectSection tile fires
`connect_sheet_opened` with `source: 'connect_section'`
- [x] Telemetry — clicking header Connect button fires
`connect_sheet_opened` with `source: 'header_button'`

---------

Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-03-13 11:50:07 +09:00

105 lines
3.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { mergeSectionOrder, getSectionVisibility } from './Home.utils'
describe('mergeSectionOrder', () => {
it('returns stored order unchanged when it matches defaults', () => {
const stored = ['connect', 'getting-started', 'usage', 'advisor', 'custom-report']
expect(mergeSectionOrder(stored)).toBe(stored)
})
it('inserts missing sections at their default-relative position', () => {
expect(mergeSectionOrder(['usage', 'advisor', 'custom-report'])).toEqual([
'connect',
'getting-started',
'usage',
'advisor',
'custom-report',
])
})
it('preserves user reordering while inserting missing sections', () => {
expect(mergeSectionOrder(['getting-started', 'advisor', 'usage', 'custom-report'])).toEqual([
'connect',
'getting-started',
'advisor',
'usage',
'custom-report',
])
})
it('strips unknown sections from stored order', () => {
expect(mergeSectionOrder(['usage', 'deleted-section', 'advisor', 'custom-report'])).toEqual([
'connect',
'getting-started',
'usage',
'advisor',
'custom-report',
])
})
})
describe('getSectionVisibility', () => {
const base = {
connectSectionVariant: 'connect' as const,
isMatureProject: false,
hasProject: true,
gettingStartedState: 'empty' as const,
}
it('shows connect section for connect variant on new project', () => {
expect(getSectionVisibility(base)).toEqual({
showConnectSection: true,
showGettingStarted: false,
})
})
it('shows getting started for non-connect variant', () => {
expect(getSectionVisibility({ ...base, connectSectionVariant: 'getting-started' })).toEqual({
showConnectSection: false,
showGettingStarted: true,
})
})
it('shows neither when flag is unresolved', () => {
expect(getSectionVisibility({ ...base, connectSectionVariant: undefined })).toEqual({
showConnectSection: false,
showGettingStarted: false,
})
})
it('shows neither for mature projects', () => {
expect(getSectionVisibility({ ...base, isMatureProject: true })).toEqual({
showConnectSection: false,
showGettingStarted: false,
})
})
it('hides getting started when user dismissed it', () => {
expect(
getSectionVisibility({
...base,
connectSectionVariant: 'getting-started',
gettingStartedState: 'hidden',
})
).toEqual({
showConnectSection: false,
showGettingStarted: false,
})
})
it('shows getting started when flag resolved to false (control group)', () => {
expect(getSectionVisibility({ ...base, connectSectionVariant: false })).toEqual({
showConnectSection: false,
showGettingStarted: true,
})
})
it('shows neither when project is missing', () => {
expect(getSectionVisibility({ ...base, hasProject: false })).toEqual({
showConnectSection: false,
showGettingStarted: false,
})
})
})