Тема и общие виджеты (AssetIcon, ServiceMark, HelpTip, глоссарий), верхняя панель TopNav и вкладки Аналитики вместо NavSidebar, иконки PWA. Экраны: портфели, создание брокерского счёта, ручное событие, правка инструмента, Обзор карточками по скоупам и таблица активов, пересчёт метрик с опросом /metrics/status. design-system.md обновлён.
110 lines
2.9 KiB
Dart
110 lines
2.9 KiB
Dart
import 'package:fintracker_api/fintracker_api.dart';
|
|
import 'package:fintracker_app/features/portfolio/instrument_edit_dialog.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
InstrumentOut _instrument() => InstrumentOut(
|
|
id: 1,
|
|
assetClass: 'share',
|
|
isin: 'RU0008958863',
|
|
figi: null,
|
|
ticker: 'MSNG',
|
|
board: 'TQBR',
|
|
exchange: null,
|
|
name: 'Мосэнерго',
|
|
issuer: null,
|
|
currency: 'RUB',
|
|
lot: 1,
|
|
nominal: null,
|
|
nominalCurrency: null,
|
|
maturityDate: null,
|
|
sector: null,
|
|
country: null,
|
|
isActive: true,
|
|
);
|
|
|
|
Future<InstrumentPatch?> _open(
|
|
WidgetTester tester,
|
|
Future<void> Function() interact,
|
|
) async {
|
|
InstrumentPatch? result;
|
|
var closed = false;
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: TextButton(
|
|
onPressed: () async {
|
|
result = await showDialog<InstrumentPatch>(
|
|
context: context,
|
|
builder: (_) => InstrumentEditDialog(instrument: _instrument()),
|
|
);
|
|
closed = true;
|
|
},
|
|
child: const Text('open'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.tap(find.text('open'));
|
|
await tester.pumpAndSettle();
|
|
await interact();
|
|
await tester.pumpAndSettle();
|
|
expect(closed, isTrue);
|
|
return result;
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('only the changed lot goes into the patch', (tester) async {
|
|
final patch = await _open(tester, () async {
|
|
await tester.enterText(find.widgetWithText(TextFormField, '1'), '1000');
|
|
await tester.tap(find.text('Сохранить'));
|
|
});
|
|
|
|
expect(patch, isNotNull);
|
|
expect(patch!.lot, 1000);
|
|
expect(patch.name, isNull);
|
|
expect(patch.board, isNull);
|
|
expect(patch.assetClass, isNull);
|
|
});
|
|
|
|
testWidgets('saving without changes closes with nothing to send', (
|
|
tester,
|
|
) async {
|
|
final patch = await _open(tester, () async {
|
|
await tester.tap(find.text('Сохранить'));
|
|
});
|
|
|
|
expect(patch, isNull);
|
|
});
|
|
|
|
testWidgets('a lot below 1 is refused and the dialog stays open', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: TextButton(
|
|
onPressed: () => showDialog<InstrumentPatch>(
|
|
context: context,
|
|
builder: (_) => InstrumentEditDialog(instrument: _instrument()),
|
|
),
|
|
child: const Text('open'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.tap(find.text('open'));
|
|
await tester.pumpAndSettle();
|
|
await tester.enterText(find.widgetWithText(TextFormField, '1'), '0');
|
|
await tester.tap(find.text('Сохранить'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Целое число не меньше 1'), findsOneWidget);
|
|
expect(find.text('Сохранить'), findsOneWidget);
|
|
});
|
|
}
|