Skip to content

Commit

Permalink
feat: Added TriggerEvent method to make it easier to trigger custom…
Browse files Browse the repository at this point in the history
… events.

closes #341
  • Loading branch information
egil committed Oct 5, 2021
1 parent 8af2eaa commit 54c92d7
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ List of added functionality in this release.

- Added fake version of the `PersistentComponentState` type in Blazor that makes it possible to test components that use the type. By [@egil](https://github.com/egil).

- Added `TriggerEvent` method to make it easier to trigger custom events. By [@egil](https://github.com/egil).

### Fixed

- The `Click` and `DoubleClick` extension methods now set the `MouseEventArgs.Detail` property to `1` and `2` respectively by default, unless the user specifies something else. This makes the methods more correctly emulate how Blazor reports single or double clicks on an element in the browser. Thanks to [@David-Moreira](https://github.com/David-Moreira) for the help troubleshooting this issue. By [@egil](https://github.com/egil).
Expand Down
57 changes: 57 additions & 0 deletions docs/site/docs/interaction/trigger-event-handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,60 @@ This is what happens in the test:
- The last invocation uses the [`Click`](xref:Bunit.MouseEventDispatchExtensions.Click(AngleSharp.Dom.IElement,Microsoft.AspNetCore.Components.Web.MouseEventArgs)) method. This takes an instance of the `MouseEventArgs` type, which is passed to the event handler if it has it as an argument.

All the event dispatch helper methods have the same two overloads: one that takes a number of optional arguments, and one that takes one of the `EventArgs` types provided by Blazor.

## Triggering custom events

bUnit support triggering custom events through the `TriggerEvent` method.

Lets try to test the `<CustomPasteSample>` component below:

```cshtml
<p>Try pasting into the following text box:</p>
<input @oncustompaste="HandleCustomPaste" />
<p>@message</p>
@code {
string message = string.Empty;
void HandleCustomPaste(CustomPasteEventArgs eventArgs)
{
message = $"You pasted: {eventArgs.PastedData}";
}
}
```

Here are the custom event types:

```csharp
[EventHandler("oncustompaste", typeof(CustomPasteEventArgs), enableStopPropagation: true, enablePreventDefault: true)]
public static class EventHandlers
{
// This static class doesn't need to contain any members. It's just a place where we can put
// [EventHandler] attributes to configure event types on the Razor compiler. This affects the
// compiler output as well as code completions in the editor.
}

public class CustomPasteEventArgs : EventArgs
{
// Data for these properties will be supplied by custom JavaScript logic
public DateTime EventTimestamp { get; set; }
public string PastedData { get; set; }
}
```

To trigger the `@oncustompaste` event callback, do the following:

```csharp
// Arrange
using var ctx = new TestContext();
var cut = ctxRenderComponent<CustomPasteSample>();

// Atc - find the input element and trigger the oncustompaste event
cut.Find("input").TriggerEvent("oncustompaste", new CustomPasteEventArgs
{
EventTimestamp = DateTime.Now,
PastedData = "FOO"
});

// Assert that the custom event data was passed correctly
cut.Find("p:last-child").MarkupMatches("<p>You pasted: FOO</p>");
```
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ public static class TriggerEventDispatchExtensions
private static readonly HashSet<string> NonBubblingEvents = new(StringComparer.Ordinal) { "onabort", "onblur", "onchange", "onerror", "onfocus", "onload", "onloadend", "onloadstart", "onmouseenter", "onmouseleave", "onprogress", "onreset", "onscroll", "onsubmit", "onunload", "ontoggle", "ondomnodeinsertedintodocument", "ondomnoderemovedfromdocument" };
private static readonly HashSet<string> DisabledEventNames = new(StringComparer.Ordinal) { "onclick", "ondblclick", "onmousedown", "onmousemove", "onmouseup" };

/// <summary>
/// Raises the event <paramref name="eventName"/> on the element <paramref name="element"/>
/// passing the <paramref name="eventArgs"/> to the event handler.
/// </summary>
/// <param name="element">The element to raise the event on.</param>
/// <param name="eventName">The name of the event to raise (using on-form, e.g. <c>onclick</c>).</param>
/// <param name="eventArgs">The event arguments to pass to the event handler. Use <see cref="EventArgs.Empty"/> to pass an empty <see cref="EventArgs"/>.</param>
public static void TriggerEvent(this IElement element, string eventName, EventArgs eventArgs)
=> _ = TriggerEventAsync(element, eventName, eventArgs);

/// <summary>
/// Raises the event <paramref name="eventName"/> on the element <paramref name="element"/>
/// passing the <paramref name="eventArgs"/> to the event handler.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<p>Try pasting into the following text box:</p>
<input @oncustompaste="HandleCustomPaste" />
<p>@message</p>
30 changes: 30 additions & 0 deletions tests/bunit.testassets/SampleComponents/CustomPasteSample.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using Microsoft.AspNetCore.Components;

namespace Bunit.TestAssets.SampleComponents
{
public partial class CustomPasteSample
{
string message = string.Empty;

void HandleCustomPaste(CustomPasteEventArgs eventArgs)
{
message = $"You pasted: {eventArgs.PastedData}";
}
}

[EventHandler("oncustompaste", typeof(CustomPasteEventArgs), enableStopPropagation: true, enablePreventDefault: true)]
public static class EventHandlers
{
// This static class doesn't need to contain any members. It's just a place where we can put
// [EventHandler] attributes to configure event types on the Razor compiler. This affects the
// compiler output as well as code completions in the editor.
}

public class CustomPasteEventArgs : EventArgs
{
// Data for these properties will be supplied by custom JavaScript logic
public DateTime EventTimestamp { get; set; }
public string PastedData { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,5 +187,20 @@ public void Test115()
Should.Throw<ArgumentException>(() => div.TriggerEventAsync(eventName, EventArgs.Empty));
}

#if NET6_0_OR_GREATER
[Fact(DisplayName = "TriggerEvent can trigger custom events")]
public void Test201()
{
var cut = RenderComponent<CustomPasteSample>();

cut.Find("input").TriggerEvent("oncustompaste", new CustomPasteEventArgs
{
EventTimestamp = DateTime.Now,
PastedData = "FOO"
});

cut.Find("p:last-child").MarkupMatches("<p>You pasted: FOO</p>");
}
#endif
}
}

0 comments on commit 54c92d7

Please sign in to comment.