import { describe, test, expect } from 'bun:test' import { rewriteHtmlPaths, isHtmlContent } from './html-rewriter' describe('rewriteHtmlPaths', () => { const basePath = '/identifier/site/' describe('absolute paths', () => { test('rewrites absolute paths with leading slash', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('rewrites nested absolute paths', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) }) describe('relative paths from root document', () => { test('rewrites relative paths with ./ prefix', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('rewrites relative paths without prefix', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('rewrites relative paths with ../ (should stay at root)', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) }) describe('relative paths from nested documents', () => { test('rewrites relative path from nested document', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/index.html' ) expect(result).toBe( '' ) }) test('rewrites plain filename from nested document', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/index.html' ) expect(result).toBe( '' ) }) test('rewrites ../ to go up one level', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/folder3/index.html' ) expect(result).toBe( '' ) }) test('rewrites multiple ../ to go up multiple levels', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/folder3/index.html' ) expect(result).toBe( '' ) }) test('rewrites ../ with additional path segments', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'pages/about/index.html' ) expect(result).toBe( '' ) }) test('handles complex nested relative paths', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'pages/blog/post/index.html' ) expect(result).toBe( '' ) }) test('handles ../ going past root (stays at root)', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'folder1/index.html') expect(result).toBe('') }) }) describe('external URLs and special schemes', () => { test('does not rewrite http URLs', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('does not rewrite https URLs', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('does not rewrite protocol-relative URLs', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('does not rewrite data URIs', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('does not rewrite mailto links', () => { const html = 'Email' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('Email') }) test('does not rewrite tel links', () => { const html = 'Call' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('Call') }) }) describe('different HTML attributes', () => { test('rewrites src attribute', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('rewrites href attribute', () => { const html = 'Link' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('Link') }) test('rewrites action attribute', () => { const html = '
' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('
') }) test('rewrites data attribute', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('rewrites poster attribute', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('rewrites srcset attribute with single URL', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('rewrites srcset attribute with multiple URLs', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('rewrites srcset with width descriptors', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) test('rewrites srcset with relative paths from nested document', () => { const html = '' const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/index.html' ) expect(result).toBe( '' ) }) }) describe('quote handling', () => { test('handles double quotes', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('handles single quotes', () => { const html = "" const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe("") }) test('handles mixed quotes in same document', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) }) describe('multiple rewrites in same document', () => { test('rewrites multiple attributes in complex HTML', () => { const html = ` Logo About
` const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toContain('href="/identifier/site/css/style.css"') expect(result).toContain('src="/identifier/site/js/app.js"') expect(result).toContain('src="/identifier/site/images/logo.png"') expect(result).toContain('href="/identifier/site/about.html"') expect(result).toContain('action="/identifier/site/submit"') }) test('handles mix of relative and absolute paths', () => { const html = ` ` const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/page.html' ) expect(result).toContain('src="/identifier/site/abs/image.png"') expect(result).toContain( 'src="/identifier/site/folder1/folder2/rel/image.png"' ) expect(result).toContain( 'src="/identifier/site/folder1/parent/image.png"' ) expect(result).toContain('src="https://external.com/image.png"') }) }) describe('edge cases', () => { test('handles empty src attribute', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('handles basePath without trailing slash', () => { const html = '' const result = rewriteHtmlPaths(html, '/identifier/site', 'index.html') expect(result).toBe('') }) test('handles basePath with trailing slash', () => { const html = '' const result = rewriteHtmlPaths( html, '/identifier/site/', 'index.html' ) expect(result).toBe('') }) test('handles whitespace around equals sign', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('preserves query strings in URLs', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe('') }) test('preserves hash fragments in URLs', () => { const html = 'Link' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( 'Link' ) }) test('handles paths with special characters', () => { const html = '' const result = rewriteHtmlPaths(html, basePath, 'index.html') expect(result).toBe( '' ) }) }) describe('real-world scenario', () => { test('handles the example from the bug report', () => { // HTML file at: /folder1/folder2/folder3/index.html // Image at: /folder1/folder2/img.png // Reference: src="../img.png" const html = '' const result = rewriteHtmlPaths( html, basePath, 'folder1/folder2/folder3/index.html' ) expect(result).toBe( '' ) }) test('handles deeply nested static site structure', () => { // A typical static site with nested pages and shared assets const html = ` Logo Post Back to Blog Home ` const result = rewriteHtmlPaths( html, basePath, 'blog/posts/my-post.html' ) // Assets two levels up expect(result).toContain('href="/identifier/site/css/style.css"') expect(result).toContain('href="/identifier/site/css/theme.css"') expect(result).toContain('src="/identifier/site/js/main.js"') expect(result).toContain('src="/identifier/site/images/logo.png"') // Same directory expect(result).toContain( 'src="/identifier/site/blog/posts/post-image.jpg"' ) // One level up expect(result).toContain('href="/identifier/site/blog/index.html"') // Two levels up expect(result).toContain('href="/identifier/site/index.html"') }) }) }) describe('isHtmlContent', () => { test('identifies HTML by content type', () => { expect(isHtmlContent('file.txt', 'text/html')).toBe(true) expect(isHtmlContent('file.txt', 'text/html; charset=utf-8')).toBe( true ) }) test('identifies HTML by .html extension', () => { expect(isHtmlContent('index.html')).toBe(true) expect(isHtmlContent('page.html', undefined)).toBe(true) expect(isHtmlContent('/path/to/file.html')).toBe(true) }) test('identifies HTML by .htm extension', () => { expect(isHtmlContent('index.htm')).toBe(true) expect(isHtmlContent('page.htm', undefined)).toBe(true) }) test('handles case-insensitive extensions', () => { expect(isHtmlContent('INDEX.HTML')).toBe(true) expect(isHtmlContent('page.HTM')).toBe(true) expect(isHtmlContent('File.HtMl')).toBe(true) }) test('returns false for non-HTML files', () => { expect(isHtmlContent('script.js')).toBe(false) expect(isHtmlContent('style.css')).toBe(false) expect(isHtmlContent('image.png')).toBe(false) expect(isHtmlContent('data.json')).toBe(false) }) test('returns false for files with no extension', () => { expect(isHtmlContent('README')).toBe(false) expect(isHtmlContent('Makefile')).toBe(false) }) })