@@ -143,7 +143,7 @@ test('should filter network requests by url', async ({ runUITest, server }) => {
143143 await expect ( networkItems . getByText ( 'font.woff2' ) ) . toBeVisible ( ) ;
144144} ) ;
145145
146- test ( 'should format JSON request body' , async ( { runUITest, server } ) => {
146+ test ( 'should pretty-print JSON request body' , async ( { runUITest, server } ) => {
147147 const { page } = await runUITest ( {
148148 'network-tab.test.ts' : `
149149 import { test, expect } from '@playwright/test';
@@ -188,14 +188,14 @@ test('should format JSON request body', async ({ runUITest, server }) => {
188188 '}' ,
189189 ] , { useInnerText : true } ) ;
190190
191- // Untoggle pretty print to see original request body
191+ // Toggle off pretty print to see original request body
192192 await payloadPanel . getByRole ( 'button' , { name : 'Pretty print' , exact : true } ) . click ( ) ;
193193 await expect ( payloadPanel . locator ( '.CodeMirror-code .CodeMirror-line' ) ) . toHaveText ( [
194194 '{"data":{"key":"value","array":["value-1","value-2"]}}'
195195 ] , { useInnerText : true } ) ;
196196} ) ;
197197
198- test ( 'should format XML request body' , async ( { runUITest, server } ) => {
198+ test ( 'should pretty-print XML request body' , async ( { runUITest, server } ) => {
199199 const { page } = await runUITest ( {
200200 'network-tab.test.ts' : `
201201 import { test, expect } from '@playwright/test';
@@ -220,13 +220,69 @@ test('should format XML request body', async ({ runUITest, server }) => {
220220 '</note>'
221221 ] , { useInnerText : true } ) ;
222222
223- // Untoggle pretty print to see original request body
223+ // Toggle off pretty print to see original request body
224224 await payloadPanel . getByRole ( 'button' , { name : 'Pretty print' , exact : true } ) . click ( ) ;
225225 await expect ( payloadPanel . locator ( '.CodeMirror-code .CodeMirror-line' ) ) . toHaveText ( [
226226 '<?xml version="1.0"?><note to="Alice" from="Bob"><body>Hello & welcome!</body></note>'
227227 ] , { useInnerText : true } ) ;
228228} ) ;
229229
230+ test ( 'should pretty-print response bodies and show formatting errors' , async ( { runUITest, server } ) => {
231+ server . setRoute ( '/response-json-good' , ( _ , res ) => res . setHeader ( 'Content-Type' , 'application/json' ) . end ( '{"ok":true,"items":[1,2]}' ) ) ;
232+ server . setRoute ( '/response-json-bad' , ( _ , res ) => res . setHeader ( 'Content-Type' , 'application/json' ) . end ( '{"ok":true,,}' ) ) ;
233+
234+ const { page } = await runUITest ( {
235+ 'network-tab.test.ts' : `
236+ import { test } from '@playwright/test';
237+ test('network response tab', async ({ request }) => {
238+ await Promise.all([
239+ request.get('${ server . PREFIX } /response-json-good'),
240+ request.get('${ server . PREFIX } /response-json-bad'),
241+ ].map(r => r.then(res => res.text())));
242+ });
243+ ` ,
244+ } ) ;
245+
246+ await page . getByText ( 'network response tab' ) . dblclick ( ) ;
247+ await expect ( page . getByTestId ( 'workbench-run-status' ) ) . toContainText ( 'Passed' ) ;
248+ await page . getByRole ( 'tab' , { name : 'Network' } ) . click ( ) ;
249+
250+ const networkList = page . getByRole ( 'list' , { name : 'Network requests' } ) . getByRole ( 'listitem' ) ;
251+ const responsePanel = page . getByRole ( 'tabpanel' , { name : 'Response' } ) ;
252+
253+ // Pretty printed by default
254+ await networkList . filter ( { hasText : 'response-json-good' } ) . click ( ) ;
255+ await page . getByRole ( 'tabpanel' , { name : 'Network' } ) . getByRole ( 'tab' , { name : 'Response' } ) . click ( ) ;
256+ await expect ( responsePanel . locator ( '.CodeMirror-code .CodeMirror-line' ) ) . toHaveText ( [
257+ '{' ,
258+ ' "ok": true,' ,
259+ ' "items": [' ,
260+ ' 1,' ,
261+ ' 2' ,
262+ ' ]' ,
263+ '}' ,
264+ ] , { useInnerText : true } ) ;
265+
266+ // Toggle off to see original body
267+ const prettyPrint = responsePanel . getByRole ( 'button' , { name : 'Pretty print' , exact : true } ) ;
268+ const prettyPrintError = responsePanel . getByTitle ( 'Formatting failed' ) ;
269+ await prettyPrint . click ( ) ;
270+ await expect ( responsePanel . locator ( '.CodeMirror-code .CodeMirror-line' ) ) . toHaveText ( [
271+ '{"ok":true,"items":[1,2]}' ,
272+ ] , { useInnerText : true } ) ;
273+ await expect ( prettyPrintError ) . toBeHidden ( ) ;
274+
275+ // Re-enable pretty print so errors are surfaced
276+ await prettyPrint . click ( ) ;
277+
278+ // Malformed JSON shows badge and preserves original text
279+ await networkList . filter ( { hasText : 'response-json-bad' } ) . click ( ) ;
280+ await expect ( responsePanel . locator ( '.CodeMirror-code .CodeMirror-line' ) ) . toHaveText ( [
281+ '{"ok":true,,}' ,
282+ ] , { useInnerText : true } ) ;
283+ await expect ( prettyPrintError ) . toBeVisible ( ) ;
284+ } ) ;
285+
230286test ( 'should display list of query parameters (only if present)' , async ( { runUITest, server } ) => {
231287 const { page } = await runUITest ( {
232288 'network-tab.test.ts' : `
0 commit comments