UNPKG

@pierrad/web-carbon-analyzer

Version:

A tool to measure the carbon footprint of websites using CO2.js

190 lines 8.01 kB
"use strict"; 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