This document provides comprehensive information about the testing infrastructure for the Nuru VoicePay application.
| Component | Target Coverage | Current Status |
|---|---|---|
| Smart Contracts | 95%+ | ✅ Implemented |
| Payment Services | 90%+ | ✅ Implemented |
| Voice Processing | 85%+ | ✅ Implemented |
| React Components | 80%+ | 🚧 In Progress |
| Utilities | 90%+ | 🚧 In Progress |
# Run all contract tests
cd packages/hardhat
yarn test
# Run with gas reporting
yarn test:gas
# Generate coverage report
yarn test:coverage# Run all frontend tests
cd packages/nextjs
yarn test
# Run tests in watch mode
yarn test --watch
# Run with coverage
yarn test:coverage
# Run tests with UI
yarn test:ui# From project root
yarn testLocated in packages/hardhat/test/
-
VoiceRemittance.test.ts: Core contract functionality
- Deployment tests
- USDC payment initiation
- Payment validation
- ETH payments with ENS
- Payment completion and cancellation
- Admin functions
- Security features (rate limiting, daily limits)
-
MockERC20.sol: Mock USDC token for testing
Located in packages/nextjs/services/*/tests/
-
VoiceCommandProcessor.test.ts: Voice command parsing
- Payment intent extraction
- Voice recognition error correction
- Command validation
- Multi-language support
-
USDCPaymentHandler.test.ts: USDC payment execution
- Balance checking
- Approval handling
- Payment execution
- Error handling
-
ENSService.test.ts: ENS resolution
- Forward resolution
- Reverse resolution
- Validation
- Voice command integration
-
CurrencyConverter.test.ts: Currency conversion
- GHS to USDC conversion
- NGN to USDC conversion
- Exchange rate handling
- Formatting
import { expect } from "chai";
import { ethers } from "hardhat";
describe("VoiceRemittance", () => {
let contract: VoiceRemittance;
let owner: SignerWithAddress;
beforeEach(async () => {
[owner] = await ethers.getSigners();
const Factory = await ethers.getContractFactory("VoiceRemittance");
contract = await Factory.deploy(usdcAddress);
});
it("should initiate USDC payment", async () => {
const tx = await contract.initiateUSDCPayment(
recipient,
amount,
voiceHash,
metadata
);
await expect(tx)
.to.emit(contract, "PaymentInitiated")
.withArgs(1, owner.address, "", amount, "USDC", voiceHash);
});
});import { describe, it, expect, vi } from 'vitest';
describe('VoiceCommandProcessor', () => {
it('should parse payment command', async () => {
const result = await processor.extractPaymentIntent(
'send 50 cedis to mama.family.eth'
);
expect(result?.action).toBe('send_money');
expect(result?.amount).toBe('50');
expect(result?.recipient).toBe('mama.family.eth');
});
});-
test.yml: Runs on every push and PR
- Smart contract tests
- Frontend unit tests
- Linting and type checking
-
coverage.yml: Generates coverage reports
- Uploads to Codecov
- Comments on PRs with coverage changes
- Pull requests must maintain or improve coverage
- Minimum 80% overall coverage required
- Critical paths (payments, voice processing) require 90%+
- Test individual functions and components in isolation
- Mock external dependencies
- Fast execution (< 1 second per test)
- Test interaction between multiple components
- Use real implementations where possible
- Moderate execution time (1-5 seconds per test)
- Test smart contract functionality
- Use Hardhat network for fast execution
- Test edge cases and security features
// Good
it('should reject payments with insufficient balance')
// Bad
it('test payment')it('should transfer USDC to recipient', async () => {
// Arrange
await usdcMock.mint(user1.address, amount);
await usdcMock.connect(user1).approve(contract.address, amount);
// Act
await contract.initiateUSDCPayment(user2.address, amount, hash, metadata);
// Assert
const balance = await usdcMock.balanceOf(user2.address);
expect(balance).to.equal(expectedAmount);
});- Zero amounts
- Maximum amounts
- Invalid addresses
- Insufficient balances
- Rate limiting
- Reentrancy attacks
vi.mock('../OpenAIService', () => ({
openAIService: {
extractPaymentIntent: vi.fn(),
},
}));# Run specific test file
yarn test test/VoiceRemittance.test.ts
# Run specific test
yarn test --grep "should initiate USDC payment"
# Enable console logs
yarn test --logs# Run specific test file
yarn test VoiceCommandProcessor.test.ts
# Run in watch mode
yarn test --watch
# Debug in VS Code
# Add breakpoint and use "Debug Test" in test file# Generate HTML coverage report
cd packages/hardhat
yarn test:coverage
# Open in browser
open coverage/index.htmlConfigured in vitest.config.ts:
coverage: {
thresholds: {
lines: 80,
functions: 80,
branches: 75,
statements: 80,
},
}Solution: Increase timeout in test file
it('should complete payment', async () => {
// ...
}).timeout(10000); // 10 secondsSolution: Ensure mock is defined before import
vi.mock('./module', () => ({
// mock implementation
}));
import { functionToTest } from './module';Solution: Check USDC mock is deployed first
beforeEach(async () => {
usdcMock = await MockERC20.deploy("USDC", "USDC", 6);
await usdcMock.waitForDeployment();
contract = await VoiceRemittance.deploy(await usdcMock.getAddress());
});When adding new features:
- Write tests first (TDD approach)
- Ensure all tests pass
- Maintain or improve coverage
- Update this documentation if needed
For testing questions or issues:
- Open an issue on GitHub
- Check existing test files for examples
- Review CI/CD logs for failures