Skip to content

Repository files navigation

scanopy.net

Marketing website for Scanopy — SvelteKit + Tailwind, fully prerendered static site (@sveltejs/adapter-static). The docs sub-site in docs/ is built separately and copied into build/docs by npm run build. Deploys on push to main.

npm install       # also installs docs/ dependencies
npm run dev       # dev server
npm run build     # full production build (site + docs)

Form Monitoring

The public lead-capture forms are the inbound channel for the highest-value deals and have silently broken in production more than once (most recently June 2026: the /commercial "Request a Quote" form did nothing on click, with no error shown). A weekly Playwright suite submits each form on the live site end to end so a broken form is caught within a week instead of by a frustrated prospect.

  • Specs live in e2e/, shared helpers in e2e/helpers.ts, config in playwright.config.ts.
  • CI: .github/workflows/form-monitor.yml — every Monday 06:00 UTC, plus manual runs via the Actions tab (Form Monitor → Run workflow).
  • On failure the workflow goes red (GitHub emails the repo owner) and opens a GitHub issue labeled form-monitor (or comments on the existing open one). The Playwright report with screenshots and traces is attached to the run as an artifact.

Coverage

Every form found on the site is listed here. The contact modal posts to /api/contact, a Cloudflare Pages Function (functions/api/contact.ts) that finds or creates the Apollo account, creates the contact on it, and assigns a follow-up task; it needs the APOLLO_API_KEY Pages secret. The newsletter submits to Brevo (sibforms.com) via src/lib/brevo.ts.

Form Page tested Spec Real submission?
Contact modal: Enterprise "Request Information" /pricing e2e/contact-modal.spec.ts yes
Newsletter signup (footer, sitewide) / (home) e2e/newsletter.spec.ts yes

The contact modal is one component, mounted once in the root layout. Its only trigger is the pricing widget's Enterprise "Request Information". Every "Get a license" CTA, including the ones on /commercial (where the June 2026 silent failure happened), links to app signup instead of opening a form. The home page carries no contact CTA, so nothing is left unmonitored by not testing / here. Its footer newsletter form is covered by the newsletter row.

Each weekly run creates 1 real Apollo contact and 1 Brevo newsletter subscription (double that in the worst case, since CI retries a failed test once).

reCAPTCHA history: the forms originally attached reCAPTCHA v3 tokens, and the newsletter form enforced them in Brevo — which blocked this monitor, since automated browsers always score too low to pass v3. Enforcement was turned off in Brevo in July 2026 and the client-side integration was commented out in src/lib/brevo.ts (spam protection is now the honeypot field plus newsletter double opt-in). If the newsletter test ever fails with BREVO REJECTED SUBMISSION mentioning a captcha error, someone re-enabled enforcement in Brevo — either turn it back off, or accept that the newsletter form can only be monitored up to Brevo's bot-protection boundary (the pre-July-2026 version of e2e/newsletter.spec.ts in git history did exactly that).

Sentinel convention — keeping test data out of the lead list

Every submission the suite makes is marked so it can be filtered everywhere downstream. Downstream filters key on these exact values — don't change them casually (they live in e2e/helpers.ts):

  • Email: formtest+YYYYMMDD@scanopy.net (e.g. formtest+20260705@scanopy.net)
  • First name / last name / company: AUTOMATED TEST
  • Use-case message: AUTOMATED TEST - weekly production form monitor. Please ignore.

Suggested filters:

  • Apollo: the contact function labels sentinel submissions Form monitor instead of Website inquiry and creates no owner task for them. Bulk-delete contacts with that label periodically, and keep the label out of any workflows or sequences.
  • Brevo: a segment or automation matching EMAIL contains formtest+ (or FIRSTNAME equals AUTOMATED TEST) → auto-blocklist or periodically bulk-delete. This also keeps test contacts out of any workflows/sequences.
  • Gmail: filter to:(formtest+) → skip inbox, archive. Newsletter double-opt-in confirmations go to wherever formtest@scanopy.net routes — make sure that alias exists (or accept the bounce).

Neither the contact function nor Brevo's hosted forms have a test mode, so real submissions are intentional: the point is exercising the production code path end to end.

Running locally

npm run test:forms          # headless
npm run test:forms:headed   # watch it happen

Warning: local runs submit real (sentinel-marked) data to production Apollo and Brevo, exactly like CI.

To run the contact-modal specs against a local build instead, serve the build and point E2E_BASE_URL at it. Off production, the helpers answer /api/contact locally, so no Apollo contacts are created. The newsletter spec still submits to the real Brevo from any base URL, so run only the contact spec:

npm run build
npx vite preview --port 4173 --strictPort   # in a second terminal
E2E_BASE_URL=http://localhost:4173 npx playwright test e2e/contact-modal.spec.ts

Adding a new form to the suite

Adding a form to the site should always come with a spec here:

  1. Create e2e/<form-name>.spec.ts (one spec file per form).
  2. Use the helpers: seedCookieConsent (keeps the cookie banner from intercepting clicks and analytics from recording the run), gotoHydrated (the site is prerendered — clicking before hydration silently does nothing), sentinel values from helpers.ts, and submitAndExpectBrevoSuccess (asserts the POST fires, returns 2xx, and success:true). For a non-Brevo endpoint, add a sibling helper that matches that endpoint's URL and success shape.
  3. Assert the user-visible success state, not just the network response.
  4. Add a row to the coverage table above.

Forms / widgets that are NOT monitored, and why

  • NewsletterCTA.svelte — dead component, rendered by zero routes (the footer is the only live newsletter instance). Nothing to test in production; if it ever gets wired into a page, add a spec.
  • "Talk to Sales" / demo buttons — external Cal.com scheduling links, not forms.
  • "Get a license" CTAs: links to app signup on app.scanopy.net, not forms.
  • mailto: links (licensing@, etc.) — no form pipeline to break.
  • Cookie consent banner, service-catalog search box — no network submission.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages