Files
Oleg Isonen 3f18f44456 fix: Align Form Action add button with panel headers (#6541)
## Change

Settings collapsibles now use `fullWidth` so right-side Builder Style
and Settings panel content owns its inline padding. Existing visual
insets are preserved, and Action explicitly owns its zero inset so its
header and action rows can span the section width.

- Forward `fullWidth` through `CollapsibleSectionWithAddButton`.
- Remove the `fullWidth` prop and padding wrapper from `StyleSection`;
all ten StyleSection callers own their content insets locally, including
Size's zero inset and full-width separator.
- Move Properties & attributes, diagnostics, individual Style panel
section insets into their own content.
- Keep normal property controls inset and let Action control its own
header, rows, error, and redirect spacing.
- Retain the earlier Form Action add-trigger and resource-row changes.
Action content starts below its full section header with a small gap.

## Implementation

- [x] Prevent overlap between the Action section header and its items:
start content below the full header with the existing 2px gap,
preserving row size and inset.

- [x] Review padding-only wrappers from the right-side Settings and
Style panel refactors. Apply padding directly to an existing Flex
container where possible and remove redundant Box wrappers.

- [x] Replace the Action dropdown hardcoded 180px minimum width with the
closest existing spacing token, `theme.spacing[26]` (176px; 4px
narrower).
- [x] Review documentation impact for the dropdown token change:
reviewed the Form action documentation; no update required.

- [x] Remove the `fullWidth` prop from `StyleSection`. Each individual
Style panel section content container explicitly owns its inline
padding: ordinary sections retain 12px and Size retains zero inset, with
existing gaps preserved.

- [x] Give CollapsibleSection content zero inline padding using the
existing `fullWidth` API for right-side Builder Style and Settings panel
sections. Each section explicitly owns its inline padding, preserving
current visual insets and allowing sections such as Action to control
alignment.

## Verification

- Action spacing: 13 focused Chromium browser tests, focused oxlint,
formatting, and `git diff --check` passed. Geometry asserts a 36px
header, 2px gap before the first item, button clearance, and unchanged
24px row height.

- Restored Page Settings to its original padding ownership; all 7
focused Page Settings Chromium tests, focused oxlint, and `git diff
--check` passed.

- Padding-wrapper follow-up: removed redundant Box wrappers around the
Navigation mode Flex and baseline Action header fixture; audited
right-side Settings and Style panel padding owners. 10 focused Action
Chromium tests, focused oxlint, and `git diff --check` passed.

- Dropdown token follow-up: 13 focused Action Chromium tests, focused
oxlint, and `git diff --check` passed. The browser assertion verifies
the 176px computed minimum width.

- 428 Style panel Chromium browser tests passed after moving padding
into individual sections.
- 43 focused Chromium browser tests passed: Action, PropsSection, page
settings, search, diagnostics, and request inspector.
- Builder TypeScript check, focused oxlint, and `git diff --check`
passed.
- Assert the Properties collapsible has zero inline padding while its
child owns its 12px inset; existing Action geometry checks pass.
2026-10-16 15:52:57 +02:00
..

Builder E2E tests

Builder E2E workflows run with Playwright Test. The Playwright setup project waits for PostgREST, resets the disposable database, and warms the login route before Chromium runs the selected tests.

Run the suite

Use the full command for CI-like validation:

pnpm e2e:builder

The first run after migrations change applies the regular migration pipeline and writes an ignored schema cache under .cache/builder-e2e. Refresh it explicitly with:

pnpm e2e:builder:refresh-schema-cache

The regular E2E suite uses lightweight PostgreSQL containers. Verify that the complete migration chain also applies to the pinned Supabase PostgreSQL image with:

pnpm e2e:builder:check-supabase-migrations

Pass normal Playwright Test arguments after --. For example:

pnpm e2e:builder -- --grep "Builder can copy, duplicate, and delete a page"
pnpm e2e:builder -- 'apps/builder/e2e/tests/pages-actions.[shard-5].e2e.ts'
pnpm e2e:builder -- --debug --grep "Builder can copy"

A lightweight Playwright discovery pass validates the selection before Docker, database migrations, browser installation, or the Builder build starts. A filter that matches no tests therefore fails without starting the test environment.

Fast local reruns

Keep the E2E backend and Builder development server running to avoid rebuilding Builder and restarting Docker for each edit.

Terminal 1:

pnpm e2e:builder:dev:backend

Terminal 2:

pnpm dev

Terminal 3:

pnpm e2e:builder:dev -- --grep "Builder can copy, duplicate, and delete a page"

pnpm e2e:builder:dev defaults to E2E_BUILDER_URL=https://127.0.0.1:3000. Override it when the development server uses another port. Chromium maps wstd.dev and its project subdomains to loopback for local Builder URLs, so host-file changes are unnecessary.

The development backend uses E2E_DB_BOOTSTRAP=if-empty and keeps Docker containers running. The Playwright setup project still resets test data before each invocation.

Test organization

  • Put workflows in e2e/tests/*.e2e.ts and import test from e2e/test.ts.
  • Use Playwright's page fixture for the workflow under test. Playwright gives each test an isolated context and closes it automatically.
  • Use Playwright's context fixture when setup should share authentication with the workflow page.
  • Use withBrowserContext(browser, callback) for isolated setup or setup that runs in beforeAll. If cookies must survive from beforeAll into the tests, create an explicit context with newBrowserContext(browser) and close it in afterAll.
  • Use newIsolatedPage(browser) for identities that must not share cookies.
  • Keep tests in a file independent even though Playwright runs them in declaration order by default.

CI discovers isolated Playwright shards from filename tags. Each shard uses four workers, and files are assigned by measured CI duration to keep jobs near three to four minutes:

pages-actions.[shard-2].[shard-5].[shard-6].e2e.ts

Every E2E filename must contain at least one unique shard tag. CI derives its matrix from those tags, so adding or removing a shard does not require editing the workflow. Files with multiple tags are partitioned across those shards. All files selected by a shard must use the same set of tags. Rebalance by changing filename tags when measured job durations drift. Suites may opt into parallel mode only when every worker creates uniquely named setup data and the tests do not depend on each other's mutations.

Backend organization

Development, E2E, schema-cache, and Supabase compatibility commands share the backend definition in apps/builder/backend. compose.yaml defines the common services, and compose.<mode>.yaml defines only the differences for a named mode. Backend commands resolve these files by convention; callers do not pass Compose filenames.

The schema-cache fingerprint discovers migration sources and non-test backend files automatically. Adding a database image, initialization script, Compose override, or migration therefore invalidates the cache without updating a filename registry.

Failures

Failed shard jobs upload the Playwright HTML report, traces, screenshots, videos, and backend service logs.

When you need a completely clean backend locally:

E2E_SKIP_CLEANUP=false pnpm e2e:builder