From aeaa9f2d627eb2f5ff295210409982ee0700f03c Mon Sep 17 00:00:00 2001 From: juanatsap Date: Tue, 2 Dec 2025 18:18:43 +0000 Subject: [PATCH] test: add intro-text justification CSS verification test Tests text-align, text-align-last, hyphens, word-spacing, overflow-wrap, and font-style properties for both EN and ES --- .../mjs/77-intro-text-justification.test.mjs | 281 ++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 tests/mjs/77-intro-text-justification.test.mjs diff --git a/tests/mjs/77-intro-text-justification.test.mjs b/tests/mjs/77-intro-text-justification.test.mjs new file mode 100644 index 0000000..7482d42 --- /dev/null +++ b/tests/mjs/77-intro-text-justification.test.mjs @@ -0,0 +1,281 @@ +#!/usr/bin/env bun +/** + * INTRO TEXT JUSTIFICATION TEST + * ============================== + * Tests the intro-text paragraph styling including: + * - Full text justification (text-align: justify) + * - Last line justification (text-align-last: justify) + * - Hyphenation support (hyphens: auto) + * - Cross-browser compatibility + */ + +import { chromium } from 'playwright'; + +const URL = "http://localhost:1999"; + +async function testIntroTextJustification() { + console.log('📝 INTRO TEXT JUSTIFICATION TEST\n'); + console.log('='.repeat(70)); + + const browser = await chromium.launch({ headless: true }); + const errors = []; + const testResults = []; + + // ======================================================================== + // TEST 1: Verify intro-text element exists + // ======================================================================== + console.log("\n1️⃣ Checking intro-text element exists..."); + const page = await browser.newPage({ viewport: { width: 1076, height: 756 } }); + + page.on('console', msg => { + if (msg.type() === 'error') { + errors.push(msg.text()); + console.log(`❌ ERROR: ${msg.text()}`); + } + }); + + await page.goto(URL); + await page.waitForTimeout(1500); + + const elementExists = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + return { + exists: introText !== null, + textLength: introText ? introText.textContent.length : 0 + }; + }); + + if (elementExists.exists) { + console.log(` ✅ .intro-text element found (${elementExists.textLength} chars)`); + testResults.push({ test: "intro-text exists", passed: true }); + } else { + console.log(" ❌ .intro-text element NOT found"); + testResults.push({ test: "intro-text exists", passed: false }); + } + + // ======================================================================== + // TEST 2: Verify text-align: justify + // ======================================================================== + console.log("\n2️⃣ Checking text-align: justify..."); + + const textAlignTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + if (!introText) return { passed: false, value: 'element not found' }; + + const computed = window.getComputedStyle(introText); + const textAlign = computed.textAlign; + + return { + passed: textAlign === 'justify', + value: textAlign + }; + }); + + if (textAlignTest.passed) { + console.log(` ✅ text-align: ${textAlignTest.value}`); + testResults.push({ test: "text-align justify", passed: true }); + } else { + console.log(` ❌ text-align: ${textAlignTest.value} (expected: justify)`); + testResults.push({ test: "text-align justify", passed: false }); + } + + // ======================================================================== + // TEST 3: Verify text-align-last: justify + // ======================================================================== + console.log("\n3️⃣ Checking text-align-last: justify..."); + + const textAlignLastTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + if (!introText) return { passed: false, value: 'element not found' }; + + const computed = window.getComputedStyle(introText); + const textAlignLast = computed.textAlignLast; + + return { + passed: textAlignLast === 'justify', + value: textAlignLast + }; + }); + + if (textAlignLastTest.passed) { + console.log(` ✅ text-align-last: ${textAlignLastTest.value}`); + testResults.push({ test: "text-align-last justify", passed: true }); + } else { + console.log(` ❌ text-align-last: ${textAlignLastTest.value} (expected: justify)`); + testResults.push({ test: "text-align-last justify", passed: false }); + } + + // ======================================================================== + // TEST 4: Verify hyphens: auto + // ======================================================================== + console.log("\n4️⃣ Checking hyphens: auto..."); + + const hyphensTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + if (!introText) return { passed: false, value: 'element not found' }; + + const computed = window.getComputedStyle(introText); + // Note: Chromium returns 'auto' or 'manual' or 'none' + const hyphens = computed.hyphens || computed.webkitHyphens; + + return { + passed: hyphens === 'auto', + value: hyphens + }; + }); + + if (hyphensTest.passed) { + console.log(` ✅ hyphens: ${hyphensTest.value}`); + testResults.push({ test: "hyphens auto", passed: true }); + } else { + console.log(` ❌ hyphens: ${hyphensTest.value} (expected: auto)`); + testResults.push({ test: "hyphens auto", passed: false }); + } + + // ======================================================================== + // TEST 5: Verify word-spacing is set + // ======================================================================== + console.log("\n5️⃣ Checking word-spacing..."); + + const wordSpacingTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + if (!introText) return { passed: false, value: 'element not found' }; + + const computed = window.getComputedStyle(introText); + const wordSpacing = computed.wordSpacing; + // We set word-spacing: -1px, but computed returns in px + const value = parseFloat(wordSpacing); + + return { + passed: value < 0, // Should be negative + value: wordSpacing + }; + }); + + if (wordSpacingTest.passed) { + console.log(` ✅ word-spacing: ${wordSpacingTest.value}`); + testResults.push({ test: "word-spacing negative", passed: true }); + } else { + console.log(` ❌ word-spacing: ${wordSpacingTest.value} (expected: negative value)`); + testResults.push({ test: "word-spacing negative", passed: false }); + } + + // ======================================================================== + // TEST 6: Verify overflow-wrap: break-word + // ======================================================================== + console.log("\n6️⃣ Checking overflow-wrap: break-word..."); + + const overflowWrapTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + if (!introText) return { passed: false, value: 'element not found' }; + + const computed = window.getComputedStyle(introText); + const overflowWrap = computed.overflowWrap || computed.wordWrap; + + return { + passed: overflowWrap === 'break-word', + value: overflowWrap + }; + }); + + if (overflowWrapTest.passed) { + console.log(` ✅ overflow-wrap: ${overflowWrapTest.value}`); + testResults.push({ test: "overflow-wrap break-word", passed: true }); + } else { + console.log(` ❌ overflow-wrap: ${overflowWrapTest.value} (expected: break-word)`); + testResults.push({ test: "overflow-wrap break-word", passed: false }); + } + + // ======================================================================== + // TEST 7: Verify font-style: italic + // ======================================================================== + console.log("\n7️⃣ Checking font-style: italic..."); + + const fontStyleTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + if (!introText) return { passed: false, value: 'element not found' }; + + const computed = window.getComputedStyle(introText); + const fontStyle = computed.fontStyle; + + return { + passed: fontStyle === 'italic', + value: fontStyle + }; + }); + + if (fontStyleTest.passed) { + console.log(` ✅ font-style: ${fontStyleTest.value}`); + testResults.push({ test: "font-style italic", passed: true }); + } else { + console.log(` ❌ font-style: ${fontStyleTest.value} (expected: italic)`); + testResults.push({ test: "font-style italic", passed: false }); + } + + // ======================================================================== + // TEST 8: Test on Spanish language (different hyphenation) + // ======================================================================== + console.log("\n8️⃣ Testing Spanish version..."); + + await page.goto(`${URL}/?lang=es`); + await page.waitForTimeout(1500); + + const spanishTest = await page.evaluate(() => { + const introText = document.querySelector('.intro-text'); + const htmlLang = document.documentElement.lang; + + if (!introText) return { passed: false, lang: htmlLang, hasText: false }; + + const computed = window.getComputedStyle(introText); + + return { + passed: htmlLang === 'es' && computed.textAlign === 'justify', + lang: htmlLang, + hasText: introText.textContent.length > 0, + textAlign: computed.textAlign + }; + }); + + if (spanishTest.passed) { + console.log(` ✅ Spanish version: lang="${spanishTest.lang}", text-align: ${spanishTest.textAlign}`); + testResults.push({ test: "spanish justification", passed: true }); + } else { + console.log(` ❌ Spanish version failed - lang: ${spanishTest.lang}, text-align: ${spanishTest.textAlign}`); + testResults.push({ test: "spanish justification", passed: false }); + } + + // ======================================================================== + // SUMMARY + // ======================================================================== + console.log('\n' + '='.repeat(70)); + console.log('📊 TEST SUMMARY\n'); + + const passed = testResults.filter(t => t.passed).length; + const total = testResults.length; + const consoleErrors = errors.filter(e => !e.includes('favicon')); + + console.log(`Tests: ${passed}/${total} passed`); + console.log(`Console errors: ${consoleErrors.length}`); + + if (consoleErrors.length > 0) { + console.log('\nConsole errors:'); + consoleErrors.forEach(e => console.log(` - ${e}`)); + } + + console.log('\nDetailed results:'); + testResults.forEach(t => { + console.log(` ${t.passed ? '✅' : '❌'} ${t.test}`); + }); + + await browser.close(); + + const success = passed === total && consoleErrors.length === 0; + console.log(`\n${success ? '✅ ALL TESTS PASSED' : '❌ SOME TESTS FAILED'}\n`); + + process.exit(success ? 0 : 1); +} + +testIntroTextJustification().catch(err => { + console.error('Test failed:', err); + process.exit(1); +});