310 lines
11 KiB
JavaScript
310 lines
11 KiB
JavaScript
import { chromium } from '@playwright/test';
|
|
|
|
async function audit() {
|
|
const browser = await chromium.launch({ headless: true });
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
|
|
const results = {
|
|
homepage: {},
|
|
providers: {},
|
|
clients: {},
|
|
shop: {},
|
|
terms: {},
|
|
privacy: {},
|
|
seoRoute: {},
|
|
favicon: {}
|
|
};
|
|
|
|
// Capture console messages
|
|
const consoleMessages = [];
|
|
page.on('console', (msg) => {
|
|
consoleMessages.push(`[${msg.type()}] ${msg.text()}`);
|
|
});
|
|
|
|
// Capture errors
|
|
const pageErrors = [];
|
|
page.on('pageerror', (error) => {
|
|
pageErrors.push(error.message);
|
|
});
|
|
|
|
console.log('=== AUDIT START ===\n');
|
|
|
|
// 1. Homepage
|
|
console.log('Testing: Homepage (http://www.atlilith.lan/)');
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-homepage.png', fullPage: false });
|
|
const title = await page.title();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
results.homepage = { status: 'OK', title, bodyLength: bodyText.length };
|
|
console.log(` ✓ Status: OK | Title: "${title}" | Body length: ${bodyText.length}\n`);
|
|
} catch (e) {
|
|
results.homepage = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 2. /providers - Check for translation keys
|
|
console.log('Testing: /providers (P0 Issue #1 - i18n)');
|
|
consoleMessages.length = 0;
|
|
pageErrors.length = 0;
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/providers', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-providers.png', fullPage: false });
|
|
const title = await page.title();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
|
|
const hasTranslationKeys = bodyText.includes('forWorkers.') ||
|
|
bodyText.match(/\w+\.title/) ||
|
|
bodyText.match(/\w+\.description/);
|
|
|
|
const hasI18nError = consoleMessages.some(m => m.includes('i18next::translator: missingKey'));
|
|
|
|
results.providers = {
|
|
status: hasTranslationKeys || hasI18nError ? 'BROKEN' : 'FIXED',
|
|
title,
|
|
hasTranslationKeys,
|
|
hasI18nError,
|
|
bodyLength: bodyText.length
|
|
};
|
|
|
|
if (hasTranslationKeys || hasI18nError) {
|
|
console.log(` ✗ STILL BROKEN: Translation keys visible or i18n errors`);
|
|
console.log(` Title: "${title}"`);
|
|
console.log(` Has translation keys: ${hasTranslationKeys}`);
|
|
console.log(` Has i18n errors: ${hasI18nError}\n`);
|
|
} else {
|
|
console.log(` ✓ FIXED: No translation keys detected`);
|
|
console.log(` Title: "${title}"\n`);
|
|
}
|
|
} catch (e) {
|
|
results.providers = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 3. /clients - Check for translation keys
|
|
console.log('Testing: /clients (P0 Issue #1 - i18n)');
|
|
consoleMessages.length = 0;
|
|
pageErrors.length = 0;
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/clients', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-clients.png', fullPage: false });
|
|
const title = await page.title();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
|
|
const hasTranslationKeys = bodyText.includes('forClients.') ||
|
|
bodyText.match(/\w+\.title/) ||
|
|
bodyText.match(/\w+\.description/);
|
|
|
|
results.clients = {
|
|
status: hasTranslationKeys ? 'BROKEN' : 'FIXED',
|
|
title,
|
|
hasTranslationKeys,
|
|
bodyLength: bodyText.length
|
|
};
|
|
|
|
if (hasTranslationKeys) {
|
|
console.log(` ✗ STILL BROKEN: Translation keys visible`);
|
|
console.log(` Title: "${title}"\n`);
|
|
} else {
|
|
console.log(` ✓ FIXED: No translation keys detected`);
|
|
console.log(` Title: "${title}"\n`);
|
|
}
|
|
} catch (e) {
|
|
results.clients = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 4. /shop - Check for translation keys
|
|
console.log('Testing: /shop (P0 Issue #1 - i18n)');
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/shop', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-shop.png', fullPage: false });
|
|
const title = await page.title();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
|
|
const hasTranslationKeys = bodyText.includes('shop.') ||
|
|
bodyText.match(/\w+\.title/) ||
|
|
bodyText.match(/\w+\.description/);
|
|
|
|
results.shop = {
|
|
status: hasTranslationKeys ? 'BROKEN' : 'FIXED',
|
|
title,
|
|
hasTranslationKeys,
|
|
bodyLength: bodyText.length
|
|
};
|
|
|
|
if (hasTranslationKeys) {
|
|
console.log(` ✗ STILL BROKEN: Translation keys visible`);
|
|
console.log(` Title: "${title}"\n`);
|
|
} else {
|
|
console.log(` ✓ FIXED: No translation keys detected`);
|
|
console.log(` Title: "${title}"\n`);
|
|
}
|
|
} catch (e) {
|
|
results.shop = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 5. /company/terms - Check for crash
|
|
console.log('Testing: /company/terms (P0 Issue #2 - Page crash)');
|
|
pageErrors.length = 0;
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/company/terms', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-terms.png', fullPage: false });
|
|
const title = await page.title();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
|
|
const hasCrash = pageErrors.some(e => e.includes('accountItems.map'));
|
|
|
|
results.terms = {
|
|
status: hasCrash ? 'BROKEN' : 'FIXED',
|
|
title,
|
|
hasCrash,
|
|
bodyLength: bodyText.length,
|
|
errors: pageErrors
|
|
};
|
|
|
|
if (hasCrash) {
|
|
console.log(` ✗ STILL BROKEN: Page crashed with accountItems.map error`);
|
|
console.log(` Errors: ${pageErrors.join(', ')}\n`);
|
|
} else if (bodyText.length > 100) {
|
|
console.log(` ✓ FIXED: Page loaded successfully`);
|
|
console.log(` Title: "${title}"`);
|
|
console.log(` Body length: ${bodyText.length}\n`);
|
|
} else {
|
|
console.log(` ⚠ NEW ISSUE: Page loaded but minimal content`);
|
|
console.log(` Body length: ${bodyText.length}\n`);
|
|
}
|
|
} catch (e) {
|
|
results.terms = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 6. /company/privacy - Check for crash
|
|
console.log('Testing: /company/privacy (P0 Issue #3 - Page crash)');
|
|
pageErrors.length = 0;
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/company/privacy', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-privacy.png', fullPage: false });
|
|
const title = await page.title();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
|
|
const hasCrash = pageErrors.some(e => e.includes('locationItems.map'));
|
|
|
|
results.privacy = {
|
|
status: hasCrash ? 'BROKEN' : 'FIXED',
|
|
title,
|
|
hasCrash,
|
|
bodyLength: bodyText.length,
|
|
errors: pageErrors
|
|
};
|
|
|
|
if (hasCrash) {
|
|
console.log(` ✗ STILL BROKEN: Page crashed with locationItems.map error`);
|
|
console.log(` Errors: ${pageErrors.join(', ')}\n`);
|
|
} else if (bodyText.length > 100) {
|
|
console.log(` ✓ FIXED: Page loaded successfully`);
|
|
console.log(` Title: "${title}"`);
|
|
console.log(` Body length: ${bodyText.length}\n`);
|
|
} else {
|
|
console.log(` ⚠ NEW ISSUE: Page loaded but minimal content`);
|
|
console.log(` Body length: ${bodyText.length}\n`);
|
|
}
|
|
} catch (e) {
|
|
results.privacy = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 7. /_/en/ - SEO route (P1 Issue #6)
|
|
console.log('Testing: /_/en/ (P1 Issue #6 - SEO route)');
|
|
try {
|
|
const response = await page.goto('http://www.atlilith.lan/_/en/', { waitUntil: 'networkidle', timeout: 30000 });
|
|
await page.screenshot({ path: '/tmp/audit-seo.png', fullPage: false });
|
|
const status = response?.status();
|
|
const bodyText = (await page.locator('body').textContent()) || '';
|
|
|
|
results.seoRoute = {
|
|
status: status === 502 ? 'BROKEN' : 'FIXED',
|
|
httpStatus: status,
|
|
bodyLength: bodyText.length
|
|
};
|
|
|
|
if (status === 502) {
|
|
console.log(` ✗ STILL BROKEN: Returns 502 Bad Gateway\n`);
|
|
} else if (status === 200) {
|
|
console.log(` ✓ FIXED: Returns 200 with content`);
|
|
console.log(` Body length: ${bodyText.length}\n`);
|
|
} else {
|
|
console.log(` ⚠ NEW ISSUE: Unexpected status ${status}\n`);
|
|
}
|
|
} catch (e) {
|
|
results.seoRoute = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 8. Check page title on /providers (P1 Issue #7)
|
|
console.log('Testing: Page titles (P1 Issue #7)');
|
|
try {
|
|
await page.goto('http://www.atlilith.lan/providers', { waitUntil: 'networkidle', timeout: 30000 });
|
|
const title = await page.title();
|
|
|
|
const hasTitleKeys = title.includes('.title') || title.includes('forWorkers.');
|
|
|
|
results.pageTitle = {
|
|
status: hasTitleKeys ? 'BROKEN' : 'FIXED',
|
|
title,
|
|
hasTitleKeys
|
|
};
|
|
|
|
if (hasTitleKeys) {
|
|
console.log(` ✗ STILL BROKEN: Title shows translation keys`);
|
|
console.log(` Title: "${title}"\n`);
|
|
} else if (title.length > 3) {
|
|
console.log(` ✓ FIXED: Title shows proper text`);
|
|
console.log(` Title: "${title}"\n`);
|
|
} else {
|
|
console.log(` ⚠ NEW ISSUE: Title too short or empty`);
|
|
console.log(` Title: "${title}"\n`);
|
|
}
|
|
} catch (e) {
|
|
results.pageTitle = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
// 9. Check favicon (P1 Issue #9)
|
|
console.log('Testing: /favicon.ico (P1 Issue #9)');
|
|
try {
|
|
const response = await page.goto('http://www.atlilith.lan/favicon.ico', { waitUntil: 'domcontentloaded', timeout: 10000 });
|
|
const status = response?.status();
|
|
const contentType = response?.headers()['content-type'];
|
|
|
|
results.favicon = {
|
|
status: (status === 200 && contentType?.includes('image')) ? 'FIXED' : 'BROKEN',
|
|
httpStatus: status,
|
|
contentType
|
|
};
|
|
|
|
if (status === 200 && contentType?.includes('image')) {
|
|
console.log(` ✓ FIXED: Favicon returns valid image`);
|
|
console.log(` Status: ${status}, Content-Type: ${contentType}\n`);
|
|
} else if (status === 404) {
|
|
console.log(` ✗ STILL BROKEN: Returns 404\n`);
|
|
} else {
|
|
console.log(` ⚠ NEW ISSUE: Unexpected response`);
|
|
console.log(` Status: ${status}, Content-Type: ${contentType}\n`);
|
|
}
|
|
} catch (e) {
|
|
results.favicon = { status: 'ERROR', error: e.message };
|
|
console.log(` ✗ Error: ${e.message}\n`);
|
|
}
|
|
|
|
await browser.close();
|
|
|
|
console.log('=== AUDIT COMPLETE ===');
|
|
console.log('\nScreenshots saved to /tmp/audit-*.png');
|
|
console.log('\nSummary:');
|
|
console.log(JSON.stringify(results, null, 2));
|
|
}
|
|
|
|
audit().catch(console.error);
|