chore: rimuovi artefatti obsoleti e aggiungi test-results/ a .gitignore
This commit is contained in:
+2
-1
@@ -134,7 +134,8 @@ node_modules/
|
||||
package-lock.json
|
||||
|
||||
# Build outputs
|
||||
|
||||
test-results/
|
||||
playwright-report/
|
||||
|
||||
# Database
|
||||
*.db
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "llm-monitor-test",
|
||||
"version": "1.0.0",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"playwright": "^1.59.1"
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
const TARGET_URL = process.env.TARGET_URL || 'http://127.0.0.1:8001';
|
||||
const OLLAMA_HOST = process.env.OLLAMA_HOST || 'http://192.168.254.115:11434';
|
||||
const SERVER_ID = process.env.TEST_SERVER_ID || 'srv_e2e_cache';
|
||||
const SERVER_NAME = process.env.TEST_SERVER_NAME || 'E2E Cache Server';
|
||||
const QUIET_WINDOW_MS = Number(process.env.QUIET_WINDOW_MS || 1500);
|
||||
const CACHE_WAIT_TIMEOUT_MS = Number(process.env.CACHE_WAIT_TIMEOUT_MS || 20000);
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function waitForCache(page) {
|
||||
await page.waitForFunction(
|
||||
(serverId) => {
|
||||
return ['health', 'models', 'running'].every((suffix) => {
|
||||
return Boolean(localStorage.getItem(`llm_monitor_${suffix}_${serverId}`));
|
||||
});
|
||||
},
|
||||
SERVER_ID,
|
||||
{ timeout: CACHE_WAIT_TIMEOUT_MS }
|
||||
);
|
||||
}
|
||||
|
||||
async function configureServer(page) {
|
||||
await page.addInitScript(
|
||||
({ serverId, serverName, host }) => {
|
||||
localStorage.setItem(
|
||||
'llm_monitor_servers',
|
||||
JSON.stringify([
|
||||
{
|
||||
id: serverId,
|
||||
name: serverName,
|
||||
host
|
||||
}
|
||||
])
|
||||
);
|
||||
localStorage.setItem('llm_monitor_active_server', serverId);
|
||||
},
|
||||
{
|
||||
serverId: SERVER_ID,
|
||||
serverName: SERVER_NAME,
|
||||
host: OLLAMA_HOST
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ serviceWorkers: 'block' });
|
||||
const page = await context.newPage();
|
||||
const apiRequests = [];
|
||||
|
||||
context.on('request', (request) => {
|
||||
const url = new URL(request.url());
|
||||
if (url.pathname.startsWith('/api/v1/')) {
|
||||
apiRequests.push(url.pathname + url.search);
|
||||
}
|
||||
});
|
||||
|
||||
page.on('console', (msg) => console.log(`[console:${msg.type()}] ${msg.text()}`));
|
||||
page.on('pageerror', (error) => console.log(`[pageerror] ${error.message}`));
|
||||
|
||||
const resetApiRequests = () => {
|
||||
apiRequests.length = 0;
|
||||
};
|
||||
|
||||
const expectNoApiRequests = async (label) => {
|
||||
await sleep(QUIET_WINDOW_MS);
|
||||
if (apiRequests.length > 0) {
|
||||
throw new Error(`${label}: expected no API requests, got ${apiRequests.length} -> ${apiRequests.join(', ')}`);
|
||||
}
|
||||
console.log(`PASS ${label}: no API requests during ${QUIET_WINDOW_MS}ms quiet window`);
|
||||
};
|
||||
|
||||
try {
|
||||
await configureServer(page);
|
||||
|
||||
console.log(`Opening first page at ${TARGET_URL}/models-running?server=${SERVER_ID}`);
|
||||
await page.goto(`${TARGET_URL}/models-running?server=${SERVER_ID}`, { waitUntil: 'domcontentloaded' });
|
||||
await waitForCache(page);
|
||||
|
||||
if (apiRequests.length === 0) {
|
||||
throw new Error('Initial page load did not perform any API requests, cache warmup could not be verified');
|
||||
}
|
||||
|
||||
console.log(`PASS initial load warmed cache with ${apiRequests.length} API requests`);
|
||||
|
||||
resetApiRequests();
|
||||
await page.goto(`${TARGET_URL}/models-available?server=${SERVER_ID}`, { waitUntil: 'domcontentloaded' });
|
||||
await expectNoApiRequests('navigate running -> available');
|
||||
|
||||
resetApiRequests();
|
||||
await page.goto(`${TARGET_URL}/models-running?server=${SERVER_ID}`, { waitUntil: 'domcontentloaded' });
|
||||
await expectNoApiRequests('navigate available -> running');
|
||||
|
||||
resetApiRequests();
|
||||
await page.goto(`${TARGET_URL}/models-available?server=${SERVER_ID}`, { waitUntil: 'domcontentloaded' });
|
||||
await expectNoApiRequests('navigate running -> available again');
|
||||
|
||||
console.log('PASS cache-first navigation test completed successfully');
|
||||
} finally {
|
||||
await context.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(`FAIL ${error.message}`);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -1,147 +0,0 @@
|
||||
// test_modal_click.js
|
||||
// Playwright test to debug modal click functionality
|
||||
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
const TARGET_URL = 'http://192.168.254.12:8000';
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
|
||||
// Log console messages
|
||||
page.on('console', msg => console.log(`[CONSOLE] ${msg.type()}: ${msg.text()}`));
|
||||
page.on('pageerror', exc => console.log(`[PAGE ERROR] ${exc.message}`));
|
||||
|
||||
try {
|
||||
console.log(`\n🔍 [TEST] Navigating to ${TARGET_URL}...`);
|
||||
await page.goto(TARGET_URL, { waitUntil: 'networkidle' });
|
||||
console.log('✅ Page loaded');
|
||||
|
||||
console.log('[WAIT] Waiting for models container to populate...');
|
||||
try {
|
||||
await page.waitForSelector('[data-model-key]', { timeout: 5000 });
|
||||
console.log('✅ [SUCCESS] Models loaded - found cards with data-model-key attribute');
|
||||
} catch (e) {
|
||||
console.log(`❌ [FAILURE] No models found: ${e.message}`);
|
||||
const content = await page.content();
|
||||
console.log('\n📋 Page content (first 1000 chars):');
|
||||
console.log(content.substring(0, 1000));
|
||||
await browser.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all model cards
|
||||
const cards = await page.locator('[data-model-key]').all();
|
||||
console.log(`\n📊 Found ${cards.length} model cards`);
|
||||
|
||||
if (cards.length === 0) {
|
||||
console.log('❌ No cards found');
|
||||
await browser.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get first card info
|
||||
const firstCard = cards[0];
|
||||
const modelKey = await firstCard.getAttribute('data-model-key');
|
||||
console.log(`\n🎯 [TARGET] First card data-model-key: ${modelKey}`);
|
||||
|
||||
// Get modal state BEFORE click
|
||||
const modalElement = page.locator('#model-details-modal');
|
||||
const modalExists = await modalElement.count() > 0;
|
||||
|
||||
if (!modalExists) {
|
||||
console.log('\n❌ [ERROR] Modal element #model-details-modal not found!');
|
||||
await browser.close();
|
||||
return;
|
||||
}
|
||||
|
||||
const classAttributeBefore = await modalElement.getAttribute('class');
|
||||
const isHiddenBefore = classAttributeBefore && classAttributeBefore.includes('hidden');
|
||||
|
||||
console.log(`\n📍 [BEFORE CLICK] Modal HTML class: '${classAttributeBefore}'`);
|
||||
console.log(` Is hidden: ${isHiddenBefore}`);
|
||||
|
||||
// Check if app is initialized
|
||||
const appExists = await page.evaluate(() => typeof window.llmMonitorApp !== 'undefined');
|
||||
console.log(` App initialized: ${appExists}`);
|
||||
|
||||
// Check localStorage
|
||||
const localStorage = await page.evaluate(() => JSON.stringify(Object.fromEntries(Object.entries(window.localStorage))));
|
||||
const lsData = JSON.parse(localStorage);
|
||||
console.log(` localStorage keys: ${Object.keys(lsData).join(', ')}`);
|
||||
|
||||
// PERFORM CLICK
|
||||
console.log(`\n🖱️ [CLICK] Clicking on model card...`);
|
||||
await firstCard.click();
|
||||
|
||||
// Brief pause for DOM update
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Get modal state AFTER click
|
||||
const classAttributeAfter = await modalElement.getAttribute('class');
|
||||
const isHiddenAfter = classAttributeAfter && classAttributeAfter.includes('hidden');
|
||||
|
||||
console.log(`\n📍 [AFTER CLICK] Modal HTML class: '${classAttributeAfter}'`);
|
||||
console.log(` Is hidden: ${isHiddenAfter}`);
|
||||
|
||||
// Evaluate if modal is visible
|
||||
const modalState = await page.evaluate(() => {
|
||||
const modal = document.getElementById('model-details-modal');
|
||||
if (!modal) return 'NOT_FOUND';
|
||||
const isHidden = modal.classList.contains('hidden');
|
||||
const computedStyle = window.getComputedStyle(modal);
|
||||
return {
|
||||
hasHiddenClass: isHidden,
|
||||
display: computedStyle.display,
|
||||
visibility: computedStyle.visibility,
|
||||
opacity: computedStyle.opacity,
|
||||
zIndex: computedStyle.zIndex
|
||||
};
|
||||
});
|
||||
|
||||
console.log(`\n💻 [DOM CHECK] Modal computed state:`);
|
||||
console.log(JSON.stringify(modalState, null, 3));
|
||||
|
||||
// Check for event listeners and app methods
|
||||
const appState = await page.evaluate(() => {
|
||||
const card = document.querySelector('[data-model-key]');
|
||||
if (!card) return 'NO_CARDS';
|
||||
|
||||
if (window.llmMonitorApp && typeof window.llmMonitorApp.showModelDetails === 'function') {
|
||||
return 'APP_METHOD_EXISTS';
|
||||
}
|
||||
return 'NO_APP_METHOD';
|
||||
});
|
||||
|
||||
console.log(`\n🔗 [LISTENERS] Event handler state: ${appState}`);
|
||||
|
||||
// Take screenshot
|
||||
const screenshotPath = '/tmp/modal-test-after-click.png';
|
||||
await page.screenshot({ path: screenshotPath });
|
||||
console.log(`\n📸 Screenshot saved: ${screenshotPath}`);
|
||||
|
||||
// Final verdict
|
||||
console.log('\n' + '='.repeat(70));
|
||||
if (isHiddenBefore !== undefined && isHiddenAfter !== undefined) {
|
||||
if (isHiddenBefore && !isHiddenAfter) {
|
||||
console.log('✅ [PASS] Modal successfully opened on click!');
|
||||
} else if (isHiddenBefore && isHiddenAfter) {
|
||||
console.log('❌ [FAIL] Modal still has "hidden" class after click');
|
||||
console.log(' → Event handler may not be attached');
|
||||
console.log(' → app.js may not be loaded/initialized');
|
||||
} else {
|
||||
console.log('⚠️ [UNCLEAR] Unexpected modal state');
|
||||
}
|
||||
} else {
|
||||
console.log('❌ [ERROR] Could not compare modal states');
|
||||
}
|
||||
console.log('='.repeat(70));
|
||||
|
||||
} catch (error) {
|
||||
console.error('Test error:', error.message);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
})();
|
||||
@@ -1,142 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Playwright test to debug modal click functionality on live LLM Monitor instance
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
TARGET_URL = "http://192.168.254.12:8000"
|
||||
|
||||
async def test_modal_click():
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=True)
|
||||
context = await browser.new_context()
|
||||
page = await context.new_page()
|
||||
|
||||
# Enable console logging
|
||||
page.on("console", lambda msg: print(f"[CONSOLE] {msg.type}: {msg.text}"))
|
||||
page.on("pageerror", lambda exc: print(f"[PAGE ERROR] {exc}"))
|
||||
|
||||
print(f"\n🔍 [TEST] Navigating to {TARGET_URL}...")
|
||||
await page.goto(TARGET_URL, wait_until="networkidle")
|
||||
|
||||
# Wait for models to load
|
||||
print("[WAIT] Waiting for models container to populate...")
|
||||
try:
|
||||
await page.wait_for_selector("[data-model-key]", timeout=5000)
|
||||
print("✅ [SUCCESS] Models loaded - found cards with data-model-key attribute")
|
||||
except Exception as e:
|
||||
print(f"❌ [FAILURE] No models found: {e}")
|
||||
print("\n📋 Page content:")
|
||||
content = await page.content()
|
||||
print(content[:2000])
|
||||
await browser.close()
|
||||
return
|
||||
|
||||
# Get all model cards
|
||||
cards = await page.query_selector_all("[data-model-key]")
|
||||
print(f"\n📊 Found {len(cards)} model cards")
|
||||
|
||||
if len(cards) == 0:
|
||||
print("❌ No cards found after waiting")
|
||||
await browser.close()
|
||||
return
|
||||
|
||||
# Get first card info
|
||||
first_card = cards[0]
|
||||
model_key = await first_card.get_attribute("data-model-key")
|
||||
print(f"\n🎯 [TARGET] First card data-model-key: {model_key}")
|
||||
|
||||
# Get modal state BEFORE click
|
||||
modal_before = await page.query_selector("#model-details-modal")
|
||||
if modal_before:
|
||||
hidden_class_before = await modal_before.get_attribute("class")
|
||||
is_hidden_before = "hidden" in (hidden_class_before or "")
|
||||
print(f"\n📍 [BEFORE CLICK] Modal HTML class: '{hidden_class_before}'")
|
||||
print(f" Is hidden: {is_hidden_before}")
|
||||
else:
|
||||
print("\n❌ [ERROR] Modal element #model-details-modal not found!")
|
||||
|
||||
# Check if app is initialized
|
||||
app_exists = await page.evaluate("typeof window.llmMonitorApp !== 'undefined'")
|
||||
print(f" App initialized: {app_exists}")
|
||||
|
||||
# Check localStorage
|
||||
localStorage = await page.evaluate("JSON.stringify(localStorage)")
|
||||
print(f" localStorage keys: {list(json.loads(localStorage).keys())}")
|
||||
|
||||
# PERFORM CLICK
|
||||
print(f"\n🖱️ [CLICK] Clicking on model card...")
|
||||
await first_card.click()
|
||||
|
||||
# Brief pause for DOM update
|
||||
await page.wait_for_timeout(500)
|
||||
|
||||
# Get modal state AFTER click
|
||||
modal_after = await page.query_selector("#model-details-modal")
|
||||
if modal_after:
|
||||
hidden_class_after = await modal_after.get_attribute("class")
|
||||
is_hidden_after = "hidden" in (hidden_class_after or "")
|
||||
print(f"\n📍 [AFTER CLICK] Modal HTML class: '{hidden_class_after}'")
|
||||
print(f" Is hidden: {is_hidden_after}")
|
||||
else:
|
||||
print("\n❌ [ERROR] Modal element #model-details-modal not found after click!")
|
||||
|
||||
# Evaluate if modal is visible
|
||||
is_visible = await page.evaluate("""
|
||||
() => {
|
||||
const modal = document.getElementById('model-details-modal');
|
||||
if (!modal) return 'NOT_FOUND';
|
||||
const isHidden = modal.classList.contains('hidden');
|
||||
const computedStyle = window.getComputedStyle(modal);
|
||||
return {
|
||||
hasHiddenClass: isHidden,
|
||||
display: computedStyle.display,
|
||||
visibility: computedStyle.visibility,
|
||||
opacity: computedStyle.opacity,
|
||||
zIndex: computedStyle.zIndex
|
||||
};
|
||||
}
|
||||
""")
|
||||
print(f"\n💻 [DOM CHECK] Modal computed state:\n {json.dumps(is_visible, indent=3)}")
|
||||
|
||||
# Check for event listeners
|
||||
listeners = await page.evaluate("""
|
||||
() => {
|
||||
const card = document.querySelector('[data-model-key]');
|
||||
if (!card) return 'NO_CARDS';
|
||||
|
||||
// Try to trigger click manually via app if it exists
|
||||
if (window.llmMonitorApp && typeof window.llmMonitorApp.showModelDetails === 'function') {
|
||||
return 'APP_METHOD_EXISTS';
|
||||
}
|
||||
return 'NO_APP_METHOD';
|
||||
}
|
||||
""")
|
||||
print(f"\n🔗 [LISTENERS] Event handler state: {listeners}")
|
||||
|
||||
# Take screenshot
|
||||
screenshot_path = "/tmp/modal-test-after-click.png"
|
||||
await page.screenshot(path=screenshot_path)
|
||||
print(f"\n📸 Screenshot saved: {screenshot_path}")
|
||||
|
||||
# Final verdict
|
||||
print("\n" + "="*70)
|
||||
if hidden_class_before is not None and hidden_class_after is not None:
|
||||
if is_hidden_before and not is_hidden_after:
|
||||
print("✅ [PASS] Modal successfully opened on click!")
|
||||
elif is_hidden_before and is_hidden_after:
|
||||
print("❌ [FAIL] Modal still has 'hidden' class after click")
|
||||
print(" → Event handler may not be attached")
|
||||
print(" → app.js may not be loaded/initialized")
|
||||
else:
|
||||
print("⚠️ [UNCLEAR] Unexpected modal state")
|
||||
else:
|
||||
print("❌ [ERROR] Could not compare modal states")
|
||||
print("="*70)
|
||||
|
||||
await browser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(test_modal_click())
|
||||
Reference in New Issue
Block a user