Skip to content

Commit

Permalink
feat: Easier handling of triggering stub events
Browse files Browse the repository at this point in the history
  • Loading branch information
linkdotnet committed Aug 23, 2023
1 parent f8f23e8 commit eebcb86
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to **bUnit** will be documented in this file. The project ad

- `net8.0` support
- Increased timeout of `WaitForAssertion` to infinite when a debugger is attached. By [@linkdotnet](https://github.com/linkdotnet).
- Easier overloads for Stub's to invoke `EventCallback`s

### Fixed

Expand Down
36 changes: 36 additions & 0 deletions src/bunit.web/Extensions/RenderedComponentStubExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#if NET5_0_OR_GREATER
using System.Linq.Expressions;
using Bunit.TestDoubles;

namespace Bunit;

/// <summary>
/// Extension methods for using component doubles.
/// </summary>
public static class RenderedComponentStubExtensions
{
/// <summary>
/// Invokes the event callback from the stub.
/// </summary>
public static Task InvokeEventCallback<TComponent>(this IRenderedComponent<Stub<TComponent>> component,
Expression<Func<TComponent, EventCallback>> selector) where TComponent : IComponent
{
if (component is null)
throw new ArgumentNullException(nameof(component));

return component.Instance.InvokeEventCallback(selector);
}

/// <summary>
/// Invokes the event callback from the stub.
/// </summary>
public static Task InvokeEventCallback<TComponent, TU>(this IRenderedComponent<Stub<TComponent>> component,
Expression<Func<TComponent, EventCallback<TU>>> selector, TU value) where TComponent : IComponent
{
if (component is null)
throw new ArgumentNullException(nameof(component));

return component.Instance.InvokeEventCallback(selector, value);
}
}
#endif
2 changes: 2 additions & 0 deletions src/bunit.web/Extensions/RenderedFragmentExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Linq.Expressions;
using AngleSharp.Dom;
using Bunit.Rendering;
using Bunit.TestDoubles;

namespace Bunit;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public abstract class ComponentDoubleBase<TComponent> : IComponent
/// </summary>
protected static readonly Type DoubledType = typeof(TComponent);

/// <summary>
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
/// </summary>
protected Task InvokeAsync(Func<Task> workItem) => renderHandle.Dispatcher.InvokeAsync(workItem);

/// <summary>
/// Gets the parameters that was passed to the <typeparamref name="TComponent"/>
/// that this stub replaced in the component tree.
Expand Down
21 changes: 21 additions & 0 deletions src/bunit.web/TestDoubles/Components/Stub{TComponent}.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#if NET5_0_OR_GREATER
using System.Diagnostics;
using System.Linq.Expressions;

namespace Bunit.TestDoubles;

Expand Down Expand Up @@ -33,6 +34,26 @@ public Stub(object? replacement)
throw new ArgumentException($"The type of replacement is not supported. Replacement type = {replacement.GetType()}", nameof(replacement));
}

/// <summary>
/// Triggers an event callback from the stub.
/// </summary>
/// <param name="selector">Event to trigger.</param>
public Task InvokeEventCallback(Expression<Func<TComponent, EventCallback>> selector)
{
var callback = Parameters.Get(selector);
return InvokeAsync(callback.InvokeAsync);
}

/// <summary>
/// Triggers an event callback from the stub.
/// </summary>
/// <param name="selector">Event to trigger.</param>
public Task InvokeEventCallback<TU>(Expression<Func<TComponent, EventCallback<TU>>> selector, TU? value)
{
var callback = Parameters.Get(selector);
return InvokeAsync(() => callback.InvokeAsync(value));
}

/// <inheritdoc/>
public override string ToString() => $"Stub<{DoubledType.Name}>";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<p>User wrote: @value</p>
<InputText @bind-Value="value" />
@code {
private string value;
}
15 changes: 15 additions & 0 deletions tests/bunit.web.tests/TestDoubles/Components/StubTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Bunit.TestAssets.SampleComponents.DisposeComponents;
using Microsoft.AspNetCore.Components.Forms;

#if NET5_0_OR_GREATER
namespace Bunit.TestDoubles.Components;

Expand Down Expand Up @@ -26,5 +29,17 @@ public void Test002(string header, string attrValue)
ps => ps.ShouldContain(x => x.Key == nameof(Simple1.AttrValue) && attrValue.Equals(x.Value)),
ps => ps.Count.ShouldBe(2));
}

[Fact(DisplayName = "Stub<TComponent> can invoke event callbacks")]
public async Task Test003()
{
ComponentFactories.AddStub<InputText>();
var cut = RenderComponent<DisplayInput>();
var stubbedInput = cut.FindComponent<Stub<InputText>>();

await stubbedInput.InvokeEventCallback(t => t.ValueChanged, "Hello World");

cut.Find("p").MarkupMatches("<p>User wrote: Hello World</p>");
}
}
#endif

0 comments on commit eebcb86

Please sign in to comment.