|
| 1 | +using Bunit.JSInterop.InvocationHandlers.Implementation; |
| 2 | + |
1 | 3 | namespace Bunit;
|
2 | 4 |
|
3 | 5 | /// <summary>
|
4 | 6 | /// Helper methods for creating invocation handlers and adding the to a <see cref="BunitJSInterop"/>.
|
5 | 7 | /// </summary>
|
6 | 8 | public static partial class BunitJSInteropSetupExtensions
|
7 | 9 | {
|
| 10 | + private const string DefaultImportIdentifier = "import"; |
| 11 | + |
8 | 12 | /// <summary>
|
9 | 13 | /// Configure a JSInterop invocation handler for an <c>InvokeAsync<TResult></c> call with arguments
|
10 | 14 | /// passing the <paramref name="invocationMatcher"/> test.
|
@@ -146,6 +150,128 @@ public static JSRuntimeInvocationHandler SetupVoid(this BunitJSInterop jsInterop
|
146 | 150 | return jsInterop.TryGetHandlerFor<Microsoft.JSInterop.Infrastructure.IJSVoidResult>(invocation, x => x.IsVoidResultHandler) as JSRuntimeInvocationHandler;
|
147 | 151 | }
|
148 | 152 |
|
| 153 | + /// <summary> |
| 154 | + /// Setup a handler for a <c>IJSRuntime.InvokeAsync<IJSObjectReference>()</c> call whose input parameters is matched by the provided |
| 155 | + /// <paramref name="invocationMatcher"/>. |
| 156 | + /// </summary> |
| 157 | + /// <remarks> |
| 158 | + /// The returned <see cref="BunitJSInterop"/> can be used to setup handlers for |
| 159 | + /// <c>InvokeAsync<TValue>(string, object?[]?)"</c> calls to the module, using either |
| 160 | + /// <see cref="SetupModule(BunitJSInterop, string)"/> or Setup calls. |
| 161 | + /// </remarks> |
| 162 | + /// <param name="jsInterop">The JSInterop to setup the handler for.</param> |
| 163 | + /// <param name="invocationMatcher">The matcher to use to match <see cref="JSRuntimeInvocation"/>'s with.</param> |
| 164 | + /// <param name="isCatchAllHandler">Set to true if the created handler is a catch all handler, that should only be used if there are no other non-catch all handlers available.</param> |
| 165 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="jsInterop"/> is null.</exception> |
| 166 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="invocationMatcher"/> is null.</exception> |
| 167 | + /// <returns>A <see cref="BunitJSModuleInterop"/>.</returns> |
| 168 | + public static BunitJSModuleInterop SetupModule(this BunitJSInterop jsInterop, InvocationMatcher invocationMatcher, bool isCatchAllHandler = false) |
| 169 | + { |
| 170 | + ArgumentNullException.ThrowIfNull(jsInterop); |
| 171 | + ArgumentNullException.ThrowIfNull(invocationMatcher); |
| 172 | + |
| 173 | + var result = new JSObjectReferenceInvocationHandler(jsInterop, invocationMatcher, isCatchAllHandler); |
| 174 | + jsInterop.AddInvocationHandler(result); |
| 175 | + return result.JSInterop; |
| 176 | + } |
| 177 | + |
| 178 | + /// <summary> |
| 179 | + /// Setup a handler for a <c>IJSRuntime.InvokeAsync<IJSObjectReference>()</c> call whose input parameters is matched by the provided |
| 180 | + /// <paramref name="invocationMatcher"/> and the <paramref name="identifier"/>. |
| 181 | + /// </summary> |
| 182 | + /// <remarks> |
| 183 | + /// The returned <see cref="BunitJSInterop"/> can be used to setup handlers for |
| 184 | + /// <c>InvokeAsync<TValue>(string, object?[]?)"</c> calls to the module, using either |
| 185 | + /// <see cref="SetupModule(BunitJSInterop, string)"/> or Setup calls. |
| 186 | + /// </remarks> |
| 187 | + /// <param name="jsInterop">The JSInterop to setup the handler for.</param> |
| 188 | + /// <param name="identifier">The identifier to setup a response for.</param> |
| 189 | + /// <param name="invocationMatcher">The matcher to use to match <see cref="JSRuntimeInvocation"/>'s with.</param> |
| 190 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="jsInterop"/> is null.</exception> |
| 191 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="invocationMatcher"/> is null.</exception> |
| 192 | + /// <returns>A <see cref="BunitJSModuleInterop"/>.</returns> |
| 193 | + public static BunitJSModuleInterop SetupModule(this BunitJSInterop jsInterop, string identifier, InvocationMatcher invocationMatcher) |
| 194 | + => SetupModule(jsInterop, inv => identifier.Equals(inv.Identifier, StringComparison.Ordinal) && invocationMatcher(inv)); |
| 195 | + |
| 196 | + /// <summary> |
| 197 | + /// Setup a handler for a <c>IJSRuntime.InvokeAsync<IJSObjectReference>("import", <paramref name="moduleName"/>)</c> |
| 198 | + /// call. |
| 199 | + /// </summary> |
| 200 | + /// <remarks> |
| 201 | + /// The returned <see cref="BunitJSInterop"/> can be used to setup handlers for |
| 202 | + /// <c>InvokeAsync<TValue>(string, object?[]?)"</c> calls to the module, using either |
| 203 | + /// <see cref="SetupModule(BunitJSInterop, string)"/> or Setup calls. |
| 204 | + /// </remarks> |
| 205 | + /// <param name="jsInterop">The JSInterop to setup the handler for.</param> |
| 206 | + /// <param name="moduleName">The name of the JavaScript module to handle invocations for.</param> |
| 207 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="jsInterop"/> is null.</exception> |
| 208 | + /// <exception cref="ArgumentException">Thrown when <paramref name="moduleName"/> is null or whitespace.</exception> |
| 209 | + /// <returns>A <see cref="BunitJSModuleInterop"/>.</returns> |
| 210 | + public static BunitJSModuleInterop SetupModule(this BunitJSInterop jsInterop, string moduleName) |
| 211 | + { |
| 212 | + if (string.IsNullOrWhiteSpace(moduleName)) |
| 213 | + throw new ArgumentException($"'{nameof(moduleName)}' cannot be null or whitespace.", nameof(moduleName)); |
| 214 | + |
| 215 | + return SetupModule( |
| 216 | + jsInterop, |
| 217 | + DefaultImportIdentifier, |
| 218 | + invocation => invocation.Arguments?[0] is string requestedModuleName |
| 219 | + && requestedModuleName.Equals(moduleName, StringComparison.Ordinal)); |
| 220 | + } |
| 221 | + |
| 222 | + /// <summary> |
| 223 | + /// Setup a handler for a <c>IJSRuntime.InvokeAsync<IJSObjectReference>(<paramref name="identifier"/>, <paramref name="arguments"/>)</c> |
| 224 | + /// call. |
| 225 | + /// </summary> |
| 226 | + /// <remarks> |
| 227 | + /// The returned <see cref="BunitJSInterop"/> can be used to setup handlers for |
| 228 | + /// <c>InvokeAsync<TValue>(string, object?[]?)"</c> calls to the module, using either |
| 229 | + /// <see cref="SetupModule(BunitJSInterop, string)"/> or Setup calls. |
| 230 | + /// </remarks> |
| 231 | + /// <param name="jsInterop">The JSInterop to setup the handler for.</param> |
| 232 | + /// <param name="identifier">The identifier to setup a response for.</param> |
| 233 | + /// <param name="arguments">The arguments that an invocation to <paramref name="identifier"/> should match. Use <c>Array.Empty<object?>()</c> for none.</param> |
| 234 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="jsInterop"/> is null.</exception> |
| 235 | + /// <exception cref="ArgumentException">Thrown when <paramref name="identifier"/> is null or whitespace.</exception> |
| 236 | + /// <returns>A <see cref="BunitJSModuleInterop"/>.</returns> |
| 237 | + public static BunitJSModuleInterop SetupModule(this BunitJSInterop jsInterop, string identifier, object?[] arguments) |
| 238 | + => SetupModule(jsInterop, identifier, invocation => invocation.Arguments.SequenceEqual(arguments ?? Array.Empty<object?>())); |
| 239 | + |
| 240 | + /// <summary> |
| 241 | + /// Configure a catch all JSObjectReferenceInvocationHandler invocation handler for any module load and invocations |
| 242 | + /// on those modules. |
| 243 | + /// </summary> |
| 244 | + /// <remarks> |
| 245 | + /// The returned <see cref="BunitJSInterop"/> can be used to setup handlers for |
| 246 | + /// <c>InvokeAsync<TValue>(string, object?[]?)"</c> calls to the module, using either |
| 247 | + /// <see cref="SetupModule(BunitJSInterop, string)"/> or Setup calls. |
| 248 | + /// </remarks> |
| 249 | + /// <param name="jsInterop">The JSInterop to setup the handler for.</param> |
| 250 | + /// <exception cref="ArgumentNullException">Thrown when <paramref name="jsInterop"/> is null.</exception> |
| 251 | + /// <returns>A <see cref="BunitJSModuleInterop"/>.</returns> |
| 252 | + public static BunitJSModuleInterop SetupModule(this BunitJSInterop jsInterop) |
| 253 | + => SetupModule(jsInterop, _ => true, isCatchAllHandler: true); |
| 254 | + |
| 255 | + /// <summary> |
| 256 | + /// Looks through the registered handlers and returns the latest registered that can handle |
| 257 | + /// the provided <paramref name="identifier"/> and <paramref name="arguments"/>, and that |
| 258 | + /// will return <see cref="IJSObjectReference"/>. |
| 259 | + /// </summary> |
| 260 | + /// <param name="jsInterop">The JSInterop to setup the handler for.</param> |
| 261 | + /// <param name="identifier">The identifier the handler should match with.</param> |
| 262 | + /// <param name="arguments">The arguments that an invocation to <paramref name="identifier"/> should match.</param> |
| 263 | + /// <returns>A <see cref="BunitJSModuleInterop"/> or null if no one is found.</returns> |
| 264 | + public static BunitJSModuleInterop? TryGetModuleJSInterop(this BunitJSInterop jsInterop, string identifier, params object?[]? arguments) |
| 265 | + { |
| 266 | + ArgumentNullException.ThrowIfNull(jsInterop); |
| 267 | + |
| 268 | + var invocation = new JSRuntimeInvocation(identifier, default, arguments, typeof(IJSObjectReference), "InvokeAsync"); |
| 269 | + |
| 270 | + var handler = jsInterop.TryGetHandlerFor<IJSObjectReference>(invocation) as JSObjectReferenceInvocationHandler; |
| 271 | + |
| 272 | + return handler?.JSInterop; |
| 273 | + } |
| 274 | + |
149 | 275 | private static void EnsureResultNotIJSObjectReference<TResult>()
|
150 | 276 | {
|
151 | 277 | const string UseSetupModuleErrorMessage = "Use one of the SetupModule() methods instead to set up an invocation handler that returns an IJSObjectReference.";
|
|
0 commit comments