Flutter Tests: Waiting for a certain duration - dart

I'm trying to wait for some time after I tested tapping my button to then check the result with expect. I'm using Future.delayed for that. But that doesn't work for me. I'm getting a time out error.
TimeoutException after 0:00:05.000000: Test timed out after 5 seconds.
This is the code I use:
... // other tests
await tester.tap(find.widgetWithText(GestureDetector, "ref size"));
await new Future.delayed(new Duration(milliseconds: 50));
expect(testContainerState.childWidth, 50.0);
Does any one have an idea why this (imo) strange behavior occurs?

So, to start out with a simpler answer the correct way to wait for a period of time in a flutter test is using tester.pump.
await tester.pump(new Duration(milliseconds: 50));
The longer answer to why this happens has to do with the flutter testing environment. To make sure tests are reliable, even in the face of time-varying animations the environment mocks as much of the async behavior as possible, using utilities such as FakeAsync from package:quiver.

If you want to waiting data for Ex can you use this code :
await tester.runAsync(() async {
// test code here
});
tester is instance of WidgetTester

Related

Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked

In my react-native project, I am getting the following error message:
Warning: Please report: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code:
{"203":{"module":"MyModule","method":"startProcessing"},"276":{"module":"RNFetchBlob","method":"emitExpiredEvent"},"1855":{},"1856":{},"1857":{},"1858":{},"1859":{},"1860":{},"1861":{},"1862":{},"1863":{},"1864":{},"1865":{},"1866":{},"1867":{},"1868":{},"1869":{},"1870":{},"1871":{},"1872":{},"1873":{},"1874":{},"1875":{},"1876":{},"1877":{},"1878":{},"1879":{},"1880":{},"1881":{},"1882":{},"1883":{},"1884":{},"1885":{},"1886":{},"1887":{},"1888":{},"1889":{},"1890":{},"1891":{},"1892":{},"1893":{},"1894":{},"1895":{},"1896":{},"1897":{},"1898":{},"1899":{},"1900":{},"1901":{},"1902":{},"...(truncated keys)...":451}
Can anyone tell me what module all of these callbacks are coming from or how to interpret this message?
This was a really hard one for me to track down.
What it came down to: This would only occur when I was running on a low spec device (Galaxy A12). I had a hook that looked like this:
const [state, setState] = useState(1);
useEffect(() => {
const t = setInterval(
() => setState(valueGoesHere),
200,
);
return () => clearInterval(t);
}, []);
To poll a value.
This worked fine on higher spec'd phones but it caused the excessive promise issue. You should comb your code for anything like the above snippet, especially using setInterval as it will bank up promises and not allow prior ones time to finish before dispatch.
It seems that the issue was that an async function was being executed in a loop. The loop was firing off lots of async calls almost simultaneously which resulted in excessive number of pending callbacks.
I had this issue with an async function inside a useEffect() while the my device was running debug mode (connected to a debugger). I resolved the issue by disconnecting the debugger.
It seems that the issue when I remove [] from useEffect
React.useEffect(() => {
...do somethings
}, []);
and it work when I added it back

Testing timeout-related tests, such as Popups/Tooltips etc with Detox

I've beed using detox for a while, but after upgrade to 17.5.+ I have started facing an issue with Popups testing. I haven't find useful info on a stack overflow and on detox issues.
Problem here is the following: I have a test to check if correct popup is shown. It looks like:
it('expect to see "Answer correct" popup', async () => {
await openQuestionnaire('theory_questionnaire_learn_button');
await scroll('questionnaire_scroll_view', 150);
await element(by.id('select_1_button')).tap();
await element(by.id('questionnaire_answer_button')).tap();
// #ts-ignore
await expect(element(by.id('questionnaire_simple_popup'))).toBeVisible();
// #ts-ignore
await expect(element(by.id('questionnaire_simple_popup'))).toHaveLabel('correct');
await delay(500);
// #ts-ignore
await expect(element(by.id('questionnaire_simple_popup'))).toNotExist();
});
Background for this: after questionnaire_answer_button is tapped, popup appears. It is visible for 500ms and then it disappears. For this 500ms I'm using setTimeout({ () => dismiss() }, 500).
Popup is visible on an emulator, but my test fails with Test Failed: No elements found for “MATCHER(identifier: == “questionnaire_simple_popup”)”
Checking hierarchy I haven't find this element there. Maybe someone else have already faced this and know a solution?
If the identifier is not found, it means the identifier has not been properly set with the native view’s accessibility identifier. Check with the popup developer that testID are properly forwarded to the native views.
Ok, what have I found out after several tries. It start working after increasing timeout from 500ms to 3000ms. 2500 was still failing, 2750 haven't tried. Regarding matchers. by.id and by.text works as well.
So the reason probably was a timeout duration.

Dart await while(true) but users cannot input with stdin

