microsoft / microsoft/vscode

Component fixture screenshots render codicons as tofu — harness installs icon content rules but never the codicon @font-face

Open
#329,693 0 comments 0 reactions 1 assignee Claimed by @hediet View on GitHub
engineering testing
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

## Summary

The component fixture harness installs the codicon **content** rules for every fixture but never the codicon **`@font-face`**. The result is that every codicon resolves to a code point with no font behind it and renders as tofu (▯). Since screenshots are captured from these fixtures, the CI screenshot baselines for the large majority of fixtures currently validate a UI with visibly broken icons.

Discovered incidentally while rendering a new fixture — the icons were missing, and adding a fixture-scoped `@font-face` made them appear.

## Mechanism

Two halves of codicon styling live in different places, and the harness only wires up one of them.

1. **Content rules — installed globally, for every fixture.** `ensureGlobalStylesInstalled()` adopts `getIconsStyleSheetCached()`, which produces `.codicon-check:before { content: "\eab2" }` and friends:

https://github.com/microsoft/vscode/blob/main/src/vs/workbench/test/browser/componentFixtures/fixtureUtilsCss.ts#L216-L224

2. **The `@font-face` — never installed by the harness.** It lives in `src/vs/base/browser/ui/codicons/codicon/codicon.css` and is only reachable through `src/vs/base/browser/ui/codicons/codiconStyles.ts`, which nothing in the shared harness imports.

Because the component explorer builds a per-fixture module graph (`ComponentExplorerPlugin({ include: 'src/**/*.fixture.ts' })` in `build/rspack/rspack.serve-out.config.mts`), the font is only present for fixtures that import `codiconStyles.js` themselves.

Today that is **10 of 63 fixtures**:

```
editor/suggestWidget.fixture.ts
editor/findWidget.fixture.ts
editor/codeActionList.fixture.ts
editor/peekReference.fixture.ts
editor/renameWidget.fixture.ts
editor/inlineChatAffordance.fixture.ts
editor/inlineChatZoneWidget.fixture.ts
editor/inlineCompletions/other.fixture.ts
sessions/contrib/agentFeedback/.../agentFeedbackInputWidget.fixture.ts
sessions/contrib/changes/.../agentsDiffEditor.fixture.ts
```

The other **53 fixtures get content code points with no font → tofu**.

## Second, related trap: the `.ttf` is gitignored

`src/vs/base/browser/ui/codicons/codicon/codicon.ttf` is gitignored (`.gitignore:11`) and only materialized by a CI step:

https://github.com/microsoft/vscode/blob/main/.github/workflows/component-fixtures.yml#L71-L72

```yaml
- name: Copy codicons
run: cp node_modules/@vscode/codicons/dist/codicon.ttf src/vs/base/browser/ui/codicons/codicon/codicon.ttf
```

So `codicon.css`'s relative `src: url("./codicon.ttf")` only resolves once that copy has happened. Locally, even the 10 fixtures that *do* import `codiconStyles.js` render tofu unless the file happens to be present — meaning local renders and CI renders can silently disagree.

## Expected vs actual

- **Expected:** fixtures render codicons the way the product does, so screenshot baselines validate the real UI.
- **Actual:** ~53 of 63 fixtures render every codicon as tofu, and their committed baselines encode that.

## Suggested fix

Install the `@font-face` once in the shared harness, right next to the icon content rules it already installs, so no fixture has to remember to do it. Either:

- add `import '../../../../base/browser/ui/codicons/codiconStyles.js';` to `fixtureUtilsCss.ts`, or
- declare the `@font-face` in `fixtures.css` pointing at `node_modules/@vscode/codicons/dist/codicon.ttf`

The second option also sidesteps the gitignored-`.ttf` trap, since it does not depend on the CI copy step and resolves identically locally and in CI. This is the shape that was verified to work:

```css
@font-face {
font-family: "codicon";
font-display: block;
src: url("<...>/node_modules/@vscode/codicons/dist/codicon.ttf") format("truetype");
}
```

Once this lands, the per-fixture `codiconStyles.js` imports in the 10 fixtures above become redundant and can be removed.

## Impact on baselines

Expect a **large one-time screenshot baseline churn** — icons will appear across ~53 fixtures that previously showed tofu. That churn is the confirmation the bug was real, not a regression. Worth landing as an isolated commit so the diff is self-explanatory and reviewable.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.