 aacb45156b
			
		
	
	aacb45156b
	
	
	
		
			
			- Install Jest for unit testing with React Testing Library - Install Playwright for end-to-end testing - Configure Jest with proper TypeScript support and module mapping - Create test setup files and utilities for both unit and e2e tests Components: * Jest configuration with coverage thresholds * Playwright configuration with browser automation * Unit tests for LoginForm, AuthContext, and useSocketIO hook * E2E tests for authentication, dashboard, and agents workflows * GitHub Actions workflow for automated testing * Mock data and API utilities for consistent testing * Test documentation with best practices Testing features: - Unit tests with 70% coverage threshold - E2E tests with API mocking and user journey testing - CI/CD integration for automated test runs - Cross-browser testing support with Playwright - Authentication system testing end-to-end 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			173 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| Object.defineProperty(exports, "__esModule", { value: true });
 | |
| exports.serialize = serialize;
 | |
| exports.serializeOuter = serializeOuter;
 | |
| const html_js_1 = require("../common/html.js");
 | |
| const escape_1 = require("entities/escape");
 | |
| const default_js_1 = require("../tree-adapters/default.js");
 | |
| // Sets
 | |
| const VOID_ELEMENTS = new Set([
 | |
|     html_js_1.TAG_NAMES.AREA,
 | |
|     html_js_1.TAG_NAMES.BASE,
 | |
|     html_js_1.TAG_NAMES.BASEFONT,
 | |
|     html_js_1.TAG_NAMES.BGSOUND,
 | |
|     html_js_1.TAG_NAMES.BR,
 | |
|     html_js_1.TAG_NAMES.COL,
 | |
|     html_js_1.TAG_NAMES.EMBED,
 | |
|     html_js_1.TAG_NAMES.FRAME,
 | |
|     html_js_1.TAG_NAMES.HR,
 | |
|     html_js_1.TAG_NAMES.IMG,
 | |
|     html_js_1.TAG_NAMES.INPUT,
 | |
|     html_js_1.TAG_NAMES.KEYGEN,
 | |
|     html_js_1.TAG_NAMES.LINK,
 | |
|     html_js_1.TAG_NAMES.META,
 | |
|     html_js_1.TAG_NAMES.PARAM,
 | |
|     html_js_1.TAG_NAMES.SOURCE,
 | |
|     html_js_1.TAG_NAMES.TRACK,
 | |
|     html_js_1.TAG_NAMES.WBR,
 | |
| ]);
 | |
| function isVoidElement(node, options) {
 | |
|     return (options.treeAdapter.isElementNode(node) &&
 | |
|         options.treeAdapter.getNamespaceURI(node) === html_js_1.NS.HTML &&
 | |
|         VOID_ELEMENTS.has(options.treeAdapter.getTagName(node)));
 | |
| }
 | |
| const defaultOpts = { treeAdapter: default_js_1.defaultTreeAdapter, scriptingEnabled: true };
 | |
| /**
 | |
|  * Serializes an AST node to an HTML string.
 | |
|  *
 | |
|  * @example
 | |
|  *
 | |
|  * ```js
 | |
|  * const parse5 = require('parse5');
 | |
|  *
 | |
|  * const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
 | |
|  *
 | |
|  * // Serializes a document.
 | |
|  * const html = parse5.serialize(document);
 | |
|  *
 | |
|  * // Serializes the <html> element content.
 | |
|  * const str = parse5.serialize(document.childNodes[1]);
 | |
|  *
 | |
|  * console.log(str); //> '<head></head><body>Hi there!</body>'
 | |
|  * ```
 | |
|  *
 | |
|  * @param node Node to serialize.
 | |
|  * @param options Serialization options.
 | |
|  */
 | |
| function serialize(node, options) {
 | |
|     const opts = Object.assign(Object.assign({}, defaultOpts), options);
 | |
|     if (isVoidElement(node, opts)) {
 | |
|         return '';
 | |
|     }
 | |
|     return serializeChildNodes(node, opts);
 | |
| }
 | |
| /**
 | |
|  * Serializes an AST element node to an HTML string, including the element node.
 | |
|  *
 | |
|  * @example
 | |
|  *
 | |
|  * ```js
 | |
|  * const parse5 = require('parse5');
 | |
|  *
 | |
|  * const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
 | |
|  *
 | |
|  * // Serializes the <div> element.
 | |
|  * const str = parse5.serializeOuter(document.childNodes[0]);
 | |
|  *
 | |
|  * console.log(str); //> '<div>Hello, <b>world</b>!</div>'
 | |
|  * ```
 | |
|  *
 | |
|  * @param node Node to serialize.
 | |
|  * @param options Serialization options.
 | |
|  */
 | |
