blob: c7944dcc0c83442c20c50cf846dd15e93612a853 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:devtools_app/src/framework/notifications_view.dart';
import 'package:devtools_app/src/shared/globals.dart';
import 'package:devtools_app/src/shared/notifications.dart';
import 'package:devtools_app_shared/ui.dart';
import 'package:devtools_app_shared/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('Notifications', () {
Future<void> showNotification(
void Function() triggerNotification, {
required WidgetTester tester,
}) async {
final notificationsWidget = Directionality(
textDirection: TextDirection.ltr,
child: NotificationsView(
child: Builder(
builder: (context) {
return ElevatedButton(
onPressed: triggerNotification,
child: const SizedBox(),
);
},
),
),
);
await tester.pumpWidget(notificationsWidget);
await tester.pumpAndSettle();
await tester.tap(find.byType(ElevatedButton));
await tester.pumpAndSettle();
}
setUp(() {
setGlobal(IdeTheme, IdeTheme());
setGlobal(NotificationService, NotificationService());
});
testWidgets('displays notifications', (WidgetTester tester) async {
const notification = 'This is a notification!';
await showNotification(
() => notificationService.push(notification),
tester: tester,
);
expect(find.text(notification), findsOneWidget);
await tester.tap(find.byType(ElevatedButton));
await tester.pumpAndSettle();
expect(find.text(notification), findsNWidgets(2));
});
testWidgets(
'dismissible notifications can be dismissed',
(WidgetTester tester) async {
const notification = 'This is a notification!';
await showNotification(
() => notificationService.push(notification, isDismissible: true),
tester: tester,
);
final closeButton = find.byType(IconButton);
expect(closeButton, findsOneWidget);
await tester.tap(closeButton);
// Verify the notification has been dismissed:
await tester.pumpAndSettle();
expect(find.text(notification), findsNothing);
},
);
testWidgets(
'non-dismissible notifications expire',
(WidgetTester tester) async {
const notification = 'This is a notification!';
await showNotification(
() => notificationService.push(notification),
tester: tester,
);
expect(find.text(notification), findsOneWidget);
// Wait for the notification to disappear.
await tester.pumpAndSettle(NotificationMessage.defaultDuration);
expect(find.text(notification), findsNothing);
},
);
testWidgets(
'dismissible notifications do not expire',
(WidgetTester tester) async {
const notification = 'This is a notification!';
await showNotification(
() => notificationService.push(notification, isDismissible: true),
tester: tester,
);
// Wait for the default dismiss duration.
await tester.pumpAndSettle(NotificationMessage.defaultDuration);
// Verify the notification is still there.
expect(find.text(notification), findsOneWidget);
},
);
testWidgets('persist across routes', (WidgetTester tester) async {
const notification = 'Navigating to /details';
const detailsKey = Key('details page');
var timesPressed = 0;
Widget build() {
return MaterialApp(
builder: (context, child) => NotificationsView(child: child!),
routes: {
'/': (context) {
return ElevatedButton(
onPressed: () {
if (timesPressed == 0) {
notificationService.push(notification);
} else {
unawaited(Navigator.of(context).pushNamed('/details'));
}
timesPressed++;
},
child: const SizedBox(),
);
},
'/details': (context) {
return const SizedBox(key: detailsKey);
},
},
);
}
await tester.pumpWidget(build());
expect(find.text(notification), findsNothing);
expect(find.byKey(detailsKey), findsNothing);
// The first tap of the button will show the notification.
await tester.tap(find.byType(ElevatedButton));
await tester.pumpAndSettle();
expect(find.text(notification), findsOneWidget);
expect(find.byKey(detailsKey), findsNothing);
// The second tap will navigate to /details.
await tester.tap(find.byType(ElevatedButton));
await tester.pumpAndSettle();
expect(find.text(notification), findsOneWidget);
expect(find.byKey(detailsKey), findsOneWidget);
});
group('Error notifications', () {
testWidgets('displays errors', (WidgetTester tester) async {
const errorMessage = 'This is an error!';
await showNotification(
() => notificationService.push(errorMessage),
tester: tester,
);
expect(find.text(errorMessage), findsOneWidget);
});
testWidgets('are reportable by default', (WidgetTester tester) async {
const errorMessage = 'This is an error!';
await showNotification(
() => notificationService.pushError(errorMessage),
tester: tester,
);
expect(
find.widgetWithText(OutlinedButton, 'Report error'),
findsOneWidget,
);
});
testWidgets('are dismissable by default', (WidgetTester tester) async {
const errorMessage = 'This is an error!';
await showNotification(
() => notificationService.pushError(errorMessage),
tester: tester,
);
final closeButton = find.byType(IconButton);
expect(closeButton, findsOneWidget);
await tester.tap(closeButton);
// Verify the error has been dismissed:
await tester.pumpAndSettle();
expect(find.text(errorMessage), findsNothing);
});
});
});
}