How to Test SaaS Onboarding Flows
Short answer
Onboarding is a multi-step activation funnel—invite, profile, billing, integrations, empty states. Reliable tests use fixture-backed users seeded at each step, markScreenState checkpoints for ExploreChimp, and probes on activation flags—not single giant UI scripts or click-every-button tours.
Part of Testing Guides by industry.
Who this is for
B2B and B2C SaaS startups optimizing activation, trials, and time-to-value—with frequent onboarding experiments, A/B step order, and integration gates. PLG signup, sales-assist invite, and team invite flows all fit.
Why testing onboarding matters
Activation bugs kill growth silently:
- Revenue loss — trial users stuck before billing; paid features locked despite
onboarding_completeUI badge. - Churn — integration skip breaks downstream automation; empty dashboard on first visit.
- Experiment risk — A/B reorder breaks tests assuming fixed step sequence; winner variant untested in CI.
- Analytics drift — product shows drop-off at step 3; E2E never covers skip path or empty state.
The dashboard can render while onboarding_complete and integration flags disagree on the server. Probe user state—not only visible step indicators.
Complexity map
| Scenario | Edge case | Why tests break | Approach |
|---|---|---|---|
| Trial signup | Email verification gate | Cannot click inbox | Seed verified user (email guide) |
| Invite accept | Token expired | 404 page | Seed fresh invite token per run |
| Profile step | Required fields vary by plan | Validation flake | Probe partial profile |
| Skip integration | Optional vs required | Wrong activation | Probe flags after skip |
| A/B step order | Variant B first | Hard-coded step index | Seed at step + screen state |
| Team invite | Seat limit | Invite fails silently | Probe seat count |
| Billing attach | Trial without card | Feature gate wrong | Probe subscription status |
| Empty dashboard | No data first visit | Broken CTA | ExploreChimp + empty-state spec |
| OAuth connect | Popup in CI | Hang | Split post-connect probe (OAuth guide) |
| Feature flag variant | Onboarding v2 | Wrong funnel | Posture fixture |
| Resume mid-flow | Session timeout | Duplicate org | Probe single tenant |
| Downgrade path | Skip paid step | Wrong entitlements | Probe plan flags |
| Mobile vs desktop | Different step UI | Untested slice | trueCoverage device slice |
| SSO domain | Hosted domain only | Wrong auth path | Seed SSO test user |
| Activation metric | activated_at null | False green UI | Probe timestamp |
Screen states and ExploreChimp
Screen states anchor exploration and analytics to funnel steps—not bare URLs that change with A/B tests:
import { markScreenState } from '@testchimp/playwright'; // or your harness helper
await page.goto('/onboarding/profile');
await page.getByLabel('Company name').fill('Acme Test');
await page.getByRole('button', { name: 'Continue' }).click();
await markScreenState(page, 'onboarding:integrations');
await page.getByRole('button', { name: 'Skip for now' }).click();
await markScreenState(page, 'onboarding:dashboard');
const user = await request.get(`/api/test/probe-user?runId=${runId}`).then(r => r.json());
expect(user.onboardingComplete).toBe(true);
expect(user.integrationOptional).toBe(true);
ExploreChimp runs UX checks on SmartTests annotated with screen states—surfacing drop-offs, broken empty states, and confusing copy after funnel changes without re-recording opaque sessions (explorations).
Manual QA on staging → convert sanitized path to SmartTest with shared Arrange seed at onboarding:integrations (record-replay vs TestChimp).
Activation funnel: seed at step
Do not walk invite → profile → billing → integration in every spec:
| Step | Arrange seed | Assert probe |
|---|---|---|
| Post-signup | onboarding_step=profile | profile_complete |
| Pre-integration | onboarding_step=integrations | integration_pending |
| Post-skip | integration_skipped=true | onboarding_complete |
| Trial active | trial_end future | plan=trial |
// POST /api/test/seed-onboarding-user
// Body: { runId, step: 'integrations', plan: 'trial', integrationOptional: true }
const { userId } = await request.post('/api/test/seed-onboarding-user', {
data: { runId, step: 'integrations', plan: 'trial', integrationOptional: true },
}).then(r => r.json());
await page.goto('/onboarding/integrations');
One end-to-end smoke with synthetic data optional; focused specs per branch.
Branch scenarios
Document in markdown:
- Happy path — complete all steps; probe
activated_atset - Skip optional integration — probe
onboarding_completewithoutintegration_connected - Invite accept — probe org membership + role
- Billing required — cannot reach dashboard without payment method when policy requires
- Empty dashboard first visit — probe zero projects + CTA visible; ExploreChimp for UX
Link SmartTests with // @Scenario: ONBOARD-SKIP-INT-01 (requirement traceability).
Requirement slices to cover
onboarding_step— signup, profile, billing, integrations, dashboardonboarding_outcome— completed, skipped_integration, abandoned, invitedplan_type— trial, free, paid, enterpriseauth_method— password, google, sso
Compare onboarding_step_completed sequences prod vs test—when prod shows 35% skip integration but tests always connect Slack, evolve skip specs.
CI checklist
- Unique email per worker in signup specs
- Seed users at step boundaries for focused tests
markScreenStateat each funnel checkpoint- Probe activation flags—not only URL or step indicator
- ExploreChimp run after major onboarding PR (preview URL)
- Feature-flag posture matches preview branch
- SSO/OAuth split: post-connect probe spec per OAuth guide
Anti-patterns
| Anti-pattern | Why it fails | Better approach |
|---|---|---|
| Click every button once | Misses branch gates | Scenarios per funnel branch |
| No activation assert | Signups without setup | Probe user state + TrueCoverage |
| Shared signup email | Data collisions in CI | Seed unique emails per run |
| Ignore empty states | UX breaks first visit | ExploreChimp on onboarding paths |
| Monolithic 15-min script | Breaks on copy reorder | Step seeds + screen states |
| URL-only navigation | A/B changes routes | markScreenState anchors |
| Skip billing gate negatives | Paid leakage | Probe entitlements |
Example scenario
Situation: Trial user skips integration step but must still reach dashboard.
Expected outcome: User lands on dashboard with `onboarding_complete=true` and integration optional.
Why UI-only automation breaks: Test assumes fixed step order; A/B reorder breaks suite though product is fine.
- Arrange: Seed trial user at pre-integration state via fixture.
- Act: Click skip integration and finish onboarding in UI.
- Assert: Probe reads activation flags; `markScreenState` at dashboard for downstream ExploreChimp.
TestChimp workflow: Compare `onboarding_step_completed` sequences in prod vs test runs.
Same Arrange/Act/Assert pattern as expired-coupon checkout.
Connect scenarios to your QA workflow
Capture business rules in markdown test plans and enforce them with seed routes and probe Assert. Link SmartTests with // @Scenario: for requirement traceability. Use /testchimp test on PRs; /testchimp explore on SmartTest paths for non-functional gaps (ExploreChimp).
Related scenarios
- Trial to paid — billing conversion
- Feature entitlements — post-onboarding gates
- Seat licensing — team invites
- Firebase auth — signup and verification
- Transactional email — invite and verify emails
- Flaky E2E fixes — shared signup collisions
- HR applications — post-hire onboarding bridge
External references
Frequently asked questions
How do screen states help SaaS onboarding tests?
markScreenState anchors ExploreChimp and Atlas to funnel steps—not bare URLs—so activation regressions map to scenario coverage when /testchimp test updates SmartTests.
Should every spec walk the full onboarding funnel?
No—seed users at profile, integrations, or billing steps for focused specs. One synthetic end-to-end smoke optional; branch scenarios for skip and invite paths.
How do I test A/B onboarding order changes?
Avoid hard-coded step indices; seed user at logical step via probe field, use screen states for navigation asserts, probe activation flags for outcome.
When should I run ExploreChimp on onboarding?
After funnel UI PRs on preview URLs—especially empty dashboard and skip paths. Annotated SmartTests link UX findings back to markdown scenarios.
How do activation probes differ from UI step indicators?
Probes read onboarding_complete, integration_connected, plan, activated_at on user/org record—UI checkmarks can desync from server flags.
Invite and SSO flows in CI?
Seed fresh invite tokens per run; for OAuth use post-connect tier with probe on org membership—full popup in nightly job per OAuth guide.
How does TrueCoverage guide onboarding tests?
Compare onboarding_step and outcome sequences prod vs test. Evolve when skip integration or invite accept paths dominate prod but tests only cover happy connect.
Apply these patterns in your repo
Run `/testchimp init` to connect TestChimp to your repo, then `/testchimp test` on PRs to turn these patterns into maintained SmartTests. Use `/testchimp evolve` when you want to expand coverage as your app grows.