VerifyKitv0.5.1

Testing

This guide covers strategies for testing applications that use the VerifyKit SDK, including unit testing with mocks, integration testing, and test environment setup.


Overview

VerifyKit's verification engine runs in WebAssembly, which requires a browser or Node.js environment. For unit tests, you can mock the verifier to avoid WASM initialization overhead. For integration tests, you can use the real verifier with sample PDF files.


Mocking the Verifier

The VerifyKitVerifier interface is straightforward to mock. Create a mock that returns predetermined results for your test cases.

Creating a Mock Verifier

typescript
import type { VerifyKitVerifier, VerificationResult, PdfSignature } from '@trexolab/verifykit-core'
 
function createMockVerifier(overrides?: Partial<VerificationResult>): VerifyKitVerifier {
  const defaultResult: VerificationResult = {
    fileSize: 1024,
    fileHash: 'abc123',
    signatures: [],
    ...overrides,
  }
 
  return {
    verify: async () => defaultResult,
    extractMetadata: async () => ({
      metadata: {
        title: 'Test Document',
        author: 'Test Author',
        subject: '',
        keywords: '',
        creator: 'Test',
        producer: 'Test',
        creationDate: new Date('2025-01-01'),
        modDate: new Date('2025-01-01'),
        pdfVersion: '1.7',
        pageCount: 1,
      },
      permissions: {
        encrypted: false,
        encryptionMethod: 'none',
        permissionFlags: null,
        printing: 'allowed',
        modification: true,
        copying: true,
        annotations: true,
        formFilling: true,
        accessibility: true,
        assembly: true,
      },
    }),
    dispose: () => {},
  }
}

Mock Signatures

Create mock PdfSignature objects to test different verification outcomes:

typescript
import type { PdfSignature, SignatureCheckResult } from '@trexolab/verifykit-core'
 
function validCheck(label: string): SignatureCheckResult {
  return { label, status: 'valid', detail: 'OK' }
}
 
function createMockSignature(overrides?: Partial<PdfSignature>): PdfSignature {
  return {
    index: 0,
    name: 'Test Signer',
    fieldName: 'Signature1',
    subFilter: 'adbe.pkcs7.detached',
    byteRangeCoverage: true,
    byteRangeCoversWholeFile: true,
    integrityCheck: validCheck('Document integrity'),
    signatureCheck: validCheck('Signature cryptographic validity'),
    certificateChainCheck: validCheck('Certificate chain'),
    expiryCheck: validCheck('Certificate expiry'),
    timestampCheck: validCheck('Timestamp'),
    revocationCheck: { label: 'Revocation', status: 'unknown', detail: 'Not checked' },
    algorithmCheck: validCheck('Algorithm strength'),
    ekuCheck: validCheck('Extended key usage'),
    signerCertificate: null,
    certificateChain: [],
    timestamp: null,
    reason: '',
    location: '',
    contactInfo: '',
    signingTime: new Date('2025-01-01T12:00:00Z'),
    overallStatus: 'valid',
    overallMessage: 'Signature is valid',
    mdpPermission: null,
    isVisible: false,
    padesLevel: 'B-B',
    ...overrides,
  }
}

Testing React Components

Testing with VerifyKitProvider

Components that use useVerifyKitConfig() or useVerification() must be wrapped in a VerifyKitProvider. For tests, provide a minimal config:

tsx
import { render } from '@testing-library/react'
import { VerifyKitProvider } from '@trexolab/verifykit-react'
 
function renderWithProvider(ui: React.ReactElement) {
  return render(
    <VerifyKitProvider config={{
      workerUrl: '/pdf.worker.min.mjs',
      theme: { mode: 'light' },
    }}>
      {ui}
    </VerifyKitProvider>
  )
}

Note: In a test environment without a real PDF.js worker, the provider will initialize but PDF rendering will not work. This is acceptable for unit tests that only test component logic and UI state.

Testing Verification State

If your component consumes useVerification(), test the different states by rendering with mock data:

tsx
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { VerifyKitProvider } from '@trexolab/verifykit-react'
import { MySignatureStatus } from './MySignatureStatus'
 
describe('MySignatureStatus', () => {
  it('shows loading state', () => {
    renderWithProvider(<MySignatureStatus />)
    // Component should show initial empty state before load() is called
  })
 
  it('displays signature count after verification', async () => {
    const { getByText } = renderWithProvider(<MySignatureStatus />)
    // Trigger load and assert on the rendered output
  })
})

Test Setup

Vitest Configuration

typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
 
