Skip to content

Commit

Permalink
Add home page integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
duddu committed Oct 18, 2023
1 parent 467ebde commit 9b9ca99
Show file tree
Hide file tree
Showing 10 changed files with 343 additions and 40 deletions.
20 changes: 17 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
branches-ignore:
- main
jobs:
test:
unit-test:
runs-on: ubuntu-latest
steps:
- name: Prepare flutter
Expand All @@ -18,5 +18,19 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Flutter tests
run: flutter test --coverage -r github
- name: Flutter test
run: flutter test --coverage -r github
integration-test:
runs-on: macos-latest
steps:
- name: Prepare flutter
uses: subosito/flutter-action@v2
with:
flutter-version: 3.13.7
channel: stable
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Flutter integration test
run: flutter test -v -d macos integration_test/home_page.test.dart
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.7.8
1.7.9
236 changes: 236 additions & 0 deletions integration_test/home_page.test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:sourdoc/constants/locale.dart' as locale;
import 'package:sourdoc/widgets/home_page.dart';

void expectCalculatorValues({
required String temperatureUnit,
required String temperature,
required String weight,
required String hydration,
required String saltLevel,
required String flour,
required String water,
required String levain,
required String salt,
required String inoculation,
required String rise,
}) {
expect(
find.byWidgetPredicate((Widget widget) =>
widget is SegmentedButton &&
widget.selected.contains(temperatureUnit)),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText ==
'${locale.inputPrefixTemperature}:' &&
widget.controller!.text == temperature),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText == '${locale.inputPrefixWeight}:' &&
widget.controller!.text == weight),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText == '${locale.inputPrefixHydration}:' &&
widget.controller!.text == hydration),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText == '${locale.inputPrefixSalt}:' &&
widget.controller!.text == saltLevel),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is Text &&
widget.semanticsLabel == locale.variableLabelFlour &&
widget.data == flour),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is Text &&
widget.semanticsLabel == locale.variableLabelWater &&
widget.data == water),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is Text &&
widget.semanticsLabel == locale.variableLabelLevain &&
widget.data == levain),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is Text &&
widget.semanticsLabel == locale.variableLabelSalt &&
widget.data == salt),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is Text &&
widget.semanticsLabel == locale.variableLabelInoculation &&
widget.data == inoculation),
findsOneWidget);
expect(
find.byWidgetPredicate((Widget widget) =>
widget is Text &&
widget.semanticsLabel == locale.variableLabelDoughRise &&
widget.data == rise),
findsOneWidget);
}

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('HomePage', () {
testWidgets('should load initial default values', (tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
await tester.pumpAndSettle();

expectCalculatorValues(
temperatureUnit: 'ºC',
temperature: '22',
weight: '700',
hydration: '70',
saltLevel: '2',
flour: '366.5g',
water: '256.5g',
levain: '69.6g',
salt: '7.3g',
inoculation: '19%',
rise: '50%');
});

testWidgets('should switch to farenheit', (tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
await tester.pumpAndSettle();

await tester.tap(find.byTooltip(locale.degreesFarenheit));
await tester.pumpAndSettle();

expectCalculatorValues(
temperatureUnit: 'ºF',
temperature: '71.6',
weight: '700',
hydration: '70',
saltLevel: '2',
flour: '366.5g',
water: '256.5g',
levain: '69.6g',
salt: '7.3g',
inoculation: '19%',
rise: '50%');
});

testWidgets('should update values based on ambient temperature',
(tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
await tester.pumpAndSettle();

await tester.enterText(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText ==
'${locale.inputPrefixTemperature}:'),
'80');
await tester.pumpAndSettle();

expectCalculatorValues(
temperatureUnit: 'ºF',
temperature: '80',
weight: '700',
hydration: '70',
saltLevel: '2',
flour: '375.7g',
water: '263.0g',
levain: '53.8g',
salt: '7.5g',
inoculation: '14%',
rise: '25%');
});

testWidgets('should update values based on target bread weight',
(tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
await tester.pumpAndSettle();

await tester.enterText(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText == '${locale.inputPrefixWeight}:'),
'1350');
await tester.pumpAndSettle();

expectCalculatorValues(
temperatureUnit: 'ºF',
temperature: '80',
weight: '1350',
hydration: '70',
saltLevel: '2',
flour: '724.5g',
water: '507.2g',
levain: '103.8g',
salt: '14.5g',
inoculation: '14%',
rise: '25%');
});

testWidgets('should update values based on hydration level',
(tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
await tester.pumpAndSettle();

await tester.enterText(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText ==
'${locale.inputPrefixHydration}:'),
'85');
await tester.pumpAndSettle();

expectCalculatorValues(
temperatureUnit: 'ºF',
temperature: '80',
weight: '1350',
hydration: '85',
saltLevel: '2',
flour: '670.5g',
water: '570.0g',
levain: '96.1g',
salt: '13.4g',
inoculation: '14%',
rise: '25%');
});

