Access flutter tests result in tearDownAll - flutter

I need to access the tests result in tearDownAll callback. I want to check if any of the tests failed during the execution.
tearDownAll(() async {
final success = // code here
});
I researched classes like Invoker, Declarer, Engine, LiveTestController and test_core.dart file. Seems like this is the code that does what I need.
var success = await runZoned(() => Invoker.guard(engine.run),
zoneValues: {#test.declarer: _globalDeclarer});
if (success) return null;
print('');
unawaited(Future.error('Dummy exception to set exit code.'));
Unfortunately the engine is not accessible from outside. I've also not found API for checking the tests result in test_core library.
Is there a way to check if any of previous test has failed? I'd like use this inside a tearDownAll() or test() functions of a test group.

I found a possible solution to my question, that requires some extra stuff in the test class.
Basically you have to check every single test result in tearDown and keep track of them, then in tearDownAll you can check if any of the test has failed.
import 'package:test_api/src/backend/invoker.dart';
import 'package:test_api/src/backend/state.dart' as test_api;
final failedTests = [];
tearDown(() {
if (Invoker.current.liveTest.state.result == test_api.Result.error) {
failedTests.add(Invoker.current.liveTest.individualName);
}
});
tearDownAll(() {
if (failedTests.isNotEmpty) {
// do stuff
}
});

Related

Flutter function returning at await statement

I am using flutter with the cbl package to persist data. Trying to retrieve the entries does not seem to work because the function created is returning at the await statement and not the return statement. This does not seem like the intended result of darts async/await functionality. So I am lost.
task_database.dart
Future<dynamic> getAllTasks() async {
final tasksDb = await Database.openAsync(database); <---------- Returns here
var tasksQuery = const QueryBuilder()
.select(SelectResult.all())
.from(DataSource.database(tasksDb));
final resultSet = await tasksQuery.execute();
late var task;
await for (final result in resultSet.asStream()) {
final map = result.toPlainMap();
final taskDao = TaskDao.fromJson(map);
task = taskDao.task;
// Do something with the task...
print(task);
}
;
return task; <-------------------------------------------- Does not make it here
}
task_cubit.dart
getAllTasks() => {
allTaskMap = TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
What I have tried. I have tried to use Database.openSync instead of Database.openAsync however, the function just returns at the next await statement. I have also tried making getAllTasks asynchronous and awaiting the database as such.
Future<void> getAllTasks() async => {
allTaskMap = await TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
However this has the same issue, when the function from task_database returns prematurely it the returns at the first await function in getAllTasks which is the allTaskMap variable.
Thanks
A function cannot "return prematurely" without a return statement.
The only way the execution is cut short would be an exception being thrown.
I also don't see how you don't get syntax errors, when you don't await the Database.openAsync(database) statement.
So make sure all your awaits are in place. Use the linter to find those that are missing. While you are at it, remove the keyword dynamic from your vocabulary, it will only hurt you if you use it without a need for it. Your return type should be properly typed, then your compiler could tell you, that returning a single task from a function that is clearly supposed to return multiple tasks is not going to work.
Either catch your exceptions and make sure you know there was one, or do not catch them and watch them go all the way through into your debugger.
In addition, following the comment of #jamesdlin, your function definitions are... valid, but probably not doing what you think they are doing.
Future<void> getAllTasks() async => {
allTaskMap = await TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
needs to be
Future<void> getAllTasks() async {
allTaskMap = await TasksAbcDatabase().getAllTasks();
emit(TaskState(tasks: state. Tasks));
}

Protractor. How to restart browser between tests?

I wrote a pack of tests and separately each of them works correctly (for each test I created separate file - it important for my case) , but when I try to run them all together I have some problems:
At the first I tried to restart browser after each test with “restartBrowserBetweenTests: true” option but as a result I receive next error:
Failed: This driver instance does not have a valid session ID (did you
call WebDriver.quit()?) and may no longer be used.
I read some advice for this situation, but nothing helped me.
Basically, I can get without restarting browser but in this case I want to close all active tabs after each test and I also don’t know ho to do it. With the help of this function:
browser.getAllWindowHandles().then((handles) => {
browser.driver.switchTo().window(handles[1]);
browser.driver.close();
browser.driver.switchTo().window(handles[0]);
});
I can close active tab and return for the previous but the function works only if I place this code in the test spec, that's not comfortable for me (copy it for each test) and if I call it from special file with functions it works incorrectly due to the
“Failed: no such window: target window already closed
from unknown error: web view not found”
errors (a consequence of a lost context).
https://www.protractortest.org/#/api?view=ProtractorBrowser.prototype.restart
use instead:
browser.restart()
also try to use await
it('Test Puppeteer screenshot', async function() {
await browser.get('https://www.google.com')
let current = await browser.getWindowHandle()
await browser.executeScript("window.open('https://www.indiatoday.com')")
handles = await browser.getAllWindowHandles()
await browser.switchTo().window(handles[1]);
await browser.close();
await browser.switchTo().window(handles[0]);
});
Note if you are using page object the nyou have to reinitialize modules:
if you are using javascript object notation for page then
https://www.npmjs.com/package/decache
const decache = require('decache');
let stage1 = require('../pageobjects/stage1.js');
beforeEach(async function () {
decache('../pageobjects/stage1.js');
stage1 = require('../pageobjects/stage1.js');
elements = stage1.elements;
});
If you are using nodejs class:
let stage1 = require('../pageobjects/stage1.js');
beforeEach(async function () {
stage1 = new PageObjects.stage1();
});
This because the reference for elements have changed you have to reinitialize them

FireStore read fails silently and I have no idea why

Help is much appreciated how to trace down this issue, because I am running out of ideas.
I am calling the function getOrderCollection, below, but it aborts after the first line var myCompanyDoc = await FirebaseFirestore.instance.collection('companies').doc(myCompany).get(); Without trowing anything to the console or jumping into some library when debugging. When I click next statement it jumps back to the calling function.
I am authenticated to the database, companyCollection = FirebaseFirestore.instance.collection('companies') provides an initialized object pointing to the collection and myCompany is a constant with the document id entered by copy/paste.
If some rules for the database but I can't see successful or denied queries with the monitor.
Any ideas how I can proceed tracing down the issue?
Future<void> getOrderCollection() async {
var myCompanyDoc = await FirebaseFirestore.instance.collection('companies').doc(myCompany).get();
print("companyDoc fetched");
final myDeliveryDocRef = myCompanyDoc.data()['delivery'].toString();
orderCollection = FirebaseFirestore.instance.collection('companies').doc(myCompany).collection('features').doc(myDeliveryDocRef).collection('orders');
orderBriefDoc = FirebaseFirestore.instance.collection('companies').doc(myCompany).collection('features').doc(myDeliveryDocRef);
}
UPDATE: This is collection > document what corresponds to final String myCompany = '4U4kZKXkr3rHA6B04S5K';
As we discussed in your comments, the issue was that you forgot to await the getOrderCollection() function. Even though, as you mentioned, your caller function _deliveryRepository.initRepository() was awaited, you still had to await getOrderCollection() inside your caller method to make sure that the code is waiting for the getOrderCollection() to be executed before it proceeds to the next line.
In general, you want to have some error handling and to type the known types/classes (avoid using var).
Error handling - for async/await place the code inside a try/catch.
Typing - Dart is type safe, which is really great to prevent runtime errors.
Depending on your setup, you might be able to hover over the Firestore.instance.collection(...).doc(...) to see the return type. .doc(...).get() returns a DocumentSnapshot and .collection(...).get() returns a CollectionSnapshot.
Using the above, it should be easier to debug:
Future<void> getOrderCollection() async {
try {
DocumentSnapshot myCompanyDoc = await FirebaseFirestore.instance.collection('companies').doc(myCompany).get();
print("companyDoc fetched");
final myDeliveryDocRef = myCompanyDoc.data()['delivery'].toString();
} catch(e) {
print('Error: ' + e.toString());
}
}
Don't forget to await your other 2 Firestore queries.

Gathering performance metrics for calls to Cloud Functions from Flutter

I am attempting to use Firebase Performance monitoring with Firebase Cloud Functions. When I run the following code I get the error URL host is null or invalid. Clearly that is because I am passing in a function name rather than a URL with a host.
import 'package:flutter/widgets.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:firebase_performance/firebase_performance.dart';
/// Handles tracking metrics while calling cloud functions.
class MetricCloudFunction {
Future<HttpsCallableResult> call(String functionName, [dynamic parameters]) async {
final HttpMetric metric = FirebasePerformance.instance
.newHttpMetric(functionName, HttpMethod.Get);
final HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(
functionName: functionName,
);
await metric.start();
HttpsCallableResult response;
try {
response = await callable.call(parameters);
} catch(e) {
debugPrint('failed: ${e.toString()}');
} finally {
await metric.stop();
}
return response;
}
}
Is there some way to get the URL of the callable function so that I can create the metric for it? If not, is there another way that I can create an HTTP metric for it?
There is currently no way to programmatically get the URL for an HTTP callable type function. You can compose it by what you know about the function (the three variables are deployment region, project ID, name), or you can simply copy it from the Firebase console Functions dashboard and hard code it into your app.

NullReferenceException occurs during offline sync to Azure Mobile Service

I am trying to make offline sync to table from azure mobile service. My Xamarin Form version is 1.4.2.6359.
I try to test my code in OnCreate method of MainActivity. All preparation steps such as MobileServiceClient initialization, MobileServiceSQLiteStore initialization, SyncTable creation, etc are ok.
When I try to call PullAsync, I am getting NullReferenceException. I capture the package using Package Capture App from mobile. The request goes to Azure Mobile service and it returns the correct json data successfully.
When I try the same code in Xamarin Android project (not Xamarin Form), it is working fine.
To reproduce the issue.
Just create Xamarin Form (Portable) project and use my code.
My Code
private async Task Test() {
const string applicationURL = #"https://xxxx.azure-mobile.net/";
const string applicationKey = #"xxxx";
CurrentPlatform.Init();
var client = new MobileServiceClient(applicationURL, applicationKey);
string path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "store.db");
if (!File.Exists(path)) {
File.Create(path).Dispose();
}
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<Product>();
await client.SyncContext.InitializeAsync(store);
var productTable = client.GetSyncTable<Product>();
try {
await client.SyncContext.PushAsync();
await productTable.PullAsync("allProducts", productTable.CreateQuery());
var t = await productTable.ToListAsync();
Console.WriteLine("Product Count : " + t.Count);
}
catch (Java.Net.MalformedURLException ex) {
Console.WriteLine(ex.Message);
}
catch (Exception e) {
Console.WriteLine(e.Message);
}
}
References:
http://azure.microsoft.com/en-us/documentation/articles/mobile-services-xamarin-android-get-started-offline-data/
http://blogs.msdn.com/b/carlosfigueira/archive/2014/04/07/deep-dive-on-the-offline-support-in-the-azure-mobile-service-managed-client-sdk.aspx
I got the solution for this case.
As far as my understanding, this is what is happening. During the application is loading, I call PullAsync. It is async call and during this call, application keeps loading other components. The actual NullReferenceException is coming from OnPrepareOptionsMenu function (Xamarin.Forms.Platform.Android.AndroidActivity.OnPrepareOptionsMenu). The exception is happening on other thread and the thread simply dies. That's why I cannot get stack trace from my main thread.
This NullReferenceException issue is totally not related to Azure Mobile Service.
I override OnPrepareOptionsMenu in MainActivity and add try-catch block to base class function call. The problem is solved. Here is my code in MainActivity class.
public override bool OnPrepareOptionsMenu(IMenu menu) {
try {
// I am always getting menu.HasVisibleItems = false in my app
if (menu != null && menu.HasVisibleItems) {
// Exception is happening when the following code is executed
var result = base.OnPrepareOptionsMenu(menu);
return result;
}
}
catch{
}
return true;
}
I don't really understand why it is happening. Please point me out if you have better understanding of this case and better solution.
I think my issue is same as this : http://forums.xamarin.com/discussion/23579/exception-whilte-trying-to-open-activity-from-xamarin-forms-page