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
This commit is contained in:
@@ -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);
|
||||
});
|
||||
Reference in New Issue
Block a user