Skip to content

Commit 274471b

Browse files
committed
Swap happy-dom for linkedom.
1 parent 26aad2f commit 274471b

File tree

5 files changed

+109
-69
lines changed

5 files changed

+109
-69
lines changed

browser-extension/package-lock.json

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

browser-extension/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
"description": "Syntax highlighting and autosave for comments on GitHub (and other other markdown-friendly websites).",
1010
"devDependencies": {
1111
"@biomejs/biome": "^2.1.2",
12+
"@playwright/test": "^1.46.0",
1213
"@testing-library/jest-dom": "^6.6.4",
14+
"@types/express": "^4.17.21",
1315
"@types/node": "^22.16.5",
14-
"@playwright/test": "^1.46.0",
1516
"@vitest/coverage-v8": "^3.2.4",
1617
"@vitest/ui": "^3.2.4",
1718
"express": "^4.19.2",
18-
"@types/express": "^4.17.21",
19-
"happy-dom": "^18.0.1",
19+
"linkedom": "^0.18.12",
2020
"tsx": "^4.19.1",
2121
"typescript": "^5.8.3",
2222
"vitest": "^3.2.4",
Lines changed: 45 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
1-
import { beforeEach, describe, expect, it, vi } from 'vitest'
1+
import { describe, expect, it, vi } from 'vitest'
22
import { EnhancerRegistry } from '../../../src/lib/registries'
33
import { PAGES } from '../../har-index'
44
import fs from 'node:fs/promises'
55
import path from 'node:path'
66
import { fileURLToPath } from 'node:url'
7+
import { parseHTML } from 'linkedom'
78

8-
// Mock WXT's defineContentScript global
99
vi.stubGlobal('defineContentScript', vi.fn())
1010

11+
vi.mock('../../../src/overtype/overtype', () => {
12+
const mockConstructor = vi.fn().mockImplementation(() => [{
13+
container: document.createElement('div'),
14+
wrapper: document.createElement('div'),
15+
textarea: document.createElement('textarea'),
16+
preview: document.createElement('div'),
17+
getValue: vi.fn(() => ''),
18+
setValue: vi.fn(),
19+
focus: vi.fn(),
20+
destroy: vi.fn()
21+
}])
22+
mockConstructor.setCodeHighlighter = vi.fn()
23+
return {
24+
default: mockConstructor
25+
}
26+
})
27+
1128
const __dirname = path.dirname(fileURLToPath(import.meta.url))
1229

13-
// Helper function to load and extract HTML from HAR files
14-
async function loadHarHtml(key: string): Promise<string> {
30+
async function loadHtmlFromHar(key: string): Promise<string> {
1531
const harPath = path.join(__dirname, '../../har', `${key}.har`)
1632
const harContent = await fs.readFile(harPath, 'utf-8')
1733
const harData = JSON.parse(harContent)
1834

19-
// Find the main HTML response (same logic as har-view.ts)
2035
const mainEntry = harData.log.entries.find((entry: any) =>
2136
entry.request.url.includes('github.com') &&
2237
entry.response.content.mimeType?.includes('text/html') &&
@@ -27,66 +42,48 @@ async function loadHarHtml(key: string): Promise<string> {
2742
throw new Error(`No HTML content found in HAR file: ${key}.har`)
2843
}
2944

30-
return mainEntry.response.content.text
45+
let html = mainEntry.response.content.text
46+
47+
// Check if content is base64 encoded
48+
if (mainEntry.response.content.encoding === 'base64') {
49+
html = Buffer.from(html, 'base64').toString('utf-8')
50+
}
51+
52+
return html
3153
}
3254

3355
describe('github', () => {
34-
beforeEach(() => {
35-
// Reset DOM between tests
36-
document.body.innerHTML = ''
56+
it('should identify gh_pr textarea and create proper spot object', async () => {
57+
const html = await loadHtmlFromHar('gh_pr')
3758

38-
// Mock console methods to avoid noise
39-
vi.spyOn(console, 'warn').mockImplementation(() => {})
40-
})
41-
42-
// Helper to setup DOM environment with location mocking
43-
function setupDOMEnvironment(url: string, html: string) {
44-
// Set up the HTML content
45-
document.body.innerHTML = html
59+
// Parse HTML with linkedom
60+
const dom = parseHTML(html)
4661

47-
// Mock window.location.pathname for GitHub enhancer
48-
Object.defineProperty(window.location, 'pathname', {
49-
value: new URL(url).pathname,
50-
configurable: true
62+
// Replace global document with parsed one
63+
Object.assign(globalThis, {
64+
document: dom.document,
65+
window: {
66+
...dom.window,
67+
location: new URL(PAGES.gh_pr)
68+
}
5169
})
5270

53-
// Add GitHub hostname meta tag (for the enhancer's new hostname check)
5471
const meta = document.createElement('meta')
5572
meta.name = 'hostname'
5673
meta.content = 'github.com'
5774
document.head.appendChild(meta)
58-
}
59-
60-
it('should identify gh_pr textarea and create proper spot object', async () => {
61-
const enhancers = new EnhancerRegistry()
62-
const url = PAGES.gh_pr
63-
64-
// Load the HTML from HAR file
65-
const html = await loadHarHtml('gh_pr')
66-
67-
// Setup DOM environment with proper location
68-
setupDOMEnvironment(url, html)
6975

70-
// Get all textarea elements from the page
76+
const enhancers = new EnhancerRegistry()
7177
const textareas = document.querySelectorAll('textarea')
7278

73-
// Try to enhance each textarea - should find at least one GitHub textarea
74-
let enhancedCount = 0
75-
let lastEnhancedResult: any = null
76-
79+
let enhanced: any = null
7780
for (const textarea of textareas) {
78-
const enhancedTextarea = enhancers.tryToEnhance(textarea as HTMLTextAreaElement)
79-
if (enhancedTextarea) {
80-
enhancedCount++
81-
lastEnhancedResult = enhancedTextarea
82-
}
81+
enhanced = enhancers.tryToEnhance(textarea as HTMLTextAreaElement)
82+
if (enhanced) break
8383
}
8484

85-
expect(enhancedCount).toBeGreaterThan(0)
86-
expect(lastEnhancedResult).toBeTruthy()
87-
88-
// Snapshot test on the spot object structure
89-
expect(lastEnhancedResult.spot).toMatchInlineSnapshot(`
85+
expect(enhanced).toBeTruthy()
86+
expect(enhanced.spot).toMatchInlineSnapshot(`
9087
{
9188
"domain": "github.com",
9289
"number": 517,
@@ -95,20 +92,5 @@ describe('github', () => {
9592
"unique_key": "github.com:diffplug/selfie:517",
9693
}
9794
`)
98-
99-
// Verify specific fields based on the URL
100-
const urlObj = new URL(url)
101-
const match = urlObj.pathname.match(/^\/([^/]+)\/([^/]+)\/(?:pull|issues)\/(\d+)/)
102-
expect(match).toBeTruthy() // Ensure URL pattern matches
103-
104-
const [, owner, repo, numberStr] = match!
105-
106-
expect(owner).toBeDefined()
107-
expect(repo).toBeDefined()
108-
expect(numberStr).toBeDefined()
109-
110-
expect(lastEnhancedResult.spot.slug).toBe(`${owner}/${repo}`)
111-
expect(lastEnhancedResult.spot.number).toBe(parseInt(numberStr!, 10))
112-
expect(lastEnhancedResult.spot.unique_key).toBe(`github.com:${owner}/${repo}:${numberStr}`)
11395
})
11496
})

browser-extension/tests/setup.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,50 @@
11
import '@testing-library/jest-dom/vitest'
2+
import { parseHTML } from 'linkedom'
3+
4+
// Set up linkedom globals for browser-like environment
5+
const dom = parseHTML(`
6+
<!DOCTYPE html>
7+
<html>
8+
<head>
9+
<meta charset="utf-8">
10+
<title>Test</title>
11+
</head>
12+
<body></body>
13+
</html>
14+
`)
15+
16+
// Mock global DOM objects
17+
Object.assign(globalThis, {
18+
window: dom.window,
19+
document: dom.document,
20+
Document: dom.Document,
21+
DocumentFragment: dom.DocumentFragment,
22+
HTMLElement: dom.HTMLElement,
23+
HTMLTextAreaElement: dom.HTMLTextAreaElement,
24+
HTMLDivElement: dom.HTMLDivElement,
25+
HTMLMetaElement: dom.HTMLMetaElement,
26+
Element: dom.Element,
27+
Node: dom.Node,
28+
Text: dom.Text,
29+
location: dom.window.location
30+
})
31+
32+
// Mock querySelector methods properly
33+
const originalQuerySelector = dom.document.querySelector.bind(dom.document)
34+
const originalQuerySelectorAll = dom.document.querySelectorAll.bind(dom.document)
35+
36+
dom.document.querySelector = function(selector) {
37+
try {
38+
return originalQuerySelector(selector)
39+
} catch (e) {
40+
return null
41+
}
42+
}
43+
44+
dom.document.querySelectorAll = function(selector) {
45+
try {
46+
return originalQuerySelectorAll(selector)
47+
} catch (e) {
48+
return []
49+
}
50+
}

browser-extension/vitest.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ export default defineConfig({
1616
provider: 'v8',
1717
reporter: ['text', 'json', 'html'],
1818
},
19-
environment: 'happy-dom',
19+
environment: 'node',
20+
pool: 'threads',
2021
globals: true,
2122
setupFiles: ['./tests/setup.ts'],
2223
},

0 commit comments

Comments
 (0)