From 2605182eb6e55ea6e87aa73567ddfc023c6f7c71 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Tue, 14 Jan 2025 15:50:37 -0300 Subject: [PATCH 01/28] fix: prevent infinite loop on prettyDOM calls --- packages/utils/src/display.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/display.ts b/packages/utils/src/display.ts index f61b425787d6..de574b37008c 100644 --- a/packages/utils/src/display.ts +++ b/packages/utils/src/display.ts @@ -72,9 +72,11 @@ export function stringify( ...options, }) } - + + // Prevents infinite loop https://github.com/vitest-dev/vitest/issues/7249 + const nextMaxDepth = maxDepth === Infinity ? Number.MAX_VALUE : Math.floor(maxDepth / 2) return result.length >= MAX_LENGTH && maxDepth > 1 - ? stringify(object, Math.floor(maxDepth / 2)) + ? stringify(object, nextMaxDepth) : result } From f78072280dc16fda6b31bd9f2a5ff6bd5199f5f9 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Tue, 14 Jan 2025 16:00:47 -0300 Subject: [PATCH 02/28] fix lint --- packages/utils/src/display.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/display.ts b/packages/utils/src/display.ts index de574b37008c..a07b4977a380 100644 --- a/packages/utils/src/display.ts +++ b/packages/utils/src/display.ts @@ -72,7 +72,7 @@ export function stringify( ...options, }) } - + // Prevents infinite loop https://github.com/vitest-dev/vitest/issues/7249 const nextMaxDepth = maxDepth === Infinity ? Number.MAX_VALUE : Math.floor(maxDepth / 2) return result.length >= MAX_LENGTH && maxDepth > 1 From 0b13cbf25f5705101187eaef3a4b9b450b8adc5c Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 10:34:04 -0300 Subject: [PATCH 03/28] use MAX_SAFE_INTEGER instead of MAX_VALUE --- packages/utils/src/display.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/display.ts b/packages/utils/src/display.ts index a07b4977a380..a13e51aa53e9 100644 --- a/packages/utils/src/display.ts +++ b/packages/utils/src/display.ts @@ -74,7 +74,7 @@ export function stringify( } // Prevents infinite loop https://github.com/vitest-dev/vitest/issues/7249 - const nextMaxDepth = maxDepth === Infinity ? Number.MAX_VALUE : Math.floor(maxDepth / 2) + const nextMaxDepth = maxDepth === Infinity ? Number.MAX_SAFE_INTEGER : Math.floor(maxDepth / 2) return result.length >= MAX_LENGTH && maxDepth > 1 ? stringify(object, nextMaxDepth) : result From 6be46fe18ff12e11c146e627ee6e4caa5a322725 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 10:34:28 -0300 Subject: [PATCH 04/28] add test case to handle large nested DOM in prettyDOM calls --- .../test/__snapshots__/utils.test.ts.snap | 30 +++++++++++++++++++ test/browser/test/utils.test.ts | 16 ++++++++++ 2 files changed, 46 insertions(+) diff --git a/test/browser/test/__snapshots__/utils.test.ts.snap b/test/browser/test/__snapshots__/utils.test.ts.snap index c0ab66b34255..3ebc059f520a 100644 --- a/test/browser/test/__snapshots__/utils.test.ts.snap +++ b/test/browser/test/__snapshots__/utils.test.ts.snap @@ -35,3 +35,33 @@ exports[`prints the element with attributes 1`] = ` " `; + +exports[`should handle large nested DOM 1`] = ` +" + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+..." +`; diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index c66fcf0da811..804ca9208df6 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -37,3 +37,19 @@ test('prints the element with attributes', async () => { expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() }) + +test('should handle large nested DOM', async () => { + const depth = 20000; + + // if we try to manipulate dom to add 20000 divs, we get + // max depth exceeded error + const openingTags = "
".repeat(depth); + const closingTags = "
".repeat(depth); + const domString = `${openingTags}${closingTags}`; + + const parentDiv = document.createElement("div"); + parentDiv.innerHTML = domString; + + document.body.appendChild(parentDiv); + expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() +}); From f815b0ab933877ed863d44b0ce083fbb5e75b892 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 10:34:44 -0300 Subject: [PATCH 05/28] handle browser crash in playwright provider --- packages/browser/src/node/providers/playwright.ts | 6 ++++++ test/browser/test/browser-crash.test.ts | 15 +++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 test/browser/test/browser-crash.test.ts diff --git a/packages/browser/src/node/providers/playwright.ts b/packages/browser/src/node/providers/playwright.ts index 2a08cef23695..54a5ef84dcd6 100644 --- a/packages/browser/src/node/providers/playwright.ts +++ b/packages/browser/src/node/providers/playwright.ts @@ -185,6 +185,12 @@ export class PlaywrightBrowserProvider implements BrowserProvider { }) } + // unhandled page crashes will hang vitest process + page.on('crash', () => { + const session = this.project.vitest._browserSessions.getSession(sessionId) + session?.reject(new Error('Page crashed when executing tests')) + }) + return page } diff --git a/test/browser/test/browser-crash.test.ts b/test/browser/test/browser-crash.test.ts new file mode 100644 index 000000000000..7327521514c0 --- /dev/null +++ b/test/browser/test/browser-crash.test.ts @@ -0,0 +1,15 @@ +import { it } from 'vitest'; + +it.skip('fails gracefully when browser crashes', async () => { + let parentDiv = document.createElement("div") + let currentDiv = parentDiv; + + // Simulate crash by adding a large number of nodes + for (let i = 0; i < 20000; i++) { + const newDiv = document.createElement("div") + currentDiv.appendChild(newDiv) + currentDiv = newDiv + } + + document.body.appendChild(parentDiv) +}) \ No newline at end of file From 9b02f2077fc196956349477c124396a694332c20 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 10:44:22 -0300 Subject: [PATCH 06/28] fix lint issues --- test/browser/test/browser-crash.test.ts | 10 +++++----- test/browser/test/utils.test.ts | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/browser/test/browser-crash.test.ts b/test/browser/test/browser-crash.test.ts index 7327521514c0..873b8296b7a6 100644 --- a/test/browser/test/browser-crash.test.ts +++ b/test/browser/test/browser-crash.test.ts @@ -1,15 +1,15 @@ -import { it } from 'vitest'; +import { it } from 'vitest' it.skip('fails gracefully when browser crashes', async () => { - let parentDiv = document.createElement("div") - let currentDiv = parentDiv; + const parentDiv = document.createElement('div') + let currentDiv = parentDiv // Simulate crash by adding a large number of nodes for (let i = 0; i < 20000; i++) { - const newDiv = document.createElement("div") + const newDiv = document.createElement('div') currentDiv.appendChild(newDiv) currentDiv = newDiv } document.body.appendChild(parentDiv) -}) \ No newline at end of file +}) diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index 804ca9208df6..db56539aa061 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -39,17 +39,17 @@ test('prints the element with attributes', async () => { }) test('should handle large nested DOM', async () => { - const depth = 20000; + const depth = 20000 - // if we try to manipulate dom to add 20000 divs, we get + // if we try to manipulate dom to add 20000 divs, we get // max depth exceeded error - const openingTags = "
".repeat(depth); - const closingTags = "
".repeat(depth); - const domString = `${openingTags}${closingTags}`; + const openingTags = '
'.repeat(depth) + const closingTags = '
'.repeat(depth) + const domString = `${openingTags}${closingTags}` - const parentDiv = document.createElement("div"); - parentDiv.innerHTML = domString; + const parentDiv = document.createElement('div') + parentDiv.innerHTML = domString - document.body.appendChild(parentDiv); + document.body.appendChild(parentDiv) expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() -}); +}) From ed16cda87bed8c1e04d8b5d556eca06696d1019a Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 10:45:43 -0300 Subject: [PATCH 07/28] bump test counter --- test/browser/specs/runner.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/browser/specs/runner.test.ts b/test/browser/specs/runner.test.ts index d0f72ec1cd6d..5c75b7604653 100644 --- a/test/browser/specs/runner.test.ts +++ b/test/browser/specs/runner.test.ts @@ -41,8 +41,8 @@ describe('running browser tests', async () => { // This should match the number of actual tests from browser.json // if you added new tests, these assertion will fail and you should // update the numbers - expect(browserResultJson.testResults).toHaveLength(20 * instances.length) - expect(passedTests).toHaveLength(18 * instances.length) + expect(browserResultJson.testResults).toHaveLength(21 * instances.length) + expect(passedTests).toHaveLength(19 * instances.length) expect(failedTests).toHaveLength(2 * instances.length) expect(stderr).not.toContain('optimized dependencies changed') From 34ff6881e3155fb213e78e35cdb8da14e7da7a34 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 11:00:06 -0300 Subject: [PATCH 08/28] adjust test count --- test/browser/specs/runner.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser/specs/runner.test.ts b/test/browser/specs/runner.test.ts index 5c75b7604653..c101f5574a56 100644 --- a/test/browser/specs/runner.test.ts +++ b/test/browser/specs/runner.test.ts @@ -42,7 +42,7 @@ describe('running browser tests', async () => { // if you added new tests, these assertion will fail and you should // update the numbers expect(browserResultJson.testResults).toHaveLength(21 * instances.length) - expect(passedTests).toHaveLength(19 * instances.length) + expect(passedTests).toHaveLength(18 * instances.length) expect(failedTests).toHaveLength(2 * instances.length) expect(stderr).not.toContain('optimized dependencies changed') From c0b9c0871dab80410b61f4f92b54e0b3e1446c06 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 11:21:20 -0300 Subject: [PATCH 09/28] rebump test count --- test/browser/specs/runner.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser/specs/runner.test.ts b/test/browser/specs/runner.test.ts index c101f5574a56..5c75b7604653 100644 --- a/test/browser/specs/runner.test.ts +++ b/test/browser/specs/runner.test.ts @@ -42,7 +42,7 @@ describe('running browser tests', async () => { // if you added new tests, these assertion will fail and you should // update the numbers expect(browserResultJson.testResults).toHaveLength(21 * instances.length) - expect(passedTests).toHaveLength(18 * instances.length) + expect(passedTests).toHaveLength(19 * instances.length) expect(failedTests).toHaveLength(2 * instances.length) expect(stderr).not.toContain('optimized dependencies changed') From e2f36ac1dcf689f825730ac76bb41296dfab0b1f Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 11:46:18 -0300 Subject: [PATCH 10/28] fix browser crash test --- .../browser-crash}/browser-crash.test.ts | 2 +- .../fixtures/browser-crash/vitest.config.ts | 24 +++++++++++++++++++ test/browser/specs/browser-crash.test.ts | 11 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) rename test/browser/{test => fixtures/browser-crash}/browser-crash.test.ts (84%) create mode 100644 test/browser/fixtures/browser-crash/vitest.config.ts create mode 100644 test/browser/specs/browser-crash.test.ts diff --git a/test/browser/test/browser-crash.test.ts b/test/browser/fixtures/browser-crash/browser-crash.test.ts similarity index 84% rename from test/browser/test/browser-crash.test.ts rename to test/browser/fixtures/browser-crash/browser-crash.test.ts index 873b8296b7a6..da996d37394c 100644 --- a/test/browser/test/browser-crash.test.ts +++ b/test/browser/fixtures/browser-crash/browser-crash.test.ts @@ -1,6 +1,6 @@ import { it } from 'vitest' -it.skip('fails gracefully when browser crashes', async () => { +it('fails gracefully when browser crashes', async () => { const parentDiv = document.createElement('div') let currentDiv = parentDiv diff --git a/test/browser/fixtures/browser-crash/vitest.config.ts b/test/browser/fixtures/browser-crash/vitest.config.ts new file mode 100644 index 000000000000..b482d8bb44e6 --- /dev/null +++ b/test/browser/fixtures/browser-crash/vitest.config.ts @@ -0,0 +1,24 @@ +import { fileURLToPath } from 'node:url' +import { defineConfig } from 'vitest/config' +import { instances, provider } from '../../settings' + +export default defineConfig({ + cacheDir: fileURLToPath(new URL("./node_modules/.vite", import.meta.url)), + test: { + browser: { + enabled: true, + provider, + instances: instances.map(instance => ({ + ...instance, + context: { + actionTimeout: 500, + }, + })), + }, + expect: { + poll: { + timeout: 500, + }, + }, + }, +}) diff --git a/test/browser/specs/browser-crash.test.ts b/test/browser/specs/browser-crash.test.ts new file mode 100644 index 000000000000..e0326dccf5a7 --- /dev/null +++ b/test/browser/specs/browser-crash.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from 'vitest' +import { runBrowserTests } from './utils' + +test('fails gracefully when browser crashes', async () => { + const { stderr } = await runBrowserTests({ + root: './fixtures/browser-crash', + reporters: [['verbose', { isTTY: false }]], + }) + + expect(stderr).contains('Page crashed when executing tests') +}) From 8ee78bcf1ac8b7da58e101891859762ac6fdbb88 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 12:03:11 -0300 Subject: [PATCH 11/28] force maxDepth to be under predefined value --- packages/utils/src/display.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/utils/src/display.ts b/packages/utils/src/display.ts index a13e51aa53e9..decb2cea8b90 100644 --- a/packages/utils/src/display.ts +++ b/packages/utils/src/display.ts @@ -74,7 +74,8 @@ export function stringify( } // Prevents infinite loop https://github.com/vitest-dev/vitest/issues/7249 - const nextMaxDepth = maxDepth === Infinity ? Number.MAX_SAFE_INTEGER : Math.floor(maxDepth / 2) + const MAX_DEPTH = Number.MAX_SAFE_INTEGER + const nextMaxDepth = maxDepth > MAX_DEPTH ? MAX_DEPTH : Math.floor(maxDepth / 2) return result.length >= MAX_LENGTH && maxDepth > 1 ? stringify(object, nextMaxDepth) : result From 4d1728dc23cf3d84be92db6d23a235e060df76c2 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 12:03:22 -0300 Subject: [PATCH 12/28] bump test counter --- test/browser/specs/runner.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser/specs/runner.test.ts b/test/browser/specs/runner.test.ts index 7ce58445300b..7048b1a0d15e 100644 --- a/test/browser/specs/runner.test.ts +++ b/test/browser/specs/runner.test.ts @@ -71,7 +71,7 @@ describe('running browser tests', async () => { // This should match the number of actual tests from browser.json // if you added new tests, these assertion will fail and you should // update the numbers - expect(browserResultJson.testResults).toHaveLength(21 * instances.length) + expect(browserResultJson.testResults).toHaveLength(22 * instances.length) expect(passedTests).toHaveLength(19 * instances.length) expect(failedTests).toHaveLength(2 * instances.length) From 32a967fe0d08d7bf5c75cc920b4b83386cad7eba Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 12:36:21 -0300 Subject: [PATCH 13/28] update snapshot --- .../test/__snapshots__/utils.test.ts.snap | 95 +++++++++++++++---- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/test/browser/test/__snapshots__/utils.test.ts.snap b/test/browser/test/__snapshots__/utils.test.ts.snap index 3ebc059f520a..be100fcbc944 100644 --- a/test/browser/test/__snapshots__/utils.test.ts.snap +++ b/test/browser/test/__snapshots__/utils.test.ts.snap @@ -38,12 +38,6 @@ exports[`prints the element with attributes 1`] = ` exports[`should handle large nested DOM 1`] = ` " - - - - - -
@@ -53,15 +47,82 @@ exports[`should handle large nested DOM 1`] = `
-
-
-
-
-
-
-
-
-
- -..." +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..." `; From 9c2f84d620c82c6e3a1345f9d30b3f6b80039c2c Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 12:36:31 -0300 Subject: [PATCH 14/28] update test counters --- test/browser/specs/runner.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/browser/specs/runner.test.ts b/test/browser/specs/runner.test.ts index 7048b1a0d15e..95a6d1f442ab 100644 --- a/test/browser/specs/runner.test.ts +++ b/test/browser/specs/runner.test.ts @@ -71,8 +71,8 @@ describe('running browser tests', async () => { // This should match the number of actual tests from browser.json // if you added new tests, these assertion will fail and you should // update the numbers - expect(browserResultJson.testResults).toHaveLength(22 * instances.length) - expect(passedTests).toHaveLength(19 * instances.length) + expect(browserResultJson.testResults).toHaveLength(20 * instances.length) + expect(passedTests).toHaveLength(18 * instances.length) expect(failedTests).toHaveLength(2 * instances.length) expect(stderr).not.toContain('optimized dependencies changed') From 2189730981be6b53d002b83060bba7242e2a6251 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 12:54:54 -0300 Subject: [PATCH 15/28] add bigger timeout to large dom test --- test/browser/test/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index db56539aa061..186401f3075b 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -52,4 +52,4 @@ test('should handle large nested DOM', async () => { document.body.appendChild(parentDiv) expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() -}) +}, { timeout: 60000 }) From 3bcb162e2617d3012d72aa63953a685c6b519414 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 13:12:22 -0300 Subject: [PATCH 16/28] increase large dom test timeout --- test/browser/test/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index 186401f3075b..8d4bd15270ed 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -52,4 +52,4 @@ test('should handle large nested DOM', async () => { document.body.appendChild(parentDiv) expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() -}, { timeout: 60000 }) +}, { timeout: 120000 }) From 69299a272bc4233f6752d36d4f3bd52af5114e5d Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 14:20:43 -0300 Subject: [PATCH 17/28] exit gracefully on webdriver crash --- .../browser/src/node/providers/webdriver.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/browser/src/node/providers/webdriver.ts b/packages/browser/src/node/providers/webdriver.ts index fe80067e39f3..be9561fd7666 100644 --- a/packages/browser/src/node/providers/webdriver.ts +++ b/packages/browser/src/node/providers/webdriver.ts @@ -56,7 +56,7 @@ export class WebdriverBrowserProvider implements BrowserProvider { } } - async openBrowser() { + async openBrowser(sessionId: string) { if (this.browser) { return this.browser } @@ -78,6 +78,18 @@ export class WebdriverBrowserProvider implements BrowserProvider { ...this.options, logLevel: 'error', capabilities: this.buildCapabilities(), + }); + + // closest we can do as for detecting browser crash + setImmediate(async () => { + while(true) { + try { + await this.browser?.getTitle() + } catch { + const session = this.project.vitest._browserSessions.getSession(sessionId) + session?.reject(new Error('Page crashed when executing tests')) + } + } }) return this.browser @@ -120,8 +132,8 @@ export class WebdriverBrowserProvider implements BrowserProvider { return capabilities } - async openPage(_sessionId: string, url: string) { - const browserInstance = await this.openBrowser() + async openPage(sessionId: string, url: string) { + const browserInstance = await this.openBrowser(sessionId) await browserInstance.url(url) } From d88b2a1e983c8aa218487f3d6badfd4994b93eba Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 14:42:05 -0300 Subject: [PATCH 18/28] fix lint --- packages/browser/src/node/providers/webdriver.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/browser/src/node/providers/webdriver.ts b/packages/browser/src/node/providers/webdriver.ts index be9561fd7666..5326abf581f6 100644 --- a/packages/browser/src/node/providers/webdriver.ts +++ b/packages/browser/src/node/providers/webdriver.ts @@ -78,14 +78,15 @@ export class WebdriverBrowserProvider implements BrowserProvider { ...this.options, logLevel: 'error', capabilities: this.buildCapabilities(), - }); + }) // closest we can do as for detecting browser crash setImmediate(async () => { - while(true) { + while (true) { try { await this.browser?.getTitle() - } catch { + } + catch { const session = this.project.vitest._browserSessions.getSession(sessionId) session?.reject(new Error('Page crashed when executing tests')) } From fc4f64abe5bb6750a724a44d2f75f7fd6793fbb5 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 19:54:39 -0300 Subject: [PATCH 19/28] better crashing strategy --- .../browser-crash/browser-crash.test.ts | 17 +++++++---------- .../fixtures/browser-crash/vitest.config.ts | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/test/browser/fixtures/browser-crash/browser-crash.test.ts b/test/browser/fixtures/browser-crash/browser-crash.test.ts index da996d37394c..eccc9f375616 100644 --- a/test/browser/fixtures/browser-crash/browser-crash.test.ts +++ b/test/browser/fixtures/browser-crash/browser-crash.test.ts @@ -1,15 +1,12 @@ +import { commands } from '@vitest/browser/context' import { it } from 'vitest' -it('fails gracefully when browser crashes', async () => { - const parentDiv = document.createElement('div') - let currentDiv = parentDiv - - // Simulate crash by adding a large number of nodes - for (let i = 0; i < 20000; i++) { - const newDiv = document.createElement('div') - currentDiv.appendChild(newDiv) - currentDiv = newDiv +declare module '@vitest/browser/context' { + interface BrowserCommands { + forceCrash: () => Promise } +} - document.body.appendChild(parentDiv) +it('fails gracefully when browser crashes', async () => { + await commands.forceCrash() }) diff --git a/test/browser/fixtures/browser-crash/vitest.config.ts b/test/browser/fixtures/browser-crash/vitest.config.ts index b482d8bb44e6..3f23dfde5b97 100644 --- a/test/browser/fixtures/browser-crash/vitest.config.ts +++ b/test/browser/fixtures/browser-crash/vitest.config.ts @@ -1,11 +1,26 @@ import { fileURLToPath } from 'node:url' import { defineConfig } from 'vitest/config' import { instances, provider } from '../../settings' +import { BrowserCommand } from 'vitest/node' + +const forceCrash: BrowserCommand<[]> = async (context) => { + const browser = context.context.browser().browserType().name() + if (browser === 'chromium') { + await context.page.goto('chrome://crash') + } + + if (browser === 'firefox') { + await context.page.goto('about:crashcontent') + } + + throw new Error(`Browser crash not supported for ${browser}`) +} export default defineConfig({ cacheDir: fileURLToPath(new URL("./node_modules/.vite", import.meta.url)), test: { browser: { + commands: { forceCrash }, enabled: true, provider, instances: instances.map(instance => ({ From 346c2efb27a8601074406aa7b9a664a94cf1afb5 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 19:54:57 -0300 Subject: [PATCH 20/28] dont test crash on webkit --- test/browser/specs/browser-crash.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/browser/specs/browser-crash.test.ts b/test/browser/specs/browser-crash.test.ts index e0326dccf5a7..bff4836d8c80 100644 --- a/test/browser/specs/browser-crash.test.ts +++ b/test/browser/specs/browser-crash.test.ts @@ -1,10 +1,14 @@ import { expect, test } from 'vitest' -import { runBrowserTests } from './utils' +import { instances, runBrowserTests } from './utils' test('fails gracefully when browser crashes', async () => { const { stderr } = await runBrowserTests({ root: './fixtures/browser-crash', reporters: [['verbose', { isTTY: false }]], + browser: { + // webkit has no support for simulating browser crash + instances: instances.filter(item => item.name !== 'webkit'), + }, }) expect(stderr).contains('Page crashed when executing tests') From 39bc395839b600ec7409f7ae3dad9fee85eeec52 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 20:08:09 -0300 Subject: [PATCH 21/28] undo webdriver changes --- packages/browser/src/node/providers/webdriver.ts | 13 ------------- test/browser/specs/browser-crash.test.ts | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/browser/src/node/providers/webdriver.ts b/packages/browser/src/node/providers/webdriver.ts index 5326abf581f6..62f28f443adb 100644 --- a/packages/browser/src/node/providers/webdriver.ts +++ b/packages/browser/src/node/providers/webdriver.ts @@ -80,19 +80,6 @@ export class WebdriverBrowserProvider implements BrowserProvider { capabilities: this.buildCapabilities(), }) - // closest we can do as for detecting browser crash - setImmediate(async () => { - while (true) { - try { - await this.browser?.getTitle() - } - catch { - const session = this.project.vitest._browserSessions.getSession(sessionId) - session?.reject(new Error('Page crashed when executing tests')) - } - } - }) - return this.browser } diff --git a/test/browser/specs/browser-crash.test.ts b/test/browser/specs/browser-crash.test.ts index bff4836d8c80..4a47c37ec945 100644 --- a/test/browser/specs/browser-crash.test.ts +++ b/test/browser/specs/browser-crash.test.ts @@ -1,7 +1,7 @@ import { expect, test } from 'vitest' -import { instances, runBrowserTests } from './utils' +import { instances, provider, runBrowserTests } from './utils' -test('fails gracefully when browser crashes', async () => { +test.runIf(provider === 'playwright')('fails gracefully when browser crashes', async () => { const { stderr } = await runBrowserTests({ root: './fixtures/browser-crash', reporters: [['verbose', { isTTY: false }]], From 77b89728f9a16678a0617cad3708806bef3145b2 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 20:10:28 -0300 Subject: [PATCH 22/28] remove unneeded code --- packages/browser/src/node/providers/webdriver.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/browser/src/node/providers/webdriver.ts b/packages/browser/src/node/providers/webdriver.ts index 62f28f443adb..fe80067e39f3 100644 --- a/packages/browser/src/node/providers/webdriver.ts +++ b/packages/browser/src/node/providers/webdriver.ts @@ -56,7 +56,7 @@ export class WebdriverBrowserProvider implements BrowserProvider { } } - async openBrowser(sessionId: string) { + async openBrowser() { if (this.browser) { return this.browser } @@ -120,8 +120,8 @@ export class WebdriverBrowserProvider implements BrowserProvider { return capabilities } - async openPage(sessionId: string, url: string) { - const browserInstance = await this.openBrowser(sessionId) + async openPage(_sessionId: string, url: string) { + const browserInstance = await this.openBrowser() await browserInstance.url(url) } From 1a90e073018369821f98ab37dc3adab657a7bb3c Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 20:26:36 -0300 Subject: [PATCH 23/28] better assertion for prettyDOM test --- packages/utils/src/display.ts | 2 +- .../test/__snapshots__/utils.test.ts.snap | 91 +------------------ test/browser/test/utils.test.ts | 11 +-- 3 files changed, 11 insertions(+), 93 deletions(-) diff --git a/packages/utils/src/display.ts b/packages/utils/src/display.ts index decb2cea8b90..e7c0a0678304 100644 --- a/packages/utils/src/display.ts +++ b/packages/utils/src/display.ts @@ -77,7 +77,7 @@ export function stringify( const MAX_DEPTH = Number.MAX_SAFE_INTEGER const nextMaxDepth = maxDepth > MAX_DEPTH ? MAX_DEPTH : Math.floor(maxDepth / 2) return result.length >= MAX_LENGTH && maxDepth > 1 - ? stringify(object, nextMaxDepth) + ? stringify(object, nextMaxDepth, { maxLength, ...options }) : result } diff --git a/test/browser/test/__snapshots__/utils.test.ts.snap b/test/browser/test/__snapshots__/utils.test.ts.snap index be100fcbc944..60fb56d24d77 100644 --- a/test/browser/test/__snapshots__/utils.test.ts.snap +++ b/test/browser/test/__snapshots__/utils.test.ts.snap @@ -36,93 +36,12 @@ exports[`prints the element with attributes 1`] = ` " `; -exports[`should handle large nested DOM 1`] = ` +exports[`should handle DOM content bigger than maxLength 1`] = ` "
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..." +
+
+
+..." `; diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index 8d4bd15270ed..aefb710c6009 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -38,11 +38,10 @@ test('prints the element with attributes', async () => { expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() }) -test('should handle large nested DOM', async () => { - const depth = 20000 +test('should handle DOM content bigger than maxLength', async () => { + const depth = 100 + const maxContent = 100 - // if we try to manipulate dom to add 20000 divs, we get - // max depth exceeded error const openingTags = '
'.repeat(depth) const closingTags = '
'.repeat(depth) const domString = `${openingTags}${closingTags}` @@ -51,5 +50,5 @@ test('should handle large nested DOM', async () => { parentDiv.innerHTML = domString document.body.appendChild(parentDiv) - expect(await commands.stripVTControlCharacters(prettyDOM())).toMatchSnapshot() -}, { timeout: 120000 }) + expect(await commands.stripVTControlCharacters(prettyDOM(undefined, maxContent))).toMatchSnapshot() +}) From 0002e1b96a98fd30a04a153634fb9086493b9a3a Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 20:35:41 -0300 Subject: [PATCH 24/28] update maxContent for readability --- test/browser/test/utils.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index aefb710c6009..f8515d89dd5b 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -40,7 +40,7 @@ test('prints the element with attributes', async () => { test('should handle DOM content bigger than maxLength', async () => { const depth = 100 - const maxContent = 100 + const maxContent = 99 const openingTags = '
'.repeat(depth) const closingTags = '
'.repeat(depth) From 891036d2fe234892468f4d25b037a6661194ee0f Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 20:36:00 -0300 Subject: [PATCH 25/28] adjust test so test counter is not dynamic --- test/browser/specs/browser-crash.test.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/browser/specs/browser-crash.test.ts b/test/browser/specs/browser-crash.test.ts index 4a47c37ec945..fee4f1c4769c 100644 --- a/test/browser/specs/browser-crash.test.ts +++ b/test/browser/specs/browser-crash.test.ts @@ -1,15 +1,17 @@ import { expect, test } from 'vitest' import { instances, provider, runBrowserTests } from './utils' -test.runIf(provider === 'playwright')('fails gracefully when browser crashes', async () => { - const { stderr } = await runBrowserTests({ - root: './fixtures/browser-crash', - reporters: [['verbose', { isTTY: false }]], - browser: { - // webkit has no support for simulating browser crash - instances: instances.filter(item => item.name !== 'webkit'), - }, - }) +test('fails gracefully when browser crashes', async () => { + if (provider === 'playwright') { + const { stderr } = await runBrowserTests({ + root: './fixtures/browser-crash', + reporters: [['verbose', { isTTY: false }]], + browser: { + // webkit has no support for simulating browser crash + instances: instances.filter(item => item.name !== 'webkit'), + }, + }) - expect(stderr).contains('Page crashed when executing tests') + expect(stderr).contains('Page crashed when executing tests') + } }) From ed80dc4df1e2cc1d4edf47aca2c663ea9d16fb5e Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 21:06:28 -0300 Subject: [PATCH 26/28] use different depth and maxContent values for better snapshots --- test/browser/test/utils.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/browser/test/utils.test.ts b/test/browser/test/utils.test.ts index f8515d89dd5b..f6de6683ebe9 100644 --- a/test/browser/test/utils.test.ts +++ b/test/browser/test/utils.test.ts @@ -39,8 +39,8 @@ test('prints the element with attributes', async () => { }) test('should handle DOM content bigger than maxLength', async () => { - const depth = 100 - const maxContent = 99 + const depth = 200 + const maxContent = 150 const openingTags = '
'.repeat(depth) const closingTags = '
'.repeat(depth) From 63073274b186e1fd6b83c7610d2da7bf37cd1ced Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Wed, 15 Jan 2025 21:20:19 -0300 Subject: [PATCH 27/28] use test.runIf in browser crashing test --- test/browser/specs/browser-crash.test.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/browser/specs/browser-crash.test.ts b/test/browser/specs/browser-crash.test.ts index fee4f1c4769c..76428b0e23f5 100644 --- a/test/browser/specs/browser-crash.test.ts +++ b/test/browser/specs/browser-crash.test.ts @@ -1,17 +1,17 @@ import { expect, test } from 'vitest' import { instances, provider, runBrowserTests } from './utils' -test('fails gracefully when browser crashes', async () => { - if (provider === 'playwright') { - const { stderr } = await runBrowserTests({ - root: './fixtures/browser-crash', - reporters: [['verbose', { isTTY: false }]], - browser: { - // webkit has no support for simulating browser crash - instances: instances.filter(item => item.name !== 'webkit'), - }, - }) +// TODO handle webdriverio. Currently they +// expose no trustable way to detect browser crashes. +test.runIf(provider === 'playwright')('fails gracefully when browser crashes', async () => { + const { stderr } = await runBrowserTests({ + root: './fixtures/browser-crash', + reporters: [['verbose', { isTTY: false }]], + browser: { + // webkit has no support for simulating browser crash + instances: instances.filter(item => item.name !== 'webkit'), + }, + }) - expect(stderr).contains('Page crashed when executing tests') - } + expect(stderr).contains('Page crashed when executing tests') }) From 90600e833b5e808418f2a6ca78d78761cc398bc0 Mon Sep 17 00:00:00 2001 From: Lucas Correia Date: Thu, 16 Jan 2025 07:37:30 -0300 Subject: [PATCH 28/28] pr review fix --- packages/utils/src/display.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/utils/src/display.ts b/packages/utils/src/display.ts index e7c0a0678304..69d7bef51322 100644 --- a/packages/utils/src/display.ts +++ b/packages/utils/src/display.ts @@ -74,10 +74,8 @@ export function stringify( } // Prevents infinite loop https://github.com/vitest-dev/vitest/issues/7249 - const MAX_DEPTH = Number.MAX_SAFE_INTEGER - const nextMaxDepth = maxDepth > MAX_DEPTH ? MAX_DEPTH : Math.floor(maxDepth / 2) return result.length >= MAX_LENGTH && maxDepth > 1 - ? stringify(object, nextMaxDepth, { maxLength, ...options }) + ? stringify(object, Math.floor(Math.min(maxDepth, Number.MAX_SAFE_INTEGER) / 2), { maxLength, ...options }) : result }