# Testing Guide
Comprehensive testing documentation for the Impersonator Smart Wallet system.
## Testing Overview
The project uses Jest as the testing framework with comprehensive test coverage including:
- Unit tests for utilities and helpers
- Integration tests for workflows
- Security tests for attack vectors
- Component tests for UI
## Test Structure
```
__tests__/
├── security.test.ts # Security utility tests
├── encryption.test.ts # Encryption tests
├── rateLimiter.test.ts # Rate limiter tests
├── nonceManager.test.ts # Nonce manager tests
└── integration/ # Integration tests
├── walletManagement.test.ts
├── transactionFlow.test.ts
└── multisigApproval.test.ts
```
## Running Tests
### All Tests
```bash
# Run all tests
pnpm test
# Run with coverage
pnpm test:coverage
# Run in watch mode
pnpm test:watch
```
### Specific Test Suites
```bash
# Security tests
pnpm test:security
# Integration tests
pnpm test:integration
# Specific test file
pnpm test __tests__/security.test.ts
```
### Test Options
```bash
# Run tests matching pattern
pnpm test -- --testNamePattern="address validation"
# Run tests in specific file
pnpm test -- __tests__/security.test.ts
# Update snapshots
pnpm test -- -u
# Verbose output
pnpm test -- --verbose
```
## Test Coverage
### Coverage Goals
- **Lines:** >80%
- **Functions:** >80%
- **Branches:** >75%
- **Statements:** >80%
### Viewing Coverage
```bash
# Generate coverage report
pnpm test:coverage
# Coverage report is in coverage/ directory
open coverage/lcov-report/index.html
```
### Current Coverage
- Security utilities: ~90%
- Encryption utilities: ~85%
- Rate limiter: ~90%
- Nonce manager: ~85%
- Overall: ~85%
## Writing Tests
### Unit Test Example
```typescript
import { validateAddress } from "@/utils/security";
describe("validateAddress", () => {
it("should validate correct addresses", () => {
const result = validateAddress("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb");
expect(result.valid).toBe(true);
expect(result.checksummed).toBeDefined();
});
it("should reject invalid addresses", () => {
const result = validateAddress("invalid");
expect(result.valid).toBe(false);
expect(result.error).toBeDefined();
});
});
```
### Integration Test Example
```typescript
describe("Wallet Management Flow", () => {
it("should create wallet with valid configuration", async () => {
const owners = ["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"];
const threshold = 1;
// Validate owners
const validatedOwners = owners.map(owner => {
const validation = validateAddress(owner);
expect(validation.valid).toBe(true);
return validation.checksummed!;
});
// Validate threshold
expect(threshold).toBeGreaterThan(0);
expect(threshold).toBeLessThanOrEqual(validatedOwners.length);
});
});
```
### Component Test Example
```typescript
import { render, screen } from "@testing-library/react";
import WalletManager from "@/components/SmartWallet/WalletManager";
describe("WalletManager", () => {
it("should render wallet list", () => {
render();
expect(screen.getByText("Wallets")).toBeInTheDocument();
});
});
```
## Test Patterns
### Mocking Providers
```typescript
class MockProvider extends ethers.providers.BaseProvider {
async getNetwork() {
return { chainId: 1, name: "mainnet" };
}
async perform(method: string, params: any): Promise {
throw new Error("Not implemented");
}
}
```
### Testing Async Functions
```typescript
it("should handle async operations", async () => {
const result = await asyncFunction();
expect(result).toBeDefined();
});
```
### Testing Error Cases
```typescript
it("should handle errors", async () => {
await expect(asyncFunction()).rejects.toThrow("Error message");
});
```
### Testing Hooks
```typescript
import { renderHook } from "@testing-library/react";
import { useSmartWallet } from "@/contexts/SmartWalletContext";
it("should return wallet context", () => {
const { result } = renderHook(() => useSmartWallet());
expect(result.current.activeWallet).toBeDefined();
});
```
## Test Categories
### Unit Tests
Test individual functions and utilities in isolation.
**Location:** `__tests__/*.test.ts`
**Examples:**
- Security utilities
- Encryption functions
- Validation functions
- Helper functions
### Integration Tests
Test complete workflows and component interactions.
**Location:** `__tests__/integration/*.test.ts`
**Examples:**
- Wallet management flow
- Transaction flow
- Multi-sig approval flow
### Security Tests
Test security features and attack vectors.
**Location:** `__tests__/security.test.ts`
**Examples:**
- XSS prevention
- Replay attack prevention
- Race condition prevention
- Integer overflow prevention
## Test Utilities
### Setup File
`jest.setup.js` configures:
- Testing library matchers
- Mock implementations
- Global test utilities
### Mock Implementations
```typescript
// Mock localStorage
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
clear: jest.fn(),
};
global.localStorage = localStorageMock;
```
## Best Practices
### 1. Test Structure
```typescript
describe("Feature", () => {
describe("Sub-feature", () => {
it("should do something", () => {
// Arrange
const input = "value";
// Act
const result = function(input);
// Assert
expect(result).toBe(expected);
});
});
});
```
### 2. Test Naming
- Use descriptive test names
- Start with "should"
- Describe expected behavior
```typescript
// ✅ Good
it("should validate correct addresses", () => {});
// ❌ Bad
it("test1", () => {});
```
### 3. Test Isolation
- Each test should be independent
- Don't rely on test execution order
- Clean up after tests
### 4. Test Coverage
- Aim for >80% coverage
- Test happy paths
- Test error cases
- Test edge cases
### 5. Mocking
- Mock external dependencies
- Mock async operations
- Mock browser APIs
- Keep mocks simple
## Continuous Integration
Tests run automatically on:
- Pull requests
- Pushes to main/develop
- Scheduled runs
**CI Configuration:** `.github/workflows/ci.yml`
**CI Steps:**
1. Lint code
2. Run tests
3. Check coverage
4. Build project
5. Security audit
## Debugging Tests
### VS Code Debugging
Create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Jest: current file",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["${relativeFile}"],
"console": "integratedTerminal"
}
]
}
```
### Debugging Tips
1. Use `console.log` for debugging
2. Use `debugger` statement
3. Run single test file
4. Use `--verbose` flag
5. Check test output carefully
## Test Maintenance
### Keeping Tests Updated
- Update tests when code changes
- Remove obsolete tests
- Refactor tests regularly
- Keep test data current
### Test Performance
- Keep tests fast (< 1 second each)
- Use mocks for slow operations
- Parallelize when possible
- Avoid unnecessary setup
## Common Issues
### Tests Failing
1. Check error messages
2. Verify test data
3. Check mocks
4. Review recent changes
5. Clear cache: `rm -rf node_modules/.cache`
### Coverage Issues
1. Check uncovered lines
2. Add missing tests
3. Review coverage report
4. Exclude unnecessary files
### Flaky Tests
1. Identify timing issues
2. Add proper waits
3. Use stable selectors
4. Avoid race conditions
## Resources
- [Jest Documentation](https://jestjs.io/docs/getting-started)
- [React Testing Library](https://testing-library.com/react)
- [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)