vibetunnel/web/src/test/unit/utils.test.ts
Peter Steinberger d99ef041f7 feat: add integration tests and fix compatibility issues
- Add comprehensive integration test suite for Node.js server
  - API endpoint tests for session lifecycle, I/O operations, file system
  - WebSocket connection tests for hot reload functionality
  - Server lifecycle tests for initialization and shutdown
  - Basic binary availability tests for tty-fwd

- Fix Rust code for nix 0.30 API changes
  - Update dup2 calls to use OwnedFd instead of raw file descriptors
  - Fix read calls to pass file descriptors directly instead of raw fd
  - Remove deprecated as_raw_fd() calls where not needed

- Reorganize test structure
  - Split tests into unit/ and integration/ directories
  - Add separate Vitest configuration for integration tests
  - Create test utilities and setup files for both test types
  - Add custom test matchers for session validation

- Update test coverage configuration
  - Configure separate coverage for unit and integration tests
  - Add proper test timeouts for long-running integration tests
  - Use fork pool for integration tests to avoid port conflicts
2025-06-18 19:39:42 +02:00

168 lines
5.5 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { UrlHighlighter } from '../../client/utils/url-highlighter';
import { CastConverter } from '../../client/utils/cast-converter';
describe('Utility Functions', () => {
describe('UrlHighlighter', () => {
it('should detect http URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'Check out http://example.com for more info';
const result = highlighter.highlight(text);
expect(result).toContain('<a');
expect(result).toContain('href="http://example.com"');
expect(result).toContain('http://example.com</a>');
});
it('should detect https URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'Secure site: https://secure.example.com/path';
const result = highlighter.highlight(text);
expect(result).toContain('href="https://secure.example.com/path"');
});
it('should handle multiple URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'Visit http://site1.com and https://site2.com';
const result = highlighter.highlight(text);
const matches = result.match(/<a[^>]*>/g);
expect(matches).toHaveLength(2);
});
it('should preserve text around URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'Before http://example.com after';
const result = highlighter.highlight(text);
expect(result).toMatch(/^Before <a[^>]*>http:\/\/example\.com<\/a> after$/);
});
it('should handle text without URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'No URLs here, just plain text';
const result = highlighter.highlight(text);
expect(result).toBe(text);
});
it('should escape HTML in non-URL text', () => {
const highlighter = new UrlHighlighter();
const text = '<script>alert("xss")</script> http://safe.com';
const result = highlighter.highlight(text);
expect(result).not.toContain('<script>');
expect(result).toContain('&lt;script&gt;');
expect(result).toContain('<a');
});
it('should handle localhost URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'Local dev: http://localhost:3000/api';
const result = highlighter.highlight(text);
expect(result).toContain('href="http://localhost:3000/api"');
});
it('should handle IP address URLs', () => {
const highlighter = new UrlHighlighter();
const text = 'Server at http://192.168.1.1:8080';
const result = highlighter.highlight(text);
expect(result).toContain('href="http://192.168.1.1:8080"');
});
});
describe('CastConverter', () => {
it('should create basic cast structure', () => {
const converter = new CastConverter(80, 24);
const cast = converter.getCast();
expect(cast.version).toBe(2);
expect(cast.width).toBe(80);
expect(cast.height).toBe(24);
expect(cast.timestamp).toBeGreaterThan(0);
expect(Array.isArray(cast.events)).toBe(true);
});
it('should add output events', () => {
const converter = new CastConverter(80, 24);
converter.addOutput('Hello World\n', 1.0);
const cast = converter.getCast();
expect(cast.events).toHaveLength(1);
expect(cast.events[0]).toEqual([1.0, 'o', 'Hello World\n']);
});
it('should handle multiple events in order', () => {
const converter = new CastConverter(80, 24);
converter.addOutput('First\n', 0.5);
converter.addOutput('Second\n', 1.0);
converter.addOutput('Third\n', 1.5);
const cast = converter.getCast();
expect(cast.events).toHaveLength(3);
expect(cast.events[0][0]).toBe(0.5);
expect(cast.events[1][0]).toBe(1.0);
expect(cast.events[2][0]).toBe(1.5);
});
it('should handle empty output', () => {
const converter = new CastConverter(80, 24);
converter.addOutput('', 1.0);
const cast = converter.getCast();
expect(cast.events).toHaveLength(1);
expect(cast.events[0][2]).toBe('');
});
it('should handle special characters', () => {
const converter = new CastConverter(80, 24);
const specialChars = '\x1b[31mRed Text\x1b[0m\n';
converter.addOutput(specialChars, 1.0);
const cast = converter.getCast();
expect(cast.events[0][2]).toBe(specialChars);
});
it('should export valid JSON', () => {
const converter = new CastConverter(80, 24);
converter.addOutput('Test\n', 1.0);
const json = converter.toJSON();
const parsed = JSON.parse(json);
expect(parsed.version).toBe(2);
expect(parsed.width).toBe(80);
expect(parsed.height).toBe(24);
expect(parsed.events).toHaveLength(1);
});
it('should set custom environment', () => {
const converter = new CastConverter(80, 24);
const env = { SHELL: '/bin/bash', TERM: 'xterm-256color' };
converter.setEnvironment(env);
const cast = converter.getCast();
expect(cast.env).toEqual(env);
});
it('should set custom title', () => {
const converter = new CastConverter(80, 24);
converter.setTitle('My Recording');
const cast = converter.getCast();
expect(cast.title).toBe('My Recording');
});
it('should handle timing precision', () => {
const converter = new CastConverter(80, 24);
converter.addOutput('Output', 1.123456789);
const cast = converter.getCast();
// Should maintain precision to at least 6 decimal places
expect(cast.events[0][0]).toBeCloseTo(1.123456, 6);
});
});
});