public void MasterDetailsVM_RequestWithCustomFilter_FiltersInvoked() { var contexts = new List <VMContext>(); CustomFilter.Invoked += customFilter_Invoked; void customFilter_Invoked(object sender, Tuple <CustomFilterAttribute, VMContext> e) => contexts?.Add(e.Item2); var hubEmulator = new HubEmulatorBuilder() .Register <RootVM>() .Register <MasterVM>() .Register <DetailsVM>() .UseFilter <CustomFilter>() .Build(); var client = hubEmulator.CreateClient(); client.Connect(_detailsVMId).As <dynamic>(); client.Destroy(); Assert.IsTrue(contexts.Count >= 2); Assert.IsTrue(contexts[0].Instance is MasterVM); Assert.IsTrue(contexts[1].Instance is DetailsVM); contexts.Clear(); client.Connect("RootVM.MasterVM.DetailsVM").As <dynamic>(); Assert.IsTrue(contexts.Count >= 3); Assert.IsTrue(contexts[0].Instance is RootVM); Assert.IsTrue(contexts[1].Instance is MasterVM); Assert.IsTrue(contexts[2].Instance is DetailsVM); }
public void MinimalApiTest_WithAsyncAction_ActionAwaited() { var vmName = "LiveDataAsync"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); builder.Services.AddScoped <ILiveDataService, LiveDataService>(); var app = builder.Build(); app.MapVM(vmName, async(ILiveDataService live) => new { Greetings = await live.GreetingsAsync(), Reset = new Action(async() => await live.GreetingsAsync()) }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .Build(); var client = hubEmulator.CreateClient(); var response = client.Connect(vmName).As <dynamic>(); Assert.AreEqual("Hello World!", response.Greetings.ToString()); client.Dispatch(new { Reset = "" }); }
public void ForwardingMiddleware_Multicast_UserLeaves_OtherUserIsNotified() { var hubForwarderFactory = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory, "serverUrl", new ForwardingOptions()) .Build(); var client1 = hubEmulator.CreateClient("client1-conn-id"); var client2 = hubEmulator.CreateClient("client2-conn-id"); Setup(_forwardingClient, hubForwarderFactory, new[] { client1, client2 }); client1.Connect(nameof(ChatRoomVM)); var response = client1.Dispatch(new { AddUser = "******" }).As <dynamic>(); string expectedClient1Id = response.Users_add.Id; client2.Connect(nameof(ChatRoomVM)); client2.Dispatch(new { AddUser = "******" }); var client2Responses = client2.Listen(() => { client1.Destroy(); }); Assert.AreEqual(1, client2Responses.Count); Assert.AreEqual(expectedClient1Id, (string)client2Responses.As <dynamic>().Users_remove); Assert.IsFalse(client2.GetState <ChatRoomState>().Users.Any(x => x.Id == expectedClient1Id)); }
public void MinimalApiTest_WithAuthorizeOnAuthenticatedClient_AccessGranted() { var vmName = "HelloWorldAccessGranted"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); var app = builder.Build(); app.MapVM(vmName, [Authorize]() => new { FirstName = "Hello", LastName = "World" }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .UseFilter <AuthorizeFilter>() .Build(); var identity = Stubber.Create <IIdentity>().Setup(x => x.AuthenticationType).Returns("CustomAuth").Object; var client = hubEmulator.CreateClient(user: new ClaimsPrincipal(identity)); var response = client.Connect(vmName).As <HelloWorldState>(); Assert.AreEqual("Hello", response.FirstName); Assert.AreEqual("World", response.LastName); }
public async Task MinimalApiTest_WithCommand_CommandsExecuted() { var vmName = "LiveDataWithCommand"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); builder.Services.AddScoped <ILiveDataService, LiveDataService>(); var app = builder.Build(); app.MapVM(vmName, (ILiveDataService live) => new { Tick = live.Tick, Reset = new Action <int>(x => live.Reset(x)) }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .Build(); var client = hubEmulator.CreateClient(); client.Connect(vmName); var task = client.ListenAsync(1000); client.Dispatch(new { Reset = 1000 }); var response = (await task).As <LiveDataState>(); int.TryParse(response.Tick, out int tick); Assert.IsTrue(tick >= 1000); }
public void MinimalApiTest_MulticastVM_ViewModelShared() { var vmName = "MulticastTestVM"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); var app = builder.Build(); app.MapMulticastVM(vmName, () => new { Message = "Hello" }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .Build(); var client1 = hubEmulator.CreateClient(); var client2 = hubEmulator.CreateClient(); var response = client1.Connect(vmName).As <dynamic>(); Assert.AreEqual("Hello", (string)response.Message); var update = new Dictionary <string, object>() { { "Message", "World" } }; client1.Dispatch(update); response = client2.Connect(vmName).As <dynamic>(); Assert.AreEqual("World", (string)response.Message); }
public void Initialize() { VMController.Register("HelloWorldRuntimeVM", _ => { var vm = new BaseVM(); var firstName = vm.AddProperty("FirstName", "Hello"); var lastName = vm.AddProperty("LastName", "World"); vm.AddProperty <string>("FullName").SubscribeTo(Observable.CombineLatest(firstName, lastName, (fn, ln) => $"{fn} {ln}")); return(vm); }); VMController.Register("MyNamespace.HelloWorldRuntimeVM", _ => { var vm = new BaseVM(); var firstName = vm.AddProperty("FirstName", "John"); var lastName = vm.AddProperty("LastName", "Hancock"); vm.AddProperty <string>("FullName").SubscribeTo(Observable.CombineLatest(firstName, lastName, (fn, ln) => $"{fn} {ln}")); return(vm); }); var hubEmulatorBuilder = new HubEmulatorBuilder(); foreach (var typeHelper in VMController.VMTypes) { hubEmulatorBuilder.Register(typeHelper.FullName, typeHelper.CreateInstance()); } _hubEmulator = hubEmulatorBuilder.Build(); }
public void Initialize() { var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .Register <HelloWorldVM>() .Register <ChatRoomVM>() .Build(); _forwardingClient = hubEmulator.CreateClient("forwarder-conn-id"); }
public void Middleware_RequestStopped() { var hubEmulator = new HubEmulatorBuilder() .Register <MiddlewareTestVM>() .UseMiddleware <RequestStoppedMiddleware>() .Build(); var client = hubEmulator.CreateClient(); var request = client.Connect(nameof(MiddlewareTestVM), _vmConnectOptions); Assert.IsTrue(request.Count == 0); }
public void ForwardingMiddleware_FilterOption_ConnectForwarded() { var forwardingClient1 = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .Register <HelloWorldVM>() .Build() .CreateClient("forwarder-conn-id-1"); var forwardingClient2 = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .Register <ChatRoomVM>() .Build() .CreateClient("forwarder-conn-id-2"); var hubForwarderFactory1 = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubForwarderFactory2 = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory1, "server1Url", new ForwardingOptions { Filter = context => context.VMId == nameof(HelloWorldVM) }) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory2, "server2Url", new ForwardingOptions { Filter = context => context.VMId == nameof(ChatRoomVM) }) .Build(); var client = hubEmulator.CreateClient(); Setup(forwardingClient1, hubForwarderFactory1, client); Setup(forwardingClient2, hubForwarderFactory2, client); var response = client.Connect(nameof(HelloWorldVM)).As <HelloWorldState>(); Assert.AreEqual("Hello", response.FirstName); Assert.AreEqual("World", response.LastName); Assert.AreEqual("Hello World", response.FullName); client.Destroy(); var response2 = client.Connect(nameof(ChatRoomVM)).As <ChatRoomState>(); Assert.AreEqual(0, response2.Users.Count); }
public void Filter_PushUpdateIntercepted() { var vm = new FilterTestVM(); var hubEmulator = new HubEmulatorBuilder() .Register(nameof(FilterTestVM), vm) .UseMiddleware <JwtBearerAuthenticationMiddleware>(_tokenValidationParameters) .UseFilter <AuthorizeFilter>() .UseFilter <CustomFilter1>() .UseFilter <CustomFilter2>() .Build(); var client = hubEmulator.CreateClient(); Action filter1Assertions = null; CustomFilter1.Invoked += (sender, tuple) => { if (tuple.Item2.HubContext.CallType != "Response_VM") { return; } var attr = tuple.Item1; var vmContext = tuple.Item2; var context = vmContext.HubContext; var connectionId = context.CallerContext.ConnectionId; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); filter1Assertions = () => { Assert.AreEqual(client.ConnectionId, connectionId); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(0, pipelineData.Count); Assert.AreEqual(vm, vmContext.Instance); Assert.AreEqual("Welcome", attr.Property); }; }; client.Connect(nameof(FilterTestVM), _vmConnectOptions); vm.TriggerProperty = true; vm.PushUpdates(); filter1Assertions(); }
public void DisconnectionMiddleware_DisconnectionIntercepted() { var hubEmulator = new HubEmulatorBuilder() .Register <TestVM>() .UseMiddleware <CustomMiddleware>() .Build(); bool middlewareInvoked = false; CustomMiddleware.Invoked += (sender, e) => middlewareInvoked = true; var client = hubEmulator.CreateClient(); client.Connect(nameof(TestVM)); client.TerminateHubConnection(); Assert.IsTrue(middlewareInvoked); }
public void Middleware_ResponseIntercepted() { var hubEmulator = new HubEmulatorBuilder() .Register <MiddlewareTestVM>() .UseMiddleware <JwtBearerAuthenticationMiddleware>(_tokenValidationParameters) .UseMiddleware <CustomMiddleware3>() .Build(); var client = hubEmulator.CreateClient(); client.Connect(nameof(MiddlewareTestVM), _vmConnectOptions); var response = client.Dispatch(new Dictionary <string, object> { { "TriggerProperty", true } }).As <dynamic>(); Assert.AreEqual("TRIGGERED", (string)response.ResponseProperty); }
public void ForwardingMiddleware_ConnectForwarded() { var hubForwarderFactory = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory, "serverUrl", new ForwardingOptions()) .Build(); var client = hubEmulator.CreateClient(); Setup(_forwardingClient, hubForwarderFactory, client); var response = client.Connect(nameof(HelloWorldVM)).As <HelloWorldState>(); Assert.AreEqual("Hello", response.FirstName); Assert.AreEqual("World", response.LastName); Assert.AreEqual("Hello World", response.FullName); }
public void ForwardingMiddleware_DispatchForwarded() { var hubForwarderFactory = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory, "serverUrl", new ForwardingOptions()) .Build(); var client = hubEmulator.CreateClient(); Setup(_forwardingClient, hubForwarderFactory, client); client.Connect(nameof(HelloWorldVM)); var response = client.Dispatch(new { FirstName = "John" }).As <HelloWorldState>(); Assert.AreEqual("John World", (string)response.FullName); client.Dispatch(new { LastName = "Doe" }); Assert.AreEqual("John Doe", client.GetState <HelloWorldState>().FullName); }
public void ForwardingMiddleware_DestroyForwarded() { bool dispose = false; var hubForwarderFactory = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory, "serverUrl", new ForwardingOptions()) .Build(); var client = hubEmulator.CreateClient(); Setup(_forwardingClient, hubForwarderFactory, client, (callType, vmId) => { dispose = callType == nameof(IDotNetifyHubMethod.Dispose_VM) && vmId == nameof(HelloWorldVM); }); client.Connect(nameof(HelloWorldVM)); client.Destroy(); Assert.IsTrue(dispose); }
public void MinimalApiTest_WithStaticValue_ReturnsInitialState() { var vmName = "HelloWorld"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); var app = builder.Build(); app.MapVM(vmName, () => new { FirstName = "Hello", LastName = "World" }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .Build(); var client = hubEmulator.CreateClient(); var response = client.Connect(vmName).As <HelloWorldState>(); Assert.AreEqual("Hello", response.FirstName); Assert.AreEqual("World", response.LastName); }
public void MinimalApiTest_WithAuthorizeOnUnauthenticatedClient_AccessDenied() { var vmName = "HelloWorldAccessDenied"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); var app = builder.Build(); app.MapVM(vmName, [Authorize]() => new { FirstName = "Hello", LastName = "World" }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .UseFilter <AuthorizeFilter>() .Build(); var identity = Stubber.Create <IIdentity>().Setup(x => x.AuthenticationType).Returns(string.Empty).Object; var client = hubEmulator.CreateClient(user: null); var response = client.Connect(vmName); Assert.IsTrue(response.First().ToString().Contains(nameof(UnauthorizedAccessException))); }
public void MinimalApiTest_WithObservable_ReturnsStatePeriodically() { var vmName = "LiveData"; var builder = WebApplication.CreateBuilder(); builder.Services.AddDotNetify().AddSignalR(); builder.Services.AddScoped <ILiveDataService, LiveDataService>(); var app = builder.Build(); app.MapVM(vmName, (ILiveDataService live) => new { ServerUsage = live.ServerUsage }); var vm = VMController.CreateVMInstance(vmName); var hubEmulator = new HubEmulatorBuilder() .Register(vmName, vm) .Build(); var client = hubEmulator.CreateClient(); client.Connect(vmName); var response = client.Listen(2100); Assert.IsTrue(response.Count >= 3); }
public void Filter_RequestIntercepted() { var vm = new FilterTestVM(); var hubEmulator = new HubEmulatorBuilder() .Register(nameof(FilterTestVM), vm) .UseMiddleware <JwtBearerAuthenticationMiddleware>(_tokenValidationParameters) .UseFilter <AuthorizeFilter>() .UseFilter <CustomFilter1>() .UseFilter <CustomFilter2>() .Build(); var client = hubEmulator.CreateClient(); Action filter1Assertions = null; CustomFilter1.Invoked += (sender, tuple) => { if (filter1Assertions != null) { return; } var attr = tuple.Item1; var vmContext = tuple.Item2; var context = vmContext.HubContext; var callType = context.CallType; var connectionId = context.CallerContext.ConnectionId; var testVMPropValue = (context.Data as JObject)[nameof(FilterTestVM.Property)]; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); filter1Assertions = () => { Assert.AreEqual("Request_VM", callType); Assert.AreEqual(client.ConnectionId, connectionId); Assert.AreEqual("World", testVMPropValue); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(0, pipelineData.Count); Assert.AreEqual(vm, vmContext.Instance); Assert.AreEqual("Welcome", attr.Property); }; }; Action filter2Assertions = null; CustomFilter2.Invoked += (sender, tuple) => { if (filter2Assertions != null) { return; } var attr = tuple.Item1; var vmContext = tuple.Item2; var context = vmContext.HubContext; var callType = context.CallType; var connectionId = context.CallerContext.ConnectionId; var testVMPropValue = (context.Data as JObject)[nameof(FilterTestVM.Property)]; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); filter2Assertions = () => { Assert.AreEqual("Request_VM", callType); Assert.AreEqual(client.ConnectionId, connectionId); Assert.AreEqual("World", testVMPropValue); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(0, pipelineData.Count); Assert.AreEqual(vm, vmContext.Instance); Assert.AreEqual("Bienvenu", attr.Property); }; }; var response = client.Connect(nameof(FilterTestVM), _vmConnectOptions).As <dynamic>(); Assert.AreEqual("WORLD", (string)response.Property); filter1Assertions(); filter2Assertions(); }
public void Middleware_RequestIntercepted() { var hubEmulator = new HubEmulatorBuilder() .Register <MiddlewareTestVM>() .UseMiddleware <JwtBearerAuthenticationMiddleware>(_tokenValidationParameters) .UseMiddleware <CustomMiddleware1>() .UseMiddleware <CustomMiddleware2>() .Build(); var client = hubEmulator.CreateClient(); Action middleware1Assertions = null; CustomMiddleware1.Invoked += (sender, context) => { if (middleware1Assertions != null) { return; } var vmId = context.VMId; var callType = context.CallType; var connectionId = context.CallerContext.ConnectionId; var testVMPropValue = (context.Data as JObject)[nameof(MiddlewareTestVM.Property)]; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); middleware1Assertions = () => { Assert.AreEqual(nameof(MiddlewareTestVM), vmId); Assert.AreEqual("Request_VM", callType); Assert.AreEqual(client.ConnectionId, connectionId); Assert.AreEqual("World", testVMPropValue); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(0, pipelineData.Count); }; }; Action middleware2Assertions = null; CustomMiddleware2.Invoked += (sender, context) => { if (middleware2Assertions != null) { return; } var vmId = context.VMId; var callType = context.CallType; var connectionId = context.CallerContext.ConnectionId; var testVMPropValue = (context.Data as JObject)[nameof(MiddlewareTestVM.Property)]; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); middleware2Assertions = () => { Assert.AreEqual(nameof(MiddlewareTestVM), vmId); Assert.AreEqual("Request_VM", callType); Assert.AreEqual(client.ConnectionId, connectionId); Assert.AreEqual("World", testVMPropValue); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(1, pipelineData.Count); }; }; var request = client.Connect(nameof(MiddlewareTestVM), _vmConnectOptions).As <dynamic>(); Assert.AreEqual("World", (string)request.Property); middleware1Assertions(); middleware2Assertions(); }
public void Middleware_DisposeIntercepted() { var hubEmulator = new HubEmulatorBuilder() .Register <MiddlewareTestVM>() .UseMiddleware <JwtBearerAuthenticationMiddleware>(_tokenValidationParameters) .UseMiddleware <CustomMiddleware1>() .UseMiddleware <CustomMiddleware2>() .Build(); var client = hubEmulator.CreateClient(); Action middleware1Assertions = null; CustomMiddleware1.Invoked += (sender, context) => { if (context.CallType != "Dispose_VM") { return; } var connectionId = context.CallerContext.ConnectionId; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); middleware1Assertions = () => { Assert.AreEqual(client.ConnectionId, connectionId); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(0, pipelineData.Count); }; }; Action middleware2Assertions = null; CustomMiddleware2.Invoked += (sender, context) => { if (context.CallType != "Dispose_VM") { return; } var connectionId = context.CallerContext.ConnectionId; var authToken = (context.Headers as JObject)["Authorization"].ToString(); var principalName = context.Principal.Identity.Name; var pipelineData = new Dictionary <string, object>(context.PipelineData); middleware2Assertions = () => { Assert.AreEqual(client.ConnectionId, connectionId); Assert.IsTrue(authToken.StartsWith("Bearer ")); Assert.AreEqual("admin", principalName); Assert.AreEqual(1, pipelineData.Count); }; }; client.Connect(nameof(MiddlewareTestVM), _vmConnectOptions); client.Destroy(); middleware1Assertions(); middleware2Assertions(); }
public async Task ForwardingMiddleware_Multicast_UserSendsMessage_OtherUserReceivesMessage() { string expectedClient1Text = "Hi there!"; string expectedClient1UserName = "******"; string expectedClient2Text = "What's up, Rick?"; string expectedClient2UserName = "******"; var hubForwarderFactory = Substitute.For <IDotNetifyHubForwarderFactory>(); var hubEmulator = new HubEmulatorBuilder() .AddServices(x => x.AddLogging()) .UseMiddleware <ForwardingMiddleware>(hubForwarderFactory, "serverUrl", new ForwardingOptions()) .Build(); var client1 = hubEmulator.CreateClient("client1-conn-id"); var client2 = hubEmulator.CreateClient("client2-conn-id"); var client3 = hubEmulator.CreateClient("client3-conn-id"); Setup(_forwardingClient, hubForwarderFactory, new[] { client1, client2, client3 }); client1.Connect(nameof(ChatRoomVM)); client1.Dispatch(new { AddUser = "******" }); client2.Connect(nameof(ChatRoomVM)); client2.Dispatch(new { AddUser = "******" }); client3.Connect(nameof(ChatRoomVM)); client3.Dispatch(new { AddUser = "******" }); var client3AsyncResponses = client3.ListenAsync(); var client2AsyncResponses = client2.ListenAsync(); client1.Dispatch(new { SendMessage = new { Text = expectedClient1Text, Date = DateTime.Now, UserName = expectedClient1UserName } }); var client2Responses = await client2AsyncResponses; var client3Responses = await client3AsyncResponses; Assert.AreEqual(1, client2Responses.Count); Assert.AreEqual(expectedClient1Text, (string)client2Responses.As <dynamic>().Messages_add.Text); Assert.AreEqual(expectedClient1UserName, (string)client2Responses.As <dynamic>().Messages_add.UserName); Assert.IsTrue(client2.GetState <ChatRoomState>().Messages.Any(x => x.Text == expectedClient1Text && x.UserName == expectedClient1UserName)); Assert.AreEqual(1, client3Responses.Count); Assert.AreEqual(expectedClient1Text, (string)client3Responses.As <dynamic>().Messages_add.Text); Assert.AreEqual(expectedClient1UserName, (string)client3Responses.As <dynamic>().Messages_add.UserName); Assert.IsTrue(client3.GetState <ChatRoomState>().Messages.Any(x => x.Text == expectedClient1Text && x.UserName == expectedClient1UserName)); var client1Responses = client1.Listen(() => { client2.Dispatch(new { SendMessage = new { Text = expectedClient2Text, Date = DateTime.Now, UserName = expectedClient2UserName } }); }); Assert.AreEqual(1, client1Responses.Count); Assert.AreEqual(expectedClient2Text, (string)client1Responses.As <dynamic>().Messages_add.Text); Assert.AreEqual(expectedClient2UserName, (string)client1Responses.As <dynamic>().Messages_add.UserName); Assert.IsTrue(client1.GetState <ChatRoomState>().Messages.Any(x => x.Text == expectedClient2Text && x.UserName == expectedClient2UserName)); }