Skip to content

Commit 353bc2b

Browse files
committed
Add some feeds client tests
1 parent 0f08229 commit 353bc2b

File tree

4 files changed

+268
-11
lines changed

4 files changed

+268
-11
lines changed

packages/stream_feeds/lib/src/feeds_client.dart

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class FeedsClient {
1616
String? userToken,
1717
TokenProvider? userTokenProvider,
1818
this.config = const FeedsConfig(),
19-
this.networkMonitor,
19+
FeedsClientEnvironment environment = const FeedsClientEnvironment(),
2020
}) {
2121
tokenManager = userTokenProvider != null
2222
? TokenManager.provider(
@@ -51,7 +51,7 @@ class FeedsClient {
5151
},
5252
);
5353

54-
webSocketClient = WebSocketClient(
54+
webSocketClient = environment.createWebSocketClient(
5555
url: websocketUri.toString(),
5656
eventDecoder: FeedsWsEvent.fromEventObject,
5757
onConnectionEstablished: _authenticate,
@@ -64,7 +64,6 @@ class FeedsClient {
6464
final User user;
6565
late final TokenManager tokenManager;
6666
final FeedsConfig config;
67-
final NetworkMonitor? networkMonitor;
6867

6968
late final api.DefaultApi apiClient;
7069
late final FeedsRepository feedsRepository;
@@ -89,7 +88,7 @@ class FeedsClient {
8988

9089
connectionRecoveryHandler = DefaultConnectionRecoveryHandler(
9190
client: webSocketClient,
92-
networkMonitor: networkMonitor,
91+
networkMonitor: config.networkMonitor,
9392
);
9493

9594
_connectionCompleter = Completer<void>();
@@ -154,6 +153,28 @@ class FeedsClient {
154153
}
155154

156155
class FeedsConfig {
157-
const FeedsConfig();
158-
// TODO: Add config for feeds
156+
const FeedsConfig({
157+
this.networkMonitor,
158+
});
159+
160+
final NetworkMonitor? networkMonitor;
161+
}
162+
163+
class FeedsClientEnvironment {
164+
const FeedsClientEnvironment();
165+
166+
WebSocketClient createWebSocketClient({
167+
required String url,
168+
required EventDecoder eventDecoder,
169+
PingReguestBuilder? pingReguestBuilder,
170+
VoidCallback? onConnectionEstablished,
171+
VoidCallback? onConnected,
172+
}) =>
173+
WebSocketClient(
174+
url: url,
175+
eventDecoder: FeedsWsEvent.fromEventObject,
176+
pingReguestBuilder: pingReguestBuilder,
177+
onConnectionEstablished: onConnectionEstablished,
178+
onConnected: onConnected,
179+
);
159180
}

packages/stream_feeds/pubspec.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ dependencies:
1919
rxdart: ^0.28.0
2020
state_notifier: ^1.0.0
2121
stream_core:
22-
# path: ../../../stream-core-flutter/packages/stream_core
23-
git:
24-
url: https://github.com/GetStream/stream-core-flutter.git
25-
ref: 05c4e1d45d87f2a76161ff9301ae8896d1548676
26-
path: packages/stream_core
22+
path: ../../../stream-core-flutter/packages/stream_core
23+
# git:
24+
# url: https://github.com/GetStream/stream-core-flutter.git
25+
# ref: 05c4e1d45d87f2a76161ff9301ae8896d1548676
26+
# path: packages/stream_core
2727
uuid: ^4.5.1
2828

2929
dev_dependencies:
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
import 'dart:convert';
2+
3+
import 'package:stream_core/stream_core.dart';
4+
import 'package:stream_feeds/src/generated/api/api.dart' as api;
5+
import 'package:stream_feeds/src/ws/feeds_ws_event.dart';
6+
import 'package:stream_feeds/stream_feeds.dart';
7+
import 'package:test/test.dart';
8+
9+
void main() {
10+
group('FeedsClient', () {
11+
const testApiKey = 'test_api_key';
12+
const testUser = User(id: 'test_user_id', name: 'test_user_name');
13+
const testUserToken = 'test_user_token';
14+
15+
group('constructor', () {
16+
test('should initialize with required parameters', () {
17+
final client = FeedsClient(
18+
apiKey: testApiKey,
19+
user: testUser,
20+
userToken: testUserToken,
21+
);
22+
23+
expect(client.apiKey, equals(testApiKey));
24+
expect(client.user, equals(testUser));
25+
expect(client.config, isA<FeedsConfig>());
26+
expect(client.config.networkMonitor, isNull);
27+
});
28+
29+
test('should initialize with optional parameters', () {
30+
final client = FeedsClient(
31+
apiKey: testApiKey,
32+
user: testUser,
33+
userToken: testUserToken,
34+
);
35+
36+
expect(client.apiKey, equals(testApiKey));
37+
expect(client.user, equals(testUser));
38+
expect(client.config, isA<FeedsConfig>());
39+
});
40+
});
41+
42+
group('feed', () {
43+
test('should create feed with correct query and client', () {
44+
final client = FeedsClient(
45+
apiKey: testApiKey,
46+
user: testUser,
47+
userToken: testUserToken,
48+
);
49+
50+
final query = FeedQuery(group: 'test_group', id: 'test_id');
51+
final feed = client.feed(query: query);
52+
53+
expect(feed.query, equals(query));
54+
expect(feed.client, equals(client));
55+
});
56+
57+
test('should create multiple feeds with different queries', () {
58+
final client = FeedsClient(
59+
apiKey: testApiKey,
60+
user: testUser,
61+
userToken: testUserToken,
62+
);
63+
64+
final query1 = FeedQuery(group: 'group1', id: 'id1');
65+
final query2 = FeedQuery(group: 'group2', id: 'id2');
66+
67+
final feed1 = client.feed(query: query1);
68+
final feed2 = client.feed(query: query2);
69+
70+
expect(feed1.query, equals(query1));
71+
expect(feed2.query, equals(query2));
72+
expect(feed1.client, equals(client));
73+
expect(feed2.client, equals(client));
74+
});
75+
});
76+
77+
group('feedsRepository', () {
78+
test('should have initialized feedsRepository', () {
79+
final client = FeedsClient(
80+
apiKey: testApiKey,
81+
user: testUser,
82+
userToken: testUserToken,
83+
);
84+
85+
expect(client.feedsRepository, isNotNull);
86+
});
87+
});
88+
89+
group('apiClient', () {
90+
test('should have initialized apiClient', () {
91+
final client = FeedsClient(
92+
apiKey: testApiKey,
93+
user: testUser,
94+
userToken: testUserToken,
95+
);
96+
97+
expect(client.apiClient, isNotNull);
98+
});
99+
});
100+
101+
group('webSocketClient', () {
102+
test('should have initialized webSocketClient', () {
103+
final client = FeedsClient(
104+
apiKey: testApiKey,
105+
user: testUser,
106+
userToken: testUserToken,
107+
);
108+
109+
expect(client.webSocketClient, isNotNull);
110+
});
111+
});
112+
113+
group('tokenManager', () {
114+
test('should have initialized tokenManager with static token', () {
115+
final client = FeedsClient(
116+
apiKey: testApiKey,
117+
user: testUser,
118+
userToken: testUserToken,
119+
);
120+
121+
expect(client.tokenManager, isNotNull);
122+
});
123+
});
124+
125+
group('connectionRecoveryHandler', () {
126+
test('should be null initially', () {
127+
final client = FeedsClient(
128+
apiKey: testApiKey,
129+
user: testUser,
130+
userToken: testUserToken,
131+
);
132+
133+
expect(client.connectionRecoveryHandler, isNull);
134+
});
135+
});
136+
137+
group('endpointConfig', () {
138+
test('should use production endpoint config', () {
139+
// Test that the endpoint config is accessible
140+
expect(FeedsClient.endpointConfig, isNotNull);
141+
});
142+
});
143+
144+
group('feedsEvents', () {
145+
test('should return a stream', () {
146+
final client = FeedsClient(
147+
apiKey: testApiKey,
148+
user: testUser,
149+
userToken: testUserToken,
150+
);
151+
152+
expect(client.feedsEvents, isA<Stream<FeedsWsEvent>>());
153+
});
154+
155+
test('Should return a stream of FeedsWsEvent', () async {
156+
final client = FeedsClient(
157+
apiKey: testApiKey,
158+
user: testUser,
159+
userToken: testUserToken,
160+
);
161+
162+
final events = <WsEvent>[];
163+
164+
final eventsSubscription = client.feedsEvents.listen(events.add);
165+
166+
// Health check events are kept internal
167+
client.webSocketClient.webSocketDidReceiveMessage(
168+
jsonEncode(testHealthCheckEvent.toJson()),
169+
);
170+
171+
// Feeds specific events are passed to `feedsEvents`
172+
client.webSocketClient.webSocketDidReceiveMessage(
173+
jsonEncode(testCommentAddedEvent.toJson()),
174+
);
175+
176+
await Future<void>.delayed(Duration.zero);
177+
178+
expect(events, hasLength(1));
179+
expect(events[0], isA<FeedsWsEvent>());
180+
expect(
181+
(events[0] as FeedsWsEvent).event,
182+
isA<api.WSClientEventCommentAddedEvent>(),
183+
);
184+
185+
await eventsSubscription.cancel();
186+
});
187+
});
188+
});
189+
}
190+
191+
final testHealthCheckEvent = api.HealthCheckEvent(
192+
connectionId: 'test-id',
193+
createdAt: DateTime.now(),
194+
custom: const {},
195+
type: 'health.check',
196+
);
197+
198+
final testCommentAddedEvent = api.CommentAddedEvent(
199+
comment: api.CommentResponse(
200+
confidenceScore: 0,
201+
createdAt: DateTime.now(),
202+
downvoteCount: 0,
203+
id: 'test-id',
204+
mentionedUsers: const [],
205+
objectId: 'test-object-id',
206+
objectType: 'test-object-type',
207+
ownReactions: const [],
208+
reactionCount: 0,
209+
replyCount: 0,
210+
score: 0,
211+
status: 'active',
212+
updatedAt: DateTime.now(),
213+
upvoteCount: 0,
214+
user: testUserResponse,
215+
),
216+
createdAt: DateTime.now(),
217+
custom: const {},
218+
fid: 'test-fid',
219+
type: 'feeds.comment.added',
220+
);
221+
222+
final testUserResponse = api.UserResponse(
223+
id: 'test-user-id',
224+
banned: false,
225+
blockedUserIds: const [],
226+
createdAt: DateTime.now(),
227+
custom: const {},
228+
language: '',
229+
online: false,
230+
role: '',
231+
teams: const [],
232+
updatedAt: DateTime.now(),
233+
);

packages/stream_feeds/test/mocks.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:mocktail/mocktail.dart';
2+
import 'package:stream_core/stream_core.dart';
23
import 'package:stream_feeds/src/repositories/feeds_repository.dart';
34
import 'package:stream_feeds/src/ws/feeds_ws_event.dart';
45
import 'package:stream_feeds/stream_feeds.dart';
@@ -7,6 +8,8 @@ class MockFeedsRepository extends Mock implements FeedsRepository {}
78

89
class MockFeedsClient extends Mock implements FeedsClient {}
910

11+
class MockWebSocketClient extends Mock implements WebSocketClient {}
12+
1013
class FakeFeedsClient extends Fake implements FeedsClient {
1114
FakeFeedsClient({
1215
User? user,

0 commit comments

Comments
 (0)