// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.Teams.Core; using Microsoft.Teams.Core.Schema; using Xunit.Abstractions; namespace IntegrationTests; /// /// Integration tests for core making real API calls. /// public class ConversationClientTests : IClassFixture { private readonly IntegrationTestFixture _f; private readonly ITestOutputHelper _output; public ConversationClientTests(IntegrationTestFixture fixture, ITestOutputHelper output) { _f = fixture; _f.OutputHelper = output; _output = output; } [Fact(Timeout = 5000)] [Trait("Category", "Activities")] public async Task SendActivity() { CoreActivity activity = CoreActivity.CreateBuilder() .WithType(ActivityType.Message) .WithFrom(IntegrationTestFixture.GetChannelAccountWithAgenticProperties()) .WithServiceUrl(_f.ServiceUrl) .WithConversation(new(_f.ConversationId)) .WithProperty("text", $"[ConversationClient] SendActivity at `{DateTime.UtcNow:s}`") .Build(); SendActivityResponse? res = await _f.ConversationClient.SendActivityAsync(activity); Assert.NotNull(res); Assert.NotNull(res.Id); _output.WriteLine($"Sent activity: {res.Id}"); } [Fact(Timeout = 5000)] [Trait("Category", "Activities")] public async Task UpdateActivity() { CoreActivity activity = CoreActivity.CreateBuilder() .WithType(ActivityType.Message) .WithFrom(IntegrationTestFixture.GetChannelAccountWithAgenticProperties()) .WithServiceUrl(_f.ServiceUrl) .WithConversation(new(_f.ConversationId)) .WithProperty("text", $"[ConversationClient] Original at `{DateTime.UtcNow:s}`") .Build(); SendActivityResponse? sent = await _f.ConversationClient.SendActivityAsync(activity); Assert.NotNull(sent?.Id); CoreActivity updated = CoreActivity.CreateBuilder() .WithType(ActivityType.Message) .WithFrom(IntegrationTestFixture.GetChannelAccountWithAgenticProperties()) .WithServiceUrl(_f.ServiceUrl) .WithConversation(new(_f.ConversationId)) .WithProperty("text", $"[ConversationClient] Updated at `{DateTime.UtcNow:s}`") .Build(); UpdateActivityResponse res = await _f.ConversationClient.UpdateActivityAsync( _f.ConversationId, sent.Id, updated, false, _f.AgenticIdentity); Assert.NotNull(res?.Id); _output.WriteLine($"Updated activity: {res.Id}"); } [Fact(Timeout = 5000)] [Trait("Category", "Activities")] public async Task DeleteActivity() { CoreActivity activity = CoreActivity.CreateBuilder() .WithType(ActivityType.Message) .WithFrom(IntegrationTestFixture.GetChannelAccountWithAgenticProperties()) .WithServiceUrl(_f.ServiceUrl) .WithConversation(new(_f.ConversationId)) .WithProperty("text", $"[ConversationClient] To delete at `{DateTime.UtcNow:s}`") .Build(); SendActivityResponse? sent = await _f.ConversationClient.SendActivityAsync(activity); Assert.NotNull(sent?.Id); await Task.Delay(2000); await _f.ConversationClient.DeleteActivityAsync( _f.ConversationId, sent.Id, _f.ServiceUrl, _f.AgenticIdentity); _output.WriteLine($"Deleted activity: {sent.Id}"); } [Fact(Timeout = 5000)] [Trait("Category", "Activities")] public async Task GetConversationMembers() { IList members = await _f.ConversationClient.GetConversationMembersAsync( _f.ConversationId, _f.ServiceUrl, _f.AgenticIdentity); Assert.NotNull(members); Assert.NotEmpty(members); foreach (ChannelAccount m in members) { _output.WriteLine($"Member: {m.Id} — {m.Name}"); } } [Fact(Timeout = 5000)] [Trait("Category", "Activities")] public async Task GetConversationMember() { string memberId = _f.MemberMri1!; ChannelAccount member = await _f.ConversationClient.GetConversationMemberAsync( _f.ConversationId, memberId, _f.ServiceUrl, _f.AgenticIdentity); Assert.NotNull(member); Assert.Equal(memberId, member.Id); _output.WriteLine($"Member: {member.Id} — {member.Name}"); } [SkippableFact(Timeout = 5000)] [Trait("Category", "Activities")] public async Task GetPagedMembers() { Skip.If(_f.AgenticIdentity is not null, "Paged members returns 500 with agentic identity — service limitation"); Skip.If(_f.IsCanary, "Paged members returns empty on canary — service limitation"); PagedMembersResult result = await _f.ConversationClient.GetConversationPagedMembersAsync( _f.ConversationId, _f.ServiceUrl, pageSize: 5, agenticIdentity: _f.AgenticIdentity); Assert.NotNull(result?.Members); Assert.NotEmpty(result.Members); foreach (ChannelAccount m in result.Members.Take(5)) { _output.WriteLine($"Member: {m.Id} — {m.Name}"); } } [SkippableFact] [Trait("Category", "Activities")] public async Task AddAndDeleteReaction() { Skip.If(_f.AgenticIdentity is not null, "Reactions API returns 404 with agentic identity — service limitation"); Skip.If(_f.IsCanary, "Reactions API returns 404 on canary — service limitation"); CoreActivity activity = CoreActivity.CreateBuilder() .WithType(ActivityType.Message) .WithServiceUrl(_f.ServiceUrl) .WithFrom(IntegrationTestFixture.GetChannelAccountWithAgenticProperties()) .WithConversation(new(_f.ConversationId)) .WithProperty("text", $"[ConversationClient] Reaction test at `{DateTime.UtcNow:s}`") .Build(); SendActivityResponse? sent = await _f.ConversationClient.SendActivityAsync(activity); Assert.NotNull(sent?.Id); await _f.ConversationClient.AddReactionAsync( _f.ConversationId, sent.Id, "like", _f.ServiceUrl, _f.AgenticIdentity); _output.WriteLine("Added 'like' reaction"); await Task.Delay(1000); await _f.ConversationClient.DeleteReactionAsync( _f.ConversationId, sent.Id, "like", _f.ServiceUrl, _f.AgenticIdentity); _output.WriteLine("Removed 'like' reaction"); } }