/** * shot_search_advanced.cjs — Verificación del buscador avanzado (#8) * Comprueba: FULLTEXT, filtro autor, filtro tema, filtro cita bíblica, * filtro fecha, combinado palabra+autor, multiidioma, formulario desktop/móvil. * * Uso: NODE_PATH=/home/rafa/joomla-migration/tools/e2e/node_modules node tools/e2e/shot_search_advanced.cjs */ const { chromium } = require('playwright'); const path = require('path'); const fs = require('fs'); const BASE = 'http://localhost:8081'; const OUT = '/tmp/claude-1000/-mnt-c-Users-Chia/2802dab4-7a28-4ab7-ad16-457debcccc00/scratchpad'; // Ensure output dir fs.mkdirSync(OUT, { recursive: true }); function shotPath(name) { return path.join(OUT, name + '.png'); } async function check(page, label, fn) { try { const result = await fn(page); console.log(`✓ ${label}:`, result); } catch (e) { console.error(`✗ ${label}: ERROR`, e.message); } } (async () => { const b = await chromium.launch({ headless: true }); // ── 1. FULLTEXT por relevancia ────────────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?s=oraci%C3%B3n`, { waitUntil: 'networkidle' }); // Comprueba que hay resultados const cards = await p.$$('.fea-archive-card'); console.log(`✓ FULLTEXT /?s=oración: ${cards.length} tarjetas`); // Comprueba que el formulario avanzado está presente const form = await p.$('.fea-adv-form'); console.log(` formulario avanzado en resultados: ${!!form}`); const counter = await p.$('.fea-adv-count'); const countText = counter ? await counter.textContent() : 'no counter'; console.log(` contador: ${countText}`); await p.screenshot({ path: shotPath('1_fulltext_oración'), fullPage: false }); await p.close(); } // ── 2. Filtro autor ───────────────────────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); // Fray Marcos = 382, Florentino Ulibarri = 395 await p.goto(`${BASE}/?s=&fea_author=382`, { waitUntil: 'networkidle' }); const cards = await p.$$('.fea-archive-card'); console.log(`✓ Filtro autor (fea_author=382 Fray Marcos): ${cards.length} tarjetas`); // Verify selected value in form const selVal = await p.$eval('#fea-author', el => el.value).catch(() => 'n/a'); console.log(` select author value: ${selVal}`); await p.screenshot({ path: shotPath('2_filtro_autor'), fullPage: false }); await p.close(); } // ── 3. Filtro categoría + verificación del desplegable ─────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?fea_cat=1650`, { waitUntil: 'networkidle' }); const cards = await p.$$('.fea-archive-card'); console.log(`✓ Filtro categoría (fea_cat=1650 Artículos): ${cards.length} tarjetas`); const selVal = await p.$eval('#fea-cat', el => el.value).catch(() => 'n/a'); console.log(` select cat value: ${selVal}`); // Label debe decir "Categoría" const catLabel = await p.$eval('label[for="fea-cat"]', el => el.textContent).catch(() => 'n/a'); console.log(` label categoría: "${catLabel}"`); // Contar y listar opciones de categoría (idioma ES) const catOpts = await p.$$eval('#fea-cat option', els => els.map(e => e.textContent)); console.log(` nº opciones categoría: ${catOpts.length}`); console.log(` opciones: ${catOpts.join(' | ')}`); // No debe contener categorías de carta ni "Testament" const badCat = catOpts.filter(t => /Testament/i.test(t)); console.log(` opciones con 'Testament': ${badCat.length}`); await p.screenshot({ path: shotPath('3_filtro_categoria'), fullPage: false }); await p.close(); } // ── 3b. Desplegable de AUTOR: sin "Testamento" ─────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?s=fe`, { waitUntil: 'networkidle' }); const autOpts = await p.$$eval('#fea-author option', els => els.map(e => e.textContent)); console.log(`✓ Desplegable autor: ${autOpts.length} opciones`); const badAut = autOpts.filter(t => /Testament/i.test(t)); console.log(` opciones autor con 'Testament': ${badAut.length} ${badAut.length ? '→ ' + badAut.join(', ') : ''}`); await p.close(); } // ── 4. Filtro cita bíblica (PREFIJO) ───────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?fea_cita=Jn`, { waitUntil: 'networkidle' }); const cards = await p.$$('.fea-archive-card'); console.log(`✓ Filtro cita PREFIJO (fea_cita=Jn): ${cards.length} tarjetas`); const citaVal = await p.$eval('#fea-cita', el => el.value).catch(() => 'n/a'); console.log(` input cita value: ${citaVal}`); const chip = await p.$('.fea-adv-chip'); const chipText = chip ? await chip.textContent() : 'no chip'; console.log(` chip activo: ${chipText}`); // Placeholder corto + foco para ver que NO se corta const ph = await p.$eval('#fea-cita', el => el.placeholder).catch(() => 'n/a'); console.log(` placeholder cita: "${ph}"`); await p.screenshot({ path: shotPath('4_filtro_cita'), fullPage: false }); await p.close(); } // ── 4b. Cita bíblica con valor largo: comprobar que no desborda ────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?fea_cita=Jn%2020%2C%2019-31`, { waitUntil: 'networkidle' }); // Medir overflow: scrollWidth vs clientWidth del input y de su fila const metrics = await p.$eval('#fea-cita', el => ({ scrollW: el.scrollWidth, clientW: el.clientWidth, offsetW: el.offsetWidth, parentW: el.parentElement.clientWidth, })).catch(() => null); console.log(`✓ Cita valor largo (Jn 20, 19-31): ${JSON.stringify(metrics)}`); const overflow = metrics ? (metrics.offsetW > metrics.parentW + 1) : 'n/a'; console.log(` input desborda su celda: ${overflow}`); await p.screenshot({ path: shotPath('4b_cita_largo_nocorta'), fullPage: false }); await p.close(); } // ── 5. Filtro fecha ───────────────────────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?fea_date_from=2020-01-01&fea_date_to=2020-12-31`, { waitUntil: 'networkidle' }); const cards = await p.$$('.fea-archive-card'); console.log(`✓ Filtro fecha (2020): ${cards.length} tarjetas`); await p.screenshot({ path: shotPath('5_filtro_fecha'), fullPage: false }); await p.close(); } // ── 6. Combinado palabra + autor ──────────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?s=amor&fea_author=384`, { waitUntil: 'networkidle' }); // Enrique Martínez Lozano const cards = await p.$$('.fea-archive-card'); console.log(`✓ Combinado s=amor + fea_author=384 (Enrique M.L.): ${cards.length} tarjetas`); await p.screenshot({ path: shotPath('6_combinado_palabra_autor'), fullPage: false }); await p.close(); } // ── 7. Multiidioma /en/?s=love ────────────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/en/?s=love`, { waitUntil: 'networkidle' }); const cards = await p.$$('.fea-archive-card'); // Check form action points to /en/ const formAction = await p.$eval('.fea-adv-form', el => el.action).catch(() => 'n/a'); console.log(`✓ Multiidioma /en/?s=love: ${cards.length} tarjetas, form action: ${formAction}`); // Check if labels are in English const firstLabel = await p.$eval('.fea-adv-label', el => el.textContent).catch(() => 'n/a'); console.log(` primer label: ${firstLabel}`); await p.screenshot({ path: shotPath('7_multiidioma_en'), fullPage: false }); await p.close(); } // ── 8a. Formulario visible en desktop ─────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/?s=fe`, { waitUntil: 'networkidle' }); const formVisible = await p.isVisible('.fea-adv-form'); console.log(`✓ Formulario desktop (1280px): visible=${formVisible}`); await p.screenshot({ path: shotPath('8a_form_desktop'), fullPage: false }); await p.close(); } // ── 8b. Formulario visible en móvil ──────────────────────────────────── { const p = await b.newPage({ viewport: { width: 390, height: 844 } }); await p.goto(`${BASE}/?s=fe`, { waitUntil: 'networkidle' }); const formVisible = await p.isVisible('.fea-adv-form'); console.log(`✓ Formulario móvil (390px): visible=${formVisible}`); // Check advanced link in mobile header const advLink = await p.$('.fea-adv-link'); const advLinkVisible = advLink ? await advLink.isVisible() : false; console.log(` enlace búsqueda avanzada móvil: visible=${advLinkVisible}`); await p.screenshot({ path: shotPath('8b_form_mobile'), fullPage: false }); await p.close(); } // ── 9. Página /buscar ──────────────────────────────────────────────────── { const p = await b.newPage({ viewport: { width: 1280, height: 900 } }); await p.goto(`${BASE}/buscar/`, { waitUntil: 'networkidle' }); const status = p.url(); const form = await p.$('.fea-adv-form'); console.log(`✓ Página /buscar: url=${status}, form=${!!form}`); await p.screenshot({ path: shotPath('9_pagina_buscar'), fullPage: false }); await p.close(); } await b.close(); console.log(`\nCapturas guardadas en: ${OUT}`); })();