Testing in the IgniteUI Blazor (Lite) repository itself: the bUnit unit suite (tests/IgniteUI.Blazor.Tests — base classes, attribute/serialization specs, declarative interop wire contracts) and the Playwright integration suite (tests/IgniteUI.Blazor.Lite.IntegrationTests + TestBed — reflection-driven live-browser sweep, componentsConfig.json). Use when adding or changing tests in this repo, covering a new component, pinning interop behavior, or deciding which suite a check belongs in. Not for consumer-facing component usage — use igniteui-blazor-components for that.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Testing in the IgniteUI Blazor (Lite) repository itself: the bUnit unit suite (tests/IgniteUI.Blazor.Tests — base classes, attribute/serialization specs, declarative interop wire contracts) and the Playwright integration suite (tests/IgniteUI.Blazor.Lite.IntegrationTests + TestBed — reflection-driven live-browser sweep, componentsConfig.json). Use when adding or changing tests in this repo, covering a new component, pinning interop behavior, or deciding which suite a check belongs in. Not for consumer-facing component usage — use igniteui-blazor-components for that.
user-invocable
true
Testing in the IgniteUI Blazor (Lite) repo
Three test projects under tests/, two suites:
Project
Suite
What it is
IgniteUI.Blazor.Tests
Unit
xUnit + bUnit, multi-targeted net8.0/net9.0/net10.0; renders components in-process with a recording JS runtime — no browser
IgniteUI.Blazor.Lite.IntegrationTests
Integration
NUnit + Playwright; one generated test fixture per component
IgniteUI.Blazor.Lite.TestBed
(integration host)
Blazor app the integration tests drive; renders one component per run and sweeps its surface
Parent/child collection membership — a child registering itself into its parent's collection and leaving again over the child's lifetime
unit: plain bUnit facts in the parent's suite, in a #region Child collection lifecycle — membership only; name resolution off that collection is interop behavior and stays in the contract
unit: automated sweep (ScriptPropTests, all components at once — no per-contract entries, no integration coverage exists)
End-to-end prop/event/method behavior against the real web component in a real browser
integration: the TestBed sweep
Visual output, client-side component logic
integration / e2e — never unit
The two suites overlap on purpose but answer different questions: integration proves the full pipeline works end-to-end (but can't attribute a failure to a side of the boundary, and skips everything excluded in componentsConfig.json); interop contracts pin the .NET side of the wire protocol at unit speed, per member — including the members integration excludes — and can accommodate different implementations via the InteropHarness seam (InteropHarnessRegistry swaps stacks per component).
Unit suite (tests/IgniteUI.Blazor.Tests)
Base classes
BlazorComponentTestBase — bUnit BunitContext with setup IIgniteUIBlazor service, a recording JS runtime (JSRuntimeMode.Loose; every invocation recorded) and an Interop harness property (an InteropHarness, resolved per component type via InteropFor<TComponent>()). Default base for suites without an interop contract.
ComponentWithContractTestBase<TComponent> — adds a declarative ComponentContract<TComponent>, protected runners (VerifyMethodContract/VerifyPropContract/VerifyEventContract) that the suite exposes as one-liner [Fact]s, and an inherited Contract_SectionsHaveFacts guard that fails if a non-empty contract section has no runner fact. Exactly one suite per component carries the contract; sync/async method pairs are declared together via the twin overloads.
Running
dotnet test tests/IgniteUI.Blazor.Tests -f net10.0 --nologo --filter "FullyQualifiedName~<Name>Tests"
Iterate on one TFM (-f net10.0); finish with a full run on all TFMs (drop -f).
Contract failure stacks carry the violated contract line as the top frame — the test UI navigates to the spec, not the shared runner.
Conventions
Generally follow one file per component: <Name>Tests.cs holds <Name>Tests. A component's child components may share the parent's file (SelectTests.cs also holds SelectItemTests/SelectGroupTests/SelectHeaderTests; likewise Card, List, Dropdown, NavDrawer, Tabs, Stepper, TileManager, Tree, Rating, Slider) — that's the only permitted multi-class file. Cross-cutting suites (BaseControlTests, *SerializationTests, ScriptPropTests, Interop*Tests) are keyed to a class/behavior, not a component, and keep their own files.
New facts go into the existing <Name>Tests class; if the class carries a contract, plain bUnit facts sit alongside the contract runners in the same class.
Shared test helpers live in ElementAssertionExtensions.cs.
Readable arrange/act/assert in the test beats sharing. A little repetition across suites is fine; extract obvious repeated mechanics if needed, but ensure those are well documented and easy to grasp without breaking the flow of the test itself.
Skips need a mechanism reason. Bug-tracker or componentsConfig.json listings are not skip reasons. If a member's decode hits a gap in shared infrastructure the change doesn't own, cover it pinning current behavior and write the correct assertion commented out under a // TODO: explaining the gap — ready to uncomment when fixed. A gap in a component under construction is a bug to fix, not to pin — see the two authoring modes in the interop reference.
Components are partial — the generated src/components/Blazor/<Name>.cs is not the whole class; always check src/componentsBase/WebInputs/<Name>.cs for hand-written extensions before drawing conclusions.
Formatting: only dotnet format whitespace --folder is safe in this repo — a full dotnet format writes conflict markers into multi-targeted sources.
Integration suite (Playwright + TestBed)
One generic NUnit test per component (ComponentTest, fixture-sourced from the TestBed's
component list): it boots the TestBed app (in-memory by default), calls the browser-side
renderComponent('<IgbName>'), and asserts getErrors() returns nothing. The real work
happens inside the TestBed (Components/Pages/Home.razor): a reflection-driven sweep
over the component's public surface —
TestProps: sets each [Parameter] server-side with generated sample values and compares against the live web component's DOM property in the browser (TestUtil.PropertyValuesAreEqual, client value via stringifyObject).
TestEvents: dispatches synthetic events against the web component and verifies the bound .NET callbacks fire.
Method spies (spyOnMethod/checkOnSpy in wwwroot/app.js): invoking the .NET API must call the matching web-component method with the right args/result. Async methods only — the sweep filters to *Async and also excludes Get*Async getters; sync variants can't run on the Server-hosted TestBed (no in-process JS runtime), so sync variants, getters, and <Member>Script params have no integration coverage — the unit suite is their only net.
componentsConfig.json (in the TestBed project) gates the sweep per component:
ExcludedProps, ExcludedEvents, DependantProps/DependantMethods — each entry usually cites a BUG number or a shape the generic sweep can't model. An excluded member has no integration coverage at all — treat those as higher priority for the unit interop contract, never as members to skip there too.
Running
One-time: build, then install browsers — pwsh tests/IgniteUI.Blazor.Lite.IntegrationTests/bin/Debug/net<version>/playwright.ps1 install chromium.
dotnet test tests/IgniteUI.Blazor.Lite.IntegrationTests (or per component from the Test Explorer — fixtures are named by component).
.runsettings knobs: headless off for local debugging; useInMemoryClient: false to run against your own dotnet run instance of the TestBed.
Unit suite: bUnit facts for rendered attributes/markup; if the component has an interop surface (it sends interop invocations or registers JS-originated event handlers — the reference explains how to identify these per stack), add a ComponentContract per references/interop-contracts.md. For a brand-new component this works TDD-style: author the contract first from the intended API following the library's conventions; the contract doubles as the API design record (spec mode in the reference).
If it is a parent that collects children, or a child that registers with a parent, exercise that membership over the child's lifetime, not just at first render: the children are the collection in order, a disposed child leaves it, all disposed empties it. Keep these facts to membership and asserting resolution that are covered by the interop contract.
Integration: the sweep picks the component up automatically; add componentsConfig.json entries only for members the generic sweep genuinely cannot model (cite why), and mirror each exclusion with unit contract coverage.
Verify: unit full-suite on all TFMs, plus the component's integration fixture.