Skip to content

Commit 45af16c

Browse files
committed
add test
1 parent 5911bfa commit 45af16c

File tree

1 file changed

+234
-0
lines changed

1 file changed

+234
-0
lines changed
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// npx vitest services/browser/__tests__/BrowserSession.spec.ts
2+
3+
import { describe, it, expect, vi, beforeEach } from "vitest"
4+
import { BrowserSession } from "../BrowserSession"
5+
import { discoverChromeHostUrl, tryChromeHostUrl } from "../browserDiscovery"
6+
import { fileExistsAtPath } from "../../../utils/fs"
7+
8+
// Mock dependencies
9+
vi.mock("vscode", () => ({
10+
ExtensionContext: vi.fn(),
11+
Uri: {
12+
file: vi.fn((path) => ({ fsPath: path })),
13+
},
14+
}))
15+
16+
// Mock puppeteer-core
17+
vi.mock("puppeteer-core", () => {
18+
const mockBrowser = {
19+
newPage: vi.fn().mockResolvedValue({
20+
goto: vi.fn().mockResolvedValue(undefined),
21+
on: vi.fn(),
22+
off: vi.fn(),
23+
screenshot: vi.fn().mockResolvedValue("mockScreenshotBase64"),
24+
url: vi.fn().mockReturnValue("https://example.com"),
25+
}),
26+
pages: vi.fn().mockResolvedValue([]),
27+
close: vi.fn().mockResolvedValue(undefined),
28+
disconnect: vi.fn().mockResolvedValue(undefined),
29+
}
30+
31+
return {
32+
Browser: vi.fn(),
33+
Page: vi.fn(),
34+
TimeoutError: class TimeoutError extends Error {},
35+
launch: vi.fn().mockResolvedValue(mockBrowser),
36+
connect: vi.fn().mockResolvedValue(mockBrowser),
37+
}
38+
})
39+
40+
// Mock PCR
41+
vi.mock("puppeteer-chromium-resolver", () => {
42+
return {
43+
default: vi.fn().mockResolvedValue({
44+
puppeteer: {
45+
launch: vi.fn().mockImplementation(async () => {
46+
const { launch } = await import("puppeteer-core")
47+
return launch()
48+
}),
49+
},
50+
executablePath: "/mock/path/to/chromium",
51+
}),
52+
}
53+
})
54+
55+
// Mock fs
56+
vi.mock("fs/promises", () => ({
57+
mkdir: vi.fn().mockResolvedValue(undefined),
58+
readFile: vi.fn(),
59+
writeFile: vi.fn(),
60+
access: vi.fn(),
61+
}))
62+
63+
// Mock fileExistsAtPath
64+
vi.mock("../../../utils/fs", () => ({
65+
fileExistsAtPath: vi.fn().mockResolvedValue(false),
66+
}))
67+
68+
// Mock browser discovery functions
69+
vi.mock("../browserDiscovery", () => ({
70+
discoverChromeHostUrl: vi.fn().mockResolvedValue(null),
71+
tryChromeHostUrl: vi.fn().mockResolvedValue(false),
72+
}))
73+
74+
// Mock delay
75+
vi.mock("delay", () => ({
76+
default: vi.fn().mockResolvedValue(undefined),
77+
}))
78+
79+
// Mock p-wait-for
80+
vi.mock("p-wait-for", () => ({
81+
default: vi.fn().mockResolvedValue(undefined),
82+
}))
83+
84+
describe("BrowserSession", () => {
85+
let browserSession: BrowserSession
86+
let mockContext: any
87+
88+
beforeEach(() => {
89+
vi.clearAllMocks()
90+
91+
// Set up mock context
92+
mockContext = {
93+
globalState: {
94+
get: vi.fn(),
95+
update: vi.fn(),
96+
},
97+
globalStorageUri: {
98+
fsPath: "/mock/global/storage/path",
99+
},
100+
extensionUri: {
101+
fsPath: "/mock/extension/path",
102+
},
103+
}
104+
105+
// Create browser session
106+
browserSession = new BrowserSession(mockContext)
107+
})
108+
109+
describe("Remote browser disabled", () => {
110+
it("should launch a local browser when remote browser is disabled", async () => {
111+
// Mock context to indicate remote browser is disabled
112+
mockContext.globalState.get.mockImplementation((key: string) => {
113+
if (key === "remoteBrowserEnabled") return false
114+
return undefined
115+
})
116+
117+
await browserSession.launchBrowser()
118+
119+
const puppeteerCore = await import("puppeteer-core")
120+
121+
// Verify that a local browser was launched
122+
expect(puppeteerCore.launch).toHaveBeenCalled()
123+
124+
// Verify that remote browser connection was not attempted
125+
expect(discoverChromeHostUrl).not.toHaveBeenCalled()
126+
expect(tryChromeHostUrl).not.toHaveBeenCalled()
127+
128+
expect((browserSession as any).isUsingRemoteBrowser).toBe(false)
129+
})
130+
})
131+
132+
describe("Remote browser successfully connects", () => {
133+
it("should connect to a remote browser when enabled and connection succeeds", async () => {
134+
// Mock context to indicate remote browser is enabled
135+
mockContext.globalState.get.mockImplementation((key: string) => {
136+
if (key === "remoteBrowserEnabled") return true
137+
if (key === "remoteBrowserHost") return "http://remote-browser:9222"
138+
return undefined
139+
})
140+
141+
// Mock successful remote browser connection
142+
vi.mocked(tryChromeHostUrl).mockResolvedValue(true)
143+
144+
await browserSession.launchBrowser()
145+
146+
const puppeteerCore = await import("puppeteer-core")
147+
148+
// Verify that connect was called
149+
expect(puppeteerCore.connect).toHaveBeenCalled()
150+
151+
// Verify that local browser was not launched
152+
expect(puppeteerCore.launch).not.toHaveBeenCalled()
153+
154+
expect((browserSession as any).isUsingRemoteBrowser).toBe(true)
155+
})
156+
})
157+
158+
describe("Remote browser enabled but falls back to local", () => {
159+
it("should fall back to local browser when remote connection fails", async () => {
160+
// Mock context to indicate remote browser is enabled
161+
mockContext.globalState.get.mockImplementation((key: string) => {
162+
if (key === "remoteBrowserEnabled") return true
163+
if (key === "remoteBrowserHost") return "http://remote-browser:9222"
164+
return undefined
165+
})
166+
167+
// Mock failed remote browser connection
168+
vi.mocked(tryChromeHostUrl).mockResolvedValue(false)
169+
vi.mocked(discoverChromeHostUrl).mockResolvedValue(null)
170+
171+
await browserSession.launchBrowser()
172+
173+
// Import puppeteer-core to check if launch was called
174+
const puppeteerCore = await import("puppeteer-core")
175+
176+
// Verify that local browser was launched as fallback
177+
expect(puppeteerCore.launch).toHaveBeenCalled()
178+
179+
// Verify that isUsingRemoteBrowser is false
180+
expect((browserSession as any).isUsingRemoteBrowser).toBe(false)
181+
})
182+
})
183+
184+
describe("closeBrowser", () => {
185+
it("should close a local browser properly", async () => {
186+
const puppeteerCore = await import("puppeteer-core")
187+
188+
// Create a mock browser directly
189+
const mockBrowser = {
190+
newPage: vi.fn().mockResolvedValue({}),
191+
pages: vi.fn().mockResolvedValue([]),
192+
close: vi.fn().mockResolvedValue(undefined),
193+
disconnect: vi.fn().mockResolvedValue(undefined),
194+
}
195+
196+
// Set browser and page on the session
197+
;(browserSession as any).browser = mockBrowser
198+
;(browserSession as any).page = {}
199+
;(browserSession as any).isUsingRemoteBrowser = false
200+
201+
await browserSession.closeBrowser()
202+
203+
// Verify that browser.close was called
204+
expect(mockBrowser.close).toHaveBeenCalled()
205+
expect(mockBrowser.disconnect).not.toHaveBeenCalled()
206+
207+
// Verify that browser state was reset
208+
expect((browserSession as any).browser).toBeUndefined()
209+
expect((browserSession as any).page).toBeUndefined()
210+
expect((browserSession as any).isUsingRemoteBrowser).toBe(false)
211+
})
212+
213+
it("should disconnect from a remote browser properly", async () => {
214+
// Create a mock browser directly
215+
const mockBrowser = {
216+
newPage: vi.fn().mockResolvedValue({}),
217+
pages: vi.fn().mockResolvedValue([]),
218+
close: vi.fn().mockResolvedValue(undefined),
219+
disconnect: vi.fn().mockResolvedValue(undefined),
220+
}
221+
222+
// Set browser and page on the session
223+
;(browserSession as any).browser = mockBrowser
224+
;(browserSession as any).page = {}
225+
;(browserSession as any).isUsingRemoteBrowser = true
226+
227+
await browserSession.closeBrowser()
228+
229+
// Verify that browser.disconnect was called
230+
expect(mockBrowser.disconnect).toHaveBeenCalled()
231+
expect(mockBrowser.close).not.toHaveBeenCalled()
232+
})
233+
})
234+
})

0 commit comments

Comments
 (0)