From fab7bc3c5afc904be197c871514cc30d86be313f Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 4 Jul 2026 13:04:11 -0700 Subject: [PATCH] Reset maxAtlasPages after tests that lower it setMaxAtlasPages mutates a static that lives for the page's lifetime, so a lowered cap silently leaked into every renderer built by later tests in the same file (their GL texture and shader sampler arrays were sized at the tiny cap, making tests order-dependent). Add resetMaxAtlasPages and call it in afterEach wherever the cap is lowered on a shared page. --- .../addon-webgl/test/WebglAtlasOverflow.test.ts | 9 ++------- addons/addon-webgl/test/WebglGlyph.test.ts | 4 ++++ .../test/WebglReproExperiment.test.ts | 5 ++++- .../test/WebglSingleTermStress.test.ts | 4 ++++ test/playwright/RendererTestUtils.ts | 17 +++++++++++++++++ 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/addons/addon-webgl/test/WebglAtlasOverflow.test.ts b/addons/addon-webgl/test/WebglAtlasOverflow.test.ts index 98a4c5944..9f866122c 100644 --- a/addons/addon-webgl/test/WebglAtlasOverflow.test.ts +++ b/addons/addon-webgl/test/WebglAtlasOverflow.test.ts @@ -23,6 +23,7 @@ import { captureRowSignatures, expectSignatureMatches, loadWebglStrict, + resetMaxAtlasPages, setMaxAtlasPages, writeAndWaitForRender } from '../../../test/playwright/RendererTestUtils'; @@ -96,13 +97,7 @@ test.describe('atlas page overflow (#322756 class)', () => { } finally { ctx.page.off('pageerror', onError); // Restore the default so a lowered cap can never leak into other tests. - await ctx.page.evaluate(() => { - const renderer = (window as any).term._core._renderService._renderer.value; - const atlas = renderer?._charAtlas; - if (atlas) { - (atlas.constructor as any).maxAtlasPages = undefined; - } - }).catch(() => { /* page may already be unusable after a crash */ }); + await resetMaxAtlasPages(ctx).catch(() => { /* page may already be unusable after a crash */ }); await ctx.page.close(); } }); diff --git a/addons/addon-webgl/test/WebglGlyph.test.ts b/addons/addon-webgl/test/WebglGlyph.test.ts index c6cf260ea..dff2c275e 100644 --- a/addons/addon-webgl/test/WebglGlyph.test.ts +++ b/addons/addon-webgl/test/WebglGlyph.test.ts @@ -23,6 +23,7 @@ import { expectSignatureMatches, floodDistinctGlyphs, loadWebglStrict, + resetMaxAtlasPages, setMaxAtlasPages, waitForRender, writeAndWaitForRender @@ -45,6 +46,9 @@ test.describe('WebGL glyph + atlas integrity', () => { await loadWebglStrict(ctx); }); + // A lowered page cap must not leak into renderers built by later tests. + test.afterEach(async () => await resetMaxAtlasPages(ctx)); + test('renders distinct, non-blank glyphs', async () => { await writeAndWaitForRender(ctx, 'A W .'); await assertTextureAtlasPresent(ctx); diff --git a/addons/addon-webgl/test/WebglReproExperiment.test.ts b/addons/addon-webgl/test/WebglReproExperiment.test.ts index 99034b940..67d64b9f2 100644 --- a/addons/addon-webgl/test/WebglReproExperiment.test.ts +++ b/addons/addon-webgl/test/WebglReproExperiment.test.ts @@ -14,7 +14,7 @@ */ import test, { expect } from '@playwright/test'; import { ITestContext, createTestContext, openTerminal } from '../../../test/playwright/TestUtils'; -import { captureRowSignatures, expectSignatureMatches, getAtlasPageCount, loadWebglStrict, setMaxAtlasPages, writeAndWaitForRender } from '../../../test/playwright/RendererTestUtils'; +import { captureRowSignatures, expectSignatureMatches, getAtlasPageCount, loadWebglStrict, resetMaxAtlasPages, setMaxAtlasPages, writeAndWaitForRender } from '../../../test/playwright/RendererTestUtils'; import { generateColoredAsciiFlood } from '../../../test/playwright/SyntheticTui'; const HEADER = ' HEADER_REF_0123456789'; @@ -27,6 +27,9 @@ test.describe('single-terminal merge integrity (#322756 class)', () => { test.skip(({ browserName }) => browserName !== 'chromium'); test.describe.configure({ timeout: 60000 }); + // A lowered page cap must not leak into renderers built by later tests. + test.afterEach(async () => await resetMaxAtlasPages(ctx)); + test('pinned header renders identically across 30 merge-heavy body redraws', async () => { await openTerminal(ctx, { cols: 80, rows: 24 }); await loadWebglStrict(ctx); diff --git a/addons/addon-webgl/test/WebglSingleTermStress.test.ts b/addons/addon-webgl/test/WebglSingleTermStress.test.ts index d4bbe9be4..fbe12d1bb 100644 --- a/addons/addon-webgl/test/WebglSingleTermStress.test.ts +++ b/addons/addon-webgl/test/WebglSingleTermStress.test.ts @@ -16,6 +16,7 @@ import { floodDistinctGlyphs, getAtlasPageCount, loadWebglStrict, + resetMaxAtlasPages, setMaxAtlasPages, waitForRender, writeAndWaitForRender @@ -37,6 +38,9 @@ test.describe('WebGL single-terminal heavy render + merge', () => { await loadWebglStrict(ctx); }); + // A lowered page cap must not leak into renderers built by later tests. + test.afterEach(async () => await resetMaxAtlasPages(ctx)); + test('heavy merge churn must not crash the GlyphRenderer (vscode#322756)', async () => { // Guard: heavy merges must not throw from GlyphRenderer.render. Note the // page cap here is lowered AFTER the renderer was built, so _atlasTextures diff --git a/test/playwright/RendererTestUtils.ts b/test/playwright/RendererTestUtils.ts index a3862c77f..e6d1e8593 100644 --- a/test/playwright/RendererTestUtils.ts +++ b/test/playwright/RendererTestUtils.ts @@ -292,6 +292,23 @@ export async function setMaxAtlasPages(ctx: ITestContext, maxAtlasPages: number) expect(applied, 'should be able to reach the texture atlas to set maxAtlasPages').toBe(true); } +/** + * Resets `maxAtlasPages` to undefined so the next constructed renderer re-derives it from GL + * capabilities. Call after any test that used {@link setMaxAtlasPages}: the static lives for + * the page's lifetime, so without a reset every terminal opened later in the same file builds + * its GL texture and shader sampler arrays at the lowered cap. + * @param ctx The test context. + */ +export async function resetMaxAtlasPages(ctx: ITestContext): Promise { + await ctx.page.evaluate(() => { + const renderer = (window as any).term?._core?._renderService?._renderer?.value; + const atlas = renderer?._charAtlas; + if (atlas) { + (atlas.constructor as any).maxAtlasPages = undefined; + } + }); +} + /** * Writes `chunks` screenfuls of distinct glyphs, rendering after each chunk. *