diff --git a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart index b04542fc..73f5eb61 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart @@ -142,6 +142,7 @@ class StreamChatCoreState extends State @override void dispose() { WidgetsBinding.instance.removeObserver(this); + _disconnectTimer?.cancel(); super.dispose(); } } diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index c0c2a55a..5037e5e8 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -19,40 +19,5 @@ dev_dependencies: mockito: ^4.1.4 flutter_test: sdk: flutter - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages + fake_async: ^1.1.0 + \ No newline at end of file diff --git a/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart new file mode 100644 index 00000000..714375de --- /dev/null +++ b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart @@ -0,0 +1,189 @@ +import 'dart:async'; + +import 'package:fake_async/fake_async.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'package:mockito/mockito.dart'; + +import 'mocks.dart'; + +class MockShowLocalNotifications extends Mock { + void call(Message m, ChannelModel cm); +} + +void main() { + testWidgets( + 'StreamChatCore.of(context) should throw an exception', + (WidgetTester tester) async { + await tester.pumpWidget( + Builder( + builder: (context) { + expect(() => StreamChatCore.of(context), throwsException); + return Container(); + }, + ), + ); + }, + ); + + testWidgets( + 'StreamChatCore.of(context) should return the StreamChatCore ancestor', + (WidgetTester tester) async { + final client = MockClient(); + await tester.pumpWidget( + StreamChatCore( + client: client, + child: Builder( + builder: (context) { + final sc = StreamChatCore.of(context); + expect(sc, isNotNull); + return Container(); + }, + ), + ), + ); + }, + ); + + testWidgets( + 'StreamChatCore.of(context).client should return the client', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn( + OwnUser( + id: 'test', + ), + ); + final userStream = Stream.value( + OwnUser( + id: 'test', + ), + ); + when(clientState.userStream).thenAnswer( + (_) => userStream, + ); + + await tester.pumpWidget( + StreamChatCore( + client: client, + child: Builder( + builder: (context) { + final sc = StreamChatCore.of(context); + expect(sc.client, client); + expect(sc.user, client.state.user); + expect(sc.userStream, userStream); + return Container(); + }, + ), + ), + ); + }, + ); + + testWidgets( + 'StreamChatCore should disconnect on background', + (WidgetTester tester) async { + await fakeAsync((_async) { + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel(); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn( + OwnUser( + id: 'test', + ), + ); + final showLocalNotificationMock = MockShowLocalNotifications().call; + when(client.showLocalNotification) + .thenReturn(showLocalNotificationMock); + when(client.backgroundKeepAlive).thenReturn(Duration( + seconds: 4, + )); + final eventStreamController = StreamController(); + when(client.on(EventType.messageNew)) + .thenAnswer((_) => eventStreamController.stream); + + when(client.channel('test', id: 'testid')).thenReturn(channel); + + final scKey = GlobalKey(); + tester.pumpWidget( + StreamChatCore( + key: scKey, + client: client, + child: Builder( + builder: (context) { + return Container(); + }, + ), + ), + ); + + final sc = scKey.currentState; + sc.didChangeAppLifecycleState(AppLifecycleState.paused); + + _async.elapse(Duration(seconds: 5)); + + verify(client.disconnect()).called(1); + }); + }, + ); + + testWidgets( + 'StreamChatCore should handle notifications when on background and connected', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel(); + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn( + OwnUser( + id: 'test', + ), + ); + final showLocalNotificationMock = MockShowLocalNotifications().call; + when(client.showLocalNotification).thenReturn(showLocalNotificationMock); + when(client.backgroundKeepAlive).thenReturn(Duration( + seconds: 4, + )); + final eventStreamController = StreamController(); + when(client.on(EventType.messageNew)) + .thenAnswer((_) => eventStreamController.stream); + + when(client.channel('test', id: 'testid')).thenReturn(channel); + + final scKey = GlobalKey(); + await tester.pumpWidget( + StreamChatCore( + key: scKey, + client: client, + child: Builder( + builder: (context) { + return Container(); + }, + ), + ), + ); + + final sc = scKey.currentState; + sc.didChangeAppLifecycleState(AppLifecycleState.paused); + final event = Event( + type: EventType.messageNew, + message: Message(text: 'hey'), + channelType: 'test', + channelId: 'testid', + user: User(id: 'other user'), + ); + eventStreamController.add(event); + + await untilCalled(showLocalNotificationMock(any, any)); + + verify(showLocalNotificationMock( + event.message, + any, + )).called(1); + }, + ); +} diff --git a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart deleted file mode 100644 index 2100f744..00000000 --- a/packages/stream_chat_flutter_core/test/stream_chat_flutter_core_test.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets( - 'it should show basic channel information', - (WidgetTester tester) async { - // final client = MockClient(); - // final clientState = MockClientState(); - // final channel = MockChannel(); - // final channelState = MockChannelState(); - // final lastMessageAt = DateTime.parse('2020-06-22 12:00:00'); - // - // when(client.state).thenReturn(clientState); - // when(clientState.user).thenReturn(OwnUser(id: 'user-id')); - // when(channel.lastMessageAt).thenReturn(lastMessageAt); - // when(channel.state).thenReturn(channelState); - // when(channel.client).thenReturn(client); - // when(channel.isMuted).thenReturn(false); - // when(channel.isMutedStream).thenAnswer((i) => Stream.value(false)); - // when(channel.extraDataStream).thenAnswer((i) => Stream.value({ - // 'name': 'test name', - // })); - // when(channel.extraData).thenReturn({ - // 'name': 'test name', - // }); - // when(channelState.unreadCount).thenReturn(1); - // when(channelState.unreadCountStream).thenAnswer((i) => Stream.value(1)); - // when(channelState.membersStream).thenAnswer((i) => Stream.value([ - // Member( - // userId: 'user-id', - // user: User(id: 'user-id'), - // ) - // ])); - // when(channelState.members).thenReturn([ - // Member( - // userId: 'user-id', - // user: User(id: 'user-id'), - // ), - // ]); - // when(channelState.messages).thenReturn([ - // Message( - // text: 'hello', - // user: User(id: 'other-user'), - // ) - // ]); - // when(channelState.messagesStream).thenAnswer((i) => Stream.value([ - // Message( - // text: 'hello', - // user: User(id: 'other-user'), - // ) - // ])); - - await tester.pumpWidget( - // MaterialApp( - // home: StreamChatCore( - // client: client, - // child: StreamChannel( - // channel: channel, - // child: Scaffold( - // body: MessageListCore( - // loadingBuilder: (context) { - // return Center(); - // }, - // emptyBuilder: (context) { - // return Center(); - // }, - // messageListBuilder: (context, list) { - // return ListView.builder( - // itemBuilder: (context, position) { - // return Text(list[position].text); - // }, - // itemCount: list.length, - // ); - // }, - // ), - // ), - // ), - // ), - // ), - MaterialApp(home: Scaffold(body: Text('hello'))), - ); - - expect(find.text('hello'), findsOneWidget); - }, - ); -}