Skip to content

Commit 40929bd

Browse files
committed
chore: added initial setup for walletconnect integration tests
1 parent 5cfee6d commit 40929bd

12 files changed

+380
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: '3.8'
2+
3+
services:
4+
redis:
5+
image: redis:latest
6+
ports:
7+
# Expose Redis port mainly for debugging if needed, not strictly necessary for relay
8+
- "6379:6379"
9+
healthcheck:
10+
test: ["CMD", "redis-cli", "ping"]
11+
interval: 1s
12+
timeout: 3s
13+
retries: 30
14+
15+
relay:
16+
image: reown/relay
17+
ports:
18+
- "5555:5000" # Expose relay port
19+
environment:
20+
- REDIS_URL=redis://redis:6379/0 # Use service name 'redis' for internal communication
21+
depends_on:
22+
redis:
23+
condition: service_healthy # Wait for Redis to be healthy
24+
# Add a simple healthcheck if possible (e.g., checking if the port is open)
25+
# Or rely on depends_on and --wait in docker-compose up
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
rootDir: '.', // Look for tests in the integration-tests directory
6+
roots: [
7+
'<rootDir>/src' // Source files for tests
8+
],
9+
testMatch: [
10+
'**/__tests__/**/*.+(ts|tsx|js)',
11+
'**/?(*.)+(spec|test).+(ts|tsx|js)'
12+
],
13+
transform: {
14+
'^.+.tsx?$': ['ts-jest', {
15+
// ts-jest configuration options
16+
tsconfig: 'tsconfig.json' // Assuming tsconfig is in hathor-rpc-handler root
17+
}]
18+
},
19+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
20+
// Specify global setup and teardown scripts
21+
globalSetup: '<rootDir>/jest.globalSetup.ts',
22+
globalTeardown: '<rootDir>/jest.globalTeardown.ts',
23+
// Run tests sequentially because they share the Docker environment
24+
maxWorkers: 1,
25+
// Set a longer timeout for integration tests and hooks
26+
testTimeout: 90000, // 90 seconds
27+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { execSync } from 'child_process';
2+
import * as path from 'path';
3+
4+
const integrationTestsDir = __dirname; // Correctly refers to the integration-tests directory
5+
const composeFile = path.join(integrationTestsDir, 'docker-compose.yml');
6+
7+
export default async () => {
8+
console.log('\nSetting up integration test environment...');
9+
try {
10+
// Use --wait to ensure services are healthy/running before proceeding
11+
execSync(`docker compose -f "${composeFile}" up -d --wait`, { stdio: 'inherit' });
12+
console.log('Docker containers started successfully.');
13+
// Add a small delay just in case services need a moment to fully initialize after becoming "healthy"
14+
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 seconds delay
15+
console.log('Integration test environment setup complete.');
16+
} catch (error) {
17+
console.error('Failed to start Docker containers:', error);
18+
// Optionally, try to bring down containers if setup failed partially
19+
try {
20+
execSync(`docker compose -f "${composeFile}" down`, { stdio: 'inherit' });
21+
} catch (downError) {
22+
console.error('Failed to run docker compose down after setup error:', downError);
23+
}
24+
process.exit(1); // Exit if setup fails
25+
}
26+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { execSync } from 'child_process';
2+
import * as path from 'path';
3+
4+
const integrationTestsDir = __dirname; // Correctly refers to the integration-tests directory
5+
const composeFile = path.join(integrationTestsDir, 'docker-compose.yml');
6+
7+
export default async () => {
8+
console.log('\nTearing down integration test environment...');
9+
try {
10+
execSync(`docker compose -f "${composeFile}" down -v --remove-orphans`, { stdio: 'inherit' });
11+
console.log('Docker containers stopped and removed successfully.');
12+
} catch (error) {
13+
console.error('Failed to stop Docker containers:', error);
14+
// Don't exit here, as tests might have finished, but teardown failed.
15+
}
16+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const HATHOR_TEST_SEED = 'castle item critic hand disorder girl across prevent claw fault vacuum combine food debris arrow member autumn half spirit sick priority evil step genius';
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {
2+
initializeWalletConnectClient,
3+
getWalletConnectClient,
4+
disconnectWalletConnectClient,
5+
} from './walletConnectClient';
6+
7+
jest.setTimeout(120000); // Set longer timeout for the entire test suite
8+
9+
describe('WalletConnect Connection', () => {
10+
// Initialize client and wait for relay connection before tests
11+
beforeAll(async () => {
12+
try {
13+
const client = await initializeWalletConnectClient();
14+
console.log('Test Suite: WalletConnect client object initialized.');
15+
16+
if (client.core.relayer.connected) {
17+
console.log('Test Suite: Relayer already connected.');
18+
return; // Already connected
19+
}
20+
21+
console.log('Test Suite: Waiting for relayer connection...');
22+
await new Promise<void>((resolve, reject) => {
23+
// Timeout if connection takes too long
24+
const timeout = setTimeout(() => {
25+
console.error('Test Suite: Relayer connection attempt timed out.');
26+
reject(new Error('Relayer connection timeout'));
27+
}, 60000); // Increased timeout to 60 seconds
28+
29+
// Use .once() as we only need the first connection event for setup
30+
client.core.relayer.once('relayer_connect', () => {
31+
clearTimeout(timeout);
32+
console.log("Test Suite: 'relayer_connect' event received.");
33+
resolve();
34+
});
35+
36+
client.core.relayer.once('relayer_error', (error: Error) => {
37+
clearTimeout(timeout);
38+
console.error("Test Suite: 'relayer_error' event received.", error);
39+
reject(error);
40+
});
41+
});
42+
43+
} catch (error) {
44+
console.error('Test Suite Error: Failed during WalletConnect client initialization or connection wait', error);
45+
// Optionally throw to fail the suite immediately
46+
throw error;
47+
}
48+
});
49+
50+
// Disconnect client after all tests in this suite have run
51+
afterAll(async () => {
52+
// No need for complex cleanup with done() since we're using --forceExit
53+
await disconnectWalletConnectClient();
54+
console.log('Test Suite: WalletConnect client disconnected.');
55+
});
56+
57+
it('should initialize the WalletConnect client successfully', () => {
58+
// The beforeAll block handles initialization, so we just check if getClient works
59+
expect(() => getWalletConnectClient()).not.toThrow();
60+
const client = getWalletConnectClient();
61+
expect(client).toBeDefined();
62+
// Add more specific checks if needed, e.g., client properties
63+
expect(client.core.relayer.connected).toBe(true); // Check if relay connection is active
64+
});
65+
66+
// Add more tests related to connection status or initial setup here
67+
});
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { HathorWallet } from '@hathor/wallet-lib';
2+
import { HATHOR_TEST_SEED } from './config';
3+
4+
let walletInstance: HathorWallet | null = null;
5+
6+
/**
7+
* Initializes and returns a singleton HathorWallet instance for testing.
8+
*
9+
* Note: This basic initialization might need adjustments depending on
10+
* specific test requirements (e.g., network, server).
11+
*/
12+
export function initializeHathorWallet(): HathorWallet {
13+
if (walletInstance) {
14+
return walletInstance;
15+
}
16+
17+
// Basic configuration, adjust as necessary
18+
const walletConfig = {
19+
seed: HATHOR_TEST_SEED,
20+
network: 'testnet', // Assuming testnet for integration tests
21+
connection: undefined, // Use default connection or configure if needed
22+
password: '123', // Default password for testing
23+
pinCode: '123', // Default pin for testing
24+
};
25+
26+
walletInstance = new HathorWallet(walletConfig);
27+
28+
// Start the wallet (important step)
29+
// Note: Starting might involve network requests, ensure environment allows this.
30+
// Consider if starting should happen here or per-test suite.
31+
// For now, let's assume starting here is fine.
32+
// await walletInstance.start(); // Uncomment and handle async if needed
33+
34+
console.log('Hathor Wallet initialized for testing.');
35+
return walletInstance;
36+
}
37+
38+
/**
39+
* Gets the initialized HathorWallet instance.
40+
* Throws an error if the wallet hasn't been initialized.
41+
*/
42+
export function getHathorWallet(): HathorWallet {
43+
if (!walletInstance) {
44+
throw new Error('Hathor Wallet is not initialized. Call initializeHathorWallet first.');
45+
}
46+
return walletInstance;
47+
}
48+
49+
// Optional: Add a function to stop/clean up the wallet if necessary
50+
export async function stopHathorWallet(): Promise<void> {
51+
if (walletInstance) {
52+
// await walletInstance.stop(); // Uncomment if wallet needs explicit stopping
53+
walletInstance = null;
54+
console.log('Hathor Wallet stopped.');
55+
}
56+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Client from '@walletconnect/sign-client';
2+
import {
3+
WC_APP_METADATA,
4+
WC_LOGGER_LEVEL,
5+
WC_PROJECT_ID,
6+
WC_RELAY_URL,
7+
} from './walletConnectConfig';
8+
9+
let clientInstance: Client | null = null;
10+
11+
/**
12+
* Initializes and returns a singleton WalletConnect Client instance.
13+
*/
14+
export async function initializeWalletConnectClient(): Promise<Client> {
15+
if (clientInstance) {
16+
console.log('WalletConnect Client already initialized.');
17+
return clientInstance;
18+
}
19+
20+
console.log(`Initializing WalletConnect Client with relay: ${WC_RELAY_URL}`);
21+
try {
22+
clientInstance = await Client.init({
23+
logger: WC_LOGGER_LEVEL,
24+
relayUrl: WC_RELAY_URL,
25+
projectId: WC_PROJECT_ID,
26+
metadata: WC_APP_METADATA,
27+
});
28+
29+
return clientInstance;
30+
} catch (error) {
31+
console.error('Failed to initialize WalletConnect client:', error);
32+
throw error; // Re-throw error to fail tests if connection fails
33+
}
34+
}
35+
36+
/**
37+
* Gets the initialized WalletConnect Client instance.
38+
* Throws an error if the client hasn't been initialized.
39+
*/
40+
export function getWalletConnectClient(): Client {
41+
if (!clientInstance) {
42+
throw new Error('WalletConnect client is not initialized. Call initializeWalletConnectClient first.');
43+
}
44+
return clientInstance;
45+
}
46+
47+
/**
48+
* Disconnects the WalletConnect client if it's initialized.
49+
*/
50+
export async function disconnectWalletConnectClient(): Promise<void> {
51+
if (clientInstance) {
52+
try {
53+
console.log('Disconnecting WalletConnect Client...');
54+
// Just nullify the client and let garbage collection handle cleanup
55+
clientInstance = null;
56+
console.log('WalletConnect Client disconnected.');
57+
} catch (error) {
58+
console.error('Error during WalletConnect client disconnection:', error);
59+
// Ensure client is nullified
60+
clientInstance = null;
61+
}
62+
} else {
63+
console.log('WalletConnect Client was not initialized, no need to disconnect.');
64+
}
65+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { SignClientTypes } from '@walletconnect/types'; // Import Metadata type
2+
3+
// Use the Project ID observed in the working relay log
4+
export const WC_PROJECT_ID = '8264fff563181da658ce64ee80e80458';
5+
6+
export const WC_RELAY_URL = 'ws://localhost:5555'; // Keep as localhost for now
7+
8+
export const WC_LOGGER_LEVEL = 'debug';
9+
10+
export const WC_APP_METADATA: SignClientTypes.Metadata = {
11+
name: 'Hathor RPC Integration Test',
12+
description: 'Integration tests for hathor-rpc-handler',
13+
url: '#', // Placeholder URL
14+
icons: [], // Placeholder Icons
15+
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import Client from '@walletconnect/sign-client';
2+
import {
3+
initializeWalletConnectClient,
4+
disconnectWalletConnectClient,
5+
} from './src/walletConnectClient';
6+
7+
let client: Client | null = null;
8+
9+
async function runConnectionTest() {
10+
console.log('Starting standalone connection test...');
11+
try {
12+
// Initialize client
13+
client = await initializeWalletConnectClient();
14+
console.log('Client initialized.');
15+
16+
// Check initial connection state
17+
console.log(`Initial connection state: ${client.core.relayer.connected}`);
18+
19+
// Set up event listener without waiting
20+
client.core.relayer.once('relayer_connect', () => {
21+
console.log('>>> relayer_connect event received! <<<');
22+
console.log(`Connection state after event: ${client!.core.relayer.connected}`);
23+
});
24+
25+
client.core.relayer.once('relayer_error', (error: Error) => {
26+
console.error('>>> relayer_error event received! <<<', error);
27+
});
28+
29+
// Wait a bit to see if we get the connect event
30+
await new Promise(resolve => setTimeout(resolve, 10000));
31+
32+
console.log(`Final connection state: ${client.core.relayer.connected}`);
33+
console.log('Connection test completed.');
34+
35+
} catch (error) {
36+
console.error('Connection test failed:', error);
37+
process.exitCode = 1; // Set exit code to indicate failure
38+
} finally {
39+
// Attempt to disconnect
40+
console.log('Attempting to disconnect...');
41+
await disconnectWalletConnectClient();
42+
console.log('Standalone test finished.');
43+
}
44+
}
45+
46+
// Run the test
47+
runConnectionTest();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2022",
4+
"module": "CommonJS",
5+
"sourceMap": true,
6+
"strict": true,
7+
"esModuleInterop": true,
8+
"skipLibCheck": true,
9+
"forceConsistentCasingInFileNames": true,
10+
"moduleResolution": "node",
11+
"outDir": "dist",
12+
"rootDir": ".",
13+
"baseUrl": ".",
14+
"paths": {
15+
"@/*": ["src/*"]
16+
},
17+
"lib": ["ES2016", "DOM"],
18+
"types": ["node", "jest"]
19+
},
20+
"include": [
21+
"src/**/*.ts",
22+
"jest.config.js",
23+
"jest.globalSetup.ts",
24+
"jest.globalTeardown.ts"
25+
],
26+
"exclude": [
27+
"node_modules",
28+
"dist"
29+
]
30+
}

0 commit comments

Comments
 (0)