Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands - CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround - CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check - NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere - MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates - LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference Co-authored-by: Cursor <cursoragent@cursor.com>
283 lines
11 KiB
JavaScript
Executable File
283 lines
11 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
||
/**
|
||
* Test All Add Button Strategies
|
||
*
|
||
* This script systematically tests all possible ways to find and click
|
||
* the Add button for static routes, including:
|
||
* - All button detection methods
|
||
* - Keyboard shortcuts
|
||
* - Clicking in different areas
|
||
* - Testing menu items
|
||
*/
|
||
|
||
import { chromium } from 'playwright';
|
||
import { readFileSync } from 'fs';
|
||
import { join } from 'path';
|
||
import { homedir } from 'os';
|
||
|
||
// Load environment variables
|
||
const envPath = join(homedir(), '.env');
|
||
function loadEnvFile(filePath) {
|
||
try {
|
||
const envFile = readFileSync(filePath, 'utf8');
|
||
const envVars = envFile.split('\n').filter(
|
||
(line) => line.includes('=') && !line.trim().startsWith('#')
|
||
);
|
||
for (const line of envVars) {
|
||
const [key, ...values] = line.split('=');
|
||
if (key && values.length > 0 && /^[A-Z_][A-Z0-9_]*$/.test(key.trim())) {
|
||
let value = values.join('=').trim();
|
||
if (
|
||
(value.startsWith('"') && value.endsWith('"')) ||
|
||
(value.startsWith("'") && value.endsWith("'"))
|
||
) {
|
||
value = value.slice(1, -1);
|
||
}
|
||
process.env[key.trim()] = value;
|
||
}
|
||
}
|
||
return true;
|
||
} catch {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
loadEnvFile(envPath);
|
||
|
||
const UDM_URL = process.env.UNIFI_UDM_URL || 'https://192.168.0.1';
|
||
const USERNAME = process.env.UNIFI_BROWSER_USERNAME || process.env.UNIFI_USERNAME || 'unifi_api';
|
||
const PASSWORD = process.env.UNIFI_BROWSER_PASSWORD || process.env.UNIFI_PASSWORD;
|
||
|
||
console.log('🧪 Testing All Add Button Strategies');
|
||
console.log('===================================\n');
|
||
|
||
if (!PASSWORD) {
|
||
console.error('❌ UNIFI_PASSWORD must be set in ~/.env');
|
||
process.exit(1);
|
||
}
|
||
|
||
(async () => {
|
||
const browser = await chromium.launch({ headless: false });
|
||
const context = await browser.newContext({ ignoreHTTPSErrors: true });
|
||
const page = await context.newPage();
|
||
|
||
try {
|
||
console.log('1. Logging in...');
|
||
await page.goto(UDM_URL, { waitUntil: 'networkidle' });
|
||
await page.waitForSelector('input[type="text"]');
|
||
await page.fill('input[type="text"]', USERNAME);
|
||
await page.fill('input[type="password"]', PASSWORD);
|
||
await page.click('button[type="submit"]');
|
||
await page.waitForTimeout(5000);
|
||
|
||
console.log('2. Navigating to Routing page...');
|
||
await page.goto(`${UDM_URL}/network/default/settings/routing`, { waitUntil: 'networkidle' });
|
||
await page.waitForTimeout(10000);
|
||
|
||
await page.waitForURL('**/settings/routing**', { timeout: 20000 }).catch(() => {});
|
||
await page.waitForTimeout(5000);
|
||
|
||
console.log(` Current URL: ${page.url()}\n`);
|
||
|
||
// Wait for routes API
|
||
try {
|
||
await page.waitForResponse(response =>
|
||
response.url().includes('/rest/routing') || response.url().includes('/trafficroutes'),
|
||
{ timeout: 15000 }
|
||
);
|
||
} catch (error) {
|
||
// Continue
|
||
}
|
||
|
||
await page.waitForTimeout(5000);
|
||
|
||
console.log('3. Testing Strategies:\n');
|
||
console.log('='.repeat(80));
|
||
|
||
const strategies = [];
|
||
let success = false;
|
||
|
||
// Strategy 1: Find all buttons and test each
|
||
console.log('\n📋 Strategy 1: Testing All Buttons');
|
||
const allButtons = await page.evaluate(() => {
|
||
const buttons = Array.from(document.querySelectorAll('button, [role="button"]'));
|
||
return buttons.map((btn, index) => {
|
||
const rect = btn.getBoundingClientRect();
|
||
const styles = window.getComputedStyle(btn);
|
||
if (rect.width > 0 && rect.height > 0 && styles.display !== 'none' && styles.visibility !== 'hidden') {
|
||
return {
|
||
index,
|
||
text: btn.textContent?.trim() || '',
|
||
className: btn.className || '',
|
||
id: btn.id || '',
|
||
ariaLabel: btn.getAttribute('aria-label') || '',
|
||
enabled: !btn.disabled,
|
||
selector: btn.id ? `#${btn.id}` : `.${btn.className.split(' ')[0]}`,
|
||
};
|
||
}
|
||
return null;
|
||
}).filter(b => b !== null);
|
||
});
|
||
|
||
console.log(` Found ${allButtons.length} buttons`);
|
||
|
||
for (const btn of allButtons.slice(0, 10)) { // Test first 10 buttons
|
||
try {
|
||
console.log(`\n Testing Button ${btn.index}: "${btn.text}" (${btn.className.substring(0, 50)})`);
|
||
|
||
// Try clicking
|
||
await page.click(btn.selector, { timeout: 3000 }).catch(async () => {
|
||
// Try JavaScript click
|
||
await page.evaluate((id) => {
|
||
const el = document.getElementById(id);
|
||
if (el) el.click();
|
||
}, btn.id).catch(() => {});
|
||
});
|
||
|
||
await page.waitForTimeout(3000);
|
||
|
||
// Check for form
|
||
const hasForm = await page.locator('input[name="name"], input[name="destination"]').first().isVisible({ timeout: 2000 }).catch(() => false);
|
||
if (hasForm) {
|
||
console.log(` ✅✅✅ SUCCESS! Button ${btn.index} opened the form! ✅✅✅`);
|
||
console.log(` Selector: ${btn.selector}`);
|
||
console.log(` ID: ${btn.id || 'none'}`);
|
||
console.log(` Class: ${btn.className}`);
|
||
success = true;
|
||
strategies.push({ strategy: 'Button Click', button: btn, success: true });
|
||
break;
|
||
}
|
||
|
||
// Check for menu
|
||
const hasMenu = await page.locator('[role="menu"], [role="listbox"]').first().isVisible({ timeout: 2000 }).catch(() => false);
|
||
if (hasMenu) {
|
||
console.log(` ⚠️ Menu appeared`);
|
||
const menuItems = await page.evaluate(() => {
|
||
const menu = document.querySelector('[role="menu"], [role="listbox"]');
|
||
if (!menu) return [];
|
||
return Array.from(menu.querySelectorAll('[role="menuitem"], [role="option"], li, div')).map(item => ({
|
||
text: item.textContent?.trim() || '',
|
||
})).filter(item => item.text.length > 0 && (item.text.toLowerCase().includes('add') || item.text.toLowerCase().includes('route')));
|
||
});
|
||
|
||
if (menuItems.length > 0) {
|
||
console.log(` Found Add-related menu items: ${menuItems.map(m => `"${m.text}"`).join(', ')}`);
|
||
// Try clicking first Add-related item
|
||
for (const item of menuItems) {
|
||
try {
|
||
await page.click(`text="${item.text}"`, { timeout: 2000 });
|
||
await page.waitForTimeout(3000);
|
||
const hasForm2 = await page.locator('input[name="name"], input[name="destination"]').first().isVisible({ timeout: 2000 }).catch(() => false);
|
||
if (hasForm2) {
|
||
console.log(` ✅✅✅ SUCCESS! Menu item "${item.text}" opened the form! ✅✅✅`);
|
||
success = true;
|
||
strategies.push({ strategy: 'Menu Item Click', button: btn, menuItem: item, success: true });
|
||
break;
|
||
}
|
||
} catch (error) {
|
||
// Try next item
|
||
}
|
||
}
|
||
}
|
||
|
||
// Close menu
|
||
await page.keyboard.press('Escape');
|
||
await page.waitForTimeout(1000);
|
||
}
|
||
|
||
if (success) break;
|
||
} catch (error) {
|
||
console.log(` ❌ Error: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// Strategy 2: Keyboard shortcuts
|
||
if (!success) {
|
||
console.log('\n⌨️ Strategy 2: Testing Keyboard Shortcuts');
|
||
const shortcuts = ['Control+N', 'Control+KeyN', '+', 'Control+Plus', 'Insert'];
|
||
|
||
for (const shortcut of shortcuts) {
|
||
try {
|
||
console.log(` Trying: ${shortcut}`);
|
||
await page.keyboard.press(shortcut);
|
||
await page.waitForTimeout(3000);
|
||
|
||
const hasForm = await page.locator('input[name="name"], input[name="destination"]').first().isVisible({ timeout: 2000 }).catch(() => false);
|
||
if (hasForm) {
|
||
console.log(` ✅✅✅ SUCCESS! Keyboard shortcut ${shortcut} opened the form! ✅✅✅`);
|
||
success = true;
|
||
strategies.push({ strategy: 'Keyboard Shortcut', shortcut, success: true });
|
||
break;
|
||
}
|
||
} catch (error) {
|
||
// Try next shortcut
|
||
}
|
||
}
|
||
}
|
||
|
||
// Strategy 3: Click in routes area
|
||
if (!success) {
|
||
console.log('\n🖱️ Strategy 3: Clicking in Routes Area');
|
||
try {
|
||
const routesArea = await page.locator(':text("Static Routes"), :text("Routes"), table').first();
|
||
if (await routesArea.isVisible({ timeout: 3000 })) {
|
||
const box = await routesArea.boundingBox();
|
||
if (box) {
|
||
// Try clicking in different areas
|
||
const positions = [
|
||
{ x: box.x + box.width - 50, y: box.y + 20, name: 'top-right' },
|
||
{ x: box.x + box.width - 100, y: box.y + 20, name: 'top-right-2' },
|
||
{ x: box.x + 50, y: box.y + 20, name: 'top-left' },
|
||
];
|
||
|
||
for (const pos of positions) {
|
||
console.log(` Clicking at ${pos.name} (${pos.x}, ${pos.y})`);
|
||
await page.mouse.click(pos.x, pos.y);
|
||
await page.waitForTimeout(2000);
|
||
|
||
const hasForm = await page.locator('input[name="name"], input[name="destination"]').first().isVisible({ timeout: 2000 }).catch(() => false);
|
||
if (hasForm) {
|
||
console.log(` ✅✅✅ SUCCESS! Clicking at ${pos.name} opened the form! ✅✅✅`);
|
||
success = true;
|
||
strategies.push({ strategy: 'Area Click', position: pos, success: true });
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.log(` ❌ Error: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
// Summary
|
||
console.log('\n\n📊 Summary:');
|
||
console.log('='.repeat(80));
|
||
if (success) {
|
||
console.log('✅ SUCCESS! Found working strategy:');
|
||
strategies.filter(s => s.success).forEach(s => {
|
||
console.log(` - ${s.strategy}`);
|
||
if (s.button) console.log(` Button: "${s.button.text}" (${s.button.selector})`);
|
||
if (s.menuItem) console.log(` Menu Item: "${s.menuItem.text}"`);
|
||
if (s.shortcut) console.log(` Shortcut: ${s.shortcut}`);
|
||
if (s.position) console.log(` Position: ${s.position.name}`);
|
||
});
|
||
} else {
|
||
console.log('❌ No working strategy found');
|
||
console.log('\nNext steps:');
|
||
console.log('1. Manually inspect the page in the browser');
|
||
console.log('2. Identify the Add button location');
|
||
console.log('3. Update the script with the correct selector');
|
||
}
|
||
|
||
console.log('\n⏸️ Browser will stay open for 60 seconds for manual inspection...');
|
||
await page.waitForTimeout(60000);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Error:', error.message);
|
||
await page.screenshot({ path: 'test-strategies-error.png', fullPage: true });
|
||
} finally {
|
||
await browser.close();
|
||
}
|
||
})();
|