mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-28 23:57:17 +09:00
## Summary Explain what the Form component can do, with short chapters for actions, email, uploads, search and filters, submission feedback, and Preview testing. - Replace the old guide with the reviewed text. - Add five tightly cropped screenshots, each in light and dark themes. - Update links from the Variables and Webhook Form guides to the new sections. ## Checklist - [x] Update the Form documentation and review its behavior claims against the implementation. - [x] Add five matching light/dark screenshot pairs with descriptive alt text. - [x] Verify 21 local links and anchors, all 10 image references, formatting, and the final diff. - [x] Fix the CI database port conflict in browser shard 2. - [x] Re-run the shard 3 email tests locally with the CI build and schema artifacts: 4/4 passed in 61 seconds. - [x] Use sanitized CI diagnostics to investigate the MCP submit failures, then remove all temporary diagnostic code. - [x] Pin the MCP test fixture to installed Playwright Chromium and run E2E shards with two workers. - [x] Review documentation impact of CI changes: no additional docs are needed. - [x] Confirm required CI checks pass. The CI follow-up keeps test setup stable: Docker assigns free PostgreSQL and PostgREST host ports, the MCP test fixture uses the installed Playwright Chromium, and each E2E shard uses two workers. Local startup passed with port 55434 occupied; the focused email tests passed 4/4. The final clean CI run passed all ten E2E shards, Main, Visual regression, Lint PR, and Check submodules. Temporary diagnostics have been removed. The exact cause of the earlier browser startup failures was not proven. These CI changes do not change Form behavior.
240 lines
7.4 KiB
Bash
240 lines
7.4 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
|
mode="${1:-run}"
|
|
if [ "$#" -gt 0 ]; then
|
|
shift
|
|
fi
|
|
|
|
case "$mode" in
|
|
run)
|
|
;;
|
|
dev-backend)
|
|
export E2E_SKIP_CLEANUP=true
|
|
export E2E_RUN_TESTS=false
|
|
export E2E_START_POSTGREST=true
|
|
export E2E_DB_BOOTSTRAP=if-empty
|
|
export E2E_INSTALL_PLAYWRIGHT=false
|
|
;;
|
|
dev)
|
|
export E2E_SKIP_CLEANUP=true
|
|
export E2E_DB_BOOTSTRAP=if-empty
|
|
export E2E_INSTALL_PLAYWRIGHT=false
|
|
export E2E_BUILDER_URL="${E2E_BUILDER_URL:-https://127.0.0.1:3000}"
|
|
;;
|
|
schema-cache)
|
|
export E2E_DB_BOOTSTRAP=migrations
|
|
export E2E_WRITE_SCHEMA_SNAPSHOT=true
|
|
export E2E_RUN_TESTS=false
|
|
;;
|
|
supabase-migrations)
|
|
export E2E_BACKEND_MODE=supabase
|
|
export E2E_BUILD_DATABASE_IMAGE=false
|
|
export E2E_DB_BOOTSTRAP=migrations
|
|
export E2E_RUN_TESTS=false
|
|
;;
|
|
ci-shard)
|
|
export E2E_BACKEND_MODE=snapshot
|
|
export E2E_BUILD_DATABASE_IMAGE=false
|
|
export E2E_SKIP_BUILDER_BUILD=true
|
|
export E2E_SKIP_CLEANUP=true
|
|
export E2E_PGPORT="${E2E_PGPORT:-0}"
|
|
export E2E_POSTGREST_PORT="${E2E_POSTGREST_PORT:-0}"
|
|
;;
|
|
*)
|
|
echo "Unknown Builder E2E mode: $mode" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
PLAYWRIGHT_ARGS=("$@")
|
|
if [ "${PLAYWRIGHT_ARGS[0]:-}" = "--" ]; then
|
|
PLAYWRIGHT_ARGS=("${PLAYWRIGHT_ARGS[@]:1}")
|
|
fi
|
|
|
|
export PGPORT="${E2E_PGPORT:-55434}"
|
|
export POSTGREST_PORT="${E2E_POSTGREST_PORT:-55435}"
|
|
export POSTGRES_DB="${E2E_POSTGRES_DB:-webstudio}"
|
|
# The Supabase image owns the schema as this required bootstrap role. Callers
|
|
# can still replace migration connections through E2E_DATABASE_URL and
|
|
# E2E_DIRECT_URL.
|
|
export POSTGRES_USER="supabase_admin"
|
|
export POSTGRES_PASSWORD="${E2E_POSTGRES_PASSWORD:-pass}"
|
|
export E2E_BACKEND_MODE="${E2E_BACKEND_MODE:-test}"
|
|
|
|
source "$ROOT_DIR/apps/builder/backend/lib.sh"
|
|
source "$ROOT_DIR/apps/builder/e2e/run-step.sh"
|
|
builder_backend_init "$E2E_BACKEND_MODE"
|
|
builder_backend_init_schema_snapshot
|
|
|
|
export E2E_DB_BOOTSTRAP="${E2E_DB_BOOTSTRAP:-auto}"
|
|
export E2E_BUILD_DATABASE_IMAGE="${E2E_BUILD_DATABASE_IMAGE:-true}"
|
|
export E2E_GENERATE_PRISMA="${E2E_GENERATE_PRISMA:-auto}"
|
|
export E2E_DOCKER_PULL_TIMEOUT_SECONDS="${E2E_DOCKER_PULL_TIMEOUT_SECONDS:-300}"
|
|
export E2E_DOCKER_TIMEOUT_SECONDS="${E2E_DOCKER_TIMEOUT_SECONDS:-60}"
|
|
export E2E_MIGRATIONS_TIMEOUT_SECONDS="${E2E_MIGRATIONS_TIMEOUT_SECONDS:-300}"
|
|
export E2E_INSTALL_PLAYWRIGHT="${E2E_INSTALL_PLAYWRIGHT:-auto}"
|
|
export E2E_PLAYWRIGHT_INSTALL_TIMEOUT_SECONDS="${E2E_PLAYWRIGHT_INSTALL_TIMEOUT_SECONDS:-600}"
|
|
export E2E_RUN_TESTS="${E2E_RUN_TESTS:-true}"
|
|
export E2E_START_POSTGREST="${E2E_START_POSTGREST:-$E2E_RUN_TESTS}"
|
|
export E2E_BUILDER_BUILD_TIMEOUT_SECONDS="${E2E_BUILDER_BUILD_TIMEOUT_SECONDS:-600}"
|
|
export E2E_TEST_COMMAND_TIMEOUT_SECONDS="${E2E_TEST_COMMAND_TIMEOUT_SECONDS:-900}"
|
|
export E2E_TEST_SELECTION_TIMEOUT_SECONDS="${E2E_TEST_SELECTION_TIMEOUT_SECONDS:-60}"
|
|
export E2E_WRITE_SCHEMA_SNAPSHOT="${E2E_WRITE_SCHEMA_SNAPSHOT:-false}"
|
|
|
|
cleanup() {
|
|
if [ "${E2E_SKIP_CLEANUP:-}" = "true" ]; then
|
|
return
|
|
fi
|
|
|
|
builder_backend_down --volumes --remove-orphans
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
|
|
bootstrap_database() {
|
|
if [ "$E2E_DB_BOOTSTRAP" = "if-empty" ]; then
|
|
builder_backend_bootstrap_if_empty
|
|
else
|
|
builder_backend_bootstrap "$E2E_DB_BOOTSTRAP"
|
|
fi
|
|
|
|
if [ "$E2E_WRITE_SCHEMA_SNAPSHOT" = "true" ]; then
|
|
builder_backend_write_schema_snapshot
|
|
fi
|
|
}
|
|
|
|
install_playwright_chromium() {
|
|
chromium_executable_exists() {
|
|
pnpm --dir "$ROOT_DIR" --filter=@webstudio-is/builder exec node -e '
|
|
const { chromium } = require("@playwright/test");
|
|
const { existsSync } = require("node:fs");
|
|
process.exit(existsSync(chromium.executablePath()) ? 0 : 1);
|
|
' >/dev/null 2>&1
|
|
}
|
|
|
|
case "$E2E_INSTALL_PLAYWRIGHT" in
|
|
true)
|
|
pnpm --dir "$ROOT_DIR" --filter=@webstudio-is/builder exec playwright install --with-deps chromium
|
|
;;
|
|
auto)
|
|
if chromium_executable_exists; then
|
|
echo "Skipping Playwright Chromium install; cached executable already exists"
|
|
else
|
|
pnpm --dir "$ROOT_DIR" --filter=@webstudio-is/builder exec playwright install --with-deps chromium
|
|
fi
|
|
;;
|
|
false)
|
|
echo "Skipping Playwright Chromium install"
|
|
;;
|
|
*)
|
|
echo "Unknown E2E_INSTALL_PLAYWRIGHT value: $E2E_INSTALL_PLAYWRIGHT" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
build_e2e_apps() {
|
|
pnpm --dir "$ROOT_DIR" e2e:builder:build
|
|
}
|
|
|
|
verify_e2e_apps_built() {
|
|
local builder_server="$ROOT_DIR/apps/builder/build/server"
|
|
local builder_assets="$ROOT_DIR/apps/builder/build/client/assets"
|
|
|
|
if [ ! -d "$builder_server" ] || [ ! -d "$builder_assets" ]; then
|
|
echo "E2E_SKIP_BUILDER_BUILD requires prebuilt Builder artifacts" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
run_builder_e2e_tests() {
|
|
(
|
|
cd "$ROOT_DIR/apps/builder"
|
|
if [ "${#PLAYWRIGHT_ARGS[@]}" -eq 0 ]; then
|
|
pnpm e2e:ci
|
|
else
|
|
pnpm e2e:ci "${PLAYWRIGHT_ARGS[@]}"
|
|
fi
|
|
)
|
|
}
|
|
|
|
validate_builder_e2e_selection() {
|
|
(
|
|
cd "$ROOT_DIR/apps/builder"
|
|
export E2E_BUILDER_URL="${E2E_BUILDER_URL:-https://127.0.0.1:3000}"
|
|
if [ "${#PLAYWRIGHT_ARGS[@]}" -eq 0 ]; then
|
|
pnpm e2e:ci --list
|
|
else
|
|
pnpm e2e:ci --list "${PLAYWRIGHT_ARGS[@]}"
|
|
fi
|
|
)
|
|
}
|
|
|
|
prepare_e2e_database_image() {
|
|
if [ "$E2E_BUILD_DATABASE_IMAGE" = "true" ]; then
|
|
builder_compose build --pull db
|
|
return
|
|
fi
|
|
|
|
builder_backend_pull_db
|
|
}
|
|
|
|
if [ "$E2E_RUN_TESTS" = "true" ]; then
|
|
run_step "validate builder e2e test selection" \
|
|
"$E2E_TEST_SELECTION_TIMEOUT_SECONDS" validate_builder_e2e_selection
|
|
fi
|
|
|
|
run_step "prepare e2e database image" "$E2E_DOCKER_PULL_TIMEOUT_SECONDS" \
|
|
prepare_e2e_database_image
|
|
|
|
run_step "start e2e database" "$E2E_DOCKER_TIMEOUT_SECONDS" \
|
|
builder_backend_start_db
|
|
|
|
db_port="$PGPORT"
|
|
if [ "$db_port" = 0 ]; then
|
|
db_port="$(builder_compose port db 5432)"
|
|
db_port="${db_port##*:}"
|
|
fi
|
|
export DATABASE_URL="${E2E_DATABASE_URL:-postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${db_port}/${POSTGRES_DB}?pgbouncer=true}"
|
|
export DIRECT_URL="${E2E_DIRECT_URL:-postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${db_port}/${POSTGRES_DB}}"
|
|
|
|
run_step "generate prisma client" "$E2E_MIGRATIONS_TIMEOUT_SECONDS" \
|
|
builder_generate_prisma_client "$E2E_GENERATE_PRISMA"
|
|
|
|
run_step "wait for e2e database" "$E2E_DOCKER_TIMEOUT_SECONDS" \
|
|
builder_backend_wait_for_db "$E2E_DOCKER_TIMEOUT_SECONDS"
|
|
|
|
run_step "bootstrap database schema" "$E2E_MIGRATIONS_TIMEOUT_SECONDS" \
|
|
bootstrap_database
|
|
|
|
if [ "$E2E_START_POSTGREST" = "true" ]; then
|
|
run_step "start e2e postgrest" "$E2E_DOCKER_TIMEOUT_SECONDS" \
|
|
builder_backend_start_postgrest
|
|
fi
|
|
postgrest_port="$POSTGREST_PORT"
|
|
if [ "$E2E_START_POSTGREST" = "true" ] && [ "$postgrest_port" = 0 ]; then
|
|
postgrest_port="$(builder_compose port postgrest 3000)"
|
|
postgrest_port="${postgrest_port##*:}"
|
|
fi
|
|
export POSTGREST_URL="${E2E_POSTGREST_URL:-http://localhost:${postgrest_port}}"
|
|
|
|
if [ "$E2E_RUN_TESTS" = "true" ]; then
|
|
run_step "install playwright chromium" "$E2E_PLAYWRIGHT_INSTALL_TIMEOUT_SECONDS" \
|
|
install_playwright_chromium
|
|
|
|
if [ "${E2E_BUILDER_URL:-}" = "" ]; then
|
|
if [ "${E2E_SKIP_BUILDER_BUILD:-false}" = "true" ]; then
|
|
run_step "verify prebuilt builder artifacts" "$E2E_BUILDER_BUILD_TIMEOUT_SECONDS" \
|
|
verify_e2e_apps_built
|
|
else
|
|
run_step "build builder and generated preview dependencies" "$E2E_BUILDER_BUILD_TIMEOUT_SECONDS" \
|
|
build_e2e_apps
|
|
fi
|
|
fi
|
|
|
|
run_step "run builder e2e tests" "$E2E_TEST_COMMAND_TIMEOUT_SECONDS" \
|
|
run_builder_e2e_tests
|
|
fi
|