(factory: BrowserFactory)
| 192 | * Call this from each provider's test file. |
| 193 | */ |
| 194 | export function createProviderTests(factory: BrowserFactory) { |
| 195 | const configs = getActiveConfigs(); |
| 196 | |
| 197 | describe(`${factory.name} profile lifecycle`, () => { |
| 198 | afterEach(() => sleep(500)); |
| 199 | |
| 200 | for (const config of configs) { |
| 201 | describe(configLabel(config), () => { |
| 202 | it('programmatic close — process exits, cleans up', async () => { |
| 203 | const profileDir = config.profile ? mkdtempSync(join(tmpdir(), 'browser-test-')) : undefined; |
| 204 | let browser: MastraBrowser | undefined; |
| 205 | |
| 206 | try { |
| 207 | // Seed a Preferences file with exit_type: Crashed. |
| 208 | // Chrome only creates this after extended use (e.g. logging in), |
| 209 | // so short-lived test sessions never trigger it organically. |
| 210 | // Seeding it lets us verify that close() patches it to Normal. |
| 211 | if (profileDir) { |
| 212 | seedCrashedPreferences(profileDir); |
| 213 | } |
| 214 | |
| 215 | browser = factory.create({ |
| 216 | profile: profileDir, |
| 217 | scope: config.scope, |
| 218 | headless: config.headless, |
| 219 | }); |
| 220 | |
| 221 | if (config.scope === 'thread') { |
| 222 | browser.setCurrentThread(THREAD_ID); |
| 223 | } |
| 224 | |
| 225 | await browser.ensureReady(); |
| 226 | await factory.navigate(browser, TEST_URL, config.scope === 'thread' ? THREAD_ID : undefined); |
| 227 | |
| 228 | // Get the PID we spawned |
| 229 | const pid = await factory.getPid(browser, config.scope === 'thread' ? THREAD_ID : undefined); |
| 230 | expect(pid).toBeDefined(); |
| 231 | expect(isProcessRunning(pid!)).toBe(true); |
| 232 | |
| 233 | // Close |
| 234 | if (config.scope === 'thread') { |
| 235 | await browser.closeThreadSession(THREAD_ID); |
| 236 | } else { |
| 237 | await browser.close(); |
| 238 | } |
| 239 | |
| 240 | // Verify our process exited |
| 241 | const exited = await waitForProcessExit(pid!, 5000); |
| 242 | expect(exited).toBe(true); |
| 243 | |
| 244 | // Verify profile cleanup |
| 245 | if (profileDir) { |
| 246 | expect(hasLockFiles(profileDir)).toBe(false); |
| 247 | // We seeded exit_type: Crashed before launch. |
| 248 | // Providers that patch exit_type (Stagehand) must set it to Normal. |
| 249 | if (factory.patchesExitType) { |
| 250 | expect(getExitType(profileDir)).toBe('Normal'); |
| 251 | } |
no test coverage detected
searching dependent graphs…