Skip to content

fixes flaky fixtures#308295

Merged
hediet merged 1 commit intomainfrom
hediet/b/international-reindeer
Apr 7, 2026
Merged

fixes flaky fixtures#308295
hediet merged 1 commit intomainfrom
hediet/b/international-reindeer

Conversation

@hediet
Copy link
Copy Markdown
Member

@hediet hediet commented Apr 7, 2026

No description provided.

Copilot AI review requested due to automatic review settings April 7, 2026 18:32
@hediet hediet enabled auto-merge (rebase) April 7, 2026 18:32
@hediet hediet self-assigned this Apr 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Screenshot Changes

Base: fc99d59e Current: e8ff4a64

Changed (144)

sessions/agentFeedback/agentFeedbackEditorOverlayWidget/ZeroOfZero/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/SingleFeedback/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/SingleFeedback/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/FirstOfThree/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/FirstOfThree/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/ReviewOnlyTwoComments/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/ReviewOnlyTwoComments/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/MiddleOfThree/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/MiddleOfThree/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/MixedFourComments/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/MixedFourComments/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/LastOfThree/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/LastOfThree/Light
Before After
before after
sessions/aiCustomizationShortcutsWidget/WithMcpServers/Dark
Before After
before after
sessions/aiCustomizationShortcutsWidget/WithMcpServers/Light
Before After
before after
sessions/aiCustomizationShortcutsWidget/WithCounts/Dark
Before After
before after
sessions/aiCustomizationShortcutsWidget/WithCounts/Light
Before After
before after
chat/aiStats/AiStatsHover/Dark
Before After
before after
chat/aiStats/AiStatsHover/Light
Before After
before after
chat/aiStats/AiStatsHoverNoData/Dark
Before After
before after
chat/aiStats/AiStatsHoverNoData/Light
Before After
before after
editor/inlineCompletions/SideBySideView/Light
Before After
before after
editor/inlineCompletions/WordReplacementView/Dark
Before After
before after
editor/inlineCompletions/WordReplacementView/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorOverlayWidget/ZeroOfZero/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/CollapsedSingleComment/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/CollapsedSingleComment/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedSingleComment/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedSingleComment/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/CollapsedMultiComment/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/CollapsedMultiComment/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedMultiComment/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedMultiComment/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedFocusedFeedback/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedFocusedFeedback/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedReviewOnly/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedReviewOnly/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedMixedComments/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedMixedComments/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedFocusedReviewComment/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedFocusedReviewComment/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedReviewSuggestion/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedReviewSuggestion/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedPRReviewOnly/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedPRReviewOnly/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedAllSourcesMixed/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedAllSourcesMixed/Light
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedFocusedPRReview/Dark
Before After
before after
sessions/agentFeedback/agentFeedbackEditorWidget/ExpandedFocusedPRReview/Light
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceSelectedCheckedEmpty/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceSelectedCheckedEmpty/Light
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceSelectedCheckedFilled/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceSelectedCheckedFilled/Light
Before After
before after
sessions/runScriptCustomTaskWidget/UserSelectedCheckedEmpty/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/UserSelectedCheckedEmpty/Light
Before After
before after
sessions/runScriptCustomTaskWidget/UserSelectedCheckedFilled/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/UserSelectedCheckedFilled/Light
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceUnavailableCheckedEmpty/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceUnavailableCheckedEmpty/Light
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceUnavailableCheckedFilled/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/WorkspaceUnavailableCheckedFilled/Light
Before After
before after
sessions/runScriptCustomTaskWidget/ExistingUserTaskLockedChecked/Dark
Before After
before after
sessions/runScriptCustomTaskWidget/ExistingUserTaskLockedChecked/Light
Before After
before after
sessions/aiCustomizationShortcutsWidget/Expanded/Dark
Before After
before after
sessions/aiCustomizationShortcutsWidget/Expanded/Light
Before After
before after
chat/chatProgressContentPart/WithCustomIcon/Dark
Before After
before after
chat/chatProgressContentPart/WithCustomIcon/Light
Before After
before after
chat/chatQuestionCarousel/SingleTextQuestion/Dark
Before After
before after
chat/chatQuestionCarousel/SingleTextQuestion/Light
Before After
before after
chat/chatQuestionCarousel/SingleSelectQuestion/Dark
Before After
before after
chat/chatQuestionCarousel/SingleSelectQuestion/Light
Before After
before after
chat/chatQuestionCarousel/MultiSelectQuestion/Dark
Before After
before after
chat/chatQuestionCarousel/MultiSelectQuestion/Light
Before After
before after
chat/chatQuestionCarousel/MultipleQuestions/Dark
Before After
before after
chat/chatQuestionCarousel/MultipleQuestions/Light
Before After
before after
chat/chatQuestionCarousel/NoSkip/Dark
Before After
before after
chat/chatQuestionCarousel/NoSkip/Light
Before After
before after
chat/promptFilePickers/PromptFiles/Dark
Before After
before after
chat/promptFilePickers/PromptFiles/Light
Before After
before after
chat/promptFilePickers/InstructionFilesWithAgentInstructions/Dark
Before After
before after
chat/promptFilePickers/InstructionFilesWithAgentInstructions/Light
Before After
before after
chat/aiCustomizations/aiCustomizationListWidget/InstructionsTabWithItems/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationListWidget/InstructionsTabWithItems/Light
Before After
before after
chat/aiCustomizations/aiCustomizationListWidget/InstructionsTabEmpty/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationListWidget/InstructionsTabEmpty/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/LocalHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/LocalHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/CliHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/CliHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/ClaudeHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/ClaudeHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/Sessions/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/Sessions/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SessionsSkillsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SessionsSkillsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SkillsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SkillsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/InstructionsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/InstructionsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginBrowseMode/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginBrowseMode/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabNarrow/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTabNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTabNarrow/Light
Before After
before after
baseUI/Buttons/Dark
Before After
before after
baseUI/Buttons/Light
Before After
before after
baseUI/ButtonBar/Dark
Before After
before after
baseUI/ButtonBar/Light
Before After
before after
baseUI/Toggles/Dark
Before After
before after
baseUI/Toggles/Light
Before After
before after
editor/codeActionList/SimpleQuickFixes/Dark
Before After
before after
editor/codeActionList/SimpleQuickFixes/Light
Before After
before after
editor/inlineCompletions/SideBySideView/Dark
Before After
before after
editor/inlineCompletionsExtras/HintsToolbar/Dark
Before After
before after
editor/inlineCompletionsExtras/HintsToolbar/Light
Before After
before after
editor/inlineCompletionsExtras/HintsToolbarHovered/Dark
Before After
before after
editor/inlineCompletionsExtras/HintsToolbarHovered/Light
Before After
before after
editor/inlineCompletionsExtras/JumpToHint/Dark
Before After
before after
editor/inlineCompletionsExtras/JumpToHint/Light
Before After
before after
editor/inlineCompletionsExtras/GutterMenu/Dark
Before After
before after
editor/inlineCompletionsExtras/GutterMenu/Light
Before After
before after
editor/suggestWidget/MethodCompletions/Dark
Before After
before after
editor/suggestWidget/MethodCompletions/Light
Before After
before after
editor/suggestWidget/MixedKinds/Dark
Before After
before after
editor/suggestWidget/MixedKinds/Light
Before After
before after

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to reduce flakiness in the component fixture/screenshot pipeline by making fixture rendering more deterministic (scheduler control + disabling animations) and ensuring required assets/services are available during CI screenshot runs.

