I am creating a message extension in Microsoft teams and I am running into some issues with chaining task modules from the CommandBar (This is the important part)
I have 2 task modules, A and B.
The Goal:
Run a command from the CommandBar that will respond with task module A. On submitting the task module the message extension should respond task module B.
The issue:
I can't work out how to respond with a task module from inside the onSubmitAction function (on the message extension implementing IMessagingExtensionMiddlewareProcessor.
Here is a cut down version of my code:
export default class HelpDeskMessageExtension implements IMessagingExtensionMiddlewareProcessor {
public async onFetchTask(): Promise<MessagingExtensionResult | TaskModuleContinueResponse | TaskModuleMessageResponse> {
return Promise.resolve<TaskModuleContinueResponse>({
type: "continue",
value: {
url: `${process.env.HostName}/helpdesk.html`,
width: 500,
height: 500,
},
});
}
public async onSubmitAction(context: TurnContext): Promise<any> {
//TODO: If this submit came from task module A, respond with Task module B
// If this came from task module B, respond with a success card
const heroCard = CardFactory.heroCard('<span style="color: green">Message successfully sent</span>',);
await context.sendActivity({ attachments: [heroCard] });
}
}
Note:
This works fine when using the message extension from the compose box. The issue is running this extension from the CommandBar
Any help would be greatly appreciated.
Posting the Answer for better knowledge
Copying from #Ghojzilla comments.
I was using a npm package called botbuilder-teams-messagingextensions which I thought was part of MS bot framework. The package was wrapping any response object from the submit action in a "composeExtension" property so I couldn't wrap it in a task.
Related
As you may already know, Nightwatch 2 now includes methods for making calls to CDP protocol.
So, I'm trying to capture network responses. I know that the "Network" target has to be enabled and also we have to subscribe a callback to the Network.responseReceived event. I've already done it in another framework tool, but I can't find any related example in the Nightwatch documentation that uses CDP events.
At this point, I don't know which is the method that allows this subscription or where is it, is it in browser.driver or in cdpConnection objects?
This is the code I'm currently trying:
module.exports = {
'#tags': ['njs2-03'],
async myTest (browser) {
await browser.driver.sendAndGetDevToolsCommand('Network.enable')
const cdpConnection = await browser.driver.createCDPConnection('page');
cdpConnection._wsConnection.on('Network.responseReceived', entry => {
console.log('ENTRY >>', entry)
})
await browser.url('https://duckduckgo.com/')
}
}
Any suggestion would be really helpful, Thanks!
I was looking for an answer to a similar problem myself. It appears that it is sometimes much better to analyze the source code of Nightwatch directly. Especially after version 2 was released.
Analysis of the CDP commands eg. the mockNetworkResponse method in the Nightwatch code in the method-mappings.js file give answers.
https://github.com/nightwatchjs/nightwatch/blob/098306cf77d4e380b69ab836231947fe94a12ca0/lib/transport/selenium-webdriver/method-mappings.js
Mind that you are using directly the _wsConnection object. Therefore, that is the message event you are looking for. https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/message_event
Thus, try the following
async myTest (browser) {
await browser.driver.sendAndGetDevToolsCommand('Network.enable')
const cdpConnection = await browser.driver.createCDPConnection('page')
cdpConnection._wsConnection.on('message', message => {
const messageParsed = JSON.parse(message)
if (messageParsed.method === 'Network.responseReceived') {
console.log('DEVTOOLS EVENT PARAMS >>', messageParsed.['params'])
}
})
await browser.url('https://duckduckgo.com/')
}
in our use case, we have the team channel id with me. This is captured and stored into the DB in the event below
this.onTeamsChannelCreatedEvent(async (channelInfo: any, teamInfo: any, turnContext: any, next: () => Promise<void>): Promise<void> => {
}
We are running a periodic job and need to find out the members of a channel to perform some operations. So, how can i find members info from the channelid?
I have seen examples which using the context or context.activity. But in this case context wont be available. we are using nodejs v4.
My code here is
var client = new ConnectorClient(credentials, { baseUri: channel.serviceUrl });
client.fetchMembers(channel.serviceUrl, channel.channelId,
(err, result) => {
if (err) {
functions.logger.log("failed to fetch team members")
}
else {
functions.logger.log("Team members are", result)
}
}
);
This now throws error
TypeError: client.fetchMembers is not a function
i have also tried client.fetchMembers but similar error.
There are two main ways you can do this:
Using the Microsoft Graph, in particular see the List Members operation.
By having a bot registered in the channel, which it sounds like you have already. You don't need an 'activity' at all, you can do this any time by accessing the Conversations object. In fact, this code doesn't even need to run in your "bot" project at all - as long as the bot is added to the team/channel, it will work to use the bot's credentials. You can see sample code here in the Microsoft docs, and I have a sample from a recent conference session, doing this in dotnet from a console app over here.
One thing that's worth noting, the members of a channel and the members of a Team are largely the same (only excluding Private channels), so that's why some of these options refer to the Team or Group.
You'll want to use teamsInfo.getTeamMembers() or teamsInfo.getPagedMembers() (if you want a paginated list), as in this sample:
async getPagedMembers(context) {
var continuationToken;
var members = [];
do {
var pagedMembers = await TeamsInfo.getPagedMembers(context, 100, continuationToken);
continuationToken = pagedMembers.continuationToken;
members.push(...pagedMembers.members);
} while (continuationToken !== undefined);
return members;
}
Code's like below, similar to the built-in Custom Tool Window code template.
To load the package I have to find the ToolWindow button (Command) and press it. When I open up a folder this package is not loaded.
However this extension depends on evnets provided by some services (IVsFileChangeEx, .etc), and they needed to be loaded by AsyncPackage.GetServiceAsync. What should I do?
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[Guid(Guids.packageGuidStr)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideToolWindow(typeof(ToolWindow))]
public sealed class ExuedPackage : AsyncPackage
{
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
"Init Package".Log();
.... Get some services and store them ...
.... Register callbacks to them ....
await ToolWindowCommand.InitializeAsync(this);
}
}
I'm using a TextPrompt in a waterfall dialog (Microsoft Bot Framework v4, node.js) to ask a user a question. I see in the emulator that Luis Trace is returning a recognizerResult which contains the top-scoring intent, but how do I access it and act upon it?
Example steps:
async askAQuestionStep(step) {
return await step.prompt(MYQUESTION_PROMPT, {
prompt: 'How are you feeling?'
});
}
async getAnAnswerStep(step) {
if (step.result) {
if (topScoringIntent === 'Good') {
await step.context.sendActivity("Good to hear.");
} else {
return await step.next();
}
}
Need to figure out how to actually access "topScoringIntent." The example show how to do this, but I'm getting this error:
[onTurnError]: TypeError: Cannot read property 'recognize' of undefined
I'm not calling this from bot.js, but from its own dialog/file.
See this answer: Getting the Luis "topIntent" from a child dialog inside another file (Node.js)
I had to create a luisRecognizer in the dialog file and then pass the botConfig, userSate and conversationState to the dialog.
I have a 3rd party API IOS Binding which I am trying to test (more like an integration test) using TouchRunner.
An example API Method is this -
_client.AuthenticateWithUsername(username, token,
() => { // Success Callback },
() => { // NoConnection Callback },
(obj) => { // Other Error Callback });
The API when called goes off and does some work in the background then eventually makes one of the callbacks above, I would like to control the flow of the unit test using something like -
How can I unit test async methods on the UI Thread with Xamarin iOS TouchRunner
Unfortunately, when I insert the AutoResetEvent code, TouchRunner just hangs and never returns to the GUI.
I have also tried to use a TaskCompletionSource as follows -
public async Task<AuthResponse> AuthenticateUserAsync(string username, string password)
{
TaskCompletionSource<AuthResponse> tcs = new TaskCompletionSource<AuthResponse>();
AuthResponse response = new AuthResponse { Success = false };
LoginResponse loginResponse = await LoginUser(username, password);
_client.AuthenticateWithUsername(username, loginResponse.token,
() =>
{
response.Success = true;
Console.WriteLine("Auth");
tcs.SetResult(response);
},
() => { tcs.SetResult(response); },
obj => { tcs.SetResult(response); },
obj => { tcs.SetResult(response); });
return await tcs.Task;
}
[Test]
public async void AuthenticateUserAsyncTest()
{
var auth = await AuthenticateUserAsync(_username, _password);
Assert.IsTrue(auth.Success);
}
The debugger stepped through fine until the return await tcs.Task, but then results in a similar HUNG runner.
How can I work out why the hang is happening?
As this was not working, I then resorted to code like this -
_client.AuthenticateWithUsername(_username, loginResponse.token,
() =>
{
Assert.Pass("This crashes the runner");
Assert.True(true); // This DOES NOT!
},
() =>
{
// This will crash runner also
Assert.Fail("NoConnection");
},
(InvalidTokenError obj) =>
{
Assert.Fail("InvalidToken" + obj.Description);
},
(ClientError obj) =>
{
Assert.Fail("ClientError" + obj.Description);
});
As you can see, the flow ends up (understandably), run test, runs client call, end of test method completes which shows test as success, then the callback returns and the asserts get called, which crash the app, which we assume is because the runner has already completed the test, why one assert works and other crashes I do not know.
So,
Am I approaching this the right way?
Could something be happening in the 3rd Party API that will cause these approaches to hang? and how would I debug that?
Thanks #Nkosi, that is a good suggestion, I forgot to add that during my original testing that when I ran the code with async Task rather than void I got an immediate block from TouchRunner without even adding any other code other than the API call! This was a red flag I suppose, but using async void "seemed" to allow "standard" async testing, so I progressed and then ended up in the loop above.
As TouchRunner has not been updated in a very long time I have just spent time re-creating the test project using XUnit after various suggestions to try it in the forums and on stack.
https://github.com/xunit/devices.xunit - runners for Xamarin IOS + Android
https://xunit.github.io/docs/comparisons - to port NUnit syntax
Some other useful links are -
https://xunit.github.io/docs/getting-started-devices.html
https://gregshackles.com/testing-xamarin-apps-getting-started-with-xunit/
https://oren.codes/2014/07/10/getting-started-with-xunit-for-xamarin/
RESULT: I am very pleased to say all the above code now works for both the TaskCompletionSource and the AutoResetTask scenarios
I can now safely test my event based API :)
I just wanted to ensure other users are aware of this.
Thanks for your help.
One observation is that the test should be async Task and not async void ie
public async Task AuthenticateUserAsyncTest() {
//...code removed for brevity.
}
async void is a fire and forget so any exceptions thrown wont happen in the current context so they wont be caught.
Reference Async/Await - Best Practices in Asynchronous Programming