Testing

July 29, 2026 ยท View on GitHub

Use root turbo-backed commands when checking the whole repository:

pnpm verify
pnpm check-types
pnpm lint
pnpm test

Browser smoke coverage is split into two levels:

pnpm e2e:product-loop
pnpm e2e:product-loop:full

e2e:product-loop signs in to a seeded Console account, checks the main product pages, verifies published integration URLs, and renders the published style when a seeded PMTiles fixture is available. Set PLANISFY_E2E_ALLOW_MISSING_TILESET=true for non-binary CI runs that do not ship demo PMTiles data.

e2e:product-loop:full uploads a small GeoJSON through the Console, waits for the geodata worker to build a tileset, publishes the tileset, creates and publishes a style against it, fetches the public URLs, and renders the result in MapLibre. Run it against a migrated Compose stack with worker-geodata running.

The local self-host QA pass also uses:

SMOKE_BROWSER_PRODUCT_LOOP=true pnpm smoke:self-host-compose
pnpm smoke:self-host-route-protection
pnpm smoke:self-host-support-bundle
pnpm smoke:self-host-restart-persistence
pnpm smoke:self-host-backup-restore

These commands write logs, screenshots, and generated fixtures under dogfood-output/.

Public self-host fixtures can be uploaded to Cloudflare R2 with:

pnpm fixtures:upload

Set PLANISFY_FIXTURE_BASE_URL to the public v1 prefix before running scripts/self-host-setup.sh --demo-data. If that bucket is unavailable, setup can fall back to DEMO_PMTILES_FALLBACK_URL, DEMO_PMTILES_FALLBACK_PATH, or an already-installed local PMTiles file.

Managed mode can be smoked locally against real Cloudflare R2 without using public HTTPS ingress:

cat > .env.managed-local <<'EOF'
R2_ACCESS_KEY_ID="..."
R2_SECRET_ACCESS_KEY="..."
# Optional when Wrangler can discover it: R2_ACCOUNT_ID="..."
# Optional: R2_BUCKET="planisfy-managed-local-smoke"
EOF

pnpm smoke:managed-local

This workflow resets the local Compose stack, creates the private R2 smoke bucket when missing, and runs the managed smoke against http://localhost:4000 and http://localhost:3001. Billing and email are config smokes only; no Dodo checkout or ZeptoMail delivery is attempted.

Managed staging has two smoke levels:

pnpm smoke:managed-staging
MANAGED_STAGING_TEST_EMAIL="..." MANAGED_STAGING_TEST_PASSWORD="..." pnpm smoke:managed-staging-product-loop

smoke:managed-staging stays a fast public ingress, CORS, provider configuration, and storage write/read/delete check. Its ingress values must be clean public HTTPS origins; DNS answers are validated and pinned, redirects are revalidated, and response sizes and waits are bounded. The product-loop wrapper runs the full upload/process/publish/render browser flow against real managed public URLs and an existing managed test user; it does not seed data or reset the environment.

Self-host tests default to S3-compatible MinIO. Run the full product loop with the with-minio Compose profile and these storage settings:

STORAGE_PROVIDER=s3
S3_BUCKET=planisfy-artifacts
S3_REGION=auto
S3_ENDPOINT=http://localhost:9000
CONTAINER_S3_ENDPOINT=http://minio:9000
S3_PUBLIC_URL=http://localhost:9000/planisfy-artifacts
AWS_ACCESS_KEY_ID=planisfy
AWS_SECRET_ACCESS_KEY=planisfy-local-minio-password
MINIO_ROOT_USER=planisfy
MINIO_ROOT_PASSWORD=planisfy-local-minio-password

Then start Compose with --profile with-minio and run:

pnpm e2e:product-loop:full
ENV_FILE=/path/to/minio.env pnpm smoke:self-host-backup-restore

The MinIO/S3 runtime path has been proven for uploaded tilesets, published TileJSON/style rendering, profile avatars, sprite SVG assets, and backup/restore of the Compose MinIO object store.

Focused commands:

pnpm --filter docs check-types
pnpm --filter docs lint
pnpm --filter api test
pnpm --filter worker-geodata test
pnpm --filter @planisfy/events test

Current tests cover selected route behavior, worker/toolchain contracts, event parsing, storage paths, style/spec helpers, platform policy, and service-specific logic. Browser/product-loop coverage exists as scripts and should be run against a live stack when changing Console flows.

Docs changes should also run pnpm --filter docs check-types because Fumadocs generates typed content before TypeScript checks.