|
| 1 | +import 'dart:convert'; |
| 2 | + |
1 | 3 | import 'package:checks/checks.dart';
|
| 4 | +import 'package:flutter/material.dart'; |
2 | 5 | import 'package:flutter_test/flutter_test.dart';
|
| 6 | +import 'package:http/http.dart' as http; |
| 7 | +import 'package:zulip/api/model/events.dart'; |
3 | 8 | import 'package:zulip/api/model/model.dart';
|
| 9 | +import 'package:zulip/api/route/channel.dart'; |
4 | 10 | import 'package:zulip/model/localizations.dart';
|
| 11 | +import 'package:zulip/model/store.dart'; |
5 | 12 | import 'package:zulip/widgets/channel_list.dart';
|
6 | 13 |
|
| 14 | +import '../api/fake_api.dart'; |
7 | 15 | import '../model/binding.dart';
|
8 | 16 | import '../example_data.dart' as eg;
|
| 17 | +import '../stdlib_checks.dart'; |
| 18 | +import 'dialog_checks.dart'; |
9 | 19 | import 'test_app.dart';
|
10 | 20 |
|
11 | 21 | void main() {
|
12 | 22 | TestZulipBinding.ensureInitialized();
|
| 23 | + late FakeApiConnection connection; |
| 24 | + late PerAccountStore store; |
13 | 25 |
|
14 | 26 | Future<void> setupChannelListPage(WidgetTester tester, {
|
15 | 27 | required List<ZulipStream> streams, required List<Subscription> subscriptions}) async {
|
16 | 28 | addTearDown(testBinding.reset);
|
17 | 29 | final initialSnapshot = eg.initialSnapshot(
|
18 | 30 | subscriptions: subscriptions,
|
19 | 31 | streams: streams.toList(),
|
20 |
| - ); |
| 32 | + realmUsers: [eg.selfUser]); |
21 | 33 | await testBinding.globalStore.add(eg.selfAccount, initialSnapshot);
|
| 34 | + store = await testBinding.globalStore.perAccount(eg.selfAccount.id); |
| 35 | + connection = store.connection as FakeApiConnection; |
22 | 36 |
|
23 | 37 | await tester.pumpWidget(TestZulipApp(accountId: eg.selfAccount.id, child: const ChannelListPage()));
|
24 | 38 |
|
@@ -67,4 +81,117 @@ void main() {
|
67 | 81 | check(listedStreamNames(tester)).deepEquals(['a', 'b', 'c']);
|
68 | 82 | });
|
69 | 83 | });
|
| 84 | + |
| 85 | + group('subscription toggle', () { |
| 86 | + final zulipLocalizations = GlobalLocalizations.zulipLocalizations; |
| 87 | + |
| 88 | + Future<ZulipStream> prepareSingleStream(WidgetTester tester) async { |
| 89 | + final stream = eg.stream(); |
| 90 | + await setupChannelListPage(tester, streams: [stream], subscriptions: []); |
| 91 | + return stream; |
| 92 | + } |
| 93 | + |
| 94 | + Future<void> tapSubscribeButton(WidgetTester tester) async { |
| 95 | + await tester.tap(find.byIcon(Icons.add)); |
| 96 | + } |
| 97 | + |
| 98 | + Future<void> waitAndCheckSnackbarIsShown(WidgetTester tester, String message) async { |
| 99 | + await tester.pump(Duration.zero); |
| 100 | + await tester.pumpAndSettle(); |
| 101 | + check(find.text(message).evaluate()).isNotEmpty(); |
| 102 | + } |
| 103 | + |
| 104 | + testWidgets('is affected by subscription events', (WidgetTester tester) async { |
| 105 | + final stream = await prepareSingleStream(tester); |
| 106 | + connection.prepare(json: SubscribeToChannelsResult( |
| 107 | + subscribed: {eg.selfUser.email: [stream.name]}, |
| 108 | + alreadySubscribed: {}).toJson()); |
| 109 | + |
| 110 | + check(find.byIcon(Icons.add).evaluate()).isNotEmpty(); |
| 111 | + |
| 112 | + await store.handleEvent(SubscriptionAddEvent(id: 1, |
| 113 | + subscriptions: [eg.subscription(stream)])); |
| 114 | + await tester.pumpAndSettle(); |
| 115 | + |
| 116 | + check(find.byIcon(Icons.add).evaluate()).isEmpty(); |
| 117 | + |
| 118 | + await store.handleEvent(SubscriptionRemoveEvent(id: 2, streamIds: [stream.streamId])); |
| 119 | + await tester.pumpAndSettle(); |
| 120 | + |
| 121 | + check(find.byIcon(Icons.add).evaluate()).isNotEmpty(); |
| 122 | + }, skip: true); |
| 123 | + |
| 124 | + group('subscribe', () { |
| 125 | + testWidgets('is shown only for streams that user is not subscribed to', (tester) async { |
| 126 | + final streams = [eg.stream(), eg.stream(), eg.subscription(eg.stream())]; |
| 127 | + final subscriptions = [streams[2]]; |
| 128 | + await setupChannelListPage(tester, streams: streams, subscriptions: subscriptions.cast()); |
| 129 | + |
| 130 | + check(find.byIcon(Icons.add).evaluate().length).equals(2); |
| 131 | + }); |
| 132 | + |
| 133 | + testWidgets('smoke api', (tester) async { |
| 134 | + final stream = await prepareSingleStream(tester); |
| 135 | + connection.prepare(json: SubscribeToChannelsResult( |
| 136 | + subscribed: {eg.selfUser.email: [stream.name]}, |
| 137 | + alreadySubscribed: {}).toJson()); |
| 138 | + await tapSubscribeButton(tester); |
| 139 | + |
| 140 | + await tester.pump(Duration.zero); |
| 141 | + await tester.pumpAndSettle(); |
| 142 | + check(connection.lastRequest).isA<http.Request>() |
| 143 | + ..method.equals('POST') |
| 144 | + ..url.path.equals('/api/v1/users/me/subscriptions') |
| 145 | + ..bodyFields.deepEquals({ |
| 146 | + 'subscriptions': jsonEncode([{'name': stream.name}]) |
| 147 | + }); |
| 148 | + }); |
| 149 | + |
| 150 | + testWidgets('shows a snackbar when subscription passes', (WidgetTester tester) async { |
| 151 | + final stream = await prepareSingleStream(tester); |
| 152 | + connection.prepare(json: SubscribeToChannelsResult( |
| 153 | + subscribed: {eg.selfUser.email: [stream.name]}, |
| 154 | + alreadySubscribed: {}).toJson()); |
| 155 | + await tapSubscribeButton(tester); |
| 156 | + |
| 157 | + await waitAndCheckSnackbarIsShown(tester, |
| 158 | + zulipLocalizations.messageSubscribedToChannel(stream.name)); |
| 159 | + }, skip: true); |
| 160 | + |
| 161 | + testWidgets('shows a snackbar when already subscribed', (WidgetTester tester) async { |
| 162 | + final stream = await prepareSingleStream(tester); |
| 163 | + connection.prepare(json: SubscribeToChannelsResult( |
| 164 | + subscribed: {}, |
| 165 | + alreadySubscribed: {eg.selfUser.email: [stream.name]}).toJson()); |
| 166 | + await tapSubscribeButton(tester); |
| 167 | + |
| 168 | + await waitAndCheckSnackbarIsShown(tester, |
| 169 | + zulipLocalizations.messageAlreadySubscribedToChannel(stream.name)); |
| 170 | + }, skip: true); |
| 171 | + |
| 172 | + testWidgets('shows a snackbar when subscription fails', (WidgetTester tester) async { |
| 173 | + final stream = await prepareSingleStream(tester); |
| 174 | + connection.prepare(json: SubscribeToChannelsResult( |
| 175 | + subscribed: {}, |
| 176 | + alreadySubscribed: {}, |
| 177 | + unauthorized: [stream.name]).toJson()); |
| 178 | + await tapSubscribeButton(tester); |
| 179 | + |
| 180 | + await waitAndCheckSnackbarIsShown(tester, |
| 181 | + zulipLocalizations.errorFailedToSubscribedToChannel(stream.name)); |
| 182 | + }, skip: true); |
| 183 | + |
| 184 | + testWidgets('catch-all api errors', (WidgetTester tester) async { |
| 185 | + final stream = await prepareSingleStream(tester); |
| 186 | + connection.prepare(exception: http.ClientException('Oops')); |
| 187 | + await tapSubscribeButton(tester); |
| 188 | + await tester.pump(Duration.zero); |
| 189 | + await tester.pumpAndSettle(); |
| 190 | + |
| 191 | + checkErrorDialog(tester, |
| 192 | + expectedTitle: zulipLocalizations.errorFailedToSubscribedToChannel(stream.name), |
| 193 | + expectedMessage: 'NetworkException: Oops (ClientException: Oops)'); |
| 194 | + }, skip: true); |
| 195 | + }); |
| 196 | + }); |
70 | 197 | }
|
0 commit comments