Skip to content

Commit 94db706

Browse files
authored
Merge pull request #221 from e-ashitey/test/intro-screen-widget-unit-tests
Pull Request: Enhance Test Coverage for Introduction Screen
2 parents ed7fc56 + 140880a commit 94db706

File tree

5 files changed

+414
-10
lines changed

5 files changed

+414
-10
lines changed

test/src/helper_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'package:flutter_test/flutter_test.dart';
2+
import 'package:introduction_screen/src/helper.dart';
3+
4+
void main() {
5+
// Global variables
6+
final originalList = [1, 2, 3, 4, 5];
7+
final list = ['a', 'b', 'c'];
8+
9+
group('CustomList', () {
10+
test('asReversed returns reversed list when isReverse is true', () {
11+
final reversedList = originalList.asReversed(true);
12+
13+
expect(reversedList, [5, 4, 3, 2, 1]);
14+
});
15+
16+
test('asReversed returns original list when isReverse is false', () {
17+
final originalCopy = originalList.asReversed(false);
18+
19+
expect(originalCopy, originalList);
20+
});
21+
22+
test('elementAtOrNull returns the correct element for valid index', () {
23+
expect(list.elementAtOrNull(1), 'b');
24+
});
25+
26+
test('elementAtOrNull returns null for out of bounds index', () {
27+
expect(list.elementAtOrNull(5), isNull);
28+
});
29+
30+
test('elementAtOrNull returns null for negative index', () {
31+
expect(list.elementAtOrNull(-1), isNull);
32+
});
33+
});
34+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import 'package:dots_indicator/dots_indicator.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:flutter/material.dart';
4+
import 'package:introduction_screen/introduction_screen.dart';
5+
6+
void main() {
7+
// Helper function to create the IntroductionScreen widget
8+
Widget createIntroductionScreen({
9+
required List<PageViewModel> pages,
10+
VoidCallback? onDone,
11+
VoidCallback? onSkip,
12+
bool showSkipButton = false,
13+
bool showDoneButton = false,
14+
bool showNextButton = true,
15+
int? autoScrollDuration,
16+
}) {
17+
return MaterialApp(
18+
home: IntroductionScreen(
19+
pages: pages,
20+
done: showDoneButton ? Text("Done") : null,
21+
onDone: onDone,
22+
skip: showSkipButton ? Text("Skip") : null,
23+
onSkip: onSkip,
24+
next: showNextButton ? Text("Next") : null,
25+
showSkipButton: showSkipButton,
26+
showDoneButton: showDoneButton,
27+
showNextButton: showNextButton,
28+
autoScrollDuration: autoScrollDuration,
29+
),
30+
);
31+
}
32+
33+
group('IntroductionScreen Widget Tests', () {
34+
testWidgets('Initial page is rendered and buttons are displayed',
35+
(tester) async {
36+
// Act
37+
final pages = [
38+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
39+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
40+
];
41+
42+
await tester.pumpWidget(
43+
createIntroductionScreen(pages: pages, showSkipButton: true));
44+
45+
// Assert
46+
expect(find.text('Page 1'), findsOneWidget);
47+
expect(find.text('Skip'), findsOneWidget);
48+
expect(find.text('Next'), findsOneWidget);
49+
});
50+
51+
testWidgets('Next button advances the page', (tester) async {
52+
// Arrange
53+
final pages = [
54+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
55+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
56+
];
57+
await tester.pumpWidget(createIntroductionScreen(pages: pages));
58+
59+
// Act
60+
await tester.tap(find.text('Next'));
61+
await tester.pumpAndSettle();
62+
63+
// Assert
64+
expect(find.text('Page 2'), findsOneWidget);
65+
});
66+
67+
testWidgets('Skip button triggers onSkip callback', (tester) async {
68+
// Arrange
69+
var skipTapped = false;
70+
71+
final pages = [
72+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
73+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
74+
PageViewModel(title: 'Page 3', body: 'Introduction 3'),
75+
];
76+
77+
await tester.pumpWidget(
78+
createIntroductionScreen(
79+
pages: pages,
80+
onSkip: () => skipTapped = true,
81+
showSkipButton: true,
82+
),
83+
);
84+
85+
// Act
86+
await tester.tap(find.text('Skip'));
87+
await tester.pumpAndSettle();
88+
89+
// Assert
90+
expect(skipTapped, isTrue);
91+
});
92+
93+
testWidgets('Skip to end navigates to the last page',
94+
(WidgetTester tester) async {
95+
// Arrange
96+
final pages = [
97+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
98+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
99+
PageViewModel(title: 'Page 3', body: 'Introduction 3'),
100+
];
101+
await tester.pumpWidget(
102+
createIntroductionScreen(
103+
pages: pages,
104+
showSkipButton: true,
105+
),
106+
);
107+
108+
// Initially, the first page should be visible
109+
expect(find.text('Page 1'), findsOneWidget);
110+
111+
// Tap the skip button to skip to the end
112+
await tester.tap(find.text('Skip'));
113+
await tester.pumpAndSettle();
114+
115+
// Verify that we are now on the last page
116+
expect(find.text('Page 3'), findsOneWidget);
117+
});
118+
119+
testWidgets('Done button triggers onDone callback', (tester) async {
120+
// Arrange
121+
var doneTapped = false;
122+
final pages = [
123+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
124+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
125+
];
126+
127+
await tester.pumpWidget(
128+
createIntroductionScreen(
129+
pages: pages,
130+
onDone: () => doneTapped = true,
131+
showDoneButton: true,
132+
),
133+
);
134+
135+
// Act
136+
// Navigate to the last page
137+
await tester.tap(find.text('Next'));
138+
await tester.pumpAndSettle();
139+
await tester.tap(find.text('Done'));
140+
await tester.pumpAndSettle();
141+
142+
// Assert
143+
expect(doneTapped, isTrue);
144+
});
145+
146+
testWidgets('Progress indicator updates with page change', (tester) async {
147+
// Arrange
148+
final pages = [
149+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
150+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
151+
];
152+
153+
await tester.pumpWidget(createIntroductionScreen(pages: pages));
154+
155+
// Assert initial page
156+
expect(find.byType(DotsIndicator), findsOneWidget);
157+
DotsIndicator indicator = tester.widget(find.byType(DotsIndicator));
158+
expect(indicator.position, 0.0);
159+
160+
// Act - Move to the next page
161+
await tester.tap(find.text('Next'));
162+
await tester.pumpAndSettle();
163+
164+
// Assert updated indicator
165+
indicator = tester.widget(find.byType(DotsIndicator));
166+
expect(indicator.position, 1.0);
167+
});
168+
});
169+
170+
testWidgets('Auto-scroll works as expected', (WidgetTester tester) async {
171+
// Arrange
172+
final pages = [
173+
PageViewModel(title: 'Page 1', body: 'Introduction 1'),
174+
PageViewModel(title: 'Page 2', body: 'Introduction 2'),
175+
];
176+
177+
await tester.pumpWidget(
178+
createIntroductionScreen(pages: pages, autoScrollDuration: 5));
179+
180+
// Initial page should be Page 1
181+
expect(find.text('Page 1'), findsOneWidget);
182+
183+
// Simulate time passing to trigger auto-scroll
184+
await tester.pump(const Duration(milliseconds: 10));
185+
await tester.pumpAndSettle();
186+
187+
// The auto-scroll should have moved to the next page
188+
expect(find.text('Page 2'), findsOneWidget);
189+
});
190+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:introduction_screen/src/model/page_decoration.dart';
4+
5+
void main() {
6+
group('PageDecoration', () {
7+
test('default constructor initializes with correct default values', () {
8+
final decoration = PageDecoration();
9+
10+
expect(decoration.pageColor, isNull);
11+
expect(decoration.titleTextStyle.fontSize, 20.0);
12+
expect(decoration.titleTextStyle.fontWeight, FontWeight.bold);
13+
expect(decoration.bodyTextStyle.fontSize, 18.0);
14+
expect(decoration.bodyTextStyle.fontWeight, FontWeight.normal);
15+
expect(decoration.imageFlex, 1);
16+
expect(decoration.bodyFlex, 1);
17+
expect(decoration.footerFlex, 1);
18+
expect(decoration.footerFit, FlexFit.loose);
19+
expect(decoration.imagePadding, EdgeInsets.only(bottom: 24.0));
20+
expect(decoration.contentMargin, EdgeInsets.all(16.0));
21+
expect(decoration.pageMargin, EdgeInsets.only(bottom: 60.0));
22+
expect(decoration.titlePadding, EdgeInsets.only(top: 16.0, bottom: 24.0));
23+
expect(decoration.footerPadding, EdgeInsets.symmetric(vertical: 24.0));
24+
expect(decoration.bodyAlignment, Alignment.topCenter);
25+
expect(decoration.imageAlignment, Alignment.bottomCenter);
26+
expect(decoration.fullScreen, isFalse);
27+
expect(decoration.safeArea, 60);
28+
});
29+
30+
test('cannot provide both pageColor and boxDecoration', () {
31+
expect(
32+
() => PageDecoration(
33+
pageColor: Colors.white, boxDecoration: BoxDecoration()),
34+
throwsA(isA<AssertionError>()),
35+
);
36+
});
37+
38+
test('copyWith returns a new instance with updated values', () {
39+
final decoration = PageDecoration(
40+
pageColor: Colors.white,
41+
titleTextStyle: TextStyle(fontSize: 22.0),
42+
);
43+
44+
final newDecoration = decoration.copyWith(
45+
bodyTextStyle: TextStyle(fontSize: 20.0),
46+
footerFlex: 2,
47+
);
48+
49+
expect(newDecoration.pageColor, Colors.white);
50+
expect(newDecoration.titleTextStyle.fontSize, 22.0);
51+
expect(newDecoration.bodyTextStyle.fontSize, 20.0);
52+
expect(newDecoration.footerFlex, 2);
53+
expect(newDecoration.imageFlex,
54+
decoration.imageFlex); // Should remain the same
55+
});
56+
57+
test('copyWith does not modify original instance', () {
58+
final decoration = PageDecoration(pageColor: Colors.white);
59+
decoration.copyWith(titleTextStyle: TextStyle(fontSize: 22.0));
60+
61+
expect(decoration.titleTextStyle.fontSize,
62+
20.0); // Original should remain unchanged
63+
});
64+
});
65+
}

test/src/model/position_test.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:flutter_test/flutter_test.dart';
2+
import 'package:introduction_screen/src/model/position.dart';
3+
4+
void main() {
5+
group('Position', () {
6+
test('default constructor initializes with null values', () {
7+
final position = Position();
8+
9+
expect(position.left, isNull);
10+
expect(position.right, isNull);
11+
expect(position.top, isNull);
12+
expect(position.bottom, isNull);
13+
});
14+
15+
test('constructor initializes with specified values', () {
16+
final position =
17+
Position(left: 10.0, top: 20.0, right: 30.0, bottom: 40.0);
18+
19+
expect(position.left, 10.0);
20+
expect(position.top, 20.0);
21+
expect(position.right, 30.0);
22+
expect(position.bottom, 40.0);
23+
});
24+
25+
test('fromLTRB constructor initializes with specified values', () {
26+
final position = Position.fromLTRB(10.0, 20.0, 30.0, 40.0);
27+
28+
expect(position.left, 10.0);
29+
expect(position.top, 20.0);
30+
expect(position.right, 30.0);
31+
expect(position.bottom, 40.0);
32+
});
33+
34+
test('fromLTRB constructor with null values', () {
35+
final position = Position.fromLTRB(null, null, null, null);
36+
37+
expect(position.left, isNull);
38+
expect(position.top, isNull);
39+
expect(position.right, isNull);
40+
expect(position.bottom, isNull);
41+
});
42+
});
43+
}

0 commit comments

Comments
 (0)