Skip to main content

How to Test E-Signature and Document Workflows

Short answer

E-sign flows fail on sign-order violations, expired envelopes, witness requirements skipped, and completed PDFs not archived—not on whether a signature pad draws ink. Use DocuSign/HelloSign sandboxes in Arrange, probe envelope_state after each signer, assert PDF hash or clause presence via probe, and link signer_role scenarios to HR and insurance bind flows.

Part of Testing Guides by industry.

Who this is for

Teams shipping HR offers, insurance bind packets, SaaS order forms, or legal tech integrating DocuSign, Dropbox Sign, Adobe Sign, or in-house signature pads with sequential or parallel signers, witnesses, and ID verification.

Why testing e-signatures matters

Invalid signatures void contracts and block deals:

  • Sign order errors — Signer 2 completes before Signer 1; envelope legally void or stuck.
  • Expired envelopes — User signs after TTL; CRM shows won deal but no executable contract.
  • Witness skipped — Required witness role bypassed; real estate and will workflows invalid.
  • Tampered PDF — Post-sign modification; audit fails.
  • Wrong document version — Terms v3 sent, v2 signed; regulatory mismatch.

Probe envelope_state, signer_status, and archived PDF metadata—canvas stroke UI is insufficient.

Complexity map

ScenarioEdge caseWhy tests breakApproach
Sign orderSigner2 firstShould blockProbe waiting status
Parallel signAll must completePartial completeProbe each signer
Envelope expiryclock past TTLShould rejectclock + probe expired
Decline to signWorkflow stopStill advancesProbe declined
Witness requiredMissing witnessCompleted wronglyProbe roles complete
Embedded vs emailDifferent URLsUntested pathBoth specs or probe
ID verificationKBA failShould blockProbe verification
CC recipientsNot signersConfusionProbe recipient roles
Template mergeWrong field valuesBad contractProbe merged fields
Void envelopeAfter partial signOrphan CRMProbe void + CRM
Mobile signTouch padDesktop onlyMobile project
API webhook lagStatus staleEarly assertpoll envelope probe

DocuSign sandbox Arrange

// POST /api/test/create-envelope
// Returns { envelopeId, signingUrlSigner1, signingUrlSigner2 }
const { envelopeId, signingUrlSigner1 } = await request.post('/api/test/create-envelope', {
data: {
runId,
templateId: 'demo-offer',
signers: [
{ role: 'employee', email: `signer1-${runId}@test.local`, order: 1 },
{ role: 'hr', email: `signer2-${runId}@test.local`, order: 2 },
],
},
}).then(r => r.json());

Use DocuSign developer sandbox credentials in CI secrets—never prod.

Sign order enforcement

await page.goto(signingUrlSigner2); // signer 2 first — wrong order
await expect(page.getByText(/waiting|not your turn/i)).toBeVisible();
const env = await request.get(`/api/test/envelope/${envelopeId}`).then(r => r.json());
expect(env.status).toBe('sent');
expect(env.signers.find(s => s.role === 'hr').status).toBe('waiting');

await page.goto(signingUrlSigner1);
await completeSigningUI(page); // product-specific clicks + adopt signature
await expect.poll(async () =>
(await request.get(`/api/test/envelope/${envelopeId}`)).json()
).toMatchObject({ signers: expect.arrayContaining([expect.objectContaining({ role: 'employee', status: 'completed' })]) });

PDF Assert via probe

await completeBothSigners(/* ... */);
const pdf = await request.get(`/api/test/envelope/${envelopeId}/pdf`).then(r => r.json());
expect(pdf.sha256).toMatch(/^[a-f0-9]{64}$/);
expect(pdf.containsText).toContain('Offer Terms v3');

Parse PDF text in test env only—avoid storing full PDFs in CI artifacts with PII; use synthetic names.

Expiry with clock

await context.clock.install({ time: new Date('2024-06-01T10:00:00Z') });
await createEnvelope(/* expires in 1h */);
await context.clock.runFor(3_600_000 + 1);
await page.goto(signingUrlSigner1);
const env = await request.get(`/api/test/envelope/${envelopeId}`).then(r => r.json());
expect(env.status).toBe('expired');

Requirement slices to cover

  • signer_role — employee, hr, witness, counterparty
  • envelope_state — sent, completed, declined, expired, voided

Link HR offer flows (HR applications) and insurance bind (insurance quotes).

CI checklist

  1. Sandbox credentials rotated; demo templates only
  2. Sign-order negative spec
  3. Completed envelope probe + PDF metadata
  4. Expiry spec with clock
  5. Webhook handler tested via poll if async
  6. Void/decline paths update CRM probe

Anti-patterns

Anti-patternWhy it failsBetter approach
Draw signature onlyNo envelope stateProbe completed
Prod DocuSign in CILegal + rateSandbox
Skip signer2Order bugsSequential spec
Email link E2E onlyFlaky inboxsigningUrl route
No PDF assertWrong doc archivedcontainsText probe
PII PDF artifactsLeakSynthetic merge fields

Example scenario

Situation: HR offer requires employee then HR counter-sign; employee tries forwarding HR link early.

Expected outcome: HR signing blocked until employee completes; envelope remains sent not completed.

Why UI-only automation breaks: HR UI loads but completed PDF missing employee signature page—unenforceable offer.

  1. Arrange: Sandbox envelope two ordered signers for runId.
  2. Act: Attempt HR URL before employee signs; then employee signs; then HR.
  3. Assert: Probe order enforced; final PDF contains both signatures metadata; envelope completed.

TestChimp workflow: Track envelope_state by signer_role; evolve witness-required templates if prod share grows.

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).

External references

Frequently asked questions

How do I test DocuSign flows in CI?

Create envelope via sandbox API in Arrange, navigate signingUrl in Playwright, complete adopt-signature UI, poll envelope probe to completed, assert PDF metadata—never prod accounts.

How is sign order tested?

Open second signer URL before first completes—expect blocked UI and probe waiting status. Complete in order; probe completed with both signers.

How do witness flows differ?

Seed template requiring witness role; attempt complete without witness—probe should not reach completed; add witness signer and assert completed.

How do expired envelopes behave?

Install clock, create short TTL envelope, advance past expiry, attempt sign—probe expired and signing rejected.

Webhooks vs polling?

Poll test envelope probe in E2E for simplicity; unit test webhook handler separately. expect.poll until status completed.

How do I avoid PII in signed PDF artifacts?

Use synthetic merge fields and redact CI artifacts; assert containsText clauses not full PDF storage.

Which signer_roles need TrueCoverage priority?

Compare prod envelope templates—evolve witness and parallel signer patterns when undertested vs HR/insurance traffic.

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.

Start free on TestChimp · Book a demo