Skip to content

Commit 085dc41

Browse files
vasharma05-brunoarpit-bruno
authored andcommitted
Return the base64 from response formatter for svg (#48)
1 parent c3c24b2 commit 085dc41

5 files changed

Lines changed: 55 additions & 5 deletions

File tree

packages/bruno-api-docs/e2e/components/playground/response-pane.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export class ResponsePaneComponent extends BaseComponent {
5656
}
5757

5858
readonly previewToggle = this.page.getByRole('switch', { name: 'Toggle preview' });
59+
readonly previewImage = this.page.getByTestId('response-preview-image');
5960

6061
formatOption(format: ResponseBodyFormat): Locator {
6162
return this.page.getByTestId(`response-format-selector-${format}`);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Buffer } from 'buffer';
2+
import { test, expect } from '../../playwright';
3+
4+
// A small SVG whose bytes the sniffer classifies as image/svg+xml. Small SVG bodies are kept as
5+
// selectable text (no base64 copy), so the preview must build the <img> src from that text —
6+
// regression: it used to read the absent base64 buffer and render "base64,undefined".
7+
const SVG_BODY
8+
= '<?xml version="1.0" encoding="UTF-8"?>\n'
9+
+ '<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">'
10+
+ '<rect width="400" height="300" fill="red"/></svg>';
11+
const INLINE_SVG_SRC = `data:image/svg+xml;base64,${Buffer.from(SVG_BODY).toString('base64')}`;
12+
13+
test.describe('response body — SVG preview', () => {
14+
test.use({ viewport: { width: 1280, height: 900 } });
15+
16+
test.beforeEach(async ({ page }) => {
17+
await page.route('**/api/users**', (route) =>
18+
route.fulfill({
19+
status: 200,
20+
headers: { 'content-type': 'image/svg+xml' },
21+
body: SVG_BODY
22+
})
23+
);
24+
});
25+
26+
test('renders the SVG image from its inline markup, not a broken data URL', async ({
27+
page,
28+
playground,
29+
responsePane
30+
}) => {
31+
await page.goto('/#/?pg=1&dock=bottom');
32+
await playground.openSidebarItem('get users');
33+
await responsePane.send();
34+
35+
// An SVG is an image, so the pane defaults to preview and renders an <img>.
36+
await expect(responsePane.previewImage).toBeVisible();
37+
38+
// The src is the SVG markup encoded inline — not the "base64,undefined" the bug produced.
39+
await expect(responsePane.previewImage).toHaveAttribute('src', INLINE_SVG_SRC);
40+
41+
// And the browser actually decoded it: a broken data URL leaves naturalWidth at 0.
42+
await expect
43+
.poll(() =>
44+
responsePane.previewImage.evaluate(
45+
(img: HTMLImageElement) => img.complete && img.naturalWidth > 0
46+
)
47+
)
48+
.toBe(true);
49+
});
50+
});

packages/bruno-api-docs/src/components/Playground/QueryResultPreview/QueryResultPreview.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ const QueryResultPreview: React.FC<QueryResultPreviewProps> = ({
4949
return <HtmlPreview data={data} baseUrl={baseUrl} />;
5050
}
5151
case 'preview-image': {
52-
return <img src={`data:${contentType.split(';')[0].trim()};base64,${dataBuffer}`} />;
52+
const mimeType = contentType.split(';')[0].trim();
53+
return <img data-testid="response-preview-image" src={`data:${mimeType};base64,${dataBuffer}`} />;
5354
}
5455
case 'preview-pdf': {
5556
return (

packages/bruno-api-docs/src/runner/RequestExecutor.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,7 @@ export class RequestExecutor {
258258
// aren't round-trippable). A small plain-text/SVG string body carries its own bytes, so skip the
259259
// redundant copy — but oversized bodies are still encoded here, since they're actioned
260260
// (download/copy) from the reveal warning; only their formatting is deferred.
261-
const isReconstructableText
262-
= (detectedContentType === 'text/plain' || detectedContentType === 'image/svg+xml')
263-
&& typeof data === 'string';
261+
const isReconstructableText = detectedContentType === 'text/plain' && typeof data === 'string';
264262
const base64Data = isReconstructableText && !isLarge ? undefined : buffer.toString('base64');
265263

266264
return { data, size, base64Data, detectedContentType };

packages/bruno-api-docs/src/runner/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ describe('RequestExecutor parseResponse — content-type handling', () => {
535535
const res = await run();
536536
expect(res.detectedContentType).toBe('image/svg+xml');
537537
expect(res.data).toContain('<svg');
538-
expect(res.base64Data).toBeUndefined();
538+
expect(res.base64Data).toBe('PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==');
539539
global.fetch = originalFetch;
540540
});
541541

0 commit comments

Comments
 (0)