lab.waku.org/examples/dogfooding/tests/multi-node.spec.ts
2025-06-24 13:20:06 -07:00

234 lines
9.1 KiB
TypeScript

import { test, expect, Browser, BrowserContext, Page } from '@playwright/test';
test.describe('Multi-Node Light Push Messages', () => {
test('should send messages between two nodes and track delivery', async ({ browser }) => {
test.setTimeout(90000); // Set timeout to 90 seconds for this test
// Create two separate browser contexts (like incognito windows)
const context1 = await browser.newContext();
const context2 = await browser.newContext();
// Create pages in each context
const page1 = await context1.newPage();
const page2 = await context2.newPage();
// Helper function to initialize a node
const initializeNode = async (page: Page, nodeName: string) => {
await page.goto('/');
// Wait for Waku node initialization
await page.waitForFunction(() => {
return (window as any).waku !== undefined;
}, { timeout: 30000 });
// Wait for peer ID to be displayed
await page.waitForSelector('#peerIdDisplay', { state: 'visible' });
await page.waitForFunction(() => {
const el = document.querySelector('#peerIdDisplay');
return el && el.textContent !== 'Connecting...';
}, { timeout: 30000 });
// Remove webpack dev server overlay if it exists
await page.evaluate(() => {
const overlay = document.querySelector('#webpack-dev-server-client-overlay');
if (overlay) {
overlay.remove();
}
});
// Get peer ID
const peerId = await page.locator('#peerIdDisplay').textContent();
console.log(`${nodeName} initialized with Peer ID: ${peerId}`);
return peerId;
};
// Initialize both nodes
console.log('Initializing Node 1...');
const peerId1 = await initializeNode(page1, 'Node 1');
console.log('Initializing Node 2...');
const peerId2 = await initializeNode(page2, 'Node 2');
// Helper function to get counters
const getCounters = async (page: Page) => {
return await page.evaluate(() => {
return {
sent: parseInt(document.querySelector('#sentByMeCount')?.textContent || '0'),
receivedMine: parseInt(document.querySelector('#receivedMineCount')?.textContent || '0'),
receivedOthers: parseInt(document.querySelector('#receivedOthersCount')?.textContent || '0'),
failed: parseInt(document.querySelector('#failedToSendCount')?.textContent || '0')
};
});
};
// Get initial counters for both nodes
const initialCounters1 = await getCounters(page1);
const initialCounters2 = await getCounters(page2);
console.log('Initial counters Node 1:', initialCounters1);
console.log('Initial counters Node 2:', initialCounters2);
// Send 5 batches of messages from Node 1
console.log('\n--- Starting message sending from Node 1 ---');
const sendButton1 = page1.locator('#sendMessageButton');
const messagesPerBatch = 5;
const totalBatches = 5;
for (let i = 0; i < totalBatches; i++) {
console.log(`Node 1: Sending batch ${i + 1} of ${totalBatches}...`);
await sendButton1.click({ force: true });
// Wait between batches
if (i < totalBatches - 1) {
await page1.waitForTimeout(3000);
}
}
// Wait for messages to propagate
console.log('Waiting for message propagation...');
await page1.waitForTimeout(5000);
// Get final counters for both nodes
const finalCounters1 = await getCounters(page1);
const finalCounters2 = await getCounters(page2);
console.log('\n--- Final Results ---');
console.log('Final counters Node 1:', finalCounters1);
console.log('Final counters Node 2:', finalCounters2);
// Calculate results for Node 1 (sender)
const node1Results = {
sent: finalCounters1.sent - initialCounters1.sent,
receivedMine: finalCounters1.receivedMine - initialCounters1.receivedMine,
receivedOthers: finalCounters1.receivedOthers - initialCounters1.receivedOthers,
failed: finalCounters1.failed - initialCounters1.failed
};
// Calculate results for Node 2 (receiver)
const node2Results = {
sent: finalCounters2.sent - initialCounters2.sent,
receivedMine: finalCounters2.receivedMine - initialCounters2.receivedMine,
receivedOthers: finalCounters2.receivedOthers - initialCounters2.receivedOthers,
failed: finalCounters2.failed - initialCounters2.failed
};
// Generate report
console.log('\n========== DELIVERY REPORT ==========');
console.log(`Total messages sent: ${messagesPerBatch * totalBatches}`);
console.log('\nNode 1 (Sender):');
console.log(` - Peer ID: ${peerId1}`);
console.log(` - Messages sent successfully: ${node1Results.sent}`);
console.log(` - Messages failed: ${node1Results.failed}`);
console.log(` - Own messages received back: ${node1Results.receivedMine}`);
console.log(` - Messages from others: ${node1Results.receivedOthers}`);
console.log('\nNode 2 (Receiver):');
console.log(` - Peer ID: ${peerId2}`);
console.log(` - Messages received from Node 1: ${node2Results.receivedOthers}`);
console.log(` - Own messages received: ${node2Results.receivedMine}`);
const totalExpected = messagesPerBatch * totalBatches;
const node1DeliveryRate = (node1Results.receivedMine / totalExpected) * 100;
const node2DeliveryRate = (node2Results.receivedOthers / totalExpected) * 100;
console.log('\nDelivery Rates:');
console.log(` - Node 1 self-delivery rate: ${node1DeliveryRate.toFixed(2)}%`);
console.log(` - Node 2 reception rate: ${node2DeliveryRate.toFixed(2)}%`);
console.log('=====================================\n');
// Verify at least one message was delivered
expect(node1Results.receivedMine + node2Results.receivedOthers).toBeGreaterThan(0);
// Verify Node 2 received at least some messages from Node 1
expect(node2Results.receivedOthers).toBeGreaterThan(0);
// Check message elements in UI
const messageCount1 = await page1.locator('.message-item').count();
const messageCount2 = await page2.locator('.message-item').count();
console.log(`Messages in Node 1 UI: ${messageCount1}`);
console.log(`Messages in Node 2 UI: ${messageCount2}`);
// Cleanup
await context1.close();
await context2.close();
});
test('should handle bidirectional messaging between two nodes', async ({ browser }) => {
test.setTimeout(90000);
const context1 = await browser.newContext();
const context2 = await browser.newContext();
const page1 = await context1.newPage();
const page2 = await context2.newPage();
// Initialize both nodes
const initializeNode = async (page: Page, nodeName: string) => {
await page.goto('/');
await page.waitForFunction(() => (window as any).waku !== undefined, { timeout: 30000 });
await page.waitForSelector('#peerIdDisplay', { state: 'visible' });
await page.waitForFunction(() => {
const el = document.querySelector('#peerIdDisplay');
return el && el.textContent !== 'Connecting...';
}, { timeout: 30000 });
await page.evaluate(() => {
const overlay = document.querySelector('#webpack-dev-server-client-overlay');
if (overlay) overlay.remove();
});
const peerId = await page.locator('#peerIdDisplay').textContent();
console.log(`${nodeName} initialized with Peer ID: ${peerId}`);
return peerId;
};
await initializeNode(page1, 'Node 1');
await initializeNode(page2, 'Node 2');
// Helper to get message counts
const getMessageCounts = async (page: Page) => {
return await page.evaluate(() => {
return {
receivedOthers: parseInt(document.querySelector('#receivedOthersCount')?.textContent || '0')
};
});
};
const initial1 = await getMessageCounts(page1);
const initial2 = await getMessageCounts(page2);
// Send messages from both nodes alternately
console.log('\n--- Bidirectional messaging test ---');
const sendButton1 = page1.locator('#sendMessageButton');
const sendButton2 = page2.locator('#sendMessageButton');
for (let i = 0; i < 3; i++) {
console.log(`Round ${i + 1}: Node 1 sending...`);
await sendButton1.click({ force: true });
await page1.waitForTimeout(2000);
console.log(`Round ${i + 1}: Node 2 sending...`);
await sendButton2.click({ force: true });
await page2.waitForTimeout(2000);
}
// Wait for final propagation
await page1.waitForTimeout(3000);
const final1 = await getMessageCounts(page1);
const final2 = await getMessageCounts(page2);
const node1ReceivedFromNode2 = final1.receivedOthers - initial1.receivedOthers;
const node2ReceivedFromNode1 = final2.receivedOthers - initial2.receivedOthers;
console.log('\n--- Bidirectional Results ---');
console.log(`Node 1 received ${node1ReceivedFromNode2} messages from Node 2`);
console.log(`Node 2 received ${node2ReceivedFromNode1} messages from Node 1`);
// Verify bidirectional communication
expect(node1ReceivedFromNode2).toBeGreaterThan(0);
expect(node2ReceivedFromNode1).toBeGreaterThan(0);
await context1.close();
await context2.close();
});
});