pumpApp(WidgetTester tester) async {
await tester.pumpWidget(MewsApp(deps: deps, strings: strings));
await tester.pumpAndSettle();
}
testWidgets('renders a page through the full app', (tester) async {
await pumpApp(tester);
final page = parseSource(pageSource, 'https://example.com/index.html');
deps.browser.currentPage.value = page;
await tester.pumpAndSettle();
expect(find.text('Signal Bars'), findsWidgets);
expect(find.textContaining('Collecting retro phones'), findsOneWidget);
expect(find.textContaining('Sign guestbook'), findsOneWidget);
});
testWidgets('shows the broken-page error and its text view', (tester) async {
await pumpApp(tester);
deps.browser.currentPage.value = null;
deps.browser.error.value = const BrokenPage('Half a page & more');
await tester.pumpAndSettle();
expect(find.textContaining('markup error'), findsOneWidget);
await tester.tap(find.textContaining('Show page text'));
await tester.pumpAndSettle();
expect(find.textContaining('Half a page & more'), findsOneWidget);
});
testWidgets('shows the load-failed error page', (tester) async {
await pumpApp(tester);
deps.browser.error.value = const LoadFailed();
await tester.pumpAndSettle();
expect(find.textContaining('could not be loaded'), findsOneWidget);
expect(find.textContaining('Try again'), findsOneWidget);
});
testWidgets('the settings page changes presentation and keeps its place',
(tester) async {
await pumpApp(tester);
// Settings opens from the left address bar icon.
await tester.tap(find.byIcon(Icons.tune));
await tester.pumpAndSettle();
expect(deps.browser.currentPage.value?.url, InternalPages.settingsUrl);
// Rendered like a Mews page with the option groups.
expect(find.text('Settings'), findsOneWidget);
expect(find.text('Typeface'), findsOneWidget);
expect(find.text('Theme'), findsOneWidget);
expect(find.text('Colors'), findsOneWidget);
expect(find.text('Library'), findsOneWidget);
// Tapping a theme link applies it and stays on the settings page; the
// lower sections scroll into view first.
Future scrollTo(Finder target) async {
// Search down the page, then back up for targets above.
for (var i = 0; i < 20 && target.evaluate().isEmpty; i++) {
await tester.drag(find.byType(ListView), const Offset(0, -200));
await tester.pumpAndSettle();
}
for (var i = 0; i < 40 && target.evaluate().isEmpty; i++) {
await tester.drag(find.byType(ListView), const Offset(0, 200));
await tester.pumpAndSettle();
}
await tester.ensureVisible(target);
await tester.pumpAndSettle();
}
// The option rows stretch the full column width, so tap on the glyphs
// themselves rather than the widget's center.
Future tapLink(String label) async {
final rect = tester.getRect(find.text(label));
await tester.tapAt(rect.topLeft + const Offset(30, 13));
await tester.pumpAndSettle();
}
await scrollTo(find.text('Dark'));
await tapLink('Dark');
expect(deps.settings.themeMode.value, 'dark');
expect(deps.browser.currentPage.value?.url, InternalPages.settingsUrl);
expect(deps.browser.canGoBack, isFalse);
await scrollTo(find.text('Warm'));
await tapLink('Warm');
expect(deps.settings.variant.value, 'warm');
await scrollTo(find.text('Larger text'));
await tapLink('Larger text');
expect(deps.settings.fontScale.value, 1.125);
// The library links navigate and join the walk history.
await scrollTo(find.text('History'));
await tapLink('History');
await tester.pumpAndSettle();
expect(deps.browser.currentPage.value?.url, InternalPages.historyUrl);
expect(deps.browser.canGoBack, isTrue);
await deps.browser.back();
await tester.pumpAndSettle();
expect(deps.browser.currentPage.value?.url, InternalPages.settingsUrl);
});
testWidgets('bookmark and subscribe live on the address bar', (tester) async {
await pumpApp(tester);
// A page with dated entries can be subscribed to.
final page = parseSource(pageSource, 'https://example.com/index.html');
deps.browser.currentPage.value = page;
await tester.pumpAndSettle();
expect(find.byIcon(Icons.notifications_outlined), findsOneWidget);
await tester.tap(find.byIcon(Icons.notifications_outlined));
await tester.pumpAndSettle();
expect(deps.library.isSubscribed('https://example.com/index.html'), isTrue);
expect(find.byIcon(Icons.notifications_active), findsOneWidget);
expect(find.byIcon(Icons.star_border), findsOneWidget);
await tester.tap(find.byIcon(Icons.star_border));
await tester.pumpAndSettle();
expect(deps.library.isBookmarked('https://example.com/index.html'), isTrue);
expect(find.byIcon(Icons.star), findsOneWidget);
// Pages with neither Atom feed nor dated links offer no subscription.
final plain = parseSource(
_page('Plain', 'Plain
No entries here.
'),
'https://example.com/plain.html');
deps.browser.currentPage.value = plain;
await tester.pumpAndSettle();
expect(find.byIcon(Icons.notifications_outlined), findsNothing);
});
testWidgets('the address bar hides on scroll down and returns on scroll up',
(tester) async {
await pumpApp(tester);
// A page long enough to scroll.
final tall = pageSource.replaceFirst(
'