Clients Tests

This commit is contained in:
Gianfranco Gasbarri 2021-04-27 00:07:23 +01:00
parent 9c794f2596
commit 096855bb45
20 changed files with 78 additions and 36 deletions

View File

@ -632,6 +632,7 @@ const kPageSizes = [
]; ];
const String kDrawerKey = 'drawer_key'; const String kDrawerKey = 'drawer_key';
const String kSelectCompanyDropdownKey = 'select_company_dropdown_key';
const String kActivityCreateClient = '1'; const String kActivityCreateClient = '1';
const String kActivityArchiveClient = '2'; const String kActivityArchiveClient = '2';

View File

@ -5,6 +5,7 @@ import 'package:invoiceninja_flutter/utils/localization.dart';
class AppDropdownButton<T> extends StatelessWidget { class AppDropdownButton<T> extends StatelessWidget {
const AppDropdownButton({ const AppDropdownButton({
Key key,
@required this.value, @required this.value,
@required this.onChanged, @required this.onChanged,
@required this.items, @required this.items,
@ -13,7 +14,7 @@ class AppDropdownButton<T> extends StatelessWidget {
this.blankValue = '', this.blankValue = '',
this.enabled = true, this.enabled = true,
this.showUseDefault = false, this.showUseDefault = false,
}); }) : super(key: key);
final String labelText; final String labelText;
final dynamic value; final dynamic value;

View File

@ -9,7 +9,7 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
class DecoratedFormField extends StatelessWidget { class DecoratedFormField extends StatelessWidget {
const DecoratedFormField({ const DecoratedFormField({
Key key, this.formKey,
this.controller, this.controller,
this.label, this.label,
this.onSavePressed, this.onSavePressed,
@ -36,8 +36,9 @@ class DecoratedFormField extends StatelessWidget {
this.isPercent = false, this.isPercent = false,
this.showClear = true, this.showClear = true,
this.inputFormatters, this.inputFormatters,
}) : super(key: key); });
final Key formKey;
final TextEditingController controller; final TextEditingController controller;
final String label; final String label;
final String hint; final String hint;
@ -118,7 +119,7 @@ class DecoratedFormField extends StatelessWidget {
} }
return TextFormField( return TextFormField(
key: key ?? ValueKey(label), key: formKey ?? ValueKey(label),
focusNode: focusNode, focusNode: focusNode,
controller: controller, controller: controller,
autofocus: autofocus, autofocus: autofocus,

View File

@ -45,7 +45,7 @@ class _GrowableFormFieldState extends State<GrowableFormField> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DecoratedFormField( return DecoratedFormField(
key: widget.key, formKey: widget.key,
focusNode: _focusNode, focusNode: _focusNode,
initialValue: widget.initialValue, initialValue: widget.initialValue,
onChanged: widget.onChanged, onChanged: widget.onChanged,

View File

@ -35,6 +35,7 @@ class _PasswordFormFieldState extends State<PasswordFormField> {
final localization = AppLocalization.of(context); final localization = AppLocalization.of(context);
return DecoratedFormField( return DecoratedFormField(
formKey: ValueKey(widget.labelText ?? localization.password),
controller: widget.controller, controller: widget.controller,
onSavePressed: widget.onSavePressed, onSavePressed: widget.onSavePressed,
autocorrect: false, autocorrect: false,

View File

@ -164,6 +164,7 @@ class MenuDrawer extends StatelessWidget {
final _expandedCompanySelector = state.companies.isEmpty final _expandedCompanySelector = state.companies.isEmpty
? SizedBox() ? SizedBox()
: AppDropdownButton<String>( : AppDropdownButton<String>(
key: ValueKey(kSelectCompanyDropdownKey),
value: viewModel.selectedCompanyIndex, value: viewModel.selectedCompanyIndex,
items: [ items: [
...state.companies ...state.companies

View File

@ -131,6 +131,7 @@ class ClientEditDetailsState extends State<ClientEditDetails> {
FormCard( FormCard(
children: <Widget>[ children: <Widget>[
DecoratedFormField( DecoratedFormField(
formKey: ValueKey(localization.name),
autofocus: true, autofocus: true,
controller: _nameController, controller: _nameController,
validator: (String val) => !viewModel.client.hasNameSet validator: (String val) => !viewModel.client.hasNameSet

View File

@ -215,7 +215,7 @@ class ExpenseEditSettingsState extends State<ExpenseEditSettings> {
_setCurrency(currency), _setCurrency(currency),
), ),
DecoratedFormField( DecoratedFormField(
key: ValueKey('__${expense.invoiceCurrencyId}__'), formKey: ValueKey('__${expense.invoiceCurrencyId}__'),
controller: _exchangeRateController, controller: _exchangeRateController,
keyboardType: keyboardType:
TextInputType.numberWithOptions(decimal: true), TextInputType.numberWithOptions(decimal: true),

View File

@ -633,7 +633,7 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
children: [ children: [
Expanded( Expanded(
child: DecoratedFormField( child: DecoratedFormField(
key: ValueKey( formKey: ValueKey(
'__exchange_rate_${invoice.clientId}__'), '__exchange_rate_${invoice.clientId}__'),
label: localization.exchangeRate, label: localization.exchangeRate,
initialValue: formatNumber( initialValue: formatNumber(

View File

@ -389,7 +389,7 @@ class InvoiceEditDetailsState extends State<InvoiceEditDetails> {
.onChanged(invoice.rebuild((b) => b..designId = value?.id)), .onChanged(invoice.rebuild((b) => b..designId = value?.id)),
), ),
DecoratedFormField( DecoratedFormField(
key: ValueKey('__exchange_rate_${invoice.clientId}__'), formKey: ValueKey('__exchange_rate_${invoice.clientId}__'),
label: localization.exchangeRate, label: localization.exchangeRate,
initialValue: formatNumber(invoice.exchangeRate, context, initialValue: formatNumber(invoice.exchangeRate, context,
formatNumberType: FormatNumberType.inputAmount), formatNumberType: FormatNumberType.inputAmount),

View File

@ -517,7 +517,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding( Padding(
padding: const EdgeInsets.only(right: kTableColumnGap), padding: const EdgeInsets.only(right: kTableColumnGap),
child: DecoratedFormField( child: DecoratedFormField(
key: ValueKey('__line_item_${index}_cost__'), formKey: ValueKey('__line_item_${index}_cost__'),
textAlign: TextAlign.right, textAlign: TextAlign.right,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index].cost, context, lineItems[index].cost, context,
@ -536,7 +536,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding( Padding(
padding: const EdgeInsets.only(right: kTableColumnGap), padding: const EdgeInsets.only(right: kTableColumnGap),
child: DecoratedFormField( child: DecoratedFormField(
key: ValueKey('__line_item_${index}_quantity__'), formKey: ValueKey('__line_item_${index}_quantity__'),
textAlign: TextAlign.right, textAlign: TextAlign.right,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index].quantity, context, lineItems[index].quantity, context,
@ -555,7 +555,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding( Padding(
padding: const EdgeInsets.only(right: kTableColumnGap), padding: const EdgeInsets.only(right: kTableColumnGap),
child: DecoratedFormField( child: DecoratedFormField(
key: ValueKey('__line_item_${index}_discount__'), formKey: ValueKey('__line_item_${index}_discount__'),
textAlign: TextAlign.right, textAlign: TextAlign.right,
initialValue: formatNumber( initialValue: formatNumber(
lineItems[index].discount, context, lineItems[index].discount, context,

View File

@ -206,7 +206,7 @@ class _FileImportState extends State<_FileImport> {
final field = DecoratedFormField( final field = DecoratedFormField(
enabled: false, enabled: false,
key: ValueKey(uploadPart.key + formKey: ValueKey(uploadPart.key +
(multipartFile != null ? multipartFile.filename : '')), (multipartFile != null ? multipartFile.filename : '')),
label: localization.lookup(uploadPart.value), label: localization.lookup(uploadPart.value),
initialValue: !_multipartFiles.containsKey(uploadPart.key) initialValue: !_multipartFiles.containsKey(uploadPart.key)

View File

@ -220,7 +220,7 @@ class _TaskEditDesktopState extends State<TaskEditDesktop> {
isMoney: false, isMoney: false,
), ),
DecoratedFormField( DecoratedFormField(
key: ValueKey('__rate__'), formKey: ValueKey('__rate__'),
controller: _rateController, controller: _rateController,
label: rateLabel, label: rateLabel,
keyboardType: TextInputType.numberWithOptions( keyboardType: TextInputType.numberWithOptions(

View File

@ -171,7 +171,7 @@ class _TaskEditDetailsState extends State<TaskEditDetails> {
autocorrect: false, autocorrect: false,
), ),
DecoratedFormField( DecoratedFormField(
key: ValueKey('__rate__'), formKey: ValueKey('__rate__'),
controller: _rateController, controller: _rateController,
label: rateLabel, label: rateLabel,
keyboardType: keyboardType:

View File

@ -267,6 +267,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.1" version: "0.1.1"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
faker: faker:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -287,7 +294,7 @@ packages:
name: file name: file
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "5.2.1" version: "6.0.0"
file_picker: file_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -377,6 +384,11 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.5" version: "0.3.5"
flutter_driver:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_json_widget: flutter_json_widget:
dependency: "direct main" dependency: "direct main"
description: description:
@ -438,6 +450,11 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.1+1" version: "1.5.1+1"
flutter_test:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_typeahead: flutter_typeahead:
dependency: "direct main" dependency: "direct main"
description: description:
@ -452,6 +469,11 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -660,7 +682,7 @@ packages:
name: node_io name: node_io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.1.1"
node_preamble: node_preamble:
dependency: transitive dependency: transitive
description: description:
@ -800,7 +822,7 @@ packages:
name: process name: process
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.13" version: "4.0.0"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
@ -987,7 +1009,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.0"
sqflite: sqflite:
dependency: transitive dependency: transitive
description: description:
@ -1030,6 +1052,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
sync_http:
dependency: transitive
description:
name: sync_http
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:
@ -1162,7 +1191,7 @@ packages:
name: vm_service name: vm_service
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.2.0" version: "5.5.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
@ -1177,6 +1206,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
webdriver:
dependency: transitive
description:
name: webdriver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
webkit_inspection_protocol: webkit_inspection_protocol:
dependency: transitive dependency: transitive
description: description:

View File

@ -89,8 +89,8 @@ dependency_overrides:
path: packages/google_sign_in/google_sign_in_platform_interface path: packages/google_sign_in/google_sign_in_platform_interface
dev_dependencies: dev_dependencies:
#flutter_driver: # TODO Re-enable flutter_driver:
# sdk: flutter sdk: flutter
test: ^1.6.3 test: ^1.6.3
#flutter_test: #flutter_test:
# sdk: flutter # sdk: flutter

View File

@ -1,4 +1,3 @@
/*
import 'package:flutter_driver/driver_extension.dart'; import 'package:flutter_driver/driver_extension.dart';
import 'package:invoiceninja_flutter/main.dart' as app; import 'package:invoiceninja_flutter/main.dart' as app;
@ -6,4 +5,3 @@ void main() {
enableFlutterDriverExtension(); enableFlutterDriverExtension();
app.main(isTesting: true); app.main(isTesting: true);
} }
*/

View File

@ -1,4 +1,3 @@
/*
import 'package:flutter_driver/driver_extension.dart'; import 'package:flutter_driver/driver_extension.dart';
import 'package:invoiceninja_flutter/main.dart' as app; import 'package:invoiceninja_flutter/main.dart' as app;
@ -7,4 +6,3 @@ void main() {
enableFlutterDriverExtension(); enableFlutterDriverExtension();
app.main(isTesting: true); app.main(isTesting: true);
} }
*/

View File

@ -1,4 +1,3 @@
/*
import 'package:faker/faker.dart'; import 'package:faker/faker.dart';
import 'package:flutter_driver/flutter_driver.dart'; import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
@ -96,9 +95,10 @@ void runTestSuite({bool batchMode = false}) {
}); });
// Archive the edited client // Archive the edited client
test('Archieve/delete client test', () async { test('Archive/delete client test', () async {
await testArchiveAndDelete( await testArchiveAndDelete(
driver: driver, driver: driver,
name: updatedName,
archivedMessage: localization.archivedClient, archivedMessage: localization.archivedClient,
deletedMessage: localization.deletedClient, deletedMessage: localization.deletedClient,
restoredMessage: localization.restoredClient); restoredMessage: localization.restoredClient);
@ -109,4 +109,3 @@ void runTestSuite({bool batchMode = false}) {
}); });
}); });
} }
*/

View File

@ -1,9 +1,9 @@
/*
import 'dart:math'; import 'dart:math';
import 'package:faker/faker.dart'; import 'package:faker/faker.dart';
import 'package:flutter_driver/flutter_driver.dart'; import 'package:flutter_driver/flutter_driver.dart';
import 'package:invoiceninja_flutter/.env.dart'; import 'package:invoiceninja_flutter/.env.dart';
import 'package:invoiceninja_flutter/constants.dart';
import 'localizations.dart'; import 'localizations.dart';
@ -54,10 +54,11 @@ Future<void> login(FlutterDriver driver,
if (selfHosted) { if (selfHosted) {
await fillTextFields(driver, <String, dynamic>{ await fillTextFields(driver, <String, dynamic>{
localization.url: loginUrl, localization.url: loginUrl,
localization.secret: loginSecret, '${localization.secret} (${localization.optional})': loginSecret,
}); });
} }
print(localization.emailSignIn);
await driver.tap(find.text(localization.emailSignIn)); await driver.tap(find.text(localization.emailSignIn));
if (loginEmail.isNotEmpty) { if (loginEmail.isNotEmpty) {
@ -75,8 +76,10 @@ Future<void> logout(FlutterDriver driver, TestLocalization localization,
} }
//await driver.scrollUntilVisible(find.byType('Drawer'), find.text(localization.settings)); //await driver.scrollUntilVisible(find.byType('Drawer'), find.text(localization.settings));
await driver.tap(find.text(localization.settings)); //await driver.tap(find.text(localization.settings));
await driver.tap(find.text(localization.deviceSettings)); //await driver.tap(find.text(localization.deviceSettings));
await driver.tap(find.byValueKey(kSelectCompanyDropdownKey));
// Tap on Log Out // Tap on Log Out
await driver.tap(find.text(localization.logout)); await driver.tap(find.text(localization.logout));
@ -129,7 +132,7 @@ Future<void> fillAndSaveForm(FlutterDriver driver, Map<String, dynamic> values,
await fillTextFields(driver, values); await fillTextFields(driver, values);
// Await for Debouncer // Await for Debouncer
await Future<dynamic>.delayed(Duration(milliseconds: 400)); await Future<dynamic>.delayed(Duration(milliseconds: 1000));
print('Check for updated values'); print('Check for updated values');
await checkTextFields(driver, values, except: skipCheckFor); await checkTextFields(driver, values, except: skipCheckFor);
@ -145,6 +148,7 @@ Future<void> fillAndSaveForm(FlutterDriver driver, Map<String, dynamic> values,
Future<void> testArchiveAndDelete( Future<void> testArchiveAndDelete(
{FlutterDriver driver, {FlutterDriver driver,
String archivedMessage, String archivedMessage,
String name,
String deletedMessage, String deletedMessage,
String restoredMessage}) async { String restoredMessage}) async {
final localization = TestLocalization('en'); final localization = TestLocalization('en');
@ -164,6 +168,7 @@ Future<void> testArchiveAndDelete(
//await driver.waitFor(find.text(localization.archived)); //await driver.waitFor(find.text(localization.archived));
print('Restore record'); print('Restore record');
await driver.tap(find.text(name));
await selectAction(driver, localization.restore); await selectAction(driver, localization.restore);
await driver.waitFor(find.text(restoredMessage)); await driver.waitFor(find.text(restoredMessage));
await driver.waitForAbsent(find.byType('Snackbar')); await driver.waitForAbsent(find.byType('Snackbar'));
@ -174,6 +179,7 @@ Future<void> testArchiveAndDelete(
//await driver.waitFor(find.text(localization.deleted)); //await driver.waitFor(find.text(localization.deleted));
print('Restore record'); print('Restore record');
await driver.tap(find.text(name));
await selectAction(driver, localization.restore); await selectAction(driver, localization.restore);
await driver.waitFor(find.text(restoredMessage)); await driver.waitFor(find.text(restoredMessage));
await driver.waitForAbsent(find.byType('Snackbar')); await driver.waitForAbsent(find.byType('Snackbar'));
@ -189,4 +195,3 @@ String makeUnique(String value) =>
String getLineItemKey(String key, int index) => String getLineItemKey(String key, int index) =>
'${Keys.invoiceLineItemBaseKey}_${index}_${key}__'; '${Keys.invoiceLineItemBaseKey}_${index}_${key}__';
*/