import 'dart:io';
main() async {
await loop();
while(true){
print('Your input:${stdin.readLineSync()}');
}
}
loop(){
print('stuck');
//Future.delayed(Duration(days:5),(){});//works fine
//while(true);//does not work
}
Why cannot users input anything when while(true) is being executed inside loop(), instead, Future. delayed works fine with stdin?
Dart is single-threaded. That means that at most one piece of Dart code is running at a time (per isolate if you have isolates).
Code like while(true); is a tight loop that never stops. No other code will run in the same isolate until the loop ends, and the loop never ends. This is busy waiting, and it does not give other code time to run.
You never even get to the part of your code which calls stdin.readLineSync().
The await in front of loop() does nothing, because the code never gets to it. It calls loop and stays there forever.
If you create a Future.delayed(...), then ... it doesn't actually do anything. You are not returning it, so the await won't be waiting for it to complete. All you do is to create a timer, create a Future object, and when the timer runs out, something will happen which will complete the future. If you return the future, then the await will wait for that.
What did you want or expect this code to do?

How to test if Xamarin Android app closes

I am writing my first Android app, using Xamarin. I have an Exit button that, when clicked, closes the app. I want a test in Xamarin UITest that verifies clicking the button closes the app. I messed around with it for a while and finally found something that allows the test to pass.
In the app:
exitButton.Click += (o, e) =>
{
int pid = Android.OS.Process.MyPid();
Android.OS.Process.KillProcess(pid);
};
In UITest:
[Test]
public void ExitButtonClosesTheScreen()
{
try
{
app.Tap(c => c.Button("exitButton"));
Assert.Fail("App remains open.");
}
catch (System.Exception e)
{
Assert.AreEqual("The underlying connection was closed: The connection was closed unexpectedly.", e.InnerException.InnerException.InnerException.Message);
}
}
The test now passes so I guess I'm happy. My question is, is this really the best way to do this? Or is there a better way that I wasn't able to find?
Edit: Unfortunately, this is not the answer. This method allows the test to pass in VS but fails when I run it in App Center. Is there another way to run this test? Or is this something that is simply not testable with UITest? Thank you.
First of all the right code for closing the Application as per me is using finish affinity
In an Activity:
this.FinishAffinity();
In a Fragment:
this.Activity.FinishAffinity();
After doing this AppCenter should be able to figure that your app is closed.
I did a brief read up on this the other day for something similar and I am certain that the ActivityManager class would be the best way to go about this.
https://developer.xamarin.com/api/type/Android.App.ActivityManager/
There is a method within this class called RunningAppProcesses which returns a list of application processes that are running on the device - and from there I guess you can assert if your app process is on the list or not.
Hope this helps
After almost 4 years, i've encountered with the same issue.
I will do it this way in your case:
[Test]
public void ExitButtonClosesTheScreen()
{
app.Tap(c => c.Marked("exitButton"));
/** I asume exitButton click action will just exit,
no popups or alerts appear before exiting. **/
app.WaitForNoElement(q => q.Marked("exitButton"),
"Timeout waiting for element exitButton",
new TimeSpan(0, 0, 30));
AppResult[] result = app.Query();
Assert.IsTrue(result.Length == 0);
}
app.Query() returns all views visible by default, unless a query is especified by a lambda expression, as you should alredy know.
If the Application is gone, the Views visible will be 0, and as such, app.query() will return and array lenght of 0.
For WaitForNoElement's timeout I use a TimeSpan of 30 seconds, but you can use whatever timeout you prefer for this operation, i just considered 30 seconds will be ok.

Syncronous waiting for a Future or a Stream to complete in Dart

I'm playing with a tiny web server and I'm implementing one version using the async package, and one synchronous version executing each request in a separate isolate. I would like to simply pipe a file stream to the HttpResponse, but I can't do that synchronously. And I can't find a way to wait for neither the Stream nor a Future synchronously. I'm now using a RandomAccessFile instead which works, but it becomes messier.
One solution would be to execute a periodical timer to check if the future is completed (by setting a boolean or similar), but that is most definitely not something I want to use.
Is there a way to wait synchronously for a Future and a Stream? If not, why?
For future visitors coming here simply wanting to perform some task after a Future or Stream completes, use await and await for inside an async method.
Future
final myInt = await getFutureInt();
Stream
int mySum = 0;
await for (int someInt in myIntStream) {
mySum += someInt;
}
Note
This may be technically different than performing a synchronous task, but it achieves the goal of completing one task before doing another one.
AFAIK there isn't a way to wait synchronously for a Future or a Stream. Why? Because these are asynchronous pretty much definitionally, and as you are discovering, the APIs are designed with asynchronous behavior in mind.
There are a couple of Future constructors, Future.value() and Future.sync(), that execute immediately, but I don't think these are probably what you have in mind.

Resources