test script added and gitignore.csv file

This commit is contained in:
Alaguraj0361 2025-11-11 12:16:20 +05:30
parent 26a463e60a
commit 15f483c999
4 changed files with 451 additions and 2 deletions

2
.gitignore vendored
View File

@ -79,6 +79,8 @@ web_modules/
.env.production.local .env.production.local
.env.local .env.local
.csv
# parcel-bundler cache (https://parceljs.org/) # parcel-bundler cache (https://parceljs.org/)
.cache .cache
.parcel-cache .parcel-cache

186
package-lock.json generated
View File

@ -18,9 +18,11 @@
"react-image-lightbox": "^5.1.4", "react-image-lightbox": "^5.1.4",
"react-modal-video": "^2.0.1", "react-modal-video": "^2.0.1",
"sass": "^1.66.1", "sass": "^1.66.1",
"selenium-webdriver": "^4.38.0",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"swiper": "^10.2.0", "swiper": "^10.2.0",
"wowjs": "^1.1.3" "wowjs": "^1.1.3",
"xml2js": "^0.6.2"
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
@ -32,6 +34,12 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@bazel/runfiles": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@bazel/runfiles/-/runfiles-6.5.0.tgz",
"integrity": "sha512-RzahvqTkfpY2jsDxo8YItPX+/iZ6hbiikw1YhE0bA9EKBR5Og8Pa6FHn9PO9M0zaXRVsr0GFQLKbB/0rzy9SzA==",
"license": "Apache-2.0"
},
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "13.4.19", "version": "13.4.19",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.19.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.19.tgz",
@ -632,6 +640,12 @@
"url": "https://opencollective.com/core-js" "url": "https://opencollective.com/core-js"
} }
}, },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@ -936,12 +950,24 @@
"react-is": "^16.7.0" "react-is": "^16.7.0"
} }
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/immutable": { "node_modules/immutable": {
"version": "5.1.3", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
"integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-extglob": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -975,6 +1001,12 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/isotope-layout": { "node_modules/isotope-layout": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/isotope-layout/-/isotope-layout-3.0.6.tgz", "resolved": "https://registry.npmjs.org/isotope-layout/-/isotope-layout-3.0.6.tgz",
@ -994,6 +1026,27 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/jszip": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
"license": "(MIT OR GPL-3.0-or-later)",
"dependencies": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"setimmediate": "^1.0.5"
}
},
"node_modules/lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/loose-envify": { "node_modules/loose-envify": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -1152,6 +1205,12 @@
"get-size": "^2.0.2" "get-size": "^2.0.2"
} }
}, },
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"license": "(MIT AND Zlib)"
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -1195,6 +1254,12 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@ -1349,6 +1414,21 @@
"react-dom": ">=16.6.0" "react-dom": ">=16.6.0"
} }
}, },
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
@ -1362,6 +1442,12 @@
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/sass": { "node_modules/sass": {
"version": "1.89.2", "version": "1.89.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz",
@ -1397,6 +1483,37 @@
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
} }
}, },
"node_modules/selenium-webdriver": {
"version": "4.38.0",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.38.0.tgz",
"integrity": "sha512-5/UXXFSQmn7FGQkbcpAqvfhzflUdMWtT7QqpEgkFD6Q6rDucxB5EUfzgjmr6JbUj30QodcW3mDXehzoeS/Vy5w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/SeleniumHQ"
},
{
"type": "opencollective",
"url": "https://opencollective.com/selenium"
}
],
"license": "Apache-2.0",
"dependencies": {
"@bazel/runfiles": "^6.3.1",
"jszip": "^3.10.1",
"tmp": "^0.2.5",
"ws": "^8.18.3"
},
"engines": {
"node": ">= 20.0.0"
}
},
"node_modules/setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
"license": "MIT"
},
"node_modules/sitemap": { "node_modules/sitemap": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.0.tgz", "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.0.tgz",
@ -1433,6 +1550,15 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/styled-jsx": { "node_modules/styled-jsx": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
@ -1484,6 +1610,15 @@
"node": ">= 4.7.0" "node": ">= 4.7.0"
} }
}, },
"node_modules/tmp": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
"license": "MIT",
"engines": {
"node": ">=14.14"
}
},
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -1503,6 +1638,12 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/warning": { "node_modules/warning": {
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
@ -1533,6 +1674,49 @@
"animate.css": "latest" "animate.css": "latest"
} }
}, },
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"license": "MIT",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"license": "MIT",
"engines": {
"node": ">=4.0"
}
},
"node_modules/zod": { "node_modules/zod": {
"version": "3.21.4", "version": "3.21.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",

View File

@ -21,8 +21,10 @@
"react-image-lightbox": "^5.1.4", "react-image-lightbox": "^5.1.4",
"react-modal-video": "^2.0.1", "react-modal-video": "^2.0.1",
"sass": "^1.66.1", "sass": "^1.66.1",
"selenium-webdriver": "^4.38.0",
"sitemap": "^8.0.0", "sitemap": "^8.0.0",
"swiper": "^10.2.0", "swiper": "^10.2.0",
"wowjs": "^1.1.3" "wowjs": "^1.1.3",
"xml2js": "^0.6.2"
} }
} }

