Platform specific code in Flutter integration tests - testing

I have an integration test that has to open a time picker, but each platform has a different implementation of time picker. Therefor the flow of the integration test must differ between Android and iOS.. how can I achieve this?
I tried using the Platform class like this inside the test file, but it doesnt work:
//* 5) Choose time
await driver.tap(find.byValueKey('addRideTimePicker'));
if (Platform.isAndroid) {
await driver.tap(find.text("V REDU"));
}
if (Platform.isIOS) {
await driver.tap(find.text("OK"));
}
Any help would be much appreciated, thanks in advance

Not sure how you implemented TimePicker, but usually CupertinoTimePicker is the widget that renders the time picker on screen. Also, depending on where do you want to show it on screen, using CupertinoTimePicker, it renders equally from UI perspective on both platforms. For example, you may show the time picker inside Container or inside bottomsheet. A sample code to show time picker inside bottomsheet is as below:
body: Center(
child: RaisedButton(
child: Text('Click'),
onPressed: () {
showModalBottomSheet(context: context, builder: (BuildContext builder) {
return Container(
child: time()
);
});
},
)
),
Widget time() {
return CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hms,
minuteInterval: 1,
secondInterval: 1,
initialTimerDuration: initialtimer,
onTimerDurationChanged: (Duration changedtimer) {
setState(() {
initialtimer = changedtimer;
});
},
);
}
Above code shows time picker equally on both platforms as below:
This way, you may not need to use Platform class as you mentioned and directly in your flutter driver test, you may first identify the elements displayed in the bottomsheet and accordingly tap or perform actions you need.
Hope this answers your question.

Related

How to make progress bar for receiving response from API?

while receiving data from API to flutter app it takes time to receive. How to make a progress bar to load until the JSON data is received to the flutter app and move to next Screen of the app.
I'm not using ListView.Builder. Instead I use it for texts, dropdown and other things also.
You could use a FutureBuilder widget, as shown in the cookbook for retrieving and displaying data :
FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
);
This widget allows you to build your layout with information about the data your are loading and the status of the load itself.
For the future: parameter, give him your http.get request.
In the builder: param, give it an anonymous function that builds the content you want to display. In said closure, you can rely on the snapshot to know wether the data has finished downloading (snapshot.hasData) or if there was an error downloading (snapshot.hasError).
To display the progress bar you asked for, you can infer the status : if the snapshot has no data nor any error, therefore it is loading and you return you progress bar to the user.

Is it possible, in sourecode, to create a complete theme palette based on a primary color like the theme builder does?

Since the title attempts to address every part of my question, which is very difficult, I need to clearify a bit:
I want to be able to apply a theme to my Office UI Fabric application with all the different color shades an Office UI Fabric theme should have, without having to define each shade myself. The only things I want to define are the primary theme color, the body text color and the body background color. This is just what the theme generator on the Office UI Fabric website does.
So to get to the point: Is it possible to use the functionality of the theme generator in any Office UI Fabric application?
My naive approach was to use createTheme, since it accepts a partial theme, and I hoped to get a full one back:
const theme = createTheme({
palette: { themePrimary: '#007610' },
semanticColors: { bodyBackground: '#ffffff', bodyText: '#000000' },
});
loadTheme(theme);
Alas, this wasn't the case. Only the properties provided are applied.
So is there a simple (official) way to do this or are the sources of the theme creator available somewhere?
So after some investigation of the ColorPage.tsx from the Office UI Fabric repository I found the missing pieces to achieve this myself. The code below is just a very simple usage of that mechanism, that suffices my needs. For now, I don't want the user to change the main background or foreground colors, hence the simplifications. Use and extend it at your own risk, but feel free to ask me, if something isn't clear. But I guess its rather clear what's going on here.
import { loadTheme } from '#uifabric/styling';
import {
IThemeRules,
ThemeGenerator,
themeRulesStandardCreator,
} from 'office-ui-fabric-react/lib/ThemeGenerator';
import { getColorFromString } from 'office-ui-fabric-react/lib/utilities/color/getColorFromString';
import { IColor } from 'office-ui-fabric-react/lib/utilities/color/interfaces';
export default class ThemeProvider {
private themeRules: IThemeRules;
constructor() {
const themeRules = themeRulesStandardCreator();
ThemeGenerator.insureSlots(this.themeRules, false);
ThemeGenerator.setSlot(themeRules.backgroundColor, getColorFromString('#ffffff'), false, true, true);
ThemeGenerator.setSlot(themeRules.foregroundColor, getColorFromString('#000000'), false, true, true);
this.themeRules = themeRules;
}
public loadThemeForColor(hexColor: string): void {
const newColor: IColor = getColorFromString(hexColor);
const themeRules = this.themeRules;
ThemeGenerator.setSlot(themeRules.primaryColor, newColor.str, false, true, true);
this.themeRules = themeRules;
const theme = ThemeGenerator.getThemeAsJson(this.themeRules);
loadTheme({
...{ palette: theme },
isInverted: false,
});
}
}
For more insights have a look at the ColorPage.tsx yourself within the official repo, since I didn't strive to understand everything going on in there.