export default defineConfig({
  test: {
    environment: 'jsdom',
    setupFiles: ['./test/setup.ts'],
  },
})
typescript
// test/setup.ts
import { vi } from 'vitest'
 
// Mock the WASM module if tests don't need real verification
vi.mock('@trexolab/verifykit-core', async () => {
  const actual = await vi.importActual('@trexolab/verifykit-core')
  return {
    ...actual,
    createVerifier: vi.fn().mockResolvedValue({
      verify: vi.fn().mockResolvedValue({
        fileSize: 0,
        fileHash: '',
        signatures: [],
      }),
      extractMetadata: vi.fn().mockResolvedValue({
        metadata: {},
        permissions: {},
      }),
      dispose: vi.fn(),
    }),
  }
})

Jest Configuration

javascript
// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFiles: ['./test/setup.ts'],
  transformIgnorePatterns: [
    'node_modules/(?!@trexolab)',
  ],
}

Note: Both @trexolab/verifykit-core and @trexolab/verifykit-react are ESM packages. If using Jest, you may need to configure transformIgnorePatterns to allow transpilation of these packages.


Integration Testing

For integration tests that use the real WASM verifier, you need an environment that supports WebAssembly.

Using the Real Verifier in Tests

typescript
import { describe, it, expect } from 'vitest'
import { createVerifier } from '@trexolab/verifykit-core'
import { readFileSync } from 'fs'
 
describe('PDF verification (integration)', () => {
  it('verifies a signed PDF', async () => {
    const verifier = await createVerifier()
    const pdfBytes = readFileSync('./test/fixtures/signed.pdf')
    const result = await verifier.verify(pdfBytes, 'signed.pdf')
 
    expect(result.signatures).toHaveLength(1)
    expect(result.signatures[0].integrityCheck.status).toBe('valid')
    expect(result.signatures[0].signatureCheck.status).toBe('valid')
 
    verifier.dispose()
  })
 
  it('detects a tampered PDF', async () => {
    const verifier = await createVerifier()
    const pdfBytes = readFileSync('./test/fixtures/tampered.pdf')
    const result = await verifier.verify(pdfBytes, 'tampered.pdf')
 
    expect(result.signatures[0].integrityCheck.status).toBe('invalid')
 
    verifier.dispose()
  })
})

Test Fixtures

Maintain a set of sample PDFs for different test scenarios:

FixturePurpose
signed.pdfValid signature with trusted certificate
tampered.pdfValid signature but document modified after signing
expired-cert.pdfSigned with an expired certificate
self-signed.pdfSigned with a self-signed certificate (untrusted chain)
multi-sig.pdfMultiple signatures
unsigned.pdfNo signatures
encrypted.pdfPassword-protected document

Note: Do not commit real-world confidential PDFs to your repository. Create test fixtures using tools like OpenSSL, iText, or Adobe Acrobat with test certificates.


Testing Verification Results

Test individual check results to ensure your application handles all verification states:

typescript
import type { VerificationStatus } from '@trexolab/verifykit-core'
 
const statuses: VerificationStatus[] = ['valid', 'invalid', 'warning', 'unknown', 'pending']
 
describe('status handling', () => {
  for (const status of statuses) {
    it(`handles ${status} status`, () => {
      const sig = createMockSignature({ overallStatus: status })
      // Test your component or logic with this status
    })
  }
})

Testing Error Handling

typescript
import { classifyPdfError, type LoadError } from '@trexolab/verifykit-react'
 
describe('error classification', () => {
  it('classifies PDF.js errors', () => {
    const err = new Error('Invalid PDF structure')
    err.name = 'InvalidPDFException'
    const loadError = classifyPdfError(err)
    expect(loadError.name).toBe('InvalidPDFException')
  })
 
  it('classifies unknown errors', () => {
    const loadError = classifyPdfError(new Error('Something went wrong'))
    expect(loadError.name).toBe('UnknownErrorException')
  })
})

Environment Requirements

EnvironmentWASM SupportNotes
Node.js 20.19.0+YesFull support for createVerifier()
jsdom (Vitest/Jest)PartialWASM loads but no canvas/worker; mock for unit tests
Playwright/PuppeteerYesFull browser environment; best for E2E tests
Happy DOMPartialSimilar limitations to jsdom

For comprehensive testing, use a layered approach:

  1. Unit tests with mocked verifier (fast, no WASM)
  2. Integration tests with real verifier in Node.js (validates WASM + verification logic)
  3. E2E tests in a real browser via Playwright (validates the full viewer UI)