using Microsoft.Teams.Api;
using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Api.Auth;
using Microsoft.Teams.Api.Entities;
using Microsoft.Teams.Apps.Activities;
using Microsoft.Teams.Apps.Testing.Plugins;
namespace Microsoft.Teams.Apps.Tests.Activities;
#pragma warning disable ExperimentalTeamsTargeted
public class PromptPreviewTests
{
private readonly App _app = new();
private readonly IToken _token = Globals.Token;
public PromptPreviewTests()
{
_app.AddPlugin(new TestPlugin());
}
[Fact]
public async Task Send_AutoPopulates_TargetedMessageInfoEntity_WhenIncomingIsTargeted()
{
IActivity? sentActivity = null;
_app.OnMessage(async (context, cancellationToken) =>
{
sentActivity = await context.Send("Here is the result!", cancellationToken);
});
// Simulate an incoming targeted message (bot's Recipient.IsTargeted = true)
var incomingActivity = new MessageActivity("summarize")
.WithId("1772129782775")
.WithFrom(new Account() { Id = "user1", Name = "User" })
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" }, true);
await _app.Process<TestPlugin>(_token, incomingActivity);
Assert.NotNull(sentActivity);
Assert.NotNull(sentActivity!.Entities);
var targetedEntity = sentActivity.Entities!.OfType<TargetedMessageInfoEntity>().SingleOrDefault();
Assert.NotNull(targetedEntity);
Assert.Equal("1772129782775", targetedEntity!.MessageId);
}
[Fact]
public async Task Reply_AutoPopulates_TargetedMessageInfoEntity_WhenIncomingIsTargeted()
{
IActivity? sentActivity = null;
_app.OnMessage(async (context, cancellationToken) =>
{
sentActivity = await context.Reply("Here is the result!", cancellationToken);
});
var incomingActivity = new MessageActivity("summarize")
.WithId("1772129782775")
.WithFrom(new Account() { Id = "user1", Name = "User" })
.WithConversation(new Api.Conversation() { Id = "conv1" })
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" }, true);
await _app.Process<TestPlugin>(_token, incomingActivity);
Assert.NotNull(sentActivity);
Assert.NotNull(sentActivity!.Entities);
// Reply calls Send, which auto-populates the entity
var targetedEntity = sentActivity.Entities!.OfType<TargetedMessageInfoEntity>().SingleOrDefault();
Assert.NotNull(targetedEntity);
Assert.Equal("1772129782775", targetedEntity!.MessageId);
// quotedReply entities should be stripped by AddTargetedMessageInfo
Assert.DoesNotContain(sentActivity.Entities!, e => e.Type == "quotedReply");
}
[Fact]
public async Task Send_DoesNotAdd_TargetedMessageInfoEntity_WhenNotTargeted()
{
IActivity? sentActivity = null;
_app.OnMessage(async (context, cancellationToken) =>
{
sentActivity = await context.Send("Hello!", cancellationToken);
});
// Normal (non-targeted) incoming message
var incomingActivity = new MessageActivity("hello")
.WithId("123456")
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" });
await _app.Process<TestPlugin>(_token, incomingActivity);
Assert.NotNull(sentActivity);
var targetedEntity = sentActivity!.Entities?.OfType<TargetedMessageInfoEntity>().SingleOrDefault();
Assert.Null(targetedEntity);
}
[Fact]
public async Task Send_DoesNotDuplicate_TargetedMessageInfoEntity_WhenAlreadyPresent()
{
IActivity? sentActivity = null;
_app.OnMessage(async (context, cancellationToken) =>
{
// Developer manually adds the entity (proactive-like scenario)
var activity = new MessageActivity("Result")
.AddEntity(new TargetedMessageInfoEntity { MessageId = "9999" });
sentActivity = await context.Send(activity, cancellationToken);
});
// Incoming activity is targeted
var incomingActivity = new MessageActivity("summarize")
.WithId("1772129782775")
.WithFrom(new Account() { Id = "user1", Name = "User" })
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" }, true);
await _app.Process<TestPlugin>(_token, incomingActivity);
Assert.NotNull(sentActivity);
Assert.NotNull(sentActivity!.Entities);
var targetedEntities = sentActivity.Entities!.OfType<TargetedMessageInfoEntity>().ToList();
Assert.Single(targetedEntities);
// The developer-provided entity should be preserved, not overwritten
Assert.Equal("9999", targetedEntities[0].MessageId);
}
[Fact]
public async Task Send_Throws_WhenTargetedMessage_InPersonalChat()
{
_app.OnMessage(async (context, cancellationToken) =>
{
await context.Send(
new MessageActivity("Secret!")
.WithRecipient(new Account() { Id = "user1", Name = "User" }, true),
cancellationToken);
});
var incomingActivity = new MessageActivity("hello")
.WithId("123456")
.WithFrom(new Account() { Id = "user1", Name = "User" })
.WithConversation(new Api.Conversation() { Id = "conv1", Type = ConversationType.Personal })
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" });
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => _app.Process<TestPlugin>(_token, incomingActivity));
Assert.Contains("personal", ex.Message, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public async Task Send_Succeeds_WhenNonTargetedMessage_InPersonalChat()
{
IActivity? sentActivity = null;
_app.OnMessage(async (context, cancellationToken) =>
{
sentActivity = await context.Send("Hello!", cancellationToken);
});
var incomingActivity = new MessageActivity("hello")
.WithId("123456")
.WithFrom(new Account() { Id = "user1", Name = "User" })
.WithConversation(new Api.Conversation() { Id = "conv1", Type = ConversationType.Personal })
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" });
await _app.Process<TestPlugin>(_token, incomingActivity);
Assert.NotNull(sentActivity);
}
[Fact]
public async Task Send_Succeeds_WhenTargetedMessage_InGroupChat()
{
IActivity? sentActivity = null;
_app.OnMessage(async (context, cancellationToken) =>
{
sentActivity = await context.Send(
new MessageActivity("Only you can see this!")
.WithRecipient(new Account() { Id = "user1", Name = "User" }, true),
cancellationToken);
});
var incomingActivity = new MessageActivity("hello")
.WithId("123456")
.WithFrom(new Account() { Id = "user1", Name = "User" })
.WithConversation(new Api.Conversation() { Id = "conv1", Type = ConversationType.GroupChat })
.WithRecipient(new Account() { Id = "bot1", Name = "Bot" });
await _app.Process<TestPlugin>(_token, incomingActivity);
Assert.NotNull(sentActivity);
}
}microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
Tests/Microsoft.Teams.Apps.Tests/Activities/PromptPreviewTests.cs
196lines · modepreview