@casoon/auditmysite
Version:
Professional website analysis suite with robust accessibility testing, Core Web Vitals performance monitoring, SEO analysis, and content optimization insights. Features isolated browser contexts, retry mechanisms, and comprehensive API endpoints for profe
263 lines • 8.63 kB
JavaScript
;
/**
* 🌍 Geo-Audit Feature
*
* Performs website audits from different geographic locations
* to test regional performance, content variations, and accessibility.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.COMMON_LOCATIONS = void 0;
exports.performGeoAudit = performGeoAudit;
exports.compareGeoResults = compareGeoResults;
/**
* Pre-defined geographic locations for testing
*/
exports.COMMON_LOCATIONS = {
'germany-berlin': {
name: 'Germany (Berlin)',
locale: 'de-DE',
timezone: 'Europe/Berlin',
latitude: 52.52,
longitude: 13.405,
acceptLanguage: 'de-DE,de;q=0.9,en;q=0.8'
},
'usa-newyork': {
name: 'USA (New York)',
locale: 'en-US',
timezone: 'America/New_York',
latitude: 40.7128,
longitude: -74.006,
acceptLanguage: 'en-US,en;q=0.9'
},
'uk-london': {
name: 'UK (London)',
locale: 'en-GB',
timezone: 'Europe/London',
latitude: 51.5074,
longitude: -0.1278,
acceptLanguage: 'en-GB,en;q=0.9'
},
'france-paris': {
name: 'France (Paris)',
locale: 'fr-FR',
timezone: 'Europe/Paris',
latitude: 48.8566,
longitude: 2.3522,
acceptLanguage: 'fr-FR,fr;q=0.9,en;q=0.8'
},
'japan-tokyo': {
name: 'Japan (Tokyo)',
locale: 'ja-JP',
timezone: 'Asia/Tokyo',
latitude: 35.6762,
longitude: 139.6503,
acceptLanguage: 'ja-JP,ja;q=0.9,en;q=0.8'
},
'australia-sydney': {
name: 'Australia (Sydney)',
locale: 'en-AU',
timezone: 'Australia/Sydney',
latitude: -33.8688,
longitude: 151.2093,
acceptLanguage: 'en-AU,en;q=0.9'
}
};
/**
* Perform geo-located audit
*/
async function performGeoAudit(browser, options) {
const results = [];
for (const location of options.locations) {
const result = await auditFromLocation(browser, options.url, location, options);
results.push(result);
}
return results;
}
/**
* Audit from a specific geographic location
*/
async function auditFromLocation(browser, url, location, options) {
const context = await browser.newContext({
locale: location.locale,
timezoneId: location.timezone,
geolocation: {
latitude: location.latitude,
longitude: location.longitude
},
permissions: ['geolocation'],
viewport: options.viewport || { width: 1920, height: 1080 },
extraHTTPHeaders: location.acceptLanguage ? {
'Accept-Language': location.acceptLanguage
} : undefined
});
const page = await context.newPage();
const startTime = Date.now();
try {
// Navigate to URL
await page.goto(url, {
timeout: options.timeout || 30000,
waitUntil: 'load'
});
// Collect performance metrics
const performance = await collectPerformanceMetrics(page, startTime);
// Analyze content variations
const content = await analyzeContent(page);
// Basic accessibility check
const accessibility = await checkAccessibility(page);
// SEO geo-targeting check
const seo = await checkGeoSEO(page);
await context.close();
return {
location,
url,
timestamp: new Date().toISOString(),
performance,
content,
accessibility,
seo
};
}
catch (error) {
await context.close();
throw new Error(`Geo-audit failed for ${location.name}: ${error}`);
}
}
/**
* Collect performance metrics
*/
async function collectPerformanceMetrics(page, startTime) {
const loadTime = Date.now() - startTime;
try {
const metrics = await page.evaluate(() => {
const perfData = performance.getEntriesByType('navigation')[0];
const paintData = performance.getEntriesByType('paint');
return {
firstContentfulPaint: paintData.find(p => p.name === 'first-contentful-paint')?.startTime,
largestContentfulPaint: 0, // Would need observer
timeToInteractive: perfData?.domInteractive || 0
};
});
return {
loadTime,
...metrics
};
}
catch {
return { loadTime };
}
}
/**
* Analyze content variations by location
*/
async function analyzeContent(page) {
try {
const content = await page.evaluate(() => {
const html = document.documentElement.lang;
const currency = document.body.textContent?.match(/[$€£¥]/)?.[0];
return {
language: html || document.querySelector('html')?.getAttribute('lang') || undefined,
currency,
pricing: document.body.textContent?.match(/\d+[.,]\d{2}\s*[$€£¥]/)?.[0]
};
});
return content;
}
catch {
return {};
}
}
/**
* Basic accessibility check
*/
async function checkAccessibility(page) {
try {
const issues = await page.evaluate(() => {
const errors = [];
const warnings = [];
// Check for missing alt text
const imagesWithoutAlt = document.querySelectorAll('img:not([alt])').length;
if (imagesWithoutAlt > 0) {
warnings.push(`${imagesWithoutAlt} images without alt text`);
}
// Check for language attribute
if (!document.documentElement.lang) {
errors.push('Missing language attribute on html element');
}
return { errors: errors.length, warnings: warnings.length };
});
return issues;
}
catch {
return { errors: 0, warnings: 0 };
}
}
/**
* Check SEO geo-targeting
*/
async function checkGeoSEO(page) {
try {
const seo = await page.evaluate(() => {
const hreflang = Array.from(document.querySelectorAll('link[hreflang]'))
.map(link => link.getAttribute('hreflang'))
.filter(Boolean);
const hasLocalizedMeta = !!document.querySelector('meta[name="geo.region"]') ||
!!document.querySelector('meta[name="geo.placename"]');
const geoTargeting = document.querySelector('meta[name="geo.region"]')?.getAttribute('content') || undefined;
return {
hreflang: hreflang.length > 0 ? hreflang : undefined,
localizedMeta: hasLocalizedMeta,
geoTargeting
};
});
return seo;
}
catch {
return {};
}
}
/**
* Compare results across locations
*/
function compareGeoResults(results) {
if (results.length < 2) {
return {
performanceVariance: 0,
contentDifferences: [],
recommendations: []
};
}
// Calculate performance variance
const loadTimes = results.map(r => r.performance.loadTime);
const avgLoadTime = loadTimes.reduce((a, b) => a + b, 0) / loadTimes.length;
const variance = Math.max(...loadTimes) - Math.min(...loadTimes);
const performanceVariance = (variance / avgLoadTime) * 100;
// Find content differences
const languages = new Set(results.map(r => r.content.language).filter(Boolean));
const currencies = new Set(results.map(r => r.content.currency).filter(Boolean));
const contentDifferences = [];
if (languages.size > 1) {
contentDifferences.push(`Multiple languages detected: ${Array.from(languages).join(', ')}`);
}
if (currencies.size > 1) {
contentDifferences.push(`Multiple currencies detected: ${Array.from(currencies).join(', ')}`);
}
// Generate recommendations
const recommendations = [];
if (performanceVariance > 50) {
recommendations.push('Consider using a CDN to reduce geographic performance variance');
}
const hasHreflang = results.some(r => r.seo.hreflang && r.seo.hreflang.length > 0);
if (languages.size > 1 && !hasHreflang) {
recommendations.push('Add hreflang tags for multi-language support');
}
const hasGeoTargeting = results.some(r => r.seo.geoTargeting);
if (!hasGeoTargeting && results.length > 1) {
recommendations.push('Consider adding geo-targeting meta tags for regional content');
}
return {
performanceVariance,
contentDifferences,
recommendations
};
}
//# sourceMappingURL=geo-audit.js.map