From d0b8550235e8f8eed888506577e18588b1db4076 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:02:31 +0000 Subject: [PATCH 1/3] Initial plan From 24255b4f32ec97c0693f47b09df925582879110a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:05:43 +0000 Subject: [PATCH 2/3] Address PR review comments: fix docs, formatting, and add tests Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com> --- .../Microsoft.Teams.Api/Clients/ApiClient.cs | 13 +++- .../Clients/ReactionClient.cs | 13 ++-- .../Microsoft.Teams.Api/Messages/Reaction.cs | 2 +- Samples/Samples.Reactions/Program.cs | 2 +- .../Clients/ReactionClientTests.cs | 74 +++++++++++++++++++ 5 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs diff --git a/Libraries/Microsoft.Teams.Api/Clients/ApiClient.cs b/Libraries/Microsoft.Teams.Api/Clients/ApiClient.cs index 0c2f04ec..b1588d2a 100644 --- a/Libraries/Microsoft.Teams.Api/Clients/ApiClient.cs +++ b/Libraries/Microsoft.Teams.Api/Clients/ApiClient.cs @@ -14,6 +14,18 @@ public class ApiClient : Client public virtual TeamClient Teams { get; } public virtual MeetingClient Meetings { get; } + /// + /// Gets the underlying instance used by this + /// and its sub-clients to perform HTTP requests. + /// + /// + /// This property is provided for advanced scenarios where you need to issue custom HTTP + /// calls that are not yet covered by the strongly-typed clients exposed by . + /// Prefer using the typed clients (, , + /// , , ) whenever possible. + /// Relying on this property may couple your code to the current HTTP implementation and + /// could limit future refactoring of the underlying client. + /// public IHttpClient Client { get => base._http; } public ApiClient(string serviceUrl, CancellationToken cancellationToken = default) : base(cancellationToken) @@ -34,7 +46,6 @@ public ApiClient(string serviceUrl, IHttpClient client, CancellationToken cancel Users = new UserClient(_http, cancellationToken); Teams = new TeamClient(serviceUrl, _http, cancellationToken); Meetings = new MeetingClient(serviceUrl, _http, cancellationToken); - } public ApiClient(string serviceUrl, IHttpClientOptions options, CancellationToken cancellationToken = default) : base(options, cancellationToken) diff --git a/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs b/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs index 5759d686..ea166991 100644 --- a/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs +++ b/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Microsoft.Teams.Api.Messages; @@ -45,11 +45,8 @@ public ReactionClient(string serviceUrl, IHttpClientFactory factory, Cancellatio /// /// The reaction type (for example: "like", "heart", "laugh", etc.). /// - /// - /// Optional id of the user on whose behalf the reaction is added/updated (if supported by the service). - /// /// - /// A describing the reaction, or null if the service returned an empty body. + /// A representing the asynchronous operation. /// public async Task CreateOrUpdateAsync( string conversationId, @@ -72,9 +69,9 @@ ReactionType reactionType /// /// The reaction type to remove (for example: "like", "heart", "laugh", etc.). /// - /// - /// Optional id of the user whose reaction should be removed (if supported by the service). - /// + /// + /// A representing the asynchronous operation. + /// public async Task DeleteAsync( string conversationId, string activityId, diff --git a/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs b/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs index ec8613c5..1bbb568b 100644 --- a/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs +++ b/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs @@ -8,7 +8,7 @@ namespace Microsoft.Teams.Api.Messages; /// -/// The type of reaction given to the +/// The type of reaction given to the message. /// [JsonConverter(typeof(JsonConverter))] public class ReactionType(string value) : StringEnum(value) diff --git a/Samples/Samples.Reactions/Program.cs b/Samples/Samples.Reactions/Program.cs index 7b25d830..20be7dc7 100644 --- a/Samples/Samples.Reactions/Program.cs +++ b/Samples/Samples.Reactions/Program.cs @@ -32,7 +32,7 @@ teams.OnMessageReaction(async (context, cancellationToken) => { context.Log.Info($"Reaction '{context.Activity.ReactionsAdded?.FirstOrDefault()?.Type}' added by {context.Activity.From?.Name}"); - await context.Send($"you reacted with added '{context.Activity.ReactionsAdded?.FirstOrDefault()?.Type}' " + + await context.Send($"you added '{context.Activity.ReactionsAdded?.FirstOrDefault()?.Type}' " + $"and removed '{context.Activity.ReactionsRemoved?.FirstOrDefault()?.Type}'", cancellationToken); }); diff --git a/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs b/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs new file mode 100644 index 00000000..7e0ba8b4 --- /dev/null +++ b/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs @@ -0,0 +1,74 @@ +using System.Net; + +using Microsoft.Teams.Api.Clients; +using Microsoft.Teams.Api.Messages; +using Microsoft.Teams.Common.Http; + +using Moq; + +namespace Microsoft.Teams.Api.Tests.Clients; + +public class ReactionClientTests +{ + [Fact] + public async Task reactionClient_CreateOrUpdateAsync() + { + var responseMessage = new HttpResponseMessage(); + responseMessage.Headers.Add("Custom-Header", "HeaderValue"); + var mockHandler = new Mock(); + mockHandler + .Setup(handler => handler.SendAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new HttpResponse() + { + Headers = responseMessage.Headers, + StatusCode = HttpStatusCode.OK, + Body = string.Empty + }); + + string serviceUrl = "https://serviceurl.com/"; + var reactionClient = new ReactionClient(serviceUrl, mockHandler.Object); + string conversationId = "conversationId"; + string activityId = "activityId"; + var reactionType = ReactionType.Like; + + await reactionClient.CreateOrUpdateAsync(conversationId, activityId, reactionType); + + string expectedUrl = "https://serviceurl.com/v3/conversations/conversationId/activities/activityId/reactions/like"; + HttpMethod expectedMethod = HttpMethod.Put; + mockHandler.Verify(x => x.SendAsync( + It.Is(arg => arg.Url == expectedUrl && arg.Method == expectedMethod), + It.IsAny()), + Times.Once); + } + + [Fact] + public async Task reactionClient_DeleteAsync() + { + var responseMessage = new HttpResponseMessage(); + responseMessage.Headers.Add("Custom-Header", "HeaderValue"); + var mockHandler = new Mock(); + mockHandler + .Setup(handler => handler.SendAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new HttpResponse() + { + Headers = responseMessage.Headers, + StatusCode = HttpStatusCode.OK, + Body = string.Empty + }); + + string serviceUrl = "https://serviceurl.com/"; + var reactionClient = new ReactionClient(serviceUrl, mockHandler.Object); + string conversationId = "conversationId"; + string activityId = "activityId"; + var reactionType = ReactionType.Heart; + + await reactionClient.DeleteAsync(conversationId, activityId, reactionType); + + string expectedUrl = "https://serviceurl.com/v3/conversations/conversationId/activities/activityId/reactions/heart"; + HttpMethod expectedMethod = HttpMethod.Delete; + mockHandler.Verify(x => x.SendAsync( + It.Is(arg => arg.Url == expectedUrl && arg.Method == expectedMethod), + It.IsAny()), + Times.Once); + } +} From 83da339a7b2474818c00e821698e731e6319a1db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:06:48 +0000 Subject: [PATCH 3/3] Fix test method naming to use PascalCase Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com> --- .../Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs b/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs index 7e0ba8b4..cef8b1f8 100644 --- a/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs +++ b/Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs @@ -11,7 +11,7 @@ namespace Microsoft.Teams.Api.Tests.Clients; public class ReactionClientTests { [Fact] - public async Task reactionClient_CreateOrUpdateAsync() + public async Task ReactionClient_CreateOrUpdateAsync() { var responseMessage = new HttpResponseMessage(); responseMessage.Headers.Add("Custom-Header", "HeaderValue"); @@ -42,7 +42,7 @@ public async Task reactionClient_CreateOrUpdateAsync() } [Fact] - public async Task reactionClient_DeleteAsync() + public async Task ReactionClient_DeleteAsync() { var responseMessage = new HttpResponseMessage(); responseMessage.Headers.Add("Custom-Header", "HeaderValue");