/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import assert from 'node:assert'; import {readFile, rm} from 'node:fs/promises'; import {tmpdir} from 'node:os'; import {join} from 'node:path'; import {describe, it} from 'node:test'; import type {InsightName} from '../src/trace-processing/parse.js'; import { parseRawTraceBuffer, traceResultIsSuccess, } from '../src/trace-processing/parse.js'; import {serverHooks} from './server.js'; import {loadTraceAsBuffer} from './trace-processing/fixtures/load.js'; import { getImageContent, getMockAggregatedIssue, getMockRequest, getMockResponse, getTextContent, html, stabilizeResponseOutput, stabilizeStructuredContent, withMcpContext, } from './utils.js'; describe('McpResponse', () => { it('list pages', async t => { await withMcpContext(async (response, context) => { response.setIncludePages(true); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('allows response text lines to be added', async t => { await withMcpContext(async (response, context) => { response.appendResponseLine('Testing 1'); response.appendResponseLine('Testing 2'); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('does not include anything in response if snapshot is null', async t => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); page.accessibility.snapshot = async () => null; const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); assert.deepStrictEqual(getTextContent(content[0]), `# test response`); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('returns correctly formatted snapshot for a simple tree', async t => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); await page.setContent( html` `, ); await page.focus('button'); response.includeSnapshot(); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('returns values for textboxes', async t => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); await page.setContent( html``, ); await page.focus('input'); response.includeSnapshot(); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('returns verbose snapshot and structured content', async t => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); await page.setContent(html``); response.includeSnapshot({ verbose: true, }); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.(JSON.stringify(structuredContent, null, 2)); }); }); it('saves snapshot to file and returns structured content', async t => { const filePath = join(tmpdir(), 'test-screenshot.png'); try { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); await page.setContent(html``); response.includeSnapshot({ verbose: true, filePath, }); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.( stabilizeResponseOutput(getTextContent(content[0])), ); t.assert.snapshot?.( JSON.stringify( stabilizeStructuredContent(structuredContent), null, 2, ), ); }); const content = await readFile(filePath, 'utf-8'); t.assert.snapshot?.(stabilizeResponseOutput(content)); } finally { await rm(filePath, {force: true}); } }); it('preserves mapping ids across multiple snapshots', async () => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); await page.setContent(html`
Span 1
`); response.includeSnapshot(); // First snapshot const res1 = await response.handle('test', context); const text1 = getTextContent(res1.content[0]); const btn1IdMatch = text1.match(/uid=(\S+) .*Button 1/); const span1IdMatch = text1.match(/uid=(\S+) .*Span 1/); assert.ok(btn1IdMatch, 'Button 1 ID not found in first snapshot'); assert.ok(span1IdMatch, 'Span 1 ID not found in first snapshot'); const btn1Id = btn1IdMatch[1]; const span1Id = span1IdMatch[1]; // Modify page: add a new element before the others to potentially shift indices if not stable await page.evaluate(() => { const newBtn = document.createElement('button'); newBtn.textContent = 'Button 2'; document.body.prepend(newBtn); }); // Second snapshot const res2 = await response.handle('test', context); const text2 = getTextContent(res2.content[0]); const btn1IdMatch2 = text2.match(/uid=(\S+) .*Button 1/); const span1IdMatch2 = text2.match(/uid=(\S+) .*Span 1/); const btn2IdMatch = text2.match(/uid=(\S+) .*Button 2/); assert.ok(btn1IdMatch2, 'Button 1 ID not found in second snapshot'); assert.ok(span1IdMatch2, 'Span 1 ID not found in second snapshot'); assert.ok(btn2IdMatch, 'Button 2 ID not found in second snapshot'); assert.strictEqual( btn1IdMatch2[1], btn1Id, 'Button 1 ID changed between snapshots', ); assert.strictEqual( span1IdMatch2[1], span1Id, 'Span 1 ID changed between snapshots', ); assert.notStrictEqual( btn2IdMatch[1], btn1Id, 'Button 2 ID collides with Button 1', ); assert.notStrictEqual( btn2IdMatch[1], btn1Id, 'Button 2 ID collides with Button 1', ); }); }); describe('navigation', () => { const server = serverHooks(); it('resets ids after navigation', async () => { await withMcpContext(async (response, context) => { server.addHtmlRoute( '/page.html', html`
`, ); const page = context.getSelectedPage(); await page.goto(server.getRoute('/page.html')); response.includeSnapshot(); const res1 = await response.handle('test', context); const text1 = getTextContent(res1.content[0]); const btn1IdMatch = text1.match(/uid=(\S+) .*Button 1/); assert.ok(btn1IdMatch, 'Button 1 ID not found in first snapshot'); const btn1Id = btn1IdMatch[1]; // Navigate to the same page again (or meaningful navigation) await page.goto(server.getRoute('/page.html')); const res2 = await response.handle('test', context); const text2 = getTextContent(res2.content[0]); const btn1IdMatch2 = text2.match(/uid=(\S+) .*Button 1/); assert.ok(btn1IdMatch2, 'Button 1 ID not found in second snapshot'); const btn1Id2 = btn1IdMatch2[1]; assert.notStrictEqual( btn1Id2, btn1Id, 'ID should reset after navigation', ); }); }); }); it('adds throttling setting when it is not null', async t => { await withMcpContext(async (response, context) => { await context.emulate({networkConditions: 'Slow 3G'}); const {content, structuredContent} = await response.handle( 'test', context, ); assert.equal(content[0].type, 'text'); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('does not include throttling setting when it is null', async t => { await withMcpContext(async (response, context) => { const {content, structuredContent} = await response.handle( 'test', context, ); await context.emulate({networkConditions: null}); assert.equal(content[0].type, 'text'); assert.strictEqual(getTextContent(content[0]), `# test response`); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds image when image is attached', async t => { await withMcpContext(async (response, context) => { response.attachImage({data: 'imageBase64', mimeType: 'image/png'}); const {content, structuredContent} = await response.handle( 'test', context, ); assert.strictEqual(getTextContent(content[0]), `# test response`); assert.equal(content[1].type, 'image'); assert.strictEqual(getImageContent(content[1]).data, 'imageBase64'); assert.strictEqual(getImageContent(content[1]).mimeType, 'image/png'); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds cpu throttling setting when it is over 1', async t => { await withMcpContext(async (response, context) => { await context.emulate({cpuThrottlingRate: 4}); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('does not include cpu throttling setting when it is 1', async t => { await withMcpContext(async (response, context) => { await context.emulate({cpuThrottlingRate: 1}); const {content, structuredContent} = await response.handle( 'test', context, ); assert.strictEqual(getTextContent(content[0]), `# test response`); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds viewport emulation setting when it is set', async t => { await withMcpContext(async (response, context) => { await context.emulate({ viewport: {width: 400, height: 400, deviceScaleFactor: 1}, }); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds userAgent emulation setting when it is set', async t => { await withMcpContext(async (response, context) => { await context.emulate({userAgent: 'MyUA'}); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds color scheme emulation setting when it is set', async t => { await withMcpContext(async (response, context) => { await context.emulate({colorScheme: 'dark'}); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds a prompt dialog', async t => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); const dialogPromise = new Promise(resolve => { page.on('dialog', () => { resolve(); }); }); page.evaluate(() => { prompt('message', 'default'); }); await dialogPromise; const {content, structuredContent} = await response.handle( 'test', context, ); await context.getDialog()?.dismiss(); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds an alert dialog', async t => { await withMcpContext(async (response, context) => { const page = context.getSelectedPage(); const dialogPromise = new Promise(resolve => { page.on('dialog', () => { resolve(); }); }); page.evaluate(() => { alert('message'); }); await dialogPromise; const {content, structuredContent} = await response.handle( 'test', context, ); await context.getDialog()?.dismiss(); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('add network requests when setting is true', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true); context.getNetworkRequests = () => { return [getMockRequest({stableId: 1}), getMockRequest({stableId: 2})]; }; const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('does not include network requests when setting is false', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(false); context.getNetworkRequests = () => { return [getMockRequest()]; }; const {content, structuredContent} = await response.handle( 'test', context, ); assert.strictEqual(getTextContent(content[0]), `# test response`); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('add network request when attached with POST data', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true); const httpResponse = getMockResponse(); httpResponse.buffer = () => { return Promise.resolve(Buffer.from(JSON.stringify({response: 'body'}))); }; httpResponse.headers = () => { return { 'Content-Type': 'application/json', }; }; const request = getMockRequest({ method: 'POST', hasPostData: true, postData: JSON.stringify({request: 'body'}), response: httpResponse, }); context.getNetworkRequests = () => { return [request]; }; context.getNetworkRequestById = () => { return request; }; response.attachNetworkRequest(1); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('add network request when attached', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true); const request = getMockRequest(); context.getNetworkRequests = () => { return [request]; }; context.getNetworkRequestById = () => { return request; }; response.attachNetworkRequest(1); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds console messages when the setting is true', async t => { await withMcpContext(async (response, context) => { response.setIncludeConsoleData(true); const page = context.getSelectedPage(); const consoleMessagePromise = new Promise(resolve => { page.on('console', () => { resolve(); }); }); page.evaluate(() => { console.log('Hello from the test'); }); await consoleMessagePromise; const {content, structuredContent} = await response.handle( 'test', context, ); assert.ok(getTextContent(content[0])); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('adds a message when no console messages exist', async t => { await withMcpContext(async (response, context) => { response.setIncludeConsoleData(true); const {content, structuredContent} = await response.handle( 'test', context, ); assert.ok(getTextContent(content[0])); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it("doesn't list the issue message if mapping returns null", async t => { await withMcpContext(async (response, context) => { const mockAggregatedIssue = getMockAggregatedIssue(); const mockDescription = { file: 'not-existing-description-file.md', links: [], }; mockAggregatedIssue.getDescription.returns(mockDescription); response.setIncludeConsoleData(true); context.getConsoleData = () => { return [mockAggregatedIssue]; }; const {content, structuredContent} = await response.handle( 'test', context, ); const text = getTextContent(content[0]); assert.ok(text.includes('')); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('throws error if mapping returns null on get issue details', async () => { await withMcpContext(async (response, context) => { const mockAggregatedIssue = getMockAggregatedIssue(); const mockDescription = { file: 'not-existing-description-file.md', links: [], }; mockAggregatedIssue.getDescription.returns(mockDescription); response.attachConsoleMessage(1); context.getConsoleMessageById = () => { return mockAggregatedIssue; }; try { await response.handle('test', context); } catch (e) { assert.ok(e.message.includes("Can't provide detals for the msgid 1")); } }); }); }); describe('McpResponse network request filtering', () => { it('filters network requests by resource type', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true, { resourceTypes: ['script', 'stylesheet'], }); context.getNetworkRequests = () => { return [ getMockRequest({resourceType: 'script'}), getMockRequest({resourceType: 'image'}), getMockRequest({resourceType: 'stylesheet'}), getMockRequest({resourceType: 'document'}), ]; }; const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('filters network requests by single resource type', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true, { resourceTypes: ['image'], }); context.getNetworkRequests = () => { return [ getMockRequest({resourceType: 'script'}), getMockRequest({resourceType: 'image'}), getMockRequest({resourceType: 'stylesheet'}), ]; }; const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('shows no requests when filter matches nothing', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true, { resourceTypes: ['font'], }); context.getNetworkRequests = () => { return [ getMockRequest({resourceType: 'script'}), getMockRequest({resourceType: 'image'}), getMockRequest({resourceType: 'stylesheet'}), ]; }; const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('shows all requests when no filters are provided', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true); context.getNetworkRequests = () => { return [ getMockRequest({resourceType: 'script'}), getMockRequest({resourceType: 'image'}), getMockRequest({resourceType: 'stylesheet'}), getMockRequest({resourceType: 'document'}), getMockRequest({resourceType: 'font'}), ]; }; const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('shows all requests when empty resourceTypes array is provided', async t => { await withMcpContext(async (response, context) => { response.setIncludeNetworkRequests(true, { resourceTypes: [], }); context.getNetworkRequests = () => { return [ getMockRequest({resourceType: 'script'}), getMockRequest({resourceType: 'image'}), getMockRequest({resourceType: 'stylesheet'}), getMockRequest({resourceType: 'document'}), getMockRequest({resourceType: 'font'}), ]; }; const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); }); describe('McpResponse network pagination', () => { it('returns all requests when pagination is not provided', async t => { await withMcpContext(async (response, context) => { const requests = Array.from({length: 5}, () => getMockRequest()); context.getNetworkRequests = () => requests; response.setIncludeNetworkRequests(true); const {content, structuredContent} = await response.handle( 'test', context, ); const text = getTextContent(content[0]); assert.ok(text.includes('Showing 1-5 of 5 (Page 1 of 1).')); assert.ok(!text.includes('Next page:')); assert.ok(!text.includes('Previous page:')); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('returns first page by default', async t => { await withMcpContext(async (response, context) => { const requests = Array.from({length: 30}, (_, idx) => getMockRequest({method: `GET-${idx}`}), ); context.getNetworkRequests = () => { return requests; }; response.setIncludeNetworkRequests(true, {pageSize: 10}); const {content, structuredContent} = await response.handle( 'test', context, ); const text = getTextContent(content[0]); assert.ok(text.includes('Showing 1-10 of 30 (Page 1 of 3).')); assert.ok(text.includes('Next page: 1')); assert.ok(!text.includes('Previous page:')); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('returns subsequent page when pageIdx provided', async t => { await withMcpContext(async (response, context) => { const requests = Array.from({length: 25}, (_, idx) => getMockRequest({method: `GET-${idx}`}), ); context.getNetworkRequests = () => requests; response.setIncludeNetworkRequests(true, { pageSize: 10, pageIdx: 1, }); const {content, structuredContent} = await response.handle( 'test', context, ); const text = getTextContent(content[0]); assert.ok(text.includes('Showing 11-20 of 25 (Page 2 of 3).')); assert.ok(text.includes('Next page: 2')); assert.ok(text.includes('Previous page: 0')); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); it('handles invalid page number by showing first page', async t => { await withMcpContext(async (response, context) => { const requests = Array.from({length: 5}, () => getMockRequest()); context.getNetworkRequests = () => requests; response.setIncludeNetworkRequests(true, { pageSize: 2, pageIdx: 10, // Invalid page number }); const {content, structuredContent} = await response.handle( 'test', context, ); const text = getTextContent(content[0]); assert.ok( text.includes('Invalid page number provided. Showing first page.'), ); assert.ok(text.includes('Showing 1-2 of 5 (Page 1 of 3).')); t.assert.snapshot?.( JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2), ); }); }); describe('trace summaries', () => { it('includes the trace summary text and structured data', async t => { const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz'); const result = await parseRawTraceBuffer(rawData); if (!traceResultIsSuccess(result)) { throw new Error(result.error); } await withMcpContext(async (response, context) => { response.attachTraceSummary(result); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); const typedStructuredContent = structuredContent as { traceSummary?: string; traceInsights?: unknown[]; }; t.assert.snapshot?.( JSON.stringify(typedStructuredContent.traceSummary, null, 2), ); t.assert.snapshot?.( JSON.stringify(typedStructuredContent.traceInsights, null, 2), ); }); }); }); describe('trace insights', () => { it('includes the trace insight output', async t => { const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz'); const result = await parseRawTraceBuffer(rawData); if (!traceResultIsSuccess(result)) { throw new Error(result.error); } await withMcpContext(async (response, context) => { response.attachTraceInsight( result, 'NAVIGATION_0', 'LCPBreakdown' as InsightName, ); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify( stabilizeStructuredContent(structuredContent), null, 2, ), ); }); }); it('includes error if insight not found', async t => { const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz'); const result = await parseRawTraceBuffer(rawData); if (!traceResultIsSuccess(result)) { throw new Error(result.error); } await withMcpContext(async (response, context) => { response.attachTraceInsight( result, 'BAD_ID', 'LCPBreakdown' as InsightName, ); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.( JSON.stringify( stabilizeStructuredContent(structuredContent), null, 2, ), ); }); }); }); }); describe('extensions', () => { it('lists extensions', async t => { await withMcpContext(async (response, context) => { response.setListExtensions(); // Empty state testing const emptyResult = await response.handle('test', context); const emptyText = getTextContent(emptyResult.content[0]); assert.ok( emptyText.includes('No extensions installed.'), 'Should show message for ampty extensions', ); response.resetResponseLineForTesting(); // Testing with extensions context.listExtensions = () => [ { id: 'id1', name: 'Extension 1', version: '1.0', isEnabled: true, path: '/path/to/ext1', }, { id: 'id2', name: 'Extension 2', version: '2.0', isEnabled: false, path: '/path/to/ext2', }, ]; response.setListExtensions(); const {content, structuredContent} = await response.handle( 'test', context, ); t.assert.snapshot?.(getTextContent(content[0])); t.assert.snapshot?.(JSON.stringify(structuredContent, null, 2)); }); }); });