Flutter: testing widgets

what I'm trying to test is:
the user taps a button and the snackbar is shown for five second.
Here is the scaffold with its key:
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(debugLabel: "scaffoldState");
...
builder: (context, viewModel) => Scaffold(
key: _scaffoldKey,
Then the code for the button and the snackBar:
child: FlatButton(key: Key('loginButton'), onPressed: () {
validate();
...
validate() {
// FormState object can be used to save, reset, and validate
// every FormField that is a descendant of the associated Form.
final FormState form = _formKey.currentState;
if (form.validate()) {
form.save();
form.reset();
//implementation of the snackBar:
_scaffoldKey.currentState.showSnackBar(new SnackBar(
duration: new Duration(seconds: 5)
...
And I am trying to test this behaviour in this way (I'm using also Flutter redux):
void main(){
final store = Store<AppState>(reducer, initialState: AppState.initialState());
testWidgets("MaterialApp local", (WidgetTester tester) async{
await tester.pumpWidget(new StoreProvider(
store: store,
child: MaterialApp(
home: LoginView(),
)));
await tester.pumpAndSettle();
await tester.press(find.byKey(Key("loginButton")));
expect();
I don't know what to put inside expect. I was trying to take the GlobalKey using find.ByKey(Key)) and to search for the debugLabel, but it doesn't seem to work. I'm trying since 2 days, but I can't find a way out.
It might be a little late to answer this, but since it was the second result on Google when typing "Flutter test Snackbar", I will just give my two cents:
It's actually pretty simple. Don't think of the Snackbar as being something completely different only because it only resides at the bottom for a few seconds. Lastly, the Snackbar is just another Widget.
Keeping this in mind you can test it as follows:
testWidgets("MaterialApp local", (WidgetTester tester) async{
...
// Test if the Snackbar appears
expect(find.byType(SnackBar), findsOneWidget);
// Test if it contains your text
expect(find.text('TAPS!'), findsOneWidget);
});
i actually met the same condition as you did, and all i did is put a text as the content of the snackbar.
for showing the snackbar, the code i use is
scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("TAPS!"),));
}, "SEE ALL", backgroundColor: Colors.red, textColor: Colors.blue)
and i expect to find a text with the same content as i put in, and add findsOneWidget.
expect(find.text("TAPS!"), findsOneWidget);

Identify orientation with degrees on startup

Without a 3rd party lib, we can detect orientation changes with DeviceEventEmitter with this undocumented feature like this:
import { DeviceEventEmitter } from 'react-native'
function handleOrientationDidChange(data) {
console.log('orientation changed, data:', data)
}
DeviceEventEmitter.addListener('namedOrientationDidChange', handleOrientationDidChange);
This gives us data that looks like this:
{ rotationDegrees: -90, isLandscape: true, name: "landscape-primary" }
Note: I tested this only on Android. It would be nice to know if it works on iOS too.
However this only works ON CHANGE. Is there a way to get this info on startup?
Have you tried this library!
Here is example usage from the repo:
componentWillMount() {
// The getOrientation method is async. It happens sometimes that
// you need the orientation at the moment the JS runtime starts running on device.
// `getInitialOrientation` returns directly because its a constant set at the
// beginning of the JS runtime.
const initial = Orientation.getInitialOrientation();
if (initial === 'PORTRAIT') {
// do something
} else {
// do something else
}
}

Disable store load mask in Sencha 2

The Sencha store is automatically adding a ajax loader mask when populating the store, but I want to hide it since I have made a more generic mask which is shown every time the app does a ajax request.
How can I hide the store load mask? Tried to look in the documentation, but didnt find any appropriate field/method there:
See attachement:
The property exists: loadingText, which you have set to null.
{
xtype: 'list',
store: 'Store',
loadingText: null, // for ST 2.3.0 set it to false
....
}
Cheers, Oleg
Olegtaranenko: Your solution does remove the loadmask, but setting the
loadingText to 'null' also seems to break the "PullToRefresh" plugin
functionality for a list.
By 'break', I mean that after pulling the arrow down to refresh, the
ui remains in this state, and does not hide the PullToRefresh section
at the top.
Is there a way to hide the additional loadmask, while retaining the
ability to pull to refresh?
For anyone that is reading this in future and is trying to achieve what I have described above, I worked around the issue with PullToRefresh by changing the original Sencha touch 1.1.1 code (line 45346 of sencha-touch-debug-with-comments.js). This is not ideal, but provides a quick workaround.
Original (PullToRefresh breaks)
onBeforeLoad: function() {
if (this.isLoading && this.list.store.getCount() > 0) {
this.list.loadMask.disable();
return false;
}
},
Workaround
onBeforeLoad: function() {
if (this.isLoading && this.list.store.getCount() > 0) {
try{ this.list.loadMask.disable(); }
catch(err) { }
return false;
}
},
Just add on your View
viewConfig: {
loadMask: false
}