testWidgets('should update values based on salt level', (tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
await tester.pumpAndSettle();

await tester.enterText(
find.byWidgetPredicate((Widget widget) =>
widget is TextField &&
widget.decoration!.prefixText == '${locale.inputPrefixSalt}:'),
'2.5');
await tester.pumpAndSettle();

expectCalculatorValues(
temperatureUnit: 'ºF',
temperature: '80',
weight: '1350',
hydration: '85',
saltLevel: '2.5',
flour: '668.9g',
water: '568.5g',
levain: '95.9g',
salt: '16.7g',
inoculation: '14%',
rise: '25%');
});
});
}
59 changes: 31 additions & 28 deletions lib/widgets/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class _HomePageState extends State<HomePage> {
double _water = 0;
double _levain = 0;
double _salt = 0;
TemperatureUnit _temperatureUnit = form.defaultTemperatureUnit;
TemperatureUnit? _temperatureUnit;

final totalWeightController = TextEditingController();
final hydrationController = TextEditingController();
Expand All @@ -45,8 +45,8 @@ class _HomePageState extends State<HomePage> {
void _updateFermentationValues() {
final temperature = _parseValue(temperatureController);

_inoculation = getInoculationValue(temperature, _temperatureUnit);
_bulkRise = getBulkRiseValue(temperature, _temperatureUnit);
_inoculation = getInoculationValue(temperature, _temperatureUnit!);
_bulkRise = getBulkRiseValue(temperature, _temperatureUnit!);
}

void _updateFermentationState() {
Expand Down Expand Up @@ -79,7 +79,7 @@ class _HomePageState extends State<HomePage> {
.firstWhere((element) => element.value.unit == selection)
.key;
temperatureController.text = convertTemperatureUnit(
_parseValue(temperatureController), _temperatureUnit)
_parseValue(temperatureController), _temperatureUnit!)
.toStringAsFixed(1)
.replaceFirst('.0', '');
_storeTemperatureUnit();
Expand Down Expand Up @@ -123,10 +123,10 @@ class _HomePageState extends State<HomePage> {

@override
initState() {
super.initState();

_loadInitialValues();

super.initState();

temperatureController.addListener(_updateFermentationState);
temperatureController.addListener(_storeTemperatureValue);
totalWeightController.addListener(_updateIngredientsState);
Expand Down Expand Up @@ -212,30 +212,33 @@ class _HomePageState extends State<HomePage> {
fontSize:
Theme.of(context).textTheme.bodyLarge!.fontSize,
color: Colors.grey.shade800)),
UnitChoice(
a11yLabel: locale.a11yTemperatureUnitChoiceLabel,
unitList: temperatureUnitMap.values
.map((element) => UnitSingleChoiceDescriptor(
value: element.unit,
tooltip: element.description))
.toList(),
initialUnitValue:
temperatureUnitMap[_temperatureUnit]!.unit,
onSelectionChanged: _updateTemperatureUnit),
],
),
Row(
children: <TextFieldWithAffixes>[
TextFieldWithAffixes(
paddingTop: 10,
controller: temperatureController,
prefixText: locale.inputPrefixTemperature,
suffixText: temperatureUnitMap[_temperatureUnit]!.unit,
tooltip: locale.inputTooltipTemperature,
maxValue: form.maxValueTemperatureMap[_temperatureUnit]!,
),
if (_temperatureUnit != null)
UnitChoice(
a11yLabel: locale.a11yTemperatureUnitChoiceLabel,
unitList: temperatureUnitMap.values
.map((element) => UnitSingleChoiceDescriptor(
value: element.unit,
tooltip: element.description))
.toList(),
initialUnitValue:
temperatureUnitMap[_temperatureUnit]!.unit,
onSelectionChanged: _updateTemperatureUnit),
],
),
if (_temperatureUnit != null)
Row(
children: <TextFieldWithAffixes>[
TextFieldWithAffixes(
paddingTop: 10,
controller: temperatureController,
prefixText: locale.inputPrefixTemperature,
suffixText: temperatureUnitMap[_temperatureUnit]!.unit,
tooltip: locale.inputTooltipTemperature,
maxValue:
form.maxValueTemperatureMap[_temperatureUnit]!,
),
],
),
Row(
children: <TextFieldWithAffixes>[
TextFieldWithAffixes(
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/unit_choice_segmented_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class UnitChoice<T extends Enum> extends StatefulWidget {
}

class _UnitChoiceState<T extends Enum> extends State<UnitChoice> {
late String unit;
String? unit;

@override
void initState() {
Expand Down Expand Up @@ -60,7 +60,7 @@ class _UnitChoiceState<T extends Enum> extends State<UnitChoice> {
onSelectionChanged: (Set newSelection) {
setState(() {
unit = newSelection.first;
widget.onSelectionChanged(unit);
widget.onSelectionChanged(unit!);
});
},
));
Expand Down
1 change: 1 addition & 0 deletions lib/widgets/variable_with_label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class VariableWithLabel extends StatelessWidget {
Expanded(
child: Text(
'${value.toStringAsFixed(fractionDigits)}$unit',
semanticsLabel: label,
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.end,
)),
Expand Down
Loading

0 comments on commit 9b9ca99

Please sign in to comment.