@pierrad/web-carbon-analyzer
Version:
A tool to measure the carbon footprint of websites using CO2.js
190 lines • 8.01 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Browser Controller module
* Manages Playwright browser lifecycle and page navigation
*/
const playwright = __importStar(require("playwright"));
const logger_1 = __importDefault(require("../utils/logger"));
const default_1 = __importDefault(require("../config/default"));
class BrowserController {
constructor(customConfig = {}) {
this.config = { ...default_1.default.browser, ...customConfig };
this.browser = null;
this.context = null;
this.page = null;
}
/**
* Launch the browser and create a new context
*/
async launch() {
try {
logger_1.default.info(`Launching ${this.config.type} browser`);
// Configure browser launch options
const launchOptions = {
headless: this.config.headless
};
// Add remote debugging port if configured (needed for Lighthouse)
if (this.config.remoteDebuggingPort && this.config.type === 'chromium') {
launchOptions.args = [`--remote-debugging-port=${this.config.remoteDebuggingPort}`];
logger_1.default.info(`Configured remote debugging port: ${this.config.remoteDebuggingPort}`);
}
this.browser = await playwright[this.config.type].launch(launchOptions);
// Setup context options
const contextOptions = {
viewport: this.config.viewport,
userAgent: this.config.userAgent
};
// Add HTTP authentication credentials if provided
if (this.config.httpCredentials) {
contextOptions.httpCredentials = {
username: this.config.httpCredentials.username,
password: this.config.httpCredentials.password
};
logger_1.default.info('HTTP authentication credentials applied');
}
this.context = await this.browser.newContext(contextOptions);
this.page = await this.context.newPage();
logger_1.default.info('Browser launched successfully');
return this.page;
}
catch (error) {
logger_1.default.error(`Failed to launch browser: ${error.message}`);
throw error;
}
}
/**
* Navigate to a URL and wait for the page to load
* @param {string} url - The URL to navigate to
*/
async navigateTo(url) {
if (!this.page) {
throw new Error('Browser not launched. Call launch() first.');
}
try {
logger_1.default.info(`Navigating to ${url}`);
const response = await this.page.goto(url, {
timeout: this.config.timeout,
waitUntil: 'domcontentloaded'
});
if (!response) {
throw new Error(`Failed to get response from ${url}`);
}
if (response.status() >= 400) {
throw new Error(`Received HTTP ${response.status()} for ${url}`);
}
// Wait for network to become idle if configured
if (this.config.waitForNetworkIdle) {
logger_1.default.info('Waiting for network idle');
await this.page.waitForLoadState('networkidle', {
timeout: this.config.networkIdleTimeout
});
}
return response;
}
catch (error) {
logger_1.default.error(`Navigation failed: ${error.message}`);
throw error;
}
}
/**
* Simulate user scrolling behavior to trigger lazy loading
* @param {UserBehaviorConfig} userBehaviorConfig - Configuration for scrolling behavior
*/
async simulateUserBehavior(userBehaviorConfig = default_1.default.userBehavior) {
if (!this.page) {
throw new Error('Browser not launched. Call launch() first.');
}
try {
logger_1.default.info('Simulating user scrolling behavior');
const { scrollDepth, scrollDelay, maxScrollTime } = userBehaviorConfig;
const startTime = Date.now();
// Get page height for scrolling calculations
const pageHeight = await this.page.evaluate(() => document.body.scrollHeight);
const viewportHeight = this.config.viewport.height;
const scrollStep = viewportHeight * 0.8; // Scroll 80% of viewport height each time
// Calculate actual scroll steps based on page height and configured depth
const effectiveScrollDepth = Math.min(scrollDepth, Math.ceil(pageHeight / viewportHeight));
logger_1.default.info(`Page height: ${pageHeight}px, performing ${effectiveScrollDepth} scroll steps`);
for (let i = 1; i <= effectiveScrollDepth; i++) {
// Check if we've exceeded the maximum scroll time
if (Date.now() - startTime > maxScrollTime) {
logger_1.default.info(`Reached maximum scroll time (${maxScrollTime}ms), stopping`);
break;
}
// Scroll down
await this.page.evaluate((scrollY) => {
window.scrollTo(0, scrollY);
}, i * scrollStep);
logger_1.default.debug(`Scrolled to position ${i * scrollStep}px`);
// Wait for the specified delay between scrolls
await this.page.waitForTimeout(scrollDelay);
}
// Scroll back to top
await this.page.evaluate(() => {
window.scrollTo(0, 0);
});
logger_1.default.info('User behavior simulation completed');
}
catch (error) {
logger_1.default.error(`User behavior simulation failed: ${error.message}`);
throw error;
}
}
/**
* Close the browser
*/
async close() {
try {
if (this.browser) {
logger_1.default.info('Closing browser');
await this.browser.close();
this.browser = null;
this.context = null;
this.page = null;
}
}
catch (error) {
logger_1.default.error(`Failed to close browser: ${error.message}`);
throw error;
}
}
}
exports.default = BrowserController;
//# sourceMappingURL=browser-controller.js.map