Fixed tests for Tablet/Desktop layout

This commit is contained in:
Gianfranco Gasbarri 2020-06-11 19:30:24 +01:00
parent fad460dc7b
commit 4557c7e1ec
10 changed files with 368 additions and 299 deletions

View File

@ -61,3 +61,29 @@ class ActionMenuButton extends StatelessWidget {
);
}
}
/// This class is used to differentiate List and View ActionMenuButtons
/// during tests
class ViewActionMenuButton extends StatelessWidget {
const ViewActionMenuButton({
@required this.entity,
@required this.onSelected,
this.isSaving = false,
this.entityActions,
});
final BaseEntity entity;
final List<EntityAction> entityActions;
final Function(BuildContext, EntityAction) onSelected;
final bool isSaving;
@override
Widget build(BuildContext context) {
return ActionMenuButton(
entity: entity,
onSelected: onSelected,
isSaving: isSaving,
entityActions: entityActions
);
}
}

View File

@ -335,6 +335,7 @@ class _AppBottomBarState extends State<AppBottomBar> {
final prefState = store.state.prefState;
final isList = prefState.moduleLayout == ModuleLayout.list ||
widget.entityType.isSetting;
final company = state.company;
return BottomAppBar(
shape: CircularNotchedRectangle(),
@ -384,7 +385,6 @@ class _AppBottomBarState extends State<AppBottomBar> {
),
if (widget.statuses.isNotEmpty)
IconButton(
tooltip: localization.filter,
icon: Icon(Icons.filter),
onPressed: _showFilterStatusSheet,
color: store.state
@ -395,7 +395,6 @@ class _AppBottomBarState extends State<AppBottomBar> {
),
if (widget.customValues1.isNotEmpty)
IconButton(
tooltip: localization.filter,
icon: Icon(Icons.looks_one),
onPressed: _showFilterCustom1Sheet,
color: store.state
@ -406,7 +405,6 @@ class _AppBottomBarState extends State<AppBottomBar> {
),
if (widget.customValues2.isNotEmpty)
IconButton(
tooltip: localization.filter,
icon: Icon(Icons.looks_two),
onPressed: _showFilterCustom2Sheet,
color: store.state
@ -417,7 +415,6 @@ class _AppBottomBarState extends State<AppBottomBar> {
),
if (widget.customValues3.isNotEmpty)
IconButton(
tooltip: localization.filter,
icon: Icon(Icons.looks_two),
onPressed: _showFilterCustom3Sheet,
color: store.state
@ -428,7 +425,6 @@ class _AppBottomBarState extends State<AppBottomBar> {
),
if (widget.customValues4.isNotEmpty)
IconButton(
tooltip: localization.filter,
icon: Icon(Icons.looks_two),
onPressed: _showFilterCustom4Sheet,
color: store.state

View File

@ -120,6 +120,7 @@ class _EntityDropdownState extends State<EntityDropdown> {
alignment: Alignment.centerRight,
children: <Widget>[
TypeAheadFormField<String>(
validator: widget.validator,
noItemsFoundBuilder: (context) => SizedBox(),
suggestionsBoxDecoration: SuggestionsBoxDecoration(
constraints: BoxConstraints(

View File

@ -243,60 +243,70 @@ class MenuDrawer extends StatelessWidget {
entityType: EntityType.client,
icon: getEntityIcon(EntityType.client),
title: localization.clients,
iconTooltip: localization.newClient,
),
DrawerTile(
company: company,
entityType: EntityType.product,
icon: getEntityIcon(EntityType.product),
title: localization.products,
iconTooltip: localization.newProduct,
),
DrawerTile(
company: company,
entityType: EntityType.invoice,
icon: getEntityIcon(EntityType.invoice),
title: localization.invoices,
iconTooltip: localization.newInvoice,
),
DrawerTile(
company: company,
entityType: EntityType.payment,
icon: getEntityIcon(EntityType.payment),
title: localization.payments,
iconTooltip: localization.newPayment,
),
DrawerTile(
company: company,
entityType: EntityType.quote,
icon: getEntityIcon(EntityType.quote),
title: localization.quotes,
iconTooltip: localization.newQuote,
),
DrawerTile(
company: company,
entityType: EntityType.credit,
icon: getEntityIcon(EntityType.credit),
title: localization.credits,
iconTooltip: localization.newCredit,
),
DrawerTile(
company: company,
entityType: EntityType.project,
icon: getEntityIcon(EntityType.project),
title: localization.projects,
iconTooltip: localization.newProject,
),
DrawerTile(
company: company,
entityType: EntityType.task,
icon: getEntityIcon(EntityType.task),
title: localization.tasks,
iconTooltip: localization.newTask,
),
DrawerTile(
company: company,
entityType: EntityType.vendor,
icon: getEntityIcon(EntityType.vendor),
title: localization.vendors,
iconTooltip: localization.newVendor,
),
DrawerTile(
company: company,
entityType: EntityType.expense,
icon: getEntityIcon(EntityType.expense),
title: localization.expenses,
iconTooltip: localization.newExpense,
),
// STARTER: menu - do not remove comment
DrawerTile(
@ -349,6 +359,7 @@ class DrawerTile extends StatefulWidget {
this.entityType,
this.onLongPress,
this.onCreateTap,
this.iconTooltip,
});
final CompanyEntity company;
@ -358,6 +369,7 @@ class DrawerTile extends StatefulWidget {
final Function onTap;
final Function onLongPress;
final Function onCreateTap;
final String iconTooltip;
@override
_DrawerTileState createState() => _DrawerTileState();
@ -421,6 +433,7 @@ class _DrawerTileState extends State<DrawerTile> {
);
} else if (userCompany.canCreate(widget.entityType)) {
trailingWidget = IconButton(
tooltip: widget.iconTooltip,
icon: Icon(
Icons.add_circle_outline,
color: textColor,

View File

@ -88,7 +88,7 @@ class ViewScaffold extends StatelessWidget {
);
})
: Container(),
ActionMenuButton(
ViewActionMenuButton(
isSaving: state.isSaving,
entity: entity,
onSelected: (context, action) =>

View File

@ -237,7 +237,7 @@ class DashboardPanels extends StatelessWidget {
currentData: currentData,
previousData: previousData,
isLoaded: isLoaded,
title: AppLocalization.of(context).invoices);
title: AppLocalization.of(context).invoiced);
}
Widget _paymentChart(BuildContext context) {

View File

@ -42,8 +42,6 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
TabController _tabController;
FocusNode _focusNode;
static final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: '_invoiceDesktopEdit');
final _invoiceNumberController = TextEditingController();
final _poNumberController = TextEditingController();
@ -173,232 +171,228 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
final invoice = viewModel.invoice;
final company = viewModel.company;
return AppForm(
formKey: _formKey,
focusNode: _focusNode,
child: ListView(
key: ValueKey('__invoice_${invoice.id}__'),
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding / 2,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding),
children: <Widget>[
if (invoice.isNew)
ClientPicker(
autofocus: kIsWeb,
clientId: invoice.clientId,
clientState: viewModel.state.clientState,
onSelected: (client) =>
viewModel.onClientChanged(invoice, client),
onAddPressed: (completer) =>
viewModel.onAddClientPressed(context, completer),
),
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200),
child: InvoiceEditContactsScreen(),
return ListView(
key: ValueKey('__invoice_${invoice.id}__'),
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding / 2,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding),
children: <Widget>[
if (invoice.isNew)
ClientPicker(
autofocus: kIsWeb,
clientId: invoice.clientId,
clientState: viewModel.state.clientState,
onSelected: (client) =>
viewModel.onClientChanged(invoice, client),
onAddPressed: (completer) =>
viewModel.onAddClientPressed(context, completer),
),
],
),
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 200),
child: InvoiceEditContactsScreen(),
),
],
),
Expanded(
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding / 2,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding / 2),
children: <Widget>[
),
Expanded(
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding / 2,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding / 2),
children: <Widget>[
DatePicker(
validator: (String val) => val.trim().isEmpty
? AppLocalization.of(context).pleaseSelectADate
: null,
labelText: widget.entityType == EntityType.credit
? localization.creditDate
: widget.entityType == EntityType.quote
? localization.quoteDate
: localization.invoiceDate,
selectedDate: invoice.date,
onSelected: (date) {
viewModel
.onChanged(invoice.rebuild((b) => b..date = date));
},
),
if (widget.entityType != EntityType.credit)
DatePicker(
validator: (String val) => val.trim().isEmpty
? AppLocalization.of(context).pleaseSelectADate
: null,
labelText: widget.entityType == EntityType.credit
? localization.creditDate
: widget.entityType == EntityType.quote
? localization.quoteDate
: localization.invoiceDate,
selectedDate: invoice.date,
allowClearing: true,
labelText: widget.entityType == EntityType.quote
? localization.validUntil
: localization.dueDate,
selectedDate: invoice.dueDate,
onSelected: (date) {
viewModel
.onChanged(invoice.rebuild((b) => b..date = date));
viewModel.onChanged(
invoice.rebuild((b) => b..dueDate = date));
},
),
if (widget.entityType != EntityType.credit)
DatePicker(
allowClearing: true,
labelText: widget.entityType == EntityType.quote
? localization.validUntil
: localization.dueDate,
selectedDate: invoice.dueDate,
onSelected: (date) {
viewModel.onChanged(
invoice.rebuild((b) => b..dueDate = date));
},
),
DecoratedFormField(
label: localization.partialDeposit,
controller: _partialController,
keyboardType:
TextInputType.numberWithOptions(decimal: true),
DecoratedFormField(
label: localization.partialDeposit,
controller: _partialController,
keyboardType:
TextInputType.numberWithOptions(decimal: true),
),
if (invoice.partial != null && invoice.partial > 0)
DatePicker(
labelText: localization.partialDueDate,
selectedDate: invoice.partialDueDate,
onSelected: (date) {
viewModel.onChanged(
invoice.rebuild((b) => b..partialDueDate = date));
},
),
if (invoice.partial != null && invoice.partial > 0)
DatePicker(
labelText: localization.partialDueDate,
selectedDate: invoice.partialDueDate,
onSelected: (date) {
viewModel.onChanged(
invoice.rebuild((b) => b..partialDueDate = date));
},
),
CustomField(
controller: _custom1Controller,
field: CustomFieldType.invoice1,
value: invoice.customValue1,
),
CustomField(
controller: _custom3Controller,
field: CustomFieldType.invoice3,
value: invoice.customValue3,
),
],
),
CustomField(
controller: _custom1Controller,
field: CustomFieldType.invoice1,
value: invoice.customValue1,
),
CustomField(
controller: _custom3Controller,
field: CustomFieldType.invoice3,
value: invoice.customValue3,
),
],
),
Expanded(
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding / 2),
children: <Widget>[
DecoratedFormField(
controller: _invoiceNumberController,
label: widget.entityType == EntityType.credit
? localization.creditNumber
: widget.entityType == EntityType.quote
? localization.quoteNumber
: localization.invoiceNumber,
validator: (String val) =>
val.trim().isEmpty && invoice.isOld
? AppLocalization.of(context)
.pleaseEnterAnInvoiceNumber
: null,
),
DecoratedFormField(
label: localization.poNumber,
controller: _poNumberController,
),
DiscountField(
controller: _discountController,
value: invoice.discount,
isAmountDiscount: invoice.isAmountDiscount,
onTypeChanged: (value) => viewModel.onChanged(
invoice.rebuild((b) => b..isAmountDiscount = value)),
),
CustomField(
controller: _custom2Controller,
field: CustomFieldType.invoice2,
value: invoice.customValue2,
),
CustomField(
controller: _custom4Controller,
field: CustomFieldType.invoice4,
value: invoice.customValue4,
),
],
),
),
Expanded(
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding / 2),
children: <Widget>[
DecoratedFormField(
controller: _invoiceNumberController,
label: widget.entityType == EntityType.credit
? localization.creditNumber
: widget.entityType == EntityType.quote
? localization.quoteNumber
: localization.invoiceNumber,
validator: (String val) => val.trim().isEmpty &&
invoice.isOld
? AppLocalization.of(context).pleaseEnterAnInvoiceNumber
: null,
),
DecoratedFormField(
label: localization.poNumber,
controller: _poNumberController,
),
DiscountField(
controller: _discountController,
value: invoice.discount,
isAmountDiscount: invoice.isAmountDiscount,
onTypeChanged: (value) => viewModel.onChanged(
invoice.rebuild((b) => b..isAmountDiscount = value)),
),
CustomField(
controller: _custom2Controller,
field: CustomFieldType.invoice2,
value: invoice.customValue2,
),
CustomField(
controller: _custom4Controller,
field: CustomFieldType.invoice4,
value: invoice.customValue4,
),
],
),
],
),
widget.entityType == EntityType.credit
? CreditEditItemsScreen()
: widget.entityType == EntityType.quote
? QuoteEditItemsScreen()
: InvoiceEditItemsScreen(),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 2,
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding / 2,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding),
children: <Widget>[
TabBar(
),
],
),
widget.entityType == EntityType.credit
? CreditEditItemsScreen()
: widget.entityType == EntityType.quote
? QuoteEditItemsScreen()
: InvoiceEditItemsScreen(),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 2,
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding / 2,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding),
children: <Widget>[
TabBar(
controller: _tabController,
tabs: [
Tab(text: localization.publicNotes),
Tab(text: localization.privateNotes),
Tab(
text: widget.entityType == EntityType.credit
? localization.creditTerms
: widget.entityType == EntityType.quote
? localization.quoteTerms
: localization.invoiceTerms),
Tab(
text: widget.entityType == EntityType.credit
? localization.creditFooter
: widget.entityType == EntityType.quote
? localization.quoteFooter
: localization.invoiceFooter),
],
),
SizedBox(
height: 100,
child: TabBarView(
controller: _tabController,
tabs: [
Tab(text: localization.publicNotes),
Tab(text: localization.privateNotes),
Tab(
text: widget.entityType == EntityType.credit
? localization.creditTerms
: widget.entityType == EntityType.quote
? localization.quoteTerms
: localization.invoiceTerms),
Tab(
text: widget.entityType == EntityType.credit
? localization.creditFooter
: widget.entityType == EntityType.quote
? localization.quoteFooter
: localization.invoiceFooter),
children: <Widget>[
DecoratedFormField(
maxLines: 4,
controller: _publicNotesController,
keyboardType: TextInputType.multiline,
label: '',
),
DecoratedFormField(
maxLines: 4,
controller: _privateNotesController,
keyboardType: TextInputType.multiline,
label: '',
),
DecoratedFormField(
maxLines: 4,
controller: _termsController,
keyboardType: TextInputType.multiline,
label: '',
),
DecoratedFormField(
maxLines: 4,
controller: _footerController,
keyboardType: TextInputType.multiline,
label: '',
),
],
),
SizedBox(
height: 100,
child: TabBarView(
controller: _tabController,
children: <Widget>[
DecoratedFormField(
maxLines: 4,
controller: _publicNotesController,
keyboardType: TextInputType.multiline,
label: '',
),
DecoratedFormField(
maxLines: 4,
controller: _privateNotesController,
keyboardType: TextInputType.multiline,
label: '',
),
DecoratedFormField(
maxLines: 4,
controller: _termsController,
keyboardType: TextInputType.multiline,
label: '',
),
DecoratedFormField(
maxLines: 4,
controller: _footerController,
keyboardType: TextInputType.multiline,
label: '',
),
],
),
),
],
),
),
],
),
Expanded(
flex: 1,
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding / 2),
children: <Widget>[
/*
),
Expanded(
flex: 1,
child: FormCard(
padding: const EdgeInsets.only(
top: kMobileDialogPadding,
right: kMobileDialogPadding,
bottom: kMobileDialogPadding,
left: kMobileDialogPadding / 2),
children: <Widget>[
/*
DecoratedFormField(
controller: null,
enabled: false,
@ -406,60 +400,59 @@ class InvoiceEditDesktopState extends State<InvoiceEditDesktop>
label: localization.subtotal,
),
*/
UserPicker(
userId: invoice.assignedUserId,
onChanged: (userId) => viewModel.onChanged(
invoice.rebuild((b) => b..assignedUserId = userId)),
UserPicker(
userId: invoice.assignedUserId,
onChanged: (userId) => viewModel.onChanged(
invoice.rebuild((b) => b..assignedUserId = userId)),
),
DesignPicker(
initialValue: invoice.designId,
onSelected: (value) => viewModel.onChanged(
invoice.rebuild((b) => b..designId = value.id)),
),
CustomSurcharges(
surcharge1Controller: _surcharge1Controller,
surcharge2Controller: _surcharge2Controller,
surcharge3Controller: _surcharge3Controller,
surcharge4Controller: _surcharge4Controller,
),
if (company.settings.enableFirstInvoiceTaxRate)
TaxRateDropdown(
onSelected: (taxRate) =>
viewModel.onChanged(invoice.applyTax(taxRate)),
labelText: localization.tax,
initialTaxName: invoice.taxName1,
initialTaxRate: invoice.taxRate1,
),
DesignPicker(
initialValue: invoice.designId,
onSelected: (value) => viewModel.onChanged(
invoice.rebuild((b) => b..designId = value.id)),
if (company.settings.enableSecondInvoiceTaxRate)
TaxRateDropdown(
onSelected: (taxRate) => viewModel
.onChanged(invoice.applyTax(taxRate, isSecond: true)),
labelText: localization.tax,
initialTaxName: invoice.taxName2,
initialTaxRate: invoice.taxRate2,
),
CustomSurcharges(
surcharge1Controller: _surcharge1Controller,
surcharge2Controller: _surcharge2Controller,
surcharge3Controller: _surcharge3Controller,
surcharge4Controller: _surcharge4Controller,
if (company.settings.enableThirdInvoiceTaxRate)
TaxRateDropdown(
onSelected: (taxRate) => viewModel
.onChanged(invoice.applyTax(taxRate, isThird: true)),
labelText: localization.tax,
initialTaxName: invoice.taxName3,
initialTaxRate: invoice.taxRate3,
),
if (company.settings.enableFirstInvoiceTaxRate)
TaxRateDropdown(
onSelected: (taxRate) =>
viewModel.onChanged(invoice.applyTax(taxRate)),
labelText: localization.tax,
initialTaxName: invoice.taxName1,
initialTaxRate: invoice.taxRate1,
),
if (company.settings.enableSecondInvoiceTaxRate)
TaxRateDropdown(
onSelected: (taxRate) => viewModel.onChanged(
invoice.applyTax(taxRate, isSecond: true)),
labelText: localization.tax,
initialTaxName: invoice.taxName2,
initialTaxRate: invoice.taxRate2,
),
if (company.settings.enableThirdInvoiceTaxRate)
TaxRateDropdown(
onSelected: (taxRate) => viewModel.onChanged(
invoice.applyTax(taxRate, isThird: true)),
labelText: localization.tax,
initialTaxName: invoice.taxName3,
initialTaxRate: invoice.taxRate3,
),
CustomSurcharges(
surcharge1Controller: _surcharge1Controller,
surcharge2Controller: _surcharge2Controller,
surcharge3Controller: _surcharge3Controller,
surcharge4Controller: _surcharge4Controller,
isAfterTaxes: true,
),
],
),
CustomSurcharges(
surcharge1Controller: _surcharge1Controller,
surcharge2Controller: _surcharge2Controller,
surcharge3Controller: _surcharge3Controller,
surcharge4Controller: _surcharge4Controller,
isAfterTaxes: true,
),
],
),
],
),
],
),
),
],
),
],
);
}
}

