Pragament / fintracker

FinTracker is a powerful expense tracker app built with Flutter, designed to help you effortlessly manage your finances.
GNU Affero General Public License v3.0
0 stars 9 forks source link

FinTracker - Expense Tracker App

License: MIT

FinTracker is a Flutter application that helps you track your expenses and manage category budgets. It provides a user-friendly interface to enter and categorize your expenses, giving you insights into your spending habits and helping you stay within your budget.

FinTracker Screenshot

Download

You can download FinTracker from the Google Play Store:

Google Play Store

Features

Installation

  1. Clone the repository:
git clone https://github.com/nafishahmeddev/fintracker.git
  1. Change to the project directory:
cd fintracker
  1. Install dependencies:
flutter pub get
  1. Run the app:
flutter run

Usage

Roadmap

Check out our detailed roadmap for planned features and updates!

Contributing

Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request.

License

This project is licensed under the MIT License. See the LICENSE file for more information.

Acknowledgements

Contact

For any questions or inquiries, please email us at hello@nafish.me.

BDD Scenarios and Features

Prerequisites

BDD Framework: Add the bdd_widget_test package to your pubspec.yaml file.

dependencies: flutter: sdk: flutter bdd_widget_test: latest_version

Testing Framework: Ensure you have flutter_test or any other testing package installed.

Steps to Generate BDD Scenarios and Features

  1. Define Feature Files

Create a new feature file inside the test/features directory. This file should describe the behavior of your app in natural language.

Feature: Landing Page for Fintracker App

As a new user of the Fintracker app I want to see an informative landing page So that I can understand the app's purpose and get started

Scenario: Viewing the Landing Page Given I am a new user opening the Fintracker app When I arrive at the landing page Then I should see the app name "Fintracker" And I should see the tagline "Easy method to manage your savings" And I should see 3 key features of the app And I should see a "Get Started" button

Scenario: Starting the onboarding process Given I am on the landing page When I tap the "Get Started" button Then the onboarding process should begin

  1. Write Step Definitions

In your Dart code, create step definitions that correspond to the scenarios written in your feature file. Step definitions map the steps in your Gherkin scenarios to executable Dart code.

import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:bdd_widget_test/bdd_widget_test.dart';

void main() { BddWidgetTest().execute([ group('''FinTracker Home Screen''', () { testWidgets('''User views the home screen''', (tester) async { await givenTheUserOpensTheFintrackerApp(tester); await thenTheyShouldSeeTheirUsernameOrGuest(tester); });

  testWidgets('''User views account information''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await thenTheyShouldSeeAnAccountSlider(tester);
    await andTheSliderShouldDisplayAccountBalances(tester);
    await andTheSliderShouldShowAccountHolderNames(tester);
  });

  testWidgets('''User views payment summary''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await thenTheyShouldSeeAnIncomeSummary(tester);
    await andTheyShouldSeeAnExpenseSummary(tester);
  });

  testWidgets('''User views payment list''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await thenTheyShouldSeeAListOfRecentPayments(tester);
    await andEachPaymentShouldShowCategoryDateAndAmount(tester);
  });

  testWidgets('''User selects a date range''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await whenTheyTapOnTheDateRangeButton(tester);
    await thenTheyShouldBeAbleToSelectACustomDateRange(tester);
    await andThePaymentListShouldUpdateAccordingly(tester);
  });

  testWidgets('''User adds a new payment''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await whenTheyTapTheFloatingActionButton(tester);
    await thenTheyShouldBeTakenToThePaymentFormScreen(tester);
  });

  testWidgets('''User taps on a payment''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await whenTheyTapOnAPaymentInTheList(tester);
    await thenTheyShouldBeTakenToThePaymentFormScreenForThatPayment(tester);
  });

  testWidgets('''User scrolls through accounts''', (tester) async {
    await givenTheUserIsOnTheHomeScreen(tester);
    await whenTheySwipeOnTheAccountSlider(tester);
    await thenTheyShouldSeeDifferentAccountCards(tester);
    await andTheIndicatorDotsShouldUpdateToShowTheCurrentAccount(tester);
  });
})

]); }

Step Definitions

Each of the step functions (e.g., givenTheUserOpensTheFintrackerApp) should be defined in separate files or grouped logically. Here's how you can define some of these step functions:

