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
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:
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:
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:
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
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: ['./test/setup.ts'],
},
})// 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
// 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
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:
| Fixture | Purpose |
|---|---|
signed.pdf | Valid signature with trusted certificate |
tampered.pdf | Valid signature but document modified after signing |
expired-cert.pdf | Signed with an expired certificate |
self-signed.pdf | Signed with a self-signed certificate (untrusted chain) |
multi-sig.pdf | Multiple signatures |
unsigned.pdf | No signatures |
encrypted.pdf | Password-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:
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
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
| Environment | WASM Support | Notes |
|---|---|---|
| Node.js 20.19.0+ | Yes | Full support for createVerifier() |
| jsdom (Vitest/Jest) | Partial | WASM loads but no canvas/worker; mock for unit tests |
| Playwright/Puppeteer | Yes | Full browser environment; best for E2E tests |
| Happy DOM | Partial | Similar limitations to jsdom |
For comprehensive testing, use a layered approach:
- Unit tests with mocked verifier (fast, no WASM)
- Integration tests with real verifier in Node.js (validates WASM + verification logic)
- E2E tests in a real browser via Playwright (validates the full viewer UI)