소스 정보
- 저장소
- microsoft/webui
- 최근 소스 활동
- 2026년 8월 23일 18:02
- 감지된 SKILL.md 언어
- 영어
- 스타
- 82
- 포크
- 22
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/microsoft/webui --skill testing명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
| name | testing |
| description | Test patterns, fixture structure, and when to use E2E vs unit tests. |
Use this skill when writing or modifying tests in this repository.
Unit tests live alongside code in #[cfg(test)] modules. Integration tests go in each crate's tests/ directory.
cargo test -p microsoft-webui-handler # one crate
cargo test --workspace # all crates
cargo xtask test # via xtask (part of quality gate)
Every code change ships with tests:
| Change type | Requirement |
|---|---|
| New public API | At least one unit test per function/method |
| Bug fix | Regression test that fails without the fix |
| Performance change | Benchmark comparison (before/after) |
| Refactor | Existing tests pass unchanged |
Never remove, weaken, or #[ignore] an existing test unless explicitly asked.
webui-test-utils)The webui-test-utils crate provides common Rust test helpers, builders, and fixtures. Check it before writing new helpers - avoid duplicating across crates.
[dev-dependencies]
webui-test-utils = { path = "../webui-test-utils" }
The packages/webui-framework package uses Playwright for E2E tests. Each fixture is a mini WebUI app compiled and rendered by the real pipeline.
See tests/fixtures/README.md for the full reference.
tests/fixtures/<name>/
src/
index.html Page template (uses the component)
<tag-name>/
<tag-name>.html Component template (real WebUI syntax)
<tag-name>.css Component CSS (optional)
state.json Initial render state (all bound properties)
element.ts Component class (NO template registration)
<name>.spec.ts Playwright tests
webui.config.json Build options override (optional)
The test server (fixture-render.ts) auto-discovers fixtures with src/index.html, calls @microsoft/webui build() + render() to produce SSR HTML with template IIFEs, hydration markers, and inventory. The result is served at /<name>/fixture.html.
fixtures/<name>/src/index.html — page template:<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>My Fixture</title></head>
<body>
<test-widget label="Hello"></test-widget>
</body>
</html>
fixtures/<name>/src/test-widget/test-widget.html — component template:<span class="label">{{label}}</span>
<span class="count">{{count}}</span>
<button class="inc" @click="{increment()}">+</button>
fixtures/<name>/state.json — initial state:{ "label": "Hello", "count": 0 }
fixtures/<name>/element.ts — component class only:// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { WebUIElement, attr, observable } from '../../../src/index.js';
export class TestWidget extends WebUIElement {
@attr label = 'Hello';
@observable count = 0;
increment(): void {
this.count += 1;
}
}
TestWidget.define('test-widget');
fixtures/<name>/<name>.spec.ts — Playwright tests:// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { expect, test } from '@playwright/test';
test.describe('widget fixture', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/<name>/fixture.html');
await page.waitForFunction(() => {
const el = document.querySelector('test-widget');
return el && (el as any).$ready === true;
});
});
test('renders SSR content', async ({ page }) => {
await expect(page.locator('test-widget .label')).toHaveText('Hello');
await expect(page.locator('test-widget .count')).toHaveText('0');
});
test('updates on click', async ({ page }) => {
await page.locator('test-widget .inc').click();
await (page.()).();
});
});
| Feature | Syntax |
|---|---|
| Text binding | {{propertyName}} |
| Event binding | @click="{handler()}" or @click="{handler(e)}" |
| Boolean attribute | ?disabled="{{isDisabled}}" |
| Dynamic attribute | href="{{url}}" |
| Mixed attribute | href="/items/{{id}}" |
| Complex property | :items="{{items}}" |
| Element ref | w-ref="{myElement}" |
| Conditional | <if condition="show">...</if> |
| Negation | <if condition="!hidden">...</if> |
| Comparison | <if condition="count > 0">...</if> |
| Compound | <if condition="active && !busy">...</if> |
| Loop | <for each="item in items">...</for> |
| Nested loop | <for each="group in groups">...<for each="item in group.items">...</for></for> |
| Shadow DOM | <template shadowrootmode="open">...</template> |
| Root event | <template shadowrootmode="open" @click="{handler(e)}"> |
| Slot | <slot></slot> |
Components only created via document.createElement() (not in any template) need a false <if> in the page template to make their template IIFEs available:
<body>
<my-host></my-host>
<if condition="showChild"><my-child></my-child></if>
</body>
With state.json: { "showChild": false }.
Create webui.config.json to override build options:
{ "css": "module" }
Ordinary unwrapped fixture components exercise the Shadow default. Set
"dom": "light" in webui.config.json to exercise global Light rendering; a
fixture component requiring Shadow inside that build must author a sole
top-level <template shadowrootmode="open">. A sole bare top-level
<template> explicitly exercises Light even in the default Shadow fixture.
See fixtures/dom-default/ and
fixtures/light-dom/ for both paths through the real pipeline. Reserve manual
registerCompiledTemplate fixtures for raw template-metadata scenarios.
cd packages/webui-framework
pnpm build # build the framework
pnpm test # unit + E2E tests
npx playwright test # E2E only
npx playwright test tests/fixtures/<name>/ # one fixture
@microsoft/webui-test-support)The packages/webui-test-support package provides:
registerCompiledTemplate(name, meta) — register a raw TemplateMeta object (for manual/light-DOM fixtures)renderTemplateScript(name, meta) — render a template as an inline <script> tagrenderFixtures({ fixturesRoot }) — build+render all pipeline fixturesbuildFixtureEntries({ ... }) — bundle element.ts files via esbuildstartFixtureServer({ ... }) — start the HTTP fixture server| Scenario | Tool |
|---|---|
| Rust crate logic (parsing, rendering, state, expressions) | #[test] unit tests |
| Rust crate integration (full pipeline) | tests/ integration tests |
| Rust performance | cargo bench with Criterion |
| Framework hydration, reactive updates, DOM behavior | Playwright E2E fixtures |
| Router navigation, lazy loading, chain diffing | Playwright E2E fixtures |
| Template metadata encoding/decoding | Node unit tests (pnpm test:unit) |