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/')
}
Related
I am new to Blazor. I'm working on a Server App (not WASM).
On a page load, I am loading 2 things to a page. Item1 is loaded at the same time as Item2 via API calls. I'd like individual items to show up as soon as they are available. I was thinking something like
protected override async Task OnInitializedAsync()
{
var t1 = _service.GetItem1().ContinueWith(t => {
Item1Loaded = true;
Item2State = t.Result;
await InvokeAsync(StateHasChanged);
});
var t2 = _service.GetItem2().ContinueWith(t => {
Item2Loaded = true;
Item2State = t.Result;
await InvokeAsync(StateHasChanged);
});
}
I have a couple questions about this though:
Do I need to worry about canceling these lines if the user navigates away from the component? (would changing a state variable after the component is removed cause a problem) or does Blazor handle that at the framework level somehow?
Do I need to ensure this gets back to a certain thread with a Synchronization Context? It seems like InvokeAsync just does this for me but want to be sure.
Its hard to find lots of modern examples of ContinueWith. async/await is dominant, but I don't think it allows continuations to execute in the order they complete. Is this a reasonable use of it?
Since you are using Server side you can do this more cleanly (ContinueWith is more or less obsolete since async / await):
protected override async Task OnInitializedAsync()
{
var t1 = Task.Run(async () =>
{ Item1State = await _service.GetItem1();
Item1Loaded = true; // you can probably derive this from Item1State
await InvokeAsync(StateHasChanged);
});
var t2 = Task.Run(async () =>
{ Item2State = await _service.GetItem2();
Item2Loaded = true;
await InvokeAsync(StateHasChanged);
});
await Task.WhenAll(t1, t2);
}
No need to call StateHasChanged() here.
Without the ItemLoaded guards you could do this without Task.Run().
Do I need to worry about canceling these lines if the user navigates away
Most modern DB stuff can be passed a cancellation token. So, use that if you wish to cancel the operation. If It's your own code and the operations are long running, consider using cancellation tokens.
Do I need to ensure this gets back to a certain thread with a Synchronization Context?
Calling await InvokeAsync(StateHasChanged); ensures the UI code is run on the UI thread.
Question 3
Stick with simple await. Yes, it executes in order. And call await InvokeAsync(StateHasChanged) between operations to update the UI if you have more than two await operations.
Note : This will only work if you await real async code, not sync code wrapped in a Task! If there are no yields, the Renderer gets no thread time so the UI doesn't get updated till it gets some.
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;
}
I'm dipping my toe into the waters of Axios and async/await at the same time, and am trying to understand something about the control flow. Is the following legitimate?
let loading=true;
(async() => {
let response = null;
try {
response = await axios.get('https://whatever.com/api');
} finally {
loading=false;
}
if(response){
//do something with response here
}
})();
That is, can I count on the request to have returned at the point I am accessing the response variable? I appreciate I could guarantee it is by moving it into the 'try' immediately after the axios get, but then I would have to have the loading=false line before it, as well as in 'finally' (or 'catch'). I need to ensure that loading is set to false before any further actions, whether the request succeeds or fails, and I don't want to repeat myself. Maybe there's a better way of doing this?
Edit
Now that you have changed the question, the previous solution will not be working correctly. The issue is that the code inside the IIFE will be executed after everything else is finished, so loading will never be set to false from the perspective of the outside code. (the other code will be executed, and thеn the IIFE. That's because of the event loop). Your best bet is to make the outside code async and await the axios promise.
If you provide the problem details I might be able to help you refactor it.
Previous answer
I need to ensure that loading is set to false before any further actions
Any code after the await is guaranteed to NOT be loading:
(async() => {
let response = await axios.get('https://whatever.com/api');
// the request is finished, the await guarantees that
})();
If you need error handling, you can wrap it in a try/catch:
(async() => {
try {
let response = await axios.get('https://whatever.com/api');
// definitely not loading
}
catch (e) {
// definitely not loading, but an error occurred
}
})();
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
I'm trying to implement a wrapper for the Amazon IAP Plugin for Xamarin. It uses an event based system in the following way:
You can initiate method calls and listen for events. Method calls initiate requests, some of which return a response. Events are asynchronous system-generated messages that are sent in response to method calls to return the requested data to you.
See more here
My goal is to wrap this event based system into some API which allows me to use the plugin with tasks, so I can use the async-await syntax. To achieve that I'm using the TaskCompletionSource like in the following example:
public async Task<bool> GetProductInfoAsync(params string[] productIds)
{
var iapService = AmazonIapV2Impl.Instance;
var tcs = new TaskCompletionSource<bool>();
var skus = new SkusInput { Skus = productIds.ToList() };
var requestId = iapService.GetProductData(skus).RequestId;
GetProductDataResponseDelegator delegator = null;
delegator = new GetProductDataResponseDelegator(response =>
{
if(response.Id == requestId) {
var result = GetResultFromResponse(response);
tcs.SetResult(result);
//iapService.RemoveGetProductDataResponseListener(delegator.responseDelegate);
}
});
iapService.AddGetProductDataResponseListener(delegator.responseDelegate);
return await tcs.Task;
}
This code seems to work fine if the method gets called once, but if it gets called two times in a row the app crashes immediately and the only thing printed to the console is the following message..
[mono] Unhandled Exception:
[mono] System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
..which kinda makes no sense at all.
So is there something obvious I'm missing here? Or could it be a bug from the plugin?
I have created a repository with the code above so you can reproduce the problem. It's my playground, so please ignore the whole structure of the project and just focus on the classes AmazonIAPService and MainActivity.
Hint 1:
The commented line //iapService.RemoveGetProductDataResponseListener(delegator.responseDelegate); causes also a crash with the same message but already at the first call of the method.
Hint 2:
The AmazonIAPService contains a commented method which uses await Task.Delay(TimeSpan.FromMilliseconds(1)) and solves the problem from above in a very hacky way which I really don't like.
Problem seems to be that those functions have to run asynchronously. Also mentioned here in the doc. So once you run those functions synchronously somehow they throw exception, i dont what is happening in the library but your hacky solution is the actual solution for that. If you write the function as below. it also works.
PurchaseResponseDelegator delegator = null;
delegator = new PurchaseResponseDelegator(async response =>
{
await Task.Run(() =>
{
if (response.RequestId == requestId)
{
var result = GetPurchaseEventHandler(response);
var sucess = taskCompletionSource.TrySetResult(result);
context.RemovePurchaseResponseListener(delegator.responseDelegate);
}
} );
});
// Register for an event
context.AddPurchaseResponseListener(delegator.responseDelegate);
One other exception I had despite the async-await solution, somehow, it always throws exception for the line taskCompletionSource.SetResult(result); for PurchaseUpdates functions only. if i use instead this line var sucess = taskCompletionSource.TrySetResult(result); it works fine