View File

@ -0,0 +1,261 @@
// 🚀 Full SEO + Broken Link + 404 + Accessibility + Image Alt CSV Export
// Run with: node seo_full_audit.js
const { Builder, By } = require("selenium-webdriver");
const chrome = require("selenium-webdriver/chrome");
const axios = require("axios");
const xml2js = require("xml2js");
const fs = require("fs");
const path = require("path");
// CSV file for Image Alt issues
const csvPath = path.join(__dirname, "image_alt_issues.csv");
fs.writeFileSync(csvPath, "Page URL,Image Src,Alt Text,Issue Type\n", "utf8");
// ==========================
// 1⃣ Fetch URLs from sitemap.xml
// ==========================
async function getUrlsFromSitemap(sitemapUrl) {
try {
const res = await axios.get(sitemapUrl);
const parsed = await xml2js.parseStringPromise(res.data);
return parsed.urlset.url.map((u) => u.loc[0]);
} catch (err) {
console.error("❌ Failed to load sitemap:", err.message);
return [];
}
}
// ==========================
// 2⃣ Check HTTP Status
// ==========================
async function checkLinkStatus(url) {
try {
const res = await axios.get(url, {
timeout: 10000,
validateStatus: () => true,
});
if (res.status === 200 && res.data.toLowerCase().includes("page not found")) {
return "Soft 404";
}
return res.status;
} catch (err) {
return err.response ? err.response.status : "❌ No Response";
}
}
// ==========================
// 3⃣ Main SEO + Accessibility + Image Alt Audit
// ==========================
async function checkSEO(url, siteDomain) {
const options = new chrome.Options();
options.addArguments("--headless", "--no-sandbox", "--disable-gpu");
const driver = await new Builder()
.forBrowser("chrome")
.setChromeOptions(options)
.build();
try {
const pageStatus = await checkLinkStatus(url);
if (pageStatus === 404 || pageStatus === "Soft 404") {
console.log(`\n🚫 ${url} → ❌ Page not found (${pageStatus})`);
return;
}
await driver.get(url);
const pageSource = await driver.getPageSource();
// Basic SEO Elements
const title = await driver.getTitle();
const descElem = await driver.findElements(By.css('meta[name="description"]'));
const canonicalElem = await driver.findElements(By.css('link[rel="canonical"]'));
const robotsElem = await driver.findElements(By.css('meta[name="robots"]'));
const viewportElem = await driver.findElements(By.css('meta[name="viewport"]'));
const charset = await driver.findElements(By.css('meta[charset]'));
const htmlTag = await driver.findElement(By.css("html"));
const langAttr = await htmlTag.getAttribute("lang").catch(() => "");
const h1Tags = await driver.findElements(By.css("h1"));
const h2Tags = await driver.findElements(By.css("h2"));
// Meta Description
let descContent = descElem.length > 0 ? await descElem[0].getAttribute("content") : "";
const descLength = descContent.length;
const descStatus =
descLength === 0
? "❌ Missing"
: descLength < 50
? `⚠️ Too short (${descLength})`
: descLength > 160
? `⚠️ Too long (${descLength})`
: "✅ Perfect";
// Title length check
const titleLength = title.length;
const titleStatus =
titleLength === 0
? "❌ Missing"
: titleLength < 30
? `⚠️ Too short (${titleLength})`
: titleLength > 65
? `⚠️ Too long (${titleLength})`
: "✅ Perfect";
// Canonical
const canonicalURL =
canonicalElem.length > 0 ? await canonicalElem[0].getAttribute("href") : "❌ Missing";
// 🖼️ Image Accessibility Audit
const imgs = await driver.findElements(By.css("img"));
let missingAlt = 0;
let emptyAlt = 0;
let duplicateAlt = [];
const altTextMap = new Map();
for (const img of imgs) {
const src = await img.getAttribute("src");
const alt = (await img.getAttribute("alt"))?.trim() ?? null;
if (alt === null) {
missingAlt++;
fs.appendFileSync(csvPath, `"${url}","${src}","","Missing Alt"\n`, "utf8");
continue;
}
if (alt === "") {
emptyAlt++;
fs.appendFileSync(csvPath, `"${url}","${src}","(empty)","Empty Alt"\n`, "utf8");
}
if (altTextMap.has(alt)) {
altTextMap.set(alt, altTextMap.get(alt) + 1);
} else {
altTextMap.set(alt, 1);
}
}
for (const [altText, count] of altTextMap.entries()) {
if (altText && count > 1) {
duplicateAlt.push({ altText, count });
fs.appendFileSync(
csvPath,
`"${url}","","${altText}","Duplicate Alt (${count} times)"\n`,
"utf8"
);
}
}
// Detect tracking & schema tags
const hasGTM = pageSource.includes("googletagmanager.com/gtm.js");
const hasClarity = pageSource.includes("clarity.ms/tag");
const hasFBPixel = pageSource.includes("fbevents.js") || pageSource.includes("fbq(");
const hasAnalytics = pageSource.includes("www.googletagmanager.com/gtag/js");
const ogTags = await driver.findElements(By.css("meta[property^='og:']"));
const twitterTags = await driver.findElements(By.css("meta[name^='twitter:']"));
const schemaScripts = await driver.findElements(By.css('script[type="application/ld+json"]'));
// Links check
const anchorTags = await driver.findElements(By.css("a[href]"));
const brokenLinks = [];
for (const a of anchorTags) {
const href = await a.getAttribute("href");
if (!href || href.startsWith("#") || href.startsWith("mailto:")) continue;
const fullUrl = href.startsWith("http")
? href
: `${siteDomain}${href.startsWith("/") ? href : `/${href}`}`;
if (fullUrl.includes(siteDomain)) {
const status = await checkLinkStatus(fullUrl);
if (status === 404 || status === "Soft 404" || status === "❌ No Response") {
brokenLinks.push({ link: fullUrl, status });
}
}
}
// Lazy loading check
const images = await driver.findElements(By.css("img, video, iframe"));
const lazyLoadCount = await Promise.all(
images.map(async (img) => {
const loading = await img.getAttribute("loading");
return loading === "lazy";
})
);
const lazyLoaded = lazyLoadCount.filter((v) => v).length;
// Console Summary
console.log(`\n🔍 Checking: ${url}`);
console.log("-------------------------------------------");
console.log("Title:", titleStatus);
console.log("Meta Description:", descStatus);
console.log("Canonical URL:", canonicalURL);
console.log("Meta Robots:", robotsElem.length > 0 ? "✅ Found" : "⚠️ Missing");
console.log("Viewport:", viewportElem.length > 0 ? "✅ Found" : "⚠️ Missing");
console.log("Charset:", charset.length > 0 ? "✅ Found" : "❌ Missing");
console.log("HTML lang:", langAttr ? `${langAttr}` : "⚠️ Missing");
console.log("H1 Tags:", h1Tags.length > 0 ? `${h1Tags.length}` : "❌ Missing");
console.log("H2 Tags:", h2Tags.length > 0 ? ` ${h2Tags.length}` : "⚠️ None");
console.log("Images:", imgs.length);
console.log(
"Missing Alt:",
missingAlt > 0 ? `${missingAlt}` : "✅ None"
);
console.log(
"Empty Alt:",
emptyAlt > 0 ? `⚠️ ${emptyAlt}` : "✅ None"
);
console.log(
"Duplicate Alt:",
duplicateAlt.length > 0 ? `⚠️ ${duplicateAlt.length}` : "✅ None"
);
console.log("Lazy Loaded Images:", lazyLoaded > 0 ? `${lazyLoaded}` : "⚠️ None");
console.log("Open Graph Tags:", ogTags.length > 0 ? "✅ Found" : "⚠️ Missing");
console.log("Twitter Tags:", twitterTags.length > 0 ? "✅ Found" : "⚠️ Missing");
console.log("Schema Markup:", schemaScripts.length > 0 ? "✅ Found" : "⚠️ Missing");
console.log("Google Analytics:", hasAnalytics ? "✅ Found" : "⚠️ Missing");
console.log("GTM:", hasGTM ? "✅ Found" : "⚠️ Missing");
console.log("Clarity:", hasClarity ? "✅ Found" : "⚠️ Missing");
console.log("Facebook Pixel:", hasFBPixel ? "✅ Found" : "⚠️ Missing");
if (brokenLinks.length > 0) {
console.log("\n❌ Broken Links:");
brokenLinks.forEach((b) => console.log(`${b.link} [${b.status}]`));
} else {
console.log("✅ No broken links found.");
}
} catch (err) {
console.error(`❌ Error on ${url}:`, err.message);
} finally {
await driver.quit();
}
}
// ==========================
// 4⃣ Run Full Site Audit
// ==========================
(async () => {
const sitemapUrl = "http://localhost:3000/sitemap.xml"; // your sitemap
const siteDomain = "https://sixty5street.com"; // your domain
console.log("📄 Fetching URLs from sitemap...");
const urls = await getUrlsFromSitemap(sitemapUrl);
if (urls.length === 0) {
console.error("❌ No URLs found in sitemap.");
return;
}
console.log(`✅ Found ${urls.length} URLs in sitemap.`);
console.log("🚀 Starting Full SEO + Accessibility + Broken Link Audit...");
for (const url of urls) {
await checkSEO(url, siteDomain);
}
console.log("\n✅ Full SEO Audit Completed!");
console.log(`📁 CSV Report: ${csvPath}`);
})();