mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-05 11:15:57 +00:00
- 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
168 lines
5.5 KiB
TypeScript
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('<script>');
|
|
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);
|
|
});
|
|
});
|
|
});
|