| function serializeOuter(node, options) {
 | |
|     const opts = Object.assign(Object.assign({}, defaultOpts), options);
 | |
|     return serializeNode(node, opts);
 | |
| }
 | |
| function serializeChildNodes(parentNode, options) {
 | |
|     let html = '';
 | |
|     // Get container of the child nodes
 | |
|     const container = options.treeAdapter.isElementNode(parentNode) &&
 | |
|         options.treeAdapter.getTagName(parentNode) === html_js_1.TAG_NAMES.TEMPLATE &&
 | |
|         options.treeAdapter.getNamespaceURI(parentNode) === html_js_1.NS.HTML
 | |
|         ? options.treeAdapter.getTemplateContent(parentNode)
 | |
|         : parentNode;
 | |
|     const childNodes = options.treeAdapter.getChildNodes(container);
 | |
|     if (childNodes) {
 | |
|         for (const currentNode of childNodes) {
 | |
|             html += serializeNode(currentNode, options);
 | |
|         }
 | |
|     }
 | |
|     return html;
 | |
| }
 | |
| function serializeNode(node, options) {
 | |
|     if (options.treeAdapter.isElementNode(node)) {
 | |
|         return serializeElement(node, options);
 | |
|     }
 | |
|     if (options.treeAdapter.isTextNode(node)) {
 | |
|         return serializeTextNode(node, options);
 | |
|     }
 | |
|     if (options.treeAdapter.isCommentNode(node)) {
 | |
|         return serializeCommentNode(node, options);
 | |
|     }
 | |
|     if (options.treeAdapter.isDocumentTypeNode(node)) {
 | |
|         return serializeDocumentTypeNode(node, options);
 | |
|     }
 | |
|     // Return an empty string for unknown nodes
 | |
|     return '';
 | |
| }
 | |
| function serializeElement(node, options) {
 | |
|     const tn = options.treeAdapter.getTagName(node);
 | |
|     return `<${tn}${serializeAttributes(node, options)}>${isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`}`;
 | |
| }
 | |
| function serializeAttributes(node, { treeAdapter }) {
 | |
|     let html = '';
 | |
|     for (const attr of treeAdapter.getAttrList(node)) {
 | |
|         html += ' ';
 | |
|         if (attr.namespace) {
 | |
|             switch (attr.namespace) {
 | |
|                 case html_js_1.NS.XML: {
 | |
|                     html += `xml:${attr.name}`;
 | |
|                     break;
 | |
|                 }
 | |
|                 case html_js_1.NS.XMLNS: {
 | |
|                     if (attr.name !== 'xmlns') {
 | |
|                         html += 'xmlns:';
 | |
|                     }
 | |
|                     html += attr.name;
 | |
|                     break;
 | |
|                 }
 | |
|                 case html_js_1.NS.XLINK: {
 | |
|                     html += `xlink:${attr.name}`;
 | |
|                     break;
 | |
|                 }
 | |
|                 default: {
 | |
|                     html += `${attr.prefix}:${attr.name}`;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             html += attr.name;
 | |
|         }
 | |
|         html += `="${(0, escape_1.escapeAttribute)(attr.value)}"`;
 | |
|     }
 | |
|     return html;
 | |
| }
 | |
| function serializeTextNode(node, options) {
 | |
|     const { treeAdapter } = options;
 | |
|     const content = treeAdapter.getTextNodeContent(node);
 | |
|     const parent = treeAdapter.getParentNode(node);
 | |
|     const parentTn = parent && treeAdapter.isElementNode(parent) && treeAdapter.getTagName(parent);
 | |
|     return parentTn &&
 | |
|         treeAdapter.getNamespaceURI(parent) === html_js_1.NS.HTML &&
 | |
|         (0, html_js_1.hasUnescapedText)(parentTn, options.scriptingEnabled)
 | |
|         ? content
 | |
|         : (0, escape_1.escapeText)(content);
 | |
| }
 | |
| function serializeCommentNode(node, { treeAdapter }) {
 | |
|     return `<!--${treeAdapter.getCommentNodeContent(node)}-->`;
 | |
| }
 | |
| function serializeDocumentTypeNode(node, { treeAdapter }) {
 | |
|     return `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node)}>`;
 | |
| }
 |