View File

@ -136,6 +136,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TypeAheadFormField<String>(
key: ValueKey('__line_item_${index}_name__'),
initialValue: lineItems[index].productKey,
noItemsFoundBuilder: (context) => SizedBox(),
suggestionsCallback: (pattern) {
@ -238,6 +239,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TextFormField(
key: ValueKey('__line_item_${index}_description__'),
initialValue: lineItems[index].notes,
onChanged: (value) => viewModel.onChangedInvoiceItem(
lineItems[index].rebuild((b) => b..notes = value),
@ -346,6 +348,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TextFormField(
key: ValueKey('__line_item_${index}_cost__'),
textAlign: TextAlign.right,
initialValue: formatNumber(lineItems[index].cost, context,
formatNumberType: FormatNumberType.input,
@ -361,6 +364,7 @@ class _InvoiceEditItemsDesktopState extends State<InvoiceEditItemsDesktop> {
Padding(
padding: const EdgeInsets.only(right: kTableColumnGap),
child: TextFormField(
key: ValueKey('__line_item_${index}_quantity__'),
textAlign: TextAlign.right,
initialValue: formatNumber(
lineItems[index].quantity, context,

View File

@ -16,14 +16,16 @@ void runTestSuite({bool batchMode = false}) {
final clientName = makeUnique(faker.company.name());
final poNumber =
faker.randomGenerator.integer(999999, min: 100000).toString();
faker.randomGenerator.integer(999999, min: 100000).toString();
final productKey = makeUnique(faker.food.cuisine());
final clientKey = faker.randomGenerator.integer(999999, min: 100000)
.toString();
final description = faker.lorem.sentences(5).toString();
final cost =
faker.randomGenerator.decimal(min: 50, scale: 10).toStringAsFixed(2);
faker.randomGenerator.decimal(min: 50, scale: 10).toStringAsFixed(2);
final updatedPoNumber =
faker.randomGenerator.integer(999999, min: 100000).toString();
faker.randomGenerator.integer(999999, min: 100000).toString();
setUpAll(() async {
localization = TestLocalization('en');
@ -67,35 +69,53 @@ void runTestSuite({bool batchMode = false}) {
// Create a new invoice
test('Add a new invoice', () async {
print('Tap new invoice');
await driver.tap(find.byTooltip(localization.newInvoice));
print('Create new client: $clientName');
await driver.tap(find.byValueKey(Keys.clientPickerEmptyKey));
if(await isMobile(driver)) {
await driver.tap(find.byValueKey(Keys.clientPickerEmptyKey));
}
await driver.tap(find.byTooltip(localization.createNew));
print('Fill the client form');
await fillTextField(
driver: driver, field: localization.name, value: clientName);
await fillTextFields(driver, <String, String>{
localization.name: clientName,
localization.idNumber: clientKey
});
// Await for Debouncer
await Future<dynamic>.delayed(Duration(milliseconds: 500));
await driver.tap(find.text(localization.save));
// Await for Screen change
await driver.waitFor(find.text(localization.newInvoice));
print('Fill the invoice form');
await driver.tap(find.byTooltip(localization.addItem));
await driver.tap(find.byTooltip(localization.createNew));
if(await isMobile(driver)) {
await driver.tap(find.byTooltip(localization.addItem));
await driver.tap(find.byTooltip(localization.createNew));
await fillTextFields(driver, <String, String>{
localization.product: productKey,
localization.description: description,
localization.unitCost: cost,
localization.quantity: '1',
});
await fillTextFields(driver, <String, String>{
localization.product: productKey,
localization.description: description,
localization.unitCost: cost,
localization.quantity: '1',
});
// Await for Debouncer
await Future<dynamic>.delayed(Duration(milliseconds: 500));
await driver.tap(find.text(localization.done));
await driver.tap(find.text(localization.details));
// Await for Debouncer
await Future<dynamic>.delayed(Duration(milliseconds: 500));
await driver.tap(find.text(localization.done));
await driver.tap(find.text(localization.details));
} else {
await fillTextFields(driver, <String, String>{
getLineItemKey('name', 0): productKey,
getLineItemKey('description', 0): description,
getLineItemKey('cost', 0): cost,
getLineItemKey('quantity', 0): '1'
});
}
await fillAndSaveForm(driver, <String, String>{
localization.poNumber: poNumber,
@ -140,7 +160,8 @@ void runTestSuite({bool batchMode = false}) {
await selectAction(driver, localization.enterPayment);
await driver.tap(find.text(localization.save));
// "Completed" status
await driver.waitFor(find.text(localization.paymentStatus4.toUpperCase()));
await driver.waitFor(
find.text(localization.paymentStatus4.toUpperCase()));
if (await isMobile(driver)) {
await driver.tap(find.pageBack());

View File

@ -9,6 +9,7 @@ import 'localizations.dart';
class Keys {
static const String openAppDrawer = 'Open navigation menu';
static const String clientPickerEmptyKey = '__client___';
static const String invoiceLineItemBaseKey = '__line_item';
}
Future<bool> isTablet(FlutterDriver driver) async {
@ -129,15 +130,15 @@ Future<void> fillAndSaveForm(FlutterDriver driver, Map<String, dynamic> values,
// Await for Debouncer
await Future<dynamic>.delayed(Duration(milliseconds: 400));
print('Check for updated values');
await checkTextFields(driver, values, except: skipCheckFor);
print('Tap save');
await driver.tap(find.text(localization.save));
// verify snackbar
//await driver.waitFor(find.text(localization.updatedProduct));
//await driver.tap(find.pageBack());
print('Check for updated values');
await checkTextFields(driver, values, except: skipCheckFor);
}
Future<void> testArchiveAndDelete(
@ -146,32 +147,46 @@ Future<void> testArchiveAndDelete(
String deletedMessage,
String restoredMessage}) async {
final localization = TestLocalization('en');
final mobile = await isMobile(driver);
if (!mobile) {
// Show archived and deleted entries on tablet/web
await driver.tap(find.byTooltip(localization.filter));
await driver.tap(find.text(localization.archived));
await driver.tap(find.text(localization.deleted));
await driver.tap(find.byTooltip(localization.filter));
}
print('Archive record');
await selectAction(driver, localization.archive);
await driver.waitFor(find.text(archivedMessage));
await driver.waitFor(find.text(localization.archived));
//await driver.waitFor(find.text(localization.archived));
print('Restore record');
await selectAction(driver, localization.restore);
await driver.waitFor(find.text(restoredMessage));
await driver.waitForAbsent(find.text(localization.archived));
await driver.waitForAbsent(find.byType('Snackbar'));
print('Delete record');
await selectAction(driver, localization.delete);
await driver.waitFor(find.text(deletedMessage));
await driver.waitFor(find.text(localization.deleted));
//await driver.waitFor(find.text(localization.deleted));
print('Restore record');
await selectAction(driver, localization.restore);
await driver.waitFor(find.text(restoredMessage));
await driver.waitForAbsent(find.text(localization.deleted));
await driver.waitForAbsent(find.byType('Snackbar'));
}
Future<void> selectAction(FlutterDriver driver, String action) async {
await driver.tap(find.byType('ActionMenuButton'));
await driver.tap(find.byType('ViewActionMenuButton'));
await driver.tap(find.text(action));
}
String makeUnique(String value) =>
'$value ${faker.randomGenerator.integer(999999, min: 100000)}';
String getLineItemKey(String key, int index) =>
'${Keys.invoiceLineItemBaseKey}_${index}_${key}__';