Future givenTheUserOpensTheFintrackerApp(WidgetTester tester) async { // Code to simulate app opening await tester.pumpWidget(MyApp()); }

Future thenTheyShouldSeeTheirUsernameOrGuest(WidgetTester tester) async { // Verify that the username or "Guest" is visible expect(find.text('Guest'), findsOneWidget); }

Future givenTheUserIsOnTheHomeScreen(WidgetTester tester) async { // Code to ensure the user is on the home screen await tester.pumpWidget(MyApp()); }

Future thenTheyShouldSeeAnAccountSlider(WidgetTester tester) async { // Verify that the account slider is visible expect(find.byType(AccountSlider), findsOneWidget); }

Future andTheSliderShouldDisplayAccountBalances(WidgetTester tester) async { // Verify that account balances are displayed on the slider expect(find.text('Balance: \$1000'), findsWidgets); }

Future andTheSliderShouldShowAccountHolderNames(WidgetTester tester) async { // Verify that account holder names are displayed on the slider expect(find.text('John Doe'), findsWidgets); }

Future thenTheyShouldSeeAnIncomeSummary(WidgetTester tester) async { // Verify that the income summary is visible expect(find.text('Income Summary'), findsOneWidget); }

Future andTheyShouldSeeAnExpenseSummary(WidgetTester tester) async { // Verify that the expense summary is visible expect(find.text('Expense Summary'), findsOneWidget); }

Future thenTheyShouldSeeAListOfRecentPayments(WidgetTester tester) async { // Verify that a list of recent payments is visible expect(find.byType(PaymentList), findsOneWidget); }

Future andEachPaymentShouldShowCategoryDateAndAmount(WidgetTester tester) async { // Verify that each payment shows category, date, and amount expect(find.text('Groceries'), findsWidgets); expect(find.text('2023-08-01'), findsWidgets); expect(find.text('\$50'), findsWidgets); }

Future whenTheyTapOnTheDateRangeButton(WidgetTester tester) async { // Code to simulate tapping on the date range button await tester.tap(find.byKey(Key('date_range_button'))); await tester.pumpAndSettle(); }

Future thenTheyShouldBeAbleToSelectACustomDateRange(WidgetTester tester) async { // Verify that the custom date range selector is visible expect(find.byType(DateRangePicker), findsOneWidget); }

Future andThePaymentListShouldUpdateAccordingly(WidgetTester tester) async { // Verify that the payment list updates based on the selected date range expect(find.text('Payment on 2023-08-01'), findsOneWidget); }

Future whenTheyTapTheFloatingActionButton(WidgetTester tester) async { // Code to simulate tapping on the FAB await tester.tap(find.byType(FloatingActionButton)); await tester.pumpAndSettle(); }

Future thenTheyShouldBeTakenToThePaymentFormScreen(WidgetTester tester) async { // Verify that the payment form screen is displayed expect(find.byType(PaymentFormScreen), findsOneWidget); }

Future whenTheyTapOnAPaymentInTheList(WidgetTester tester) async { // Code to simulate tapping on a payment in the list await tester.tap(find.byType(PaymentListItem).first); await tester.pumpAndSettle(); }

Future thenTheyShouldBeTakenToThePaymentFormScreenForThatPayment(WidgetTester tester) async { // Verify that the payment form screen is displayed for the selected payment expect(find.byType(PaymentFormScreen), findsOneWidget); }

Future whenTheySwipeOnTheAccountSlider(WidgetTester tester) async { // Code to simulate swiping on the account slider await tester.drag(find.byType(AccountSlider), Offset(-300, 0)); await tester.pumpAndSettle(); }

Future thenTheyShouldSeeDifferentAccountCards(WidgetTester tester) async { // Verify that different account cards are displayed after swiping expect(find.text('Savings Account'), findsOneWidget); }

Future andTheIndicatorDotsShouldUpdateToShowTheCurrentAccount(WidgetTester tester) async { // Verify that the indicator dots update to show the current account expect(find.byType(IndicatorDots), findsOneWidget); }

Folder Structure

You can organize your step definitions in a folder structure like this:

test/ steps/ home_steps/ step/ the_user_opens_the_fintracker_app.dart they_should_see_their_username_or_guest.dart the_user_is_on_the_home_screen.dart they_should_see_an_account_slider.dart the_slider_should_display_account_balances.dart the_slider_should_show_account_holder_names.dart they_should_see_an_income_summary.dart they_should_see_an_expense_summary.dart they_should_see_a_list_of_recent_payments.dart each_payment_should_show_category_date_and_amount.dart they_tap_on_the_date_range_button.dart they_should_be_able_to_select_a_custom_date_range.dart the_payment_list_should_update_accordingly.dart they_tap_the_floating_action_button.dart they_should_be_taken_to_the_payment_form_screen.dart they_tap_on_a_payment_in_the_list.dart they_should_be_taken_to_the_payment_form_screen_for_that_payment.dart they_swipe_on_the_account_slider.dart they_should_see_different_account_cards.dart the_indicator_dots_should_update_to_show_the_current_account.dart