refactor: remove HTML validation functions and simplify HtmlPreview component logic (#6730)

* refactor: remove HTML validation functions and simplify HtmlPreview component logic

* chore: fix playwright - removed body value check since response is rendered in webview

---------

Co-authored-by: Bijin A B <bijin@usebruno.com>
This commit is contained in:
Abhishek S Lal
2026-01-07 22:46:31 +05:30
committed by GitHub
parent 9005e17eb5
commit 0b436e2c9f
4 changed files with 2 additions and 92 deletions

View File

@@ -1,6 +1,5 @@
import React, { useRef, useState, useEffect } from 'react';
import { isValidHtml } from 'utils/common/index';
import { escapeHtml, isValidHtmlSnippet } from 'utils/response/index';
import { escapeHtml } from 'utils/response/index';
const HtmlPreview = React.memo(({ data, baseUrl }) => {
const webviewContainerRef = useRef(null);
@@ -31,7 +30,7 @@ const HtmlPreview = React.memo(({ data, baseUrl }) => {
return () => mutationObserver.disconnect();
}, []);
if (isValidHtml(data) || isValidHtmlSnippet(data)) {
if (typeof data === 'string') {
const htmlContent = data.includes('<head>')
? data.replace('<head>', `<head><base href="${escapeHtml(baseUrl)}">`)
: `<head><base href="${escapeHtml(baseUrl)}"></head>${data}`;
@@ -60,8 +59,6 @@ const HtmlPreview = React.memo(({ data, baseUrl }) => {
displayContent = String(data);
} else if (typeof data === 'object') {
displayContent = JSON.stringify(data, null);
} else if (typeof data === 'string') {
displayContent = data;
} else {
displayContent = String(data);
}

View File

@@ -506,12 +506,6 @@ export function prettifyJavaScriptString(jsString) {
}
};
// Check if string contains valid HTML structure
export const isValidHtml = (str) => {
if (typeof str !== 'string' || !str.trim()) return false;
return /<\s*html[\s>]/i.test(str);
};
export function formatHexView(buffer) {
const width = 16;
let output = '';

View File

@@ -92,84 +92,6 @@ const isLikelyText = (buffer) => {
return (textChars / sampleSize) > 0.85;
};
/**
* Helper to detect if snippet is valid HTML
*/
export const isValidHtmlSnippet = (snippet) => {
if (!snippet || typeof snippet !== 'string') {
return false;
}
const trimmed = snippet.trim();
// Check for XML declaration
if (trimmed.startsWith('<?xml')) {
return false;
}
// Check for XML namespaces
if (/xmlns(:\w+)?=/.test(trimmed)) {
return false;
}
// Extract all tag names from the snippet
const tagMatches = trimmed.matchAll(/<\s*\/?([a-zA-Z][a-zA-Z0-9]*)/g);
const tags = [...tagMatches].map((match) => match[1].toLowerCase());
if (tags.length === 0) {
return false; // No tags found
}
// Define recognized HTML tags
const validHtmlTags = new Set([
'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio',
'b', 'base', 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button',
'canvas', 'caption', 'cite', 'code', 'col', 'colgroup',
'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt',
'em', 'embed',
'fieldset', 'figcaption', 'figure', 'footer', 'form',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html',
'i', 'iframe', 'img', 'input', 'ins',
'kbd',
'label', 'legend', 'li', 'link',
'main', 'map', 'mark', 'meta', 'meter',
'nav', 'noscript',
'object', 'ol', 'optgroup', 'option', 'output',
'p', 'param', 'picture', 'pre', 'progress',
'q',
'rp', 'rt', 'ruby',
's', 'samp', 'script', 'section', 'select', 'slot', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'svg',
'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track',
'u', 'ul',
'var', 'video',
'wbr'
]);
// Check if all tags are valid HTML tags
const allTagsValid = tags.every((tag) => validHtmlTags.has(tag));
if (!allTagsValid) {
return false; // Contains non-HTML tags
}
try {
// Parse with DOMParser
const parser = new DOMParser();
const doc = parser.parseFromString(trimmed, 'text/html');
// Check for parsing errors
const parseError = doc.querySelector('parsererror');
if (parseError) {
return false;
}
// HTML parser is lenient; if we reach here with valid tags, consider it valid
return true;
} catch (error) {
return false;
}
};
/**
* Decode only the first N bytes from a Base64 string
* Returns an empty buffer for invalid/missing input

View File

@@ -79,9 +79,6 @@ test.describe('Assertions - BRU Collection', () => {
// Verify response status
await expect(locators.response.statusCode()).toContainText('200');
// Verify response body contains "pong"
await expect(locators.response.body()).toContainText('pong', { timeout: 5000 });
});
await test.step('Delete assertion and save', async () => {