-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLighthouseRunnerWithReporting.mjs
More file actions
164 lines (148 loc) · 6.17 KB
/
Copy pathLighthouseRunnerWithReporting.mjs
File metadata and controls
164 lines (148 loc) · 6.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import { launch } from 'chrome-launcher';
import fs from 'fs';
import csv from 'csv-parser';
import { createObjectCsvWriter } from 'csv-writer';
import fetch from 'node-fetch';
import puppeteer from 'puppeteer';
import lighthouse from 'lighthouse';
import path from 'path';
const config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
const inputCsv = 'Crawler.csv';
const outputCsv = 'LighthouseResults.csv';
const urls = [];
const reportDir = 'lighthouse-reports';
// Ensure the reports directory exists
if (!fs.existsSync(reportDir)) {
fs.mkdirSync(reportDir);
}
// Read URLs from the input CSV
fs.createReadStream(inputCsv)
.pipe(csv())
.on('data', (row) => {
if (row.URL) {
urls.push(row.URL);
}
})
.on('end', async () => {
console.log('CSV file successfully processed');
let cookies = '';
if (config.authType === 'page') {
cookies = await pageAuth();
}
const results = [];
for (const url of urls) {
try {
const { scores, reportPath } = await runLighthouseWithAuth(url, cookies);
const fullReportPath = path.resolve(reportPath);
results.push({ Timestamp: new Date().toISOString(), URL: `=HYPERLINK("${url}", "${url}")`, ...scores, Report: `=HYPERLINK("${fullReportPath}", "${fullReportPath}")` });
console.log(`Processed URL: ${url}, Scores: ${JSON.stringify(scores)}, Report: ${fullReportPath}`);
} catch (error) {
console.error(`Error processing URL: ${url}, Error: ${error.message}`);
results.push({ Timestamp: new Date().toISOString(), URL: `=HYPERLINK("${url}", "${url}")`, Performance: 'Error', Accessibility: 'Error', BestPractices: 'Error', SEO: 'Error', Report: 'Error' });
}
}
// Write results to the output CSV
const csvWriter = createObjectCsvWriter({
path: outputCsv,
header: [
{ id: 'Timestamp', title: 'Timestamp' },
{ id: 'URL', title: 'URL' },
{ id: 'Performance', title: 'Performance' },
{ id: 'Accessibility', title: 'Accessibility' },
{ id: 'BestPractices', title: 'Best Practices' },
{ id: 'SEO', title: 'SEO' },
{ id: 'Report', title: 'Report' },
],
});
await csvWriter.writeRecords(results);
console.log('Results written to CSV file');
});
// Function to run Lighthouse with authentication
async function runLighthouseWithAuth(url, cookies = '') {
if (config.authType === 'basic') {
await basicAuth(url);
} else if (config.authType === 'digest') {
await digestAuth(url);
}
return await runLighthouse(url, cookies);
}
// Function for Basic Authentication
async function basicAuth(url) {
const base64Credentials = Buffer.from(`${config.basicAuth.username}:${config.basicAuth.password}`).toString('base64');
const response = await fetch(url, { headers: { 'Authorization': `Basic ${base64Credentials}` } });
if (!response.ok) {
throw new Error('Basic Authentication failed');
}
}
// Function for Digest Authentication
async function digestAuth(url) {
// Implement digest authentication if needed
// Placeholder for digest authentication logic
throw new Error('Digest Authentication not implemented');
}
// Function for Page Login Authentication
async function pageAuth() {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
try {
console.log('Navigating to login page...');
await page.goto(config.pageAuth.loginUrl, { waitUntil: 'networkidle2', timeout: 90000 });
console.log('Waiting for username field...');
await page.waitForSelector(config.pageAuth.usernameField, { timeout: 30000 });
await page.type(config.pageAuth.usernameField, config.pageAuth.username);
console.log('Entered username');
console.log('Waiting for password field...');
await page.waitForSelector(config.pageAuth.passwordField, { timeout: 30000 });
await page.type(config.pageAuth.passwordField, config.pageAuth.password);
console.log('Entered password');
console.log('Waiting for submit button...');
await page.waitForSelector(config.pageAuth.submitField, { timeout: 30000 });
await page.click(config.pageAuth.submitField);
console.log('Submitted login form');
console.log('Waiting for navigation after login...');
await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 90000 });
console.log('Login successful, waiting for navigation');
const cookies = await page.cookies();
const cookieString = cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('; ');
await page.close();
await browser.close();
return cookieString;
} catch (error) {
console.error(`Page login failed: ${error.message}`);
await browser.close();
throw error;
}
}
// Function to run Lighthouse and get the performance score
async function runLighthouse(url, cookies = '') {
console.log(`Running Lighthouse for URL: ${url}`);
const chrome = await launch({ chromeFlags: ['--headless'] });
const { port } = chrome;
const options = {
logLevel: 'info',
output: 'html', // Change to 'html' to get the HTML report
onlyCategories: ['performance', 'accessibility', 'best-practices', 'seo'],
port,
extraHeaders: cookies ? { 'Cookie': cookies } : undefined
};
let runnerResult;
try {
runnerResult = await lighthouse(url, options);
} catch (error) {
console.error(`Lighthouse error for URL: ${url}, Error: ${error.message}`);
await chrome.kill();
throw error;
}
const reportHtml = runnerResult.report;
const reportPath = path.join(reportDir, `${new Date().toISOString().replace(/:/g, '-')}_${encodeURIComponent(url.replace(/https?:\/\//, '')).replace(/[\/\\?%*:|"<>]/g, '-')}.html`);
fs.writeFileSync(reportPath, reportHtml);
const { performance, accessibility, 'best-practices': bestPractices, seo } = runnerResult.lhr.categories;
const scores = {
Performance: performance.score * 100,
Accessibility: accessibility.score * 100,
BestPractices: bestPractices.score * 100,
SEO: seo.score * 100,
};
await chrome.kill();
return { scores, reportPath };
}