feat(proj): init
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:please_pay_me/core/config/app_config.dart';
|
||||
import 'package:please_pay_me/core/storage/session_storage.dart';
|
||||
import 'package:please_pay_me/data/demo/demo_backend.dart';
|
||||
import 'package:please_pay_me/features/auth/session_controller.dart';
|
||||
import 'package:please_pay_me/features/budgets/budgets_controller.dart';
|
||||
import 'package:please_pay_me/features/journal/journal_controller.dart';
|
||||
import 'package:please_pay_me/features/work/jobs_controller.dart';
|
||||
|
||||
void main() {
|
||||
late DemoBackend backend;
|
||||
|
||||
setUp(() => backend = DemoBackend(today: DateTime(2026, 9, 19)));
|
||||
|
||||
group('BudgetsController', () {
|
||||
test('loads budgets and exposes the selected one', () async {
|
||||
final controller = BudgetsController(
|
||||
budgets: backend.budgets,
|
||||
expenses: backend.expenses,
|
||||
);
|
||||
await controller.load();
|
||||
|
||||
expect(controller.items, hasLength(2));
|
||||
expect(controller.selected?.budget.name, 'До аванса');
|
||||
expect(controller.hasBudgets, isTrue);
|
||||
});
|
||||
|
||||
test('adding an expense lowers the remaining amount', () async {
|
||||
final controller = BudgetsController(
|
||||
budgets: backend.budgets,
|
||||
expenses: backend.expenses,
|
||||
);
|
||||
await controller.load();
|
||||
final before = controller.selected!.remaining;
|
||||
|
||||
final error = await controller.addExpense(amount: 500, note: 'Обед');
|
||||
|
||||
expect(error, isNull);
|
||||
expect(controller.selected!.remaining, before - 500);
|
||||
expect(controller.isMutating, isFalse);
|
||||
});
|
||||
|
||||
test('undo removes the newest expense of the selected budget', () async {
|
||||
final controller = BudgetsController(
|
||||
budgets: backend.budgets,
|
||||
expenses: backend.expenses,
|
||||
);
|
||||
await controller.load();
|
||||
await controller.addExpense(amount: 777);
|
||||
final withExtra = controller.selected!.totalSpent;
|
||||
|
||||
await controller.undoLastExpense();
|
||||
|
||||
expect(controller.selected!.totalSpent, withExtra - 777);
|
||||
});
|
||||
|
||||
test('select switches the current envelope', () async {
|
||||
final controller = BudgetsController(
|
||||
budgets: backend.budgets,
|
||||
expenses: backend.expenses,
|
||||
);
|
||||
await controller.load();
|
||||
|
||||
await controller.select(2);
|
||||
|
||||
expect(controller.selected?.budget.id, 2);
|
||||
});
|
||||
|
||||
test('surfaces backend errors without crashing', () async {
|
||||
final empty = DemoBackend.empty();
|
||||
final controller = BudgetsController(
|
||||
budgets: empty.budgets,
|
||||
expenses: empty.expenses,
|
||||
);
|
||||
await controller.load();
|
||||
|
||||
final error = await controller.addExpense(amount: 100);
|
||||
|
||||
expect(error, 'Сначала создайте бюджет');
|
||||
expect(controller.hasBudgets, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('JournalController', () {
|
||||
test('groups operations by day, newest first', () async {
|
||||
final controller = JournalController(expenses: backend.expenses);
|
||||
await controller.load();
|
||||
|
||||
final groups = controller.groups;
|
||||
|
||||
expect(groups.first.day, DateTime(2026, 9, 19));
|
||||
expect(groups.first.items, hasLength(2));
|
||||
expect(groups.first.total, 2090);
|
||||
expect(groups.map((g) => g.day), isNot(contains(DateTime(2026, 8, 30))));
|
||||
});
|
||||
|
||||
test('scope "all" includes other budgets', () async {
|
||||
final controller = JournalController(expenses: backend.expenses);
|
||||
await controller.load();
|
||||
final currentCount = controller.items.length;
|
||||
|
||||
await controller.setScope(JournalScope.all);
|
||||
|
||||
expect(controller.items.length, greaterThan(currentCount));
|
||||
expect(controller.scope, JournalScope.all);
|
||||
});
|
||||
|
||||
test('loadMore appends the next page', () async {
|
||||
final controller = JournalController(expenses: backend.expenses, pageSize: 2);
|
||||
await controller.load();
|
||||
|
||||
expect(controller.items, hasLength(2));
|
||||
expect(controller.hasMore, isTrue);
|
||||
|
||||
await controller.loadMore();
|
||||
|
||||
expect(controller.items, hasLength(4));
|
||||
expect(controller.hasMore, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('JobsController', () {
|
||||
test('nextPay picks the closest payday', () async {
|
||||
final controller = JobsController(jobs: backend.jobs);
|
||||
await controller.load();
|
||||
|
||||
expect(controller.items, hasLength(1));
|
||||
expect(controller.nextPay?.date, DateTime(2026, 9, 27));
|
||||
});
|
||||
});
|
||||
|
||||
group('SessionController', () {
|
||||
test('restores a stored session', () async {
|
||||
final session = SessionController(
|
||||
config: AppConfig.demo,
|
||||
storage: InMemorySessionStorage({
|
||||
'token': 'jwt',
|
||||
'baseUrl': 'https://ppm.example.com',
|
||||
'user': '{"user_id":7,"username":"vlad"}',
|
||||
}),
|
||||
);
|
||||
|
||||
await session.restore();
|
||||
|
||||
expect(session.status, SessionStatus.signedIn);
|
||||
expect(session.user?.userId, 7);
|
||||
expect(session.isDemo, isFalse);
|
||||
});
|
||||
|
||||
test('without a stored token the app asks to sign in', () async {
|
||||
final session = SessionController(
|
||||
config: AppConfig.demo,
|
||||
storage: InMemorySessionStorage(),
|
||||
);
|
||||
|
||||
await session.restore();
|
||||
|
||||
expect(session.status, SessionStatus.signedOut);
|
||||
});
|
||||
|
||||
test('demo mode serves repositories from the in-memory backend', () async {
|
||||
final session = SessionController(
|
||||
config: AppConfig.demo,
|
||||
storage: InMemorySessionStorage(),
|
||||
demoBackend: backend,
|
||||
)..startDemo();
|
||||
|
||||
expect(session.status, SessionStatus.signedIn);
|
||||
expect(await session.budgets.list(), hasLength(2));
|
||||
expect(session.sessionKey, contains('demo'));
|
||||
});
|
||||
|
||||
test('sign out clears the session', () async {
|
||||
final storage = InMemorySessionStorage({
|
||||
'token': 'jwt',
|
||||
'baseUrl': 'https://ppm.example.com',
|
||||
'user': '{"user_id":7}',
|
||||
});
|
||||
final session = SessionController(config: AppConfig.demo, storage: storage);
|
||||
await session.restore();
|
||||
|
||||
await session.signOut();
|
||||
|
||||
expect(session.status, SessionStatus.signedOut);
|
||||
expect(await storage.readAll(), isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user