use-component-explorer

作者: microsoft

當專案使用元件瀏覽器(component explorer)且你處理UI相關工作(fixtures、截圖、視覺測試,新增或更改UI時請閱讀)時,請閱讀此技能。

npx skills add https://github.com/microsoft/vscode-team-kit --skill use-component-explorer

Skill: Use Component Explorer

Writing Fixtures

Fixture files end in .fixture.ts or .fixture.tsx and are auto-discovered by the Vite plugin.

Core Pattern

Every fixture has a render function that receives a container DOM element and a RenderContext:

import { defineFixture } from '@vscode/component-explorer';

export default defineFixture({
  render: (container) => {
    // Render your component into container
    return { dispose: () => { /* cleanup */ } };
  },
});

Render Context

The second argument to render provides:

  • signal — AbortSignal for cancellation (check signal.aborted or listen to 'abort')
defineFixture({
  render: async (container, { signal }) => {
    const data = await fetch('/api/data', { signal });
    container.textContent = await data.text();
  },
});

React Fixtures

import { createRoot } from 'react-dom/client';
import { defineFixture } from '@vscode/component-explorer';
import { MyComponent } from './MyComponent';

export default defineFixture({
  render: (container) => {
    const root = createRoot(container);
    root.render(<MyComponent />);
    return { dispose: () => root.unmount() };
  },
});

Fixture Groups

Group related fixtures in a single file:

import { defineFixture, defineFixtureGroup } from '@vscode/component-explorer';

export default defineFixtureGroup({
  Default: defineFixture({ render: (c) => { /* ... */ } }),
  WithError: defineFixture({ render: (c) => { /* ... */ } }),
  Disabled: defineFixture({ render: (c) => { /* ... */ } }),
});

Groups can have metadata (path prefix, labels):

export default defineFixtureGroup({ path: 'Forms/', labels: ['forms'] }, {
  Primary: defineFixture({ /* ... */ }),
  Secondary: defineFixture({ /* ... */ }),
});

Fixture Variants

For closely related variants rendered side-by-side:

import { defineFixture, defineFixtureGroup, defineFixtureVariants } from '@vscode/component-explorer';

export default defineFixtureGroup({
  Sizes: defineFixtureVariants({
    Small: defineFixture({ render: (c) => { /* ... */ } }),
    Medium: defineFixture({ render: (c) => { /* ... */ } }),
    Large: defineFixture({ render: (c) => { /* ... */ } }),
  }),
});

Background

Set background: 'dark' for components designed for dark backgrounds:

defineFixture({
  background: 'dark',
  render: (container) => { /* ... */ },
});

Important Rules

Fixtures Must Be Side-Effect Free

Fixtures must not mutate global state. Each fixture's render function should only modify the provided container element and return a dispose function that fully cleans up. No writes to document.body, global variables, localStorage, shared singletons, or other state outside the container. This ensures fixtures can be rendered in any order, in parallel, and multiple times without interference.

No Global Styles

Do not use global CSS selectors like :root, html, body, or *. Every style must be scoped to a class name (e.g. .app-root, .my-component). Components are rendered in isolation inside the explorer — global styles leak across fixtures and break the isolated rendering model.

