/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import {describe, it} from 'node:test'; import {lighthouseAudit} from '../../src/tools/lighthouse.js'; import {serverHooks} from '../server.js'; import {html, withMcpContext} from '../utils.js'; describe('lighthouse', () => { const server = serverHooks(); describe('lighthouse_audit', () => { it('runs Lighthouse audit by default (navigation, desktop)', async () => { server.addHtmlRoute('/test', html`
Test
`); await withMcpContext(async (response, context) => { const page = context.getSelectedMcpPage().pptrPage; await page.goto(server.getRoute('/test')); await lighthouseAudit.handler( { params: { mode: 'navigation', device: 'desktop', }, page: context.getSelectedMcpPage(), }, response, context, ); const data = response.attachedLighthouseResult; assert.ok(data); assert.ok(data.summary); assert.equal(data.summary.mode, 'navigation'); assert.equal(data.summary.device, 'desktop'); assert.ok(data.reports.length === 2); // json, html // Verify files exist for (const reportPath of data.reports) { const stats = await fs.stat(reportPath); assert.ok(stats.isFile()); } }); }); it('restores emulation', async () => { server.addHtmlRoute('/test-mobile', html`
Test Mobile
`); await withMcpContext(async (response, context) => { const page = context.getSelectedMcpPage().pptrPage; await page.goto(server.getRoute('/test-mobile')); await context.getSelectedMcpPage().emulate({ viewport: { width: 400, height: 400, deviceScaleFactor: 1, hasTouch: true, }, }); { const viewportData = await page.evaluate(() => { return { width: window.innerWidth, height: window.innerHeight, deviceScaleFactor: window.devicePixelRatio, hasTouch: navigator.maxTouchPoints > 0, }; }); assert.deepStrictEqual(viewportData, { width: 400, height: 400, deviceScaleFactor: 1, hasTouch: true, }); } await lighthouseAudit.handler( { params: { mode: 'snapshot', device: 'mobile', }, page: context.getSelectedMcpPage(), }, response, context, ); { const viewportData = await page.evaluate(() => { return { width: window.innerWidth, height: window.innerHeight, deviceScaleFactor: window.devicePixelRatio, hasTouch: navigator.maxTouchPoints > 0, }; }); assert.deepStrictEqual(viewportData, { width: 400, height: 400, deviceScaleFactor: 1, hasTouch: true, }); } }); }); it('runs Lighthouse in snapshot mode with mobile device', async () => { server.addHtmlRoute('/test-mobile', html`
Test Mobile
`); await withMcpContext(async (response, context) => { const page = context.getSelectedMcpPage().pptrPage; await page.goto(server.getRoute('/test-mobile')); await lighthouseAudit.handler( { params: { mode: 'snapshot', device: 'mobile', }, page: context.getSelectedMcpPage(), }, response, context, ); const data = response.attachedLighthouseResult; assert.ok(data); assert.equal(data.summary.mode, 'snapshot'); assert.equal(data.summary.device, 'mobile'); assert.ok(data.reports.length === 2); }); }); it('runs Lighthouse with custom output dir', async () => { server.addHtmlRoute('/test-mobile', html`
Test Mobile
`); const tmpDir = os.tmpdir(); const folderPath = path.join( tmpDir, `temp-folder-${crypto.randomUUID()}`, ); try { await withMcpContext(async (response, context) => { const page = context.getSelectedMcpPage().pptrPage; await page.goto(server.getRoute('/test-mobile')); await lighthouseAudit.handler( { params: { mode: 'snapshot', device: 'mobile', outputDirPath: folderPath, }, page: context.getSelectedMcpPage(), }, response, context, ); const data = response.attachedLighthouseResult; assert.ok(data); assert.equal(data.summary.mode, 'snapshot'); assert.equal(data.summary.device, 'mobile'); assert.ok(data.reports.length === 2); for (const report of data.reports) { assert.ok(report.startsWith(folderPath)); } }); } finally { await fs.rm(folderPath, {recursive: true, force: true}); } }); }); });