test: add unit tests for poultry repository and searchable dropdown functionalities
- Introduced tests for `PoultryScienceRepositoryImp` to validate delegated remote calls. - Added comprehensive tests for `SearchableDropdownLogic` covering selection, overlay, and search logic. - Enhanced `SearchableDropdown` widget tests for multi-select, label building, and overlay management.
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:rasadyar_core/presentation/widget/overlay_dropdown_widget/multi_select_dropdown/multi_select_dropdown_logic.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('SearchableDropdownLogic', () {
|
||||
test('initializes selectedItem from provided list', () {
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B'],
|
||||
selectedItem: const ['A'],
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
expect(logic.selectedItem, ['A']);
|
||||
});
|
||||
|
||||
test('initializes selectedItem from initialValue when single select', () {
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B'],
|
||||
singleSelect: true,
|
||||
initialValue: 'B',
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
expect(logic.selectedItem, ['B']);
|
||||
});
|
||||
|
||||
testWidgets('showOverlay sets isOpen and inserts overlay', (tester) async {
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B'],
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CompositedTransformTarget(
|
||||
link: logic.layerLink,
|
||||
child: GestureDetector(
|
||||
onTap: () => logic.showOverlay(context),
|
||||
child: const SizedBox(width: 200, height: 40),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(logic.isOpen.value, false);
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
await tester.pump();
|
||||
expect(logic.isOpen.value, true);
|
||||
expect(find.text('نتیجهای یافت نشد.'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('removeOverlay resets isOpen', (tester) async {
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B'],
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CompositedTransformTarget(
|
||||
link: logic.layerLink,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (!logic.isOpen.value) {
|
||||
logic.showOverlay(context);
|
||||
} else {
|
||||
logic.removeOverlay();
|
||||
}
|
||||
},
|
||||
child: const SizedBox(width: 200, height: 40),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
await tester.pump();
|
||||
expect(logic.isOpen.value, true);
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
await tester.pump();
|
||||
expect(logic.isOpen.value, false);
|
||||
});
|
||||
|
||||
testWidgets('tap item adds to selected and calls onChanged', (tester) async {
|
||||
String? changed;
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B'],
|
||||
onChanged: (s) => changed = s,
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CompositedTransformTarget(
|
||||
link: logic.layerLink,
|
||||
child: GestureDetector(
|
||||
onTap: () => logic.showOverlay(context),
|
||||
child: const SizedBox(width: 200, height: 40),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('A'));
|
||||
await tester.pump();
|
||||
expect(logic.selectedItem.contains('A'), true);
|
||||
expect(changed, 'A');
|
||||
});
|
||||
|
||||
testWidgets('singleSelect updates searchController text using labelBuilder', (tester) async {
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B'],
|
||||
singleSelect: true,
|
||||
labelBuilder: (s) => 'L:$s',
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CompositedTransformTarget(
|
||||
link: logic.layerLink,
|
||||
child: GestureDetector(
|
||||
onTap: () => logic.showOverlay(context),
|
||||
child: const SizedBox(width: 200, height: 40),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('B'));
|
||||
await tester.pump();
|
||||
expect(logic.searchController.text, 'L:B');
|
||||
});
|
||||
|
||||
testWidgets('performSearch uses onSearch and updates filteredItems', (tester) async {
|
||||
final logic = SearchableDropdownLogic<String>(
|
||||
items: const ['A', 'B', 'C'],
|
||||
onSearch: (q) async => ['B'],
|
||||
itemBuilder: (i) => Text(i),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
return CompositedTransformTarget(
|
||||
link: logic.layerLink,
|
||||
child: GestureDetector(
|
||||
onTap: () => logic.showOverlay(context),
|
||||
child: const SizedBox(width: 200, height: 40),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byType(GestureDetector));
|
||||
await tester.pump();
|
||||
logic.performSearch('x');
|
||||
await tester.pumpAndSettle();
|
||||
expect(logic.filteredItems, ['B']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:rasadyar_core/presentation/widget/overlay_dropdown_widget/multi_select_dropdown/multi_select_dropdown.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('SearchableDropdown widget', () {
|
||||
testWidgets('asserts builders based on singleSelect', (tester) async {
|
||||
expect(
|
||||
() => SearchableDropdown<String>(
|
||||
items: const ['A', 'B'],
|
||||
itemBuilder: Text.new,
|
||||
singleSelect: true,
|
||||
),
|
||||
throwsA(isA<AssertionError>()),
|
||||
);
|
||||
expect(
|
||||
() => SearchableDropdown<String>(
|
||||
items: const ['A', 'B'],
|
||||
itemBuilder: Text.new,
|
||||
singleSelect: false,
|
||||
),
|
||||
throwsA(isA<AssertionError>()),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('single select: selecting item sets text and calls onChanged', (tester) async {
|
||||
String? changed;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SearchableDropdown<String>(
|
||||
items: const ['A', 'B'],
|
||||
singleSelect: true,
|
||||
singleLabelBuilder: (s) => 'L:$s',
|
||||
itemBuilder: Text.new,
|
||||
onChanged: (v) => changed = v,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('A'));
|
||||
await tester.pump();
|
||||
final tf = tester.widget<TextField>(find.byType(TextField));
|
||||
expect(tf.controller!.text, 'L:A');
|
||||
expect(changed, 'A');
|
||||
});
|
||||
|
||||
testWidgets('multi select: shows chips and allows removing selection', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SearchableDropdown<String>(
|
||||
items: const ['A', 'B', 'C'],
|
||||
singleSelect: false,
|
||||
multiLabelBuilder: (s) => Container(
|
||||
key: Key('chip_${s ?? ''}'),
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Text(s ?? ''),
|
||||
),
|
||||
itemBuilder: Text.new,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('A'));
|
||||
await tester.pump();
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump();
|
||||
await tester.tap(find.text('B'));
|
||||
await tester.pump();
|
||||
expect(find.byKey(const Key('chip_A')), findsOneWidget);
|
||||
expect(find.byKey(const Key('chip_B')), findsOneWidget);
|
||||
await tester.tap(find.byKey(const Key('chip_A')));
|
||||
await tester.pump();
|
||||
expect(find.byKey(const Key('chip_A')), findsNothing);
|
||||
expect(find.byKey(const Key('chip_B')), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('readOnly toggles based on onSearch presence', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Column(
|
||||
children: [
|
||||
SearchableDropdown<String>(
|
||||
items: const ['A'],
|
||||
singleSelect: true,
|
||||
singleLabelBuilder: (s) => s ?? '',
|
||||
itemBuilder: Text.new,
|
||||
),
|
||||
SearchableDropdown<String>(
|
||||
items: const ['A'],
|
||||
singleSelect: true,
|
||||
singleLabelBuilder: (s) => s ?? '',
|
||||
itemBuilder: Text.new,
|
||||
onSearch: (q) async => ['A'],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final textFields = tester.widgetList<TextField>(find.byType(TextField)).toList();
|
||||
expect(textFields[0].readOnly, true);
|
||||
expect(textFields[1].readOnly, false);
|
||||
});
|
||||
|
||||
testWidgets('tapping TextField toggles overlay list visibility', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SearchableDropdown<String>(
|
||||
items: const ['A', 'B'],
|
||||
singleSelect: true,
|
||||
singleLabelBuilder: (s) => s ?? '',
|
||||
itemBuilder: Text.new,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(find.text('A'), findsNothing);
|
||||
await tester.tap(find.byType(TextField));
|
||||
await tester.pump();
|
||||
expect(find.text('A'), findsOneWidget);
|
||||
await tester.tap(find.text('A'));
|
||||
await tester.pump();
|
||||
expect(find.text('A'), findsNothing);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user