import { describe, it, expect } from 'vitest'; import { DOC_TYPE_LABEL, extractSigningToken, nextPendingSigner, } from '@/lib/services/documenso-signers'; describe('extractSigningToken', () => { it('pulls the last path segment when it looks token-shaped', () => { expect(extractSigningToken('https://sig.example.com/sign/vbT8hi3jKQmrFP_LN1WcS')).toBe( 'vbT8hi3jKQmrFP_LN1WcS', ); }); it('handles trailing slash gracefully', () => { expect(extractSigningToken('https://sig.example.com/sign/HkrptwS42ZBXdRKj1TyUo/')).toBe( 'HkrptwS42ZBXdRKj1TyUo', ); }); it('returns null for non-URL input', () => { expect(extractSigningToken('not a url at all')).toBeNull(); expect(extractSigningToken('')).toBeNull(); expect(extractSigningToken(null)).toBeNull(); expect(extractSigningToken(undefined)).toBeNull(); }); it('rejects too-short tails (defends against generic "sign" / "embed" terminators)', () => { expect(extractSigningToken('https://example.com/sign')).toBeNull(); expect(extractSigningToken('https://example.com/abc')).toBeNull(); }); it('rejects path tails with disallowed characters', () => { // Real tokens are URL-safe base64 - no spaces, no punctuation expect(extractSigningToken('https://example.com/sign/has%20space')).toBeNull(); }); it('handles real v1.32 + v2 token shapes', () => { // Documenso 1.32 token (21-char URL-safe alphabet from real webhook docs) expect(extractSigningToken('https://sig.documenso.com/sign/vbT8hi3jKQmrFP_LN1WcS')).toBe( 'vbT8hi3jKQmrFP_LN1WcS', ); // Mixed-case + underscores + dashes expect(extractSigningToken('https://app.example.com/sign/Aa_-Zz09Aa_-Zz09')).toBe( 'Aa_-Zz09Aa_-Zz09', ); }); }); describe('DOC_TYPE_LABEL', () => { it('maps the three known document types to customer-facing labels', () => { expect(DOC_TYPE_LABEL.eoi).toBe('Expression of Interest'); expect(DOC_TYPE_LABEL.contract).toBe('Sales Contract'); expect(DOC_TYPE_LABEL.reservation_agreement).toBe('Reservation Agreement'); }); }); describe('nextPendingSigner', () => { it('picks the lowest signingOrder pending signer', () => { const signers = [ { status: 'signed', signingOrder: 1 }, { status: 'pending', signingOrder: 2 }, { status: 'pending', signingOrder: 3 }, ]; expect(nextPendingSigner(signers)).toEqual({ status: 'pending', signingOrder: 2 }); }); it('returns null when every signer has signed', () => { expect( nextPendingSigner([ { status: 'signed', signingOrder: 1 }, { status: 'signed', signingOrder: 2 }, ]), ).toBeNull(); }); it('treats declined the same as no longer pending', () => { expect( nextPendingSigner([ { status: 'declined', signingOrder: 1 }, { status: 'signed', signingOrder: 2 }, ]), ).toBeNull(); }); it('handles unordered input by signingOrder', () => { const signers = [ { status: 'pending', signingOrder: 5 }, { status: 'signed', signingOrder: 1 }, { status: 'pending', signingOrder: 2 }, ]; expect(nextPendingSigner(signers)).toEqual({ status: 'pending', signingOrder: 2 }); }); });