App-level CSS files (resets, CSS variables on :root, etc.) are fine for the app itself, but they must not be imported by components or fixture files. Keep app-level styles in separate entry points (e.g. index.css imported only by the app's main.ts) so they are never loaded during fixture rendering. If a component needs shared variables or resets, apply them within the fixture's container element or via the project-local wrapper (see below).

Use a Local Wrapper Instead of defineFixture Directly

Do not use defineFixture / defineFixtureGroup from @vscode/component-explorer directly in fixture files. Instead, create a project-local wrapper (e.g. fixtureUtils.ts) that applies project-wide conventions (theme variants, shared styles, DI setup, disposable management). Fixture files then import from that local module.

This ensures consistency across all fixtures and makes it easy to evolve conventions in one place.

Example local wrapper:

// src/testing/fixtureUtils.ts
import { defineFixture, defineFixtureGroup, defineFixtureVariants } from '@vscode/component-explorer';

export { defineFixtureGroup };

interface MyFixtureContext {
  container: HTMLElement;
}

interface MyFixtureOptions {
  labels?: string[];
  render: (context: MyFixtureContext) => void | { dispose(): void } | Promise<void | { dispose(): void }>;
}

export function defineMyFixture(options: MyFixtureOptions) {
  return defineFixture({
    labels: options.labels,
    render: (container) => options.render({ container }),
  });
}

Fixture files then use the local wrapper:

// src/components/Button.fixture.tsx
import { defineMyFixture, defineFixtureGroup } from '../testing/fixtureUtils';
import { createRoot } from 'react-dom/client';
import { Button } from './Button';

export default defineFixtureGroup({
  Primary: defineMyFixture({
    labels: ['.screenshot'],
    render: ({ container }) => {
      const root = createRoot(container);
      root.render(<Button variant="primary">Click me</Button>);
      return { dispose: () => root.unmount() };
    },
  }),
});

See Project-Specific Wrapper Functions below for a more advanced example with theme variants and disposable management.

Recommended Patterns

Extract Render Functions

For complex fixtures, extract render logic into standalone named functions rather than inline lambdas. This improves readability and makes it easy to share setup across fixtures:

export default defineFixtureGroup({
  Buttons: defineFixture({
    labels: ['.screenshot'],
    render: renderButtons,
  }),
  InputBoxes: defineFixture({
    labels: ['.screenshot'],
    render: renderInputBoxes,
  }),
});

function renderButtons(container: HTMLElement): void {
  container.style.padding = '16px';
  container.style.display = 'flex';
  container.style.gap = '8px';
  // ... create and append button elements
}

function renderInputBoxes(container: HTMLElement): void {
  // ...
}

Set Explicit Container Dimensions

Fixtures should set explicit width/height on the container for deterministic screenshots:

function renderEditor(container: HTMLElement): void {
  container.style.width = '600px';
  container.style.height = '400px';
  // ...
}

Project-Specific Wrapper Functions

For large projects, create a shared utility file (e.g. fixtureUtils.ts) with wrapper functions that apply common setup to all fixtures. Examples:

  • Auto-create Dark/Light theme variants using defineFixtureVariants
  • Inject shared services or dependency injection containers
  • Manage cleanup via a disposable store
  • Apply project-wide styles or container setup
// fixtureUtils.ts — project-specific wrapper
import { defineFixture, defineFixtureVariants } from '@vscode/component-explorer';

interface MyFixtureContext {
  container: HTMLElement;
  disposables: { add<T extends { dispose(): void }>(d: T): T };
}

interface MyFixtureOptions {
  labels?: string[];
  render: (context: MyFixtureContext) => void | Promise<void>;
}

function defineMyFixture(options: MyFixtureOptions) {
  const createForTheme = (theme: 'dark' | 'light') => defineFixture({
    isolation: 'none',
    background: theme,
    render: (container) => {
      const disposables = new DisposableStore();
      applyTheme(container, theme);
      const result = options.render({ container, disposables });
      return isPromise(result) ? result.then(() => disposables) : disposables;
    },
  });
  return defineFixtureVariants(options.labels ? { labels: options.labels } : {}, {
    Dark: createForTheme('dark'),
    Light: createForTheme('light'),
  });
}

Then fixture files become concise:

import { defineMyFixture, defineThemedGroup } from './fixtureUtils';

export default defineThemedGroup({
  MyComponent: defineMyFixture({
    labels: ['.screenshot'],
    render: renderMyComponent,
  }),
});

function renderMyComponent({ container, disposables }: MyFixtureContext): void {
  container.style.width = '400px';
  // ...
}

Async Render with Services

When components need async setup (e.g. loading services, fetching data):

defineFixture({
  render: async (container, { signal }) => {
    const services = await createServices();
    const widget = services.createWidget(container, { /* options */ });
    return { dispose: () => widget.dispose() };
  },
});

Parameterized Render Functions

Share render logic across fixtures with different configurations:

interface WidgetFixtureOptions {
  code: string;
  width?: string;
  height?: string;
}

export default defineFixtureGroup({ path: 'editor/' }, {
  TypeScript: defineFixture({
    labels: ['.screenshot'],
    render: (container) => renderWidget({ code: tsCode, width: '600px', height: '400px' }, container),
  }),
  Markdown: defineFixture({
    labels: ['.screenshot'],
    render: (container) => renderWidget({ code: mdCode, width: '500px' }, container),
  }),
});

function renderWidget(options: WidgetFixtureOptions, container: HTMLElement): void {
  container.style.width = options.width ?? '400px';
  container.style.height = options.height ?? '300px';
  // ... setup widget with options.code
}

File Naming Convention

Place fixture files next to the component they test:

src/
  components/
    Button/
      Button.tsx
      Button.fixture.tsx       ← fixture file
    Input/
      Input.tsx
      Input.fixture.tsx

Or in a dedicated test directory (adjust the include glob in the vite plugin):

src/
  components/
    Button.tsx
test/
  componentFixtures/
    Button.fixture.ts

來自 microsoft 的更多技能

oss-growth
microsoft
開源增長駭客角色
agent-framework-azure-ai-py
microsoft
使用Microsoft Agent Framework Python SDK(agent-framework-azure-ai)构建Azure AI Foundry代理。适用于使用AzureAIAgentsProvider创建持久化代理、使用托管工具(代码解释器、文件搜索、网络搜索)、集成MCP服务器、管理对话线程或实现流式响应。涵盖函数工具、结构化输出和多工具代理。
development
airunway-aks-setup
microsoft
在AKS上設定AI Runway——從裸叢集到執行模型。涵蓋叢集驗證、控制器安裝、GPU評估、供應商設定及首次部署。時機:「設定AI Runway」、「上線AKS叢集」、「安裝AI Runway」、「airunway設定」、「部署模型至AKS」、「在AKS上進行GPU推論」、「在AKS上設定KAITO」、「在AKS上執行LLM」、「在AKS上使用vLLM」、「在AKS上設定模型服務」、「AI Runway控制器」。
devops
appinsights-instrumentation
microsoft
使用Azure Application Insights檢測Web應用程式的指南。提供遙測模式、SDK設定與組態參考。適用時機:如何檢測應用程式、App Insights SDK、遙測模式、什麼是App Insights、Application Insights指南、檢測範例、APM最佳實踐。
devops
applicationinsights-web-ts
microsoft
使用Application Insights JavaScript SDK(@microsoft/applicationinsights-web)為瀏覽器/Web應用程式進行檢測。適用於真實使用者監控(RUM)——頁面檢視、點擊、AJAX/fetch依賴、例外、自訂事件,以及與後端OpenTelemetry追蹤關聯的瀏覽器端GenAI代理追蹤。涵蓋SDK載入器指令碼與npm設定、框架擴充(React、React Native、Angular)、點擊分析、遙測初始化器,以及從瀏覽器發出的代理/工具/模型span的OTel GenAI語意慣例。
devops
azure-ai-anomalydetector-java
microsoft
使用適用於 Java 的 Azure AI 異常偵測器 SDK 建置異常偵測應用程式。在實作單變量/多變量異常偵測、時間序列分析或 AI 驅動監控時使用。
development
azure-ai-language-conversations-py
microsoft
使用 azure-ai-language-conversations Python SDK 實作對話語言理解(CLU)。當使用 ConversationAnalysisClient 分析對話意圖與實體、建置 NLP 功能,或將語言理解整合至應用程式時使用。
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 for Python。用於機器學習工作區、作業、模型、資料集、計算資源與管線。 觸發詞:「azure-ai-ml」、「MLClient」、「workspace」、「model registry」、「training jobs」、「datasets」。
development