mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
243 lines
8.0 KiB
JavaScript
243 lines
8.0 KiB
JavaScript
import { chromium } from 'playwright';
|
|
import { spawn } from 'child_process';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const ROOT_DIR = path.resolve(__dirname, '../..');
|
|
const ARTIFACTS_DIR = path.join(ROOT_DIR, 'artifacts');
|
|
|
|
if (!fs.existsSync(ARTIFACTS_DIR)) {
|
|
fs.mkdirSync(ARTIFACTS_DIR);
|
|
}
|
|
|
|
const DATE_STR = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
const LOG_FILE = path.join(ARTIFACTS_DIR, `smoke-${DATE_STR}.log`);
|
|
|
|
function log(message) {
|
|
const line = `[${new Date().toISOString()}] ${message}`;
|
|
console.log(line);
|
|
fs.appendFileSync(LOG_FILE, line + '\n');
|
|
}
|
|
|
|
async function startServer() {
|
|
log('Starting local server (python3)...');
|
|
const serverProcess = spawn('python3', ['-m', 'http.server', '8000'], {
|
|
cwd: ROOT_DIR,
|
|
stdio: 'ignore'
|
|
});
|
|
|
|
// Give it a moment to start
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
return serverProcess;
|
|
}
|
|
|
|
async function run() {
|
|
let serverProcess;
|
|
let browser;
|
|
let exitCode = 0;
|
|
|
|
try {
|
|
serverProcess = await startServer();
|
|
|
|
log('Launching browser...');
|
|
browser = await chromium.launch({ headless: true });
|
|
const page = await browser.newPage();
|
|
|
|
page.on('console', msg => {
|
|
const text = msg.text();
|
|
// Filter out some noise if needed, but keeping it is safer for debugging
|
|
if (msg.type() === 'error') {
|
|
log(`BROWSER ERROR: ${text}`);
|
|
} else {
|
|
// log(`BROWSER: ${text}`); // Optional verbose logging
|
|
}
|
|
});
|
|
|
|
page.on('pageerror', err => {
|
|
log(`PAGE ERROR: ${err.message}`);
|
|
});
|
|
|
|
log('Navigating to app...');
|
|
await page.goto('http://localhost:8000');
|
|
|
|
// Wait for app to load (checking for #app or similar)
|
|
await page.waitForSelector('#app', { timeout: 10000 });
|
|
log('App loaded.');
|
|
|
|
// Inject test logic
|
|
log('Running in-page smoke test...');
|
|
const result = await page.evaluate(async () => {
|
|
const logs = [];
|
|
function pageLog(m) { logs.push(m); console.log('[SmokeTest] ' + m); }
|
|
|
|
try {
|
|
// 1. Import Client
|
|
pageLog('Importing nostrClient...');
|
|
const { nostrClient } = await import('./js/nostrClientFacade.js');
|
|
const { NostrTools } = window; // Assumed to be loaded via script tag in index.html
|
|
|
|
if (!nostrClient) throw new Error('nostrClient not found');
|
|
if (!NostrTools) throw new Error('NostrTools not found on window');
|
|
|
|
// Override relays to a specific subset to avoid spamming all defaults if local relay is not available
|
|
// Ideally this would be a local relay, but we use a public one for the smoke test as fallback.
|
|
const TEST_RELAY = 'wss://relay.damus.io';
|
|
pageLog(`Configuring nostrClient to use ${TEST_RELAY}...`);
|
|
|
|
// If nostrClient is already initialized, we might need to reconnect or just update properties
|
|
nostrClient.relays = [TEST_RELAY];
|
|
nostrClient.writeRelays = [TEST_RELAY];
|
|
nostrClient.readRelays = [TEST_RELAY];
|
|
|
|
if (nostrClient.pool) {
|
|
// Ensure connection to our test relay
|
|
await nostrClient.pool.ensureRelay(TEST_RELAY);
|
|
}
|
|
|
|
// Wait a bit for connection
|
|
pageLog('Waiting for relay connection...');
|
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
|
|
// 2. Generate Identity
|
|
pageLog('Generating ephemeral identity...');
|
|
|
|
const bytesToHex = (bytes) => {
|
|
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
};
|
|
|
|
let privateKey;
|
|
if (NostrTools.generateSecretKey) {
|
|
const secret = NostrTools.generateSecretKey();
|
|
if (secret instanceof Uint8Array) {
|
|
privateKey = bytesToHex(secret);
|
|
} else {
|
|
privateKey = secret;
|
|
}
|
|
} else {
|
|
privateKey = NostrTools.generatePrivateKey();
|
|
}
|
|
|
|
const pubkey = NostrTools.getPublicKey(privateKey);
|
|
pageLog(`Generated pubkey: ${pubkey}`);
|
|
|
|
// 3. Login
|
|
pageLog('Logging in...');
|
|
await nostrClient.registerPrivateKeySigner({ privateKey, pubkey });
|
|
|
|
// 4. Publish Video
|
|
pageLog('Publishing video...');
|
|
const videoPayload = {
|
|
legacyFormData: { // extractVideoPublishPayload expects this structure or direct fields
|
|
title: `Smoke Test Video ${Date.now()}`,
|
|
description: 'Automated smoke test artifact',
|
|
url: 'https://example.com/video.mp4',
|
|
magnet: 'magnet:?xt=urn:btih:c9e15763f722f23e98ce29a8c0c4000000000000&dn=test', // Valid-ish magnet
|
|
mimeType: 'video/mp4',
|
|
isForKids: false,
|
|
isNsfw: false,
|
|
isPrivate: true,
|
|
},
|
|
fileSha256: '0000000000000000000000000000000000000000000000000000000000000000'
|
|
};
|
|
|
|
// Note: publishVideo takes (videoPayload, pubkey)
|
|
const event = await nostrClient.publishVideo(videoPayload, pubkey);
|
|
pageLog(`Video published! ID: ${event.id}`);
|
|
|
|
// 5. Verify Read Back
|
|
pageLog('Verifying read back...');
|
|
// We can use getEventById
|
|
const fetched = await nostrClient.getEventById(event.id);
|
|
if (!fetched) throw new Error('Failed to fetch published video');
|
|
if (fetched.id !== event.id) throw new Error('Fetched ID mismatch');
|
|
pageLog('Read back successful.');
|
|
|
|
// 6. DM Flow
|
|
pageLog('Testing DM flow (Self-DM)...');
|
|
// We'll send a DM to ourselves
|
|
const npub = NostrTools.nip19.npubEncode(pubkey);
|
|
const message = `Smoke Test DM ${Date.now()}`;
|
|
|
|
const dmResult = await nostrClient.sendDirectMessage(npub, message);
|
|
if (!dmResult.ok) throw new Error(`DM Send failed: ${dmResult.error}`);
|
|
pageLog('DM Sent.');
|
|
|
|
// Decrypt
|
|
// We need to fetch it. listDirectMessages
|
|
pageLog('Fetching and decrypting DMs...');
|
|
// Allow some time for propagation to relay and back
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
const dms = await nostrClient.listDirectMessages(pubkey, { limit: 10 });
|
|
|
|
const match = dms.find(r => r.content === message || r.plaintext === message);
|
|
|
|
if (!match) {
|
|
pageLog('DM not found in list. Fetched count: ' + dms.length);
|
|
console.log('DMs:', JSON.stringify(dms));
|
|
throw new Error('DM verification failed');
|
|
}
|
|
|
|
pageLog('DM Verified.');
|
|
|
|
return { success: true, logs };
|
|
|
|
} catch (e) {
|
|
pageLog(`ERROR: ${e.message}`);
|
|
return { success: false, error: e.message, stack: e.stack, logs };
|
|
}
|
|
});
|
|
|
|
if (result.success) {
|
|
log('Smoke Test Passed!');
|
|
result.logs.forEach(l => log(`[PAGE] ${l}`));
|
|
|
|
const summary = {
|
|
timestamp: new Date().toISOString(),
|
|
status: 'success',
|
|
steps: ['login', 'publish', 'dm_send', 'dm_decrypt'],
|
|
logs: result.logs
|
|
};
|
|
fs.writeFileSync(path.join(ARTIFACTS_DIR, `smoke-summary-${DATE_STR}.json`), JSON.stringify(summary, null, 2));
|
|
|
|
} else {
|
|
log('Smoke Test Failed!');
|
|
result.logs.forEach(l => log(`[PAGE] ${l}`));
|
|
log(`Error: ${result.error}`);
|
|
log(`Stack: ${result.stack}`);
|
|
|
|
const screenshotPath = path.join(ARTIFACTS_DIR, `failure-${DATE_STR}.png`);
|
|
await page.screenshot({ path: screenshotPath });
|
|
log(`Screenshot saved to ${screenshotPath}`);
|
|
|
|
const summary = {
|
|
timestamp: new Date().toISOString(),
|
|
status: 'failure',
|
|
error: result.error,
|
|
logs: result.logs
|
|
};
|
|
fs.writeFileSync(path.join(ARTIFACTS_DIR, `smoke-summary-${DATE_STR}.json`), JSON.stringify(summary, null, 2));
|
|
|
|
exitCode = 1;
|
|
}
|
|
|
|
} catch (err) {
|
|
log(`CRITICAL ERROR: ${err.message}`);
|
|
log(err.stack);
|
|
exitCode = 1;
|
|
} finally {
|
|
if (browser) await browser.close();
|
|
if (serverProcess) {
|
|
serverProcess.kill();
|
|
log('Server stopped.');
|
|
}
|
|
}
|
|
|
|
process.exit(exitCode);
|
|
}
|
|
|
|
run();
|