Skip to content

Commit 2fd82a1

Browse files
committed
Support for CUTs that call FocusAsync on an ElementReference
1 parent 64954a3 commit 2fd82a1

8 files changed

Lines changed: 116 additions & 10 deletions

File tree

src/bunit.web/JSInterop/ComponentSupport/BunitJSInteropExtensions.cs renamed to src/bunit.web/JSInterop/BunitJSInteropExtensions.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
namespace Bunit.JSInterop.ComponentSupport
1+
namespace Bunit.JSInterop
22
{
33
/// <summary>
44
/// Helper methods for registering handlers on the <see cref="BunitJSInterop"/>.
55
/// </summary>
66
public static class BunitJSInteropExtensions
77
{
88
/// <summary>
9-
/// Adds the built-in JSRuntime invocation handlers to the <paramref name="jSInterop"/>.
9+
/// Adds the built-in JSRuntime invocation handlers to the <paramref name="jsInterop"/>.
1010
/// </summary>
11-
public static BunitJSInterop AddBuiltInJSRuntimeInvocationHandlers(this BunitJSInterop jSInterop)
11+
public static BunitJSInterop AddBuiltInJSRuntimeInvocationHandlers(this BunitJSInterop jsInterop)
1212
{
1313
#if NET5_0
14-
//jSInterop.AddInvocationHandler(new Virtualize.VirtualizeJSRuntimeInvocationHandler());
14+
jsInterop.AddInvocationHandler(new InvocationHandlers.FocusAsyncInvocationHandler());
1515
#endif
16-
return jSInterop;
16+
return jsInterop;
1717
}
18-
1918
}
2019
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#if NET5_0
2+
using Bunit.JSInterop.InvocationHandlers;
3+
using Microsoft.AspNetCore.Components;
4+
using System.Collections.Generic;
5+
6+
namespace Bunit
7+
{
8+
/// <summary>
9+
/// Extensions methods for verifying <see cref="ElementReferenceExtensions.FocusAsync(ElementReference)"/> method calls.
10+
/// </summary>
11+
public static class FocusAsyncAssertJSInteropExtensions
12+
{
13+
/// <summary>
14+
/// Verifies that the <see cref="ElementReferenceExtensions.FocusAsync(ElementReference)"/> method has been invoked one time.
15+
/// </summary>
16+
/// <param name="handler">Handler to verify against.</param>
17+
/// <param name="userMessage">A custom user message to display if the assertion fails.</param>
18+
/// <returns>The <see cref="JSRuntimeInvocation"/>.</returns>
19+
public static JSRuntimeInvocation VerifyFocusAsyncInvoke(this BunitJSInterop handler, string? userMessage = null)
20+
=> handler.VerifyInvoke(FocusAsyncInvocationHandler.FocusIdentifier, userMessage);
21+
22+
/// <summary>
23+
/// Verifies that the <see cref="ElementReferenceExtensions.FocusAsync(ElementReference)"/> method has been invoked <paramref name="calledTimes"/> times.
24+
/// </summary>
25+
/// <param name="handler">Handler to verify against.</param>
26+
/// <param name="calledTimes">The number of times the invocation is expected to have been called.</param>
27+
/// <param name="userMessage">A custom user message to display if the assertion fails.</param>
28+
/// <returns>The <see cref="JSRuntimeInvocation"/>.</returns>
29+
public static IReadOnlyList<JSRuntimeInvocation> VerifyFocusAsyncInvoke(this BunitJSInterop handler, int calledTimes, string? userMessage = null)
30+
=> handler.VerifyInvoke(FocusAsyncInvocationHandler.FocusIdentifier, calledTimes, userMessage);
31+
}
32+
}
33+
#endif
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#if NET5_0
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Components;
8+
9+
namespace Bunit.JSInterop.InvocationHandlers
10+
{
11+
/// <summary>
12+
/// Represents a handler for Blazor's
13+
/// <see cref="ElementReferenceExtensions.FocusAsync(ElementReference)"/> feature.
14+
/// </summary>
15+
public class FocusAsyncInvocationHandler : JSRuntimeInvocationHandler
16+
{
17+
/// <summary>
18+
/// The internal identifier used by <see cref="ElementReferenceExtensions.FocusAsync(ElementReference)"/>
19+
/// to call it JavaScript.
20+
/// </summary>
21+
public const string FocusIdentifier = "Blazor._internal.domWrapper.focus";
22+
23+
/// <summary>
24+
/// Creates an instance of the <see cref="FocusEventDispatchExtensions"/>.
25+
/// </summary>
26+
protected internal FocusAsyncInvocationHandler() : base(FocusIdentifier, _ => true)
27+
{
28+
}
29+
}
30+
}
31+
#endif

src/bunit.web/JSInterop/JSRuntimeAssertExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static IReadOnlyList<JSRuntimeInvocation> VerifyInvoke(this BunitJSIntero
7373
/// </summary>
7474
/// <param name="actualArgument">object to verify.</param>
7575
/// <param name="expectedTargetElement">expected targeted element.</param>
76-
public static void ShouldBeElementReferenceTo(this object actualArgument, IElement expectedTargetElement)
76+
public static void ShouldBeElementReferenceTo(this object? actualArgument, IElement expectedTargetElement)
7777
{
7878
if (actualArgument is null)
7979
throw new ArgumentNullException(nameof(actualArgument));

src/bunit.web/RazorTesting/Fixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using System.Linq;
44
using System.Threading.Tasks;
55
using Bunit.Extensions;
6-
using Bunit.JSInterop.ComponentSupport;
6+
using Bunit.JSInterop;
77
using Bunit.RazorTesting;
88
using Microsoft.AspNetCore.Components;
99
using Microsoft.Extensions.DependencyInjection;

src/bunit.web/RazorTesting/SnapshotTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Threading.Tasks;
33
using Bunit.Extensions;
4-
using Bunit.JSInterop.ComponentSupport;
4+
using Bunit.JSInterop;
55
using Bunit.RazorTesting;
66
using Bunit.Rendering;
77
using Microsoft.AspNetCore.Components;

src/bunit.web/TestContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using Bunit.Extensions;
3-
using Bunit.JSInterop.ComponentSupport;
3+
using Bunit.JSInterop;
44
using Microsoft.AspNetCore.Components;
55
using Microsoft.Extensions.DependencyInjection;
66
using Microsoft.JSInterop;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#if NET5_0
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Components;
8+
using Microsoft.AspNetCore.Components.Rendering;
9+
using Xunit;
10+
11+
namespace Bunit.JSInterop.InvocationHandlers
12+
{
13+
public class FocusAsyncInvocationHandlerTest : TestContext
14+
{
15+
[Fact(DisplayName = "Can render components that calls FocusAsync")]
16+
public void Test001()
17+
{
18+
var cut = RenderComponent<FocusingComponent>();
19+
var input = cut.Find("input");
20+
JSInterop.VerifyFocusAsyncInvoke().Arguments[0].ShouldBeElementReferenceTo(input);
21+
}
22+
23+
class FocusingComponent : ComponentBase
24+
{
25+
ElementReference elmRef;
26+
protected override async Task OnAfterRenderAsync(bool firstRender)
27+
{
28+
if (firstRender)
29+
{
30+
await elmRef.FocusAsync();
31+
}
32+
}
33+
34+
protected override void BuildRenderTree(RenderTreeBuilder builder)
35+
{
36+
builder.OpenElement(1, "input");
37+
builder.AddElementReferenceCapture(2, x => elmRef = x);
38+
builder.CloseElement();
39+
}
40+
}
41+
}
42+
}
43+
#endif

0 commit comments

Comments
 (0)