Testing
Overview
SupaScan includes comprehensive testing strategies for blockchain indexing, ClickHouse database operations, API endpoints, and real-time data processing. Tests ensure data accuracy, system reliability, and performance under high load.
Test Structure
tests/
├── unit/ # Unit tests for core components
│ ├── indexing/ # Block parsing, transaction processing
│ ├── database/ # ClickHouse operations, queries
│ └── api/ # API endpoints, validation
├── integration/ # End-to-end workflows
│ ├── indexing-flow/ # Full indexing pipeline
│ └── api-integration/ # API + database integration
└── e2e/ # Complete system tests
├── webhook-delivery/ # Notification testing
└── performance/ # Load and stress tests
Running Tests
# All tests
npm test
# Unit tests only
npm run test:unit
# Integration tests
npm run test:integration
# Performance tests
npm run test:performance
# Coverage report
npm run test:coverage
Core Test Categories
1. Blockchain Indexing Tests
describe('Solana Indexing', () => {
it('should parse transaction correctly', async () => {
const mockTx = {
signature: '5J7X8C9D...',
slot: 123456789,
blockTime: 1640995200,
transaction: { /* Solana transaction data */ }
};
const result = await parseTransaction(mockTx);
expect(result.signature).toBe('5J7X8C9D...');
expect(result.tokenTransfers).toHaveLength(2);
expect(result.dexSwaps).toBeDefined();
});
it('should detect DEX swaps accurately', async () => {
const swapData = await detectDEXSwap(mockSwapTransaction);
expect(swapData.protocol).toBe('raydium');
expect(swapData.tokenIn).toBe('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
expect(swapData.amountIn).toBeGreaterThan(0);
});
});
2. ClickHouse Database Tests
describe('ClickHouse Operations', () => {
it('should insert transaction data efficiently', async () => {
const txData = generateMockTransaction();
await insertTransaction(txData);
const result = await queryClickHouse(`
SELECT * FROM transactions
WHERE signature = '${txData.signature}'
`);
expect(result.rows).toHaveLength(1);
expect(result.rows[0].success).toBe(1);
});
it('should handle large batch inserts', async () => {
const batch = generateTransactionBatch(10000);
const startTime = Date.now();
await batchInsertTransactions(batch);
const duration = Date.now() - startTime;
expect(duration).toBeLessThan(5000); // < 5 seconds
});
});
3. API Endpoint Tests
describe('API Endpoints', () => {
it('should return transaction data via REST API', async () => {
const response = await request(app)
.get('/api/v1/transactions/5J7X8C9D...')
.set('Authorization', `Bearer ${validApiKey}`)
.expect(200);
expect(response.body.signature).toBe('5J7X8C9D...');
expect(response.body.tokenTransfers).toBeDefined();
});
it('should execute SQL queries via API', async () => {
const response = await request(app)
.post('/api/v1/sql')
.set('Authorization', `Bearer ${validApiKey}`)
.send({
query: 'SELECT token_mint, SUM(volume_usd) FROM token_swaps WHERE date = today() GROUP BY token_mint ORDER BY SUM(volume_usd) DESC LIMIT 10'
})
.expect(200);
expect(response.body.data).toHaveLength(10);
expect(response.body.data[0].volume_usd).toBeGreaterThan(0);
});
});
4. Webhook & Notification Tests
describe('Webhook Delivery', () => {
it('should deliver token creation alerts', async () => {
const webhook = {
url: 'https://test-webhook.com/alerts',
filters: { minLiquidity: 10000 }
};
await createWebhook(webhook);
// Trigger token creation
const newToken = await createTestToken({ liquidity: 15000 });
// Verify webhook was called
expect(mockWebhookServer.receivedCalls).toHaveLength(1);
expect(mockWebhookServer.lastCall.body.token.mint).toBe(newToken.mint);
});
});
Test Configuration
Jest Setup
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testTimeout: 30000, // 30s for blockchain tests
setupFilesAfterEnv: ['<rootDir>/tests/setup.ts'],
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts'
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
}
};
Test Environment Setup
// tests/setup.ts
import { mockSolanaRPC } from './mocks/solana';
import { mockClickHouse } from './mocks/clickhouse';
// Mock external services
jest.mock('../src/services/solana', () => mockSolanaRPC);
jest.mock('../src/services/clickhouse', () => mockClickHouse);
// Test data setup
beforeEach(async () => {
await seedTestData();
});
afterEach(async () => {
await cleanupTestData();
});
Performance Testing
Load Testing
describe('Performance Tests', () => {
it('should handle 1000 concurrent API requests', async () => {
const requests = Array(1000).fill(null).map(() =>
request(app)
.get('/api/v1/tokens/top')
.set('Authorization', `Bearer ${validApiKey}`)
);
const startTime = Date.now();
const responses = await Promise.all(requests);
const duration = Date.now() - startTime;
expect(responses.every(r => r.status === 200)).toBe(true);
expect(duration).toBeLessThan(10000); // < 10 seconds
});
it('should index blocks in real-time', async () => {
const blocks = await generateMockBlocks(100);
const startTime = Date.now();
for (const block of blocks) {
await processBlock(block);
}
const duration = Date.now() - startTime;
expect(duration).toBeLessThan(5000); // < 5 seconds for 100 blocks
});
});
Security Testing
describe('Security Tests', () => {
it('should prevent SQL injection', async () => {
const maliciousQuery = "'; DROP TABLE transactions; --";
const response = await request(app)
.post('/api/v1/sql')
.set('Authorization', `Bearer ${validApiKey}`)
.send({ query: maliciousQuery })
.expect(400);
expect(response.body.error).toContain('Invalid query');
});
it('should validate API key permissions', async () => {
const response = await request(app)
.get('/api/v1/admin/users')
.set('Authorization', `Bearer ${freeTierApiKey}`)
.expect(403);
expect(response.body.error).toBe('Insufficient permissions');
});
});
Test Best Practices
1. Data Accuracy
- Verify blockchain data integrity
- Test edge cases in transaction parsing
- Validate ClickHouse query results
2. Performance
- Test indexing speed under load
- Monitor memory usage during batch operations
- Ensure API response times < 200ms
3. Reliability
- Test webhook delivery reliability
- Verify error handling and recovery
- Test system behavior during Solana RPC outages
4. Security
- Test input validation and sanitization
- Verify API key authentication
- Test rate limiting and abuse prevention
Continuous Integration
# .github/workflows/test.yml
name: SupaScan Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
clickhouse:
image: clickhouse/clickhouse-server:latest
ports:
- 8123:8123
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run performance tests
run: npm run test:performance