Changes:

  • Add global fixture CSS to disable animations/transitions during component rendering.
  • Refactor fixture render scheduling/wait logic using TimeTravelScheduler + new AsyncSchedulerProcessor.waitFor(...).
  • Adjust fixture service stubbing and CI workflow (codicon font) to prevent runtime/asset-related instability.
Show a summary per file
File Description
src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts Imports fixture CSS, tweaks render scheduling/waiting, and adds a stub createModelReference implementation.
src/vs/workbench/test/browser/componentFixtures/fixtures.css Introduces styles intended to disable animations/transitions in fixtures.
src/vs/workbench/test/browser/componentFixtures/chat/chatInput.fixture.ts Updates service wiring for the chat input fixture (moves stubbing responsibility, adds IFileDialogService).
src/vs/base/test/common/timeTravelScheduler.ts Refactors scheduler processor internals and adds waitFor(...) timeout helper.
.github/workflows/screenshot-test.yml Copies codicon.ttf into the expected source location before transpiling/running screenshots.

Copilot's findings

Comments suppressed due to low confidence (3)

src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:660

  • installFakeRunWhenIdle(...) is added to disposableStore, but the TimeTravelScheduler + AsyncSchedulerProcessor backing it are disposed via schedulerStore.dispose() right after actualRender(). After that point, any runWhenIdle callbacks scheduled by components will enqueue work onto a scheduler that is no longer being processed, which can leave parts of the UI permanently stale or leak queued tasks. Either keep the scheduler/processor alive for the fixture lifetime, or dispose/restore the fake runWhenIdle together with schedulerStore (e.g. register the fake runWhenIdle disposable in schedulerStore).

