/** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import assert from 'node:assert/strict'; import {describe, it} from 'node:test'; import {emulate} from '../src/tools/emulation.js'; import {lighthouseAudit} from '../src/tools/lighthouse.js'; import {navigatePage} from '../src/tools/pages.js'; import {evaluateScript} from '../src/tools/script.js'; import {serverHooks} from './server.js'; import {withMcpContext} from './utils.js'; describe('Network Blocking Integration', () => { const server = serverHooks(); it('blocks URLs in blocklist', async () => { server.addHtmlRoute('/allowed.html', 'Allowed'); server.addHtmlRoute('/blocked.html', 'Blocked'); const blockedUrlPattern = [server.getRoute('/blocked.html')]; await withMcpContext( async (response, context) => { const allowedUrl = server.getRoute('/allowed.html'); await navigatePage().handler( { params: {url: allowedUrl}, page: context.getSelectedMcpPage(), }, response, context, ); assert.strictEqual( response.responseLines[0], `Successfully navigated to ${allowedUrl}.`, ); response.resetResponseLineForTesting(); await evaluateScript().handler( { params: {function: String(() => document.body.textContent)}, }, response, context, ); assert.strictEqual( JSON.parse(response.responseLines.at(2)!), 'Allowed', ); const blockedUrl = server.getRoute('/blocked.html'); response.resetResponseLineForTesting(); await evaluateScript().handler( { params: { function: `async () => { try { await fetch("${blockedUrl}"); return 'SUCCESS'; } catch (err) { return err instanceof Error ? err.message : String(err); } }`, }, }, response, context, ); assert.strictEqual( JSON.parse(response.responseLines.at(2)!), 'Failed to fetch', ); }, { blockedUrlPattern, }, ); }); it('blocks URLs not in allowlist', async () => { server.addHtmlRoute('/allowed.html', 'Allowed'); server.addHtmlRoute('/blocked.html', 'Blocked'); const allowedUrlPattern = [server.getRoute('/allowed.html')]; await withMcpContext( async (response, context) => { const allowedUrl = server.getRoute('/allowed.html'); await navigatePage().handler( { params: {url: allowedUrl}, page: context.getSelectedMcpPage(), }, response, context, ); assert.strictEqual( response.responseLines[0], `Successfully navigated to ${allowedUrl}.`, ); response.resetResponseLineForTesting(); await evaluateScript().handler( { params: {function: String(() => document.body.textContent)}, }, response, context, ); assert.strictEqual( JSON.parse(response.responseLines.at(2)!), 'Allowed', ); const blockedUrl = server.getRoute('/blocked.html'); response.resetResponseLineForTesting(); await evaluateScript().handler( { params: { function: `async () => { try { await fetch("${blockedUrl}"); return 'SUCCESS'; } catch (err) { return err instanceof Error ? err.message : String(err); } }`, }, }, response, context, ); assert.strictEqual( JSON.parse(response.responseLines.at(2)!), 'Failed to fetch', ); }, { allowedUrlPattern, }, ); }); it('respects blocklist after Lighthouse audits', async () => { server.addHtmlRoute('/allowed.html', 'Allowed'); server.addHtmlRoute('/blocked.html', 'Blocked'); const blockedUrlPattern = [server.getRoute('/blocked.html')]; await withMcpContext( async (response, context) => { const allowedUrl = server.getRoute('/allowed.html'); await navigatePage().handler( { params: {url: allowedUrl}, page: context.getSelectedMcpPage(), }, response, context, ); assert.strictEqual( response.responseLines[0], `Successfully navigated to ${allowedUrl}.`, ); const blockedUrl = server.getRoute('/blocked.html'); // Verifies fetch is blocked before Lighthouse audit response.resetResponseLineForTesting(); await evaluateScript().handler( { params: { function: `async () => { try { await fetch("${blockedUrl}"); return 'SUCCESS'; } catch (err) { return err instanceof Error ? err.message : String(err); } }`, }, }, response, context, ); assert.strictEqual( JSON.parse(response.responseLines.at(2)!), 'Failed to fetch', 'Fetch should be blocked before audit', ); await lighthouseAudit.handler( { params: { mode: 'navigation', device: 'desktop', }, page: context.getSelectedMcpPage(), }, response, context, ); assert.equal( response.attachedLighthouseResult?.summary.mode, 'navigation', ); // 2. Verify fetch remains blocked AFTER Lighthouse audit response.resetResponseLineForTesting(); await evaluateScript().handler( { params: { function: `async () => { try { await fetch("${blockedUrl}"); return 'SUCCESS'; } catch (err) { return err instanceof Error ? err.message : String(err); } }`, }, }, response, context, ); assert.strictEqual( JSON.parse(response.responseLines.at(2)!), 'Failed to fetch', 'Fetch should still be blocked after audit', ); }, { blockedUrlPattern, }, ); }); it('throws error when trying to emulate network conditions while blocklist is configured', async () => { const blockedUrlPattern = ['*://*/*']; await withMcpContext( async (response, context) => { // Attempting to emulate network conditions should throw an error. await assert.rejects(async () => { await emulate.handler( { params: { networkConditions: 'Offline', }, page: context.getSelectedMcpPage(), }, response, context, ); }, /Network throttling is not supported when network blocking \(allowlist\/blocklist\) is configured\./); // Attempting to emulate CPU rate or other things should succeed without errors. await emulate.handler( { params: { cpuThrottlingRate: 2, }, page: context.getSelectedMcpPage(), }, response, context, ); assert.strictEqual( response.responseLines[0], 'Emulation configured successfully', ); }, { blockedUrlPattern, }, ); }); });