Reputation: 5867
In my widget's code I need to branch on Android/iOS to show widgets specific to each platform, and also call platform specific APIs (e.g. the Android widget will call an API only available on Android).
if (Platform.isAndroid) {
return WidgetAndroid(...);
} else if (Platform.isIOS) {
return WidgetIOS(...);
}
How can I test that the right widget is shown using a Flutter widget test?
I know I can check that the widget exists but how do I run the test with a specific platform.
expect(find.byType(WidgetIOS), findsOneWidget);
Upvotes: 17
Views: 9923
Reputation: 4839
It can be mocked if we are using TargetPlatform
instead of Platform
API.
Below is the code and its test, although its unit test for a function but this works for Widget tests too.
String platformName() {
final isIOS = defaultTargetPlatform == TargetPlatform.iOS;
final isAndroid = defaultTargetPlatform == TargetPlatform.android;
if (isIOS) { return "apple";}
if (isAndroid) {return "android";}
}
Unit Test
test('test platformName for given platform', () {
final platformUtils = PlatFormUtil();
debugDefaultTargetPlatformOverride = TargetPlatform.android;
expect(platformUtils.platformName(), 'android');
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
expect(platformUtils.platformName(), 'apple');
// dont forget to reset it to avoid side effect on other tests
debugDefaultTargetPlatformOverride = null;
});
Please refer https://api.flutter.dev/flutter/foundation/TargetPlatform.html
Upvotes: 1
Reputation: 4672
In 2022 it is not recommended to use dart:io
and Platform
class to determine the runtime platform. The better alternative is to use defaultTargetPlatform
available through 'package:flutter/foundation.dart'. I.e.:
if (defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS) {}
Should you have that approach for determining platform in your code overiding platform in tests is as easy as setting debugDefaultTargetPlatformOverride
in your test body.
https://api.flutter.dev/flutter/foundation/debugDefaultTargetPlatformOverride.html
E.g.:
testWidgets('DataTable2 renders with DataRow.index()',
(WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
...
debugDefaultTargetPlatformOverride = null;
});
Upvotes: 33
Reputation: 359
Platform
is in dart:io
, which is lower-level than Flutter's TargetPlatform
. In most cases, you should use the latter.
From documentation:
The [dart:io.Platform] object should only be used directly when it's critical to actually know the current platform, without any overrides possible (for example, when a system API is about to be called).
Upvotes: 4
Reputation: 1364
Like Miguel mentioned you can't mock it directly.
If you use the provider framework, you can use dependency injection in your tests to make this happen without exposing an additional param in your widget.
Create an class to use for injection:
class PlatformInfo {
final bool isIos;
final bool isAndroid;
PlatformInfo({@required this.isAndroid,@required this.isIos});
}
in your top level MultiProvider
widget, set up your provider bindings:
Provider<PlatformInfo>.value(
value: PlatformInfo(isAndroid: Platform.isAndroid, isIos: Platform.isIOS),
),
Use it in your widget:
Provider.of<PlatformInfo>(context).isIos
Upvotes: 0
Reputation: 2212
Both Platform.isAndroid
and Platform.isIOS
return false
when running testWidgets
.
Some suggestions we can apply in our tests:
else
without if
, so that will run during the tests.Platform
from https://pub.dev/packages/platform which allows mocking, which is probably the best long term solution.Upvotes: 11