This issue also appears in the following locations of the same file:

  • line 662
  • line 662
				schedulerStore.add(scheduler.installGlobally());
				disposableStore.add(installFakeRunWhenIdle((_targetWindow, callback, _timeout?) => {
					return scheduler.schedule({
						time: scheduler.now,
						run: () => {
							const deadline: IdleDeadline = {
								didTimeout: true,
								timeRemaining: () => 50,
							};
							callback(deadline);
						},
						source: {
							toString() { return 'runWhenIdle'; },
							stackTrace: undefined,
						},
					});
				}));

src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:673

  • The previous overall render timeout guard was removed. p.waitFor(1000) only times out the scheduler queue wait; if options.render(...) returns a Promise that hangs (or awaits real timers/events), the Promise.all([...]) can now block indefinitely and hang the screenshot run/CI job. Consider restoring an overall timeout around the combined render work (e.g. race the whole actualRender()/Promise.all against a real-time timeout) so failures fail fast instead of hanging.
				const result = options.render({ container, disposableStore, theme });

				const p2 = p.waitFor(1000);

				await Promise.all([
					result instanceof Promise ? result : Promise.resolve(),
					p2,
				]);
			}

			await actualRender();

src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts:669

  • result instanceof Promise is a brittle way to detect async renders (it won’t await non-native thenables, and it’s unnecessary here). Using await result (works for both void and thenables) or Promise.resolve(result) would make this more robust and simpler.
				const result = options.render({ container, disposableStore, theme });

				const p2 = p.waitFor(1000);

				await Promise.all([
					result instanceof Promise ? result : Promise.resolve(),
					p2,
				]);
  • Files reviewed: 5/5 changed files
  • Comments generated: 3

Comment thread src/vs/workbench/test/browser/componentFixtures/fixtures.css
Comment thread src/vs/workbench/test/browser/componentFixtures/fixtureUtils.ts
Comment on lines +172 to +179
waitFor(virtualTimeMs: number): Promise<void> {
return Promise.race([
this.waitForEmptyQueue(),
new Promise<void>((_resolve, reject) =>
originalGlobalValues.setTimeout(() => {
const lastTasks = this._history.slice(-10).map(h => `${h.source.toString()}: ${h.source.stackTrace}`);
reject(new Error(`waitFor timed out after ${virtualTimeMs}ms (processed ${this._history.length} tasks, ${this.scheduler.getScheduledTasks().length} pending). These are the last ${lastTasks.length} scheduled tasks:\n${lastTasks.join('\n\n\n')}`));
}, virtualTimeMs)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter name virtualTimeMs is misleading here because waitFor uses a real setTimeout to enforce a wall-clock timeout (it doesn’t advance/measure the TimeTravelScheduler's virtual time). Consider renaming to timeoutMs (or similar) to make the behavior clear to callers.

Suggested change
waitFor(virtualTimeMs: number): Promise<void> {
return Promise.race([
this.waitForEmptyQueue(),
new Promise<void>((_resolve, reject) =>
originalGlobalValues.setTimeout(() => {
const lastTasks = this._history.slice(-10).map(h => `${h.source.toString()}: ${h.source.stackTrace}`);
reject(new Error(`waitFor timed out after ${virtualTimeMs}ms (processed ${this._history.length} tasks, ${this.scheduler.getScheduledTasks().length} pending). These are the last ${lastTasks.length} scheduled tasks:\n${lastTasks.join('\n\n\n')}`));
}, virtualTimeMs)
waitFor(timeoutMs: number): Promise<void> {
return Promise.race([
this.waitForEmptyQueue(),
new Promise<void>((_resolve, reject) =>
originalGlobalValues.setTimeout(() => {
const lastTasks = this._history.slice(-10).map(h => `${h.source.toString()}: ${h.source.stackTrace}`);
reject(new Error(`waitFor timed out after ${timeoutMs}ms (processed ${this._history.length} tasks, ${this.scheduler.getScheduledTasks().length} pending). These are the last ${lastTasks.length} scheduled tasks:\n${lastTasks.join('\n\n\n')}`));
}, timeoutMs)

Copilot uses AI. Check for mistakes.
@hediet hediet merged commit da1fd60 into main Apr 7, 2026
27 checks passed
@hediet hediet deleted the hediet/b/international-reindeer branch April 7, 2026 18:54
@vs-code-engineering vs-code-engineering bot added this to the 1.116.0 milestone Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants