Skip to content

test: consolidate interop contract DSL and unify the spec runner - #290

Merged
damyanpetev merged 1 commit into
masterfrom
dpetev/interop-consolidate-update
Aug 5, 2026
Merged

test: consolidate interop contract DSL and unify the spec runner#290
damyanpetev merged 1 commit into
masterfrom
dpetev/interop-consolidate-update

Conversation

@damyanpetev

Copy link
Copy Markdown
Member

Follow-up on #288 since that required some additions to the contract and it made sense to clean up the impl. some, but moved into separate PR.

Why

Covering IgbDropdown's Show/Toggle target overloads in the previous PR needed an argument that only exists once the component has rendered — a sibling component instance or a captured ElementReference — whose wire form, the target's interop instance id, is assigned at that same moment. Supporting it first looked like it needed a new .Method overload, a new generic parameter and its own compile-time drift guard: that would have been the fourth distinct way of expressing "settle this value after the render", in a builder already at 25 overloads whose count was driven by three orthogonal dimensions expressed as overloads ({async-only | twin} × {void | scalar | explicit wire return} × {plain | arranged | hosted}), so they multiplied rather than added.

The cause was mundane. Method and getter specs already share one spec type — on this stack a getter is an invokeMethod with a p:-prefixed identifier — but the runner had two duplicated paths for them, which is why render arrangement worked for method specs only by accident (the runner honored the field; no .Method overload exposed it). This PR removes both causes. Pure test-infrastructure refactor, no behavior change.

What changed

  • One form for values settled after the render. FromRender<T> is implicitly convertible from T, so every spec stating a fixed value is untouched; a late one is built with FromRender.Of((interop, cut) => …). It now types every parameter that could need it — stubbed returns, event payloads, prop wire values, and individual elements of a method's expected arguments — replacing StubFactory, ArgsJsonFactory, ExpectedValueFactory and the one-off marker type added in the previous PR. The next kind of late value needs no new API.
  • One runner path. RunMethodSpec and RunGetterSpec merge into RunSpec + AssertObserved, ~50 lines of duplication gone. A current-state read now differs from an API call in exactly two places, both named in the code: who owns the wire identifier, and that a read has no wire shape to pin. Capabilities added to one kind of spec now exist for the other automatically.
  • arranged is no longer an overload dimension. arrange: and elements: are optional parameters on all six real .Method overloads instead of one, .Prop's arranged overload folds into its explicit-wire form, and stubs can be late on methods as well as getters.
  • Drift guards keep their teeth. The four [Obsolete(error: true)] guards that fail the build when a contract's member starts returning a value now mirror the new optional parameters — without that, passing arrange: would quietly make a guard inapplicable and let an unstated return decode slip through. Re-verified by probe.

Net API surface: 25 overloads → 24. The value is one concept replacing four and one runner replacing two, not the count. The authoring reference gains a short section on the single mechanism and its stale examples are updated.

Not changed, deliberately

.Getter's arranged and explicit-wire overloads cannot merge: they are distinguished by whether expect: is present, and "absent" cannot be spelled null because three specs pass expect: null! to assert a null decode — the meaning would invert silently. .Event cannot lose an overload either: its forms are distinguished by assert shape, and giving two of them the same non-assert signature makes an implicitly-typed assert: (cut, args) => … ambiguous at existing call sites. Both want their own review rather than being forced through here.

Testing

Full suite on net8.0, net9.0 and net10.0: 903 tests, 881 passing, 22 skipped — identical before and after, which is the whole signal for a refactor of this kind. No new build warnings in the touched files. Call-site churn is mechanical: 41 factory sites across 10 suites gained a FromRender.Of(...) wrapper. Guards were checked by temporarily declaring a spec whose member pair returns a value and confirming the build fails with CS0619.

Base automatically changed from dpetev/dropdown-toggle-overload-fix to master August 5, 2026 07:46
Co-Authored-By: Claude <noreply@anthropic.com>
@damyanpetev
damyanpetev force-pushed the dpetev/interop-consolidate-update branch from bae2964 to d428fbb Compare August 5, 2026 07:52
@damyanpetev
damyanpetev requested a review from MayaKirova August 5, 2026 07:52
@damyanpetev
damyanpetev marked this pull request as ready for review August 5, 2026 07:52
Copilot AI review requested due to automatic review settings August 5, 2026 07:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 refactors the Ignite UI for Blazor interop contract testing DSL and runner to reduce duplication and unify the way “values only knowable after render” are expressed and resolved. It primarily affects the unit-test infrastructure and updates contract authoring guidance accordingly.

Changes:

  • Introduces FromRender<T> + FromRender.Of(...) as the single mechanism for late-bound contract values (event payloads, prop wire values, stubs, and expected args).
  • Consolidates the spec runner by merging method/getter execution paths into a single RunSpec + shared assertion flow.
  • Simplifies/normalizes contract DSL overloads (notably arrange:/elements: on method specs) and updates existing test contracts + docs to the new pattern.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/IgniteUI.Blazor.Tests/Interop/ComponentContract.cs Adds FromRender<T> + updates contract spec models and DSL overloads to use it consistently.
tests/IgniteUI.Blazor.Tests/ComponentWithContractTestBase.cs Unifies method/getter runner path; resolves late values via IFromRender.
tests/IgniteUI.Blazor.Tests/DropdownTests.cs Updates dropdown contract specs to use FromRender.Of(...) for render-settled values.
tests/IgniteUI.Blazor.Tests/TreeTests.cs Wraps render-dependent args/stubs with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/TileManagerTests.cs Wraps render-dependent args/stubs with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/TabsTests.cs Wraps render-dependent event payload with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/StepperTests.cs Wraps render-dependent getter stub with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/SelectTests.cs Wraps render-dependent stubs/payloads with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/ComboTests.cs Wraps render-dependent stubs/payloads/prop wire values with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/ChatTests.cs Wraps arranged getter stub with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/CalendarTests.cs Wraps arranged getter stub with FromRender.Of(...).
tests/IgniteUI.Blazor.Tests/AccordionTests.cs Wraps arranged event payloads with FromRender.Of(...).
skills/igniteui-blazor-lite-testing/references/interop-contracts.md Updates guidance/examples to the unified FromRender<T> mechanism.

@damyanpetev
damyanpetev enabled auto-merge (squash) August 5, 2026 07:59
@damyanpetev
damyanpetev merged commit c8845f9 into master Aug 5, 2026
8 checks passed
@damyanpetev
damyanpetev deleted the dpetev/interop-consolidate-update branch August 5, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants