In your particular case the problems stems from the fact that you don't await your call:
public async Task OnCancel()
{
// ...
await JSRuntime.InvokeVoidAsync("window.close");
}
With that and your given test you would receive the following error:
Bunit.JSRuntimeUnhandledInvocationException: bUnit's JSInterop has not been configured to handle the call:
Bunit.JSRuntimeUnhandledInvocationException
bUnit's JSInterop has not been configured to handle the call:
InvokeVoidAsync("window.close")
Configure bUnit's JSInterop to handle the call with following:
SetupVoid("window.close")
So bUnit tells you how to setup your test to make it work.
JSInterop.SetupVoid("window.close").SetVoidResult();
cut.Find("button").Click();
You can find more on the official website: https://bunit.dev/docs/test-doubles/emulating-ijsruntime.html?q=jsinterop
EDIT:
Generally speaking, you don't want to have code that produces side effects in your unit tests (like Environment.Exit
). A common pattern is to create a wrapper around this logic:
public interface IProgramExit
{
void Exit();
}
public class ProgramExit : IProgramExit
{
public void Exit() => Environment.Exit(0);
}
This then can be used inside your component:
@inject IProgramExit ProgramExit
...
@code {
public async Task Cancel()
{
if (...) await JSInterop.InvokeVoidAsync("window.close");
ProgramExit.Exit();
}
}
Obviously you have to register this in your Program.cs:
Services.AddScoped<IProgramExit, ProgramExit>();
In the bUnit test, you can just register a mock or a fake, that does absolutely nothing. With the given async adjustments discussed earlier, you should be able to test every aspect.
}
}