Skip to content

Instantly share code, notes, and snippets.

@veritech
Last active July 3, 2026 06:35
Show Gist options
  • Select an option

  • Save veritech/06fae8e1f78574623f861409111e77bb to your computer and use it in GitHub Desktop.

Select an option

Save veritech/06fae8e1f78574623f861409111e77bb to your computer and use it in GitHub Desktop.
Forms refactor test plan — Epic #2553 embed → hosted handoff

Phase 0 test plan — Epic #2553 (embed → hosted handoff)

Epic: #2553 — Forms: Embed → hosted partner subdomain flow
Scope: Phase 0 — core handoff at app.leadtrap.ai/forms/continue?handoff=...
Shipped in: #2631 (closes #2550)

Environment: dev.leadtrap.ai (or production after deploy confirmation)

Flow under test: embed intake → server-driven OpenPageStep redirect → /forms/continue?handoff=… → behavioral wizard


1. Prerequisites

Partner / campaign

  • Test partner is in the internalTesting Featurevisor segment (hostedFormRedirect and formsSetupTab are 0% for * today)
  • Campaign has:
    • At least one intake form with questions
    • At least one enabled behavioral form with questions (required for redirect to fire)

Feature flags

Both must be enabled for the test partner (via internalTesting segment):

  • hostedFormRedirect — server-side gate in resolveNextStep
  • formsSetupTab — optional; provides embed code from Setup tab

Campaign config

There is no admin UI for hosted redirect yet — configure via GraphQL:

mutation {
  updateWebFormProductConfiguration(input: {
    id: "<configuration-id>"
    hostedRedirect: {
      enabled: true
      target: TOP        # also test SELF and BLANK separately
      delayMs: null      # also test 2000 for delay case
    }
  }) {
    id
    hostedRedirect { enabled target delayMs previewUrl }
  }
}
  • hostedRedirect.enabled = true
  • Confirm previewUrl is https://<FRONTEND_HOSTNAME>/forms/continue

Embed

  • Embed snippet from Forms → Setup tab (or existing embed page)
  • Test page loads the iframe embed (/platform/frame/forms?partner_id=…)

2. Happy path — full handoff

# Step Expected
1 Open partner embed page Intake form loads with branding
2 Complete all intake questions Submit succeeds
3 Observe redirect Browser navigates to …/forms/continue?handoff=<code> (top window if TOP)
4 Hosted page loads No admin chrome; full-page form (not iframe)
5 Behavioral wizard Opens directly on behavioral questions (not intake gate)
6 Intake answers hydrated Previously submitted intake values are present in session/state
7 Complete behavioral form Submit succeeds; lead updated
8 Same visitorSessionId Backend lead/session ties embed + hosted legs together

Admin verification:

  • Lead appears with intake + behavioral answers
  • Activity/timeline looks correct

3. Redirect target variants

Run the happy path three times with different hostedRedirect.target:

Target Expected navigation
TOP window.top.location → hosted URL (breaks out of iframe)
SELF iframe navigates to hosted URL
BLANK new tab opens hosted URL (noopener,noreferrer)
  • With delayMs: 2000, redirect waits ~2s before navigating

4. Negative / edge cases

# Scenario Expected
1 Visit /forms/continue with no ?handoff= “This form link is invalid.”
2 Visit with garbage handoff code “invalid or has expired”
3 Redeem same handoff URL twice (refresh/back) Second load fails — code is single-use (Redis GETDEL)
4 Wait >2 min, then redeem code Expired — code TTL is 120s
5 hostedFormRedirect flag off for partner Intake shows thank-you screen, no redirect
6 hostedRedirect.enabled = false Thank-you, no redirect
7 No behavioral forms on config Thank-you, no redirect
8 Intake incomplete (skip required field) No redirect; validation blocks submit
9 Disqualified lead (service area / qualifier) Qualifier result screen, no redirect
10 Prior embed session in same tab, then new handoff Hosted page shows correct handoff data (no stale Zustand state)

5. Security / abuse checks

  • Handoff code is opaque hex, not guessable (24 random bytes)
  • continueFormHandoff is public but returns null for bad codes (no error leakage)
  • Replay of used code returns null, not previous session
  • Hosted page loads config via partnerId from redeemed session (not URL param)

6. Dev vs prod routing

Check Dev Prod
/forms/continue?handoff=… serves hosted-forms.html [ ] [ ]
/forms/continue/ (trailing slash) works [ ] [ ]
/forms/continue does not fall through to admin SPA [ ] [ ]

7. Regression — flag off (default)

With flags at 0% for general traffic:

  • Existing embed-only partners unaffected — intake → thank-you, no redirect
  • No OpenPageStep in GraphQL response when redirect preconditions fail

8. Automated coverage (CI)

Already covered by unit/integration tests:

  • HostedFormsApp Jest tests (missing/expired/success)
  • continueFormHandoff functional + unit tests
  • executeSubmitNextStep redirect URL builder tests
  • formHandoffCodeManager single-use + TTL tests

Manual sections above remain the Phase 0 sign-off gate until e2e is added (see below).


Sign-off

Area Tester Date Pass?
Happy path (TOP)
SELF / BLANK targets
Single-use + expiry
Flag/config gating
Prod routing

E2E automation feasibility

Yes — a Playwright e2e test is possible, but it needs new fixtures; nothing in e2e/ covers forms today.

What maps well to e2e

Manual case E2E approach
Happy path (TOP) Parent HTML page embeds iframe → fill intake → assert top-level URL matches /forms/continue?handoff= → fill behavioral question
Invalid / missing handoff Direct page.goto('/forms/continue') + assert error text
Single-use replay Capture URL after redirect → goto twice → second load shows expired
Flag/config off Seed partner without redirect preconditions → assert thank-you, no navigation
SELF / BLANK Separate tests with different hostedRedirect.target in seed data

What to keep as backend tests (not e2e)

Case Why
Code TTL (120s) Waiting 2+ minutes in e2e is slow/flaky; already covered by form_handoff_code_manager tests
resolveNextStep preconditions Faster and more reliable as web_form_product_answer_manager unit/functional tests
Defense-in-depth on continueFormHandoff Resolver unit tests already exist

Work required to add e2e

  1. Test seed — extend POST /api/test/create-test-data (or add /api/test/create-forms-handoff-fixture) to create:

    • Partner in internalTesting segment (or bypass flags in test env)
    • Web form config with intake + behavioral forms
    • hostedRedirect.enabled = true
  2. Fixture pagefrontend/public/tests/e2e/forms-embed.html mirroring default.html but loading the forms iframe embed

  3. Playwright spece2e/src/tests/forms-hosted-handoff.spec.ts:

    • Helper to fill Magic Forms fields by label
    • Intercept or read handoff from URL after redirect
    • Optional: GraphQL poll to verify lead answers post-behavioral submit
  4. CI — add npm run test:forms-handoff script; wire into e2e.yml (full stack required)

Suggested first e2e spec (MVP)

forms-hosted-handoff.spec.ts
  ✓ redirects to hosted continue page after intake submit (TOP)
  ✓ shows behavioral question on hosted page
  ✓ rejects missing handoff param
  ✓ rejects replayed handoff code

Target variants (SELF, BLANK, delayMs) can be separate tests once the seed API accepts config overrides.

Estimate

~1–2 days for MVP happy path + negative URL cases, assuming test seed API work. Full parity with this manual plan would be ~3–4 days.


After Phase 0 passes: epic stays open for #2552 (partner subdomains), #2625 (remove embed “next step” display), and #2618 (handoff test polish).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment