add initialized channel tests
Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
@@ -51,9 +51,9 @@ class Channel {
|
|||||||
|
|
||||||
String? _id;
|
String? _id;
|
||||||
String? _cid;
|
String? _cid;
|
||||||
final Map<String, dynamic> _extraData;
|
final Map<String, Object?> _extraData;
|
||||||
|
|
||||||
set extraData(Map<String, dynamic> extraData) {
|
set extraData(Map<String, Object?> extraData) {
|
||||||
if (_initializedCompleter.isCompleted) {
|
if (_initializedCompleter.isCompleted) {
|
||||||
throw StateError(
|
throw StateError(
|
||||||
'Once the channel is initialized you should use channel.update '
|
'Once the channel is initialized you should use channel.update '
|
||||||
@@ -734,7 +734,7 @@ class Channel {
|
|||||||
|
|
||||||
/// Edit the channel custom data
|
/// Edit the channel custom data
|
||||||
Future<UpdateChannelResponse> update(
|
Future<UpdateChannelResponse> update(
|
||||||
Map<String, dynamic> channelData, [
|
Map<String, Object?> channelData, [
|
||||||
Message? updateMessage,
|
Message? updateMessage,
|
||||||
]) async {
|
]) async {
|
||||||
_checkInitialized();
|
_checkInitialized();
|
||||||
@@ -814,19 +814,24 @@ class Channel {
|
|||||||
final messageId = message.id;
|
final messageId = message.id;
|
||||||
final res = await _client.sendAction(id!, type, messageId, formData);
|
final res = await _client.sendAction(id!, type, messageId, formData);
|
||||||
|
|
||||||
|
// update the passed message with response message
|
||||||
if (res.message != null) {
|
if (res.message != null) {
|
||||||
state!.addMessage(res.message!);
|
state!.addMessage(res.message!);
|
||||||
} else {
|
} else {
|
||||||
|
// remove the passed message if response does
|
||||||
|
// not contain message
|
||||||
final oldIndex = state!.messages.indexWhere((m) => m.id == messageId);
|
final oldIndex = state!.messages.indexWhere((m) => m.id == messageId);
|
||||||
|
|
||||||
Message? oldMessage;
|
// remove regular message if present
|
||||||
if (oldIndex != -1) {
|
if (oldIndex != -1) {
|
||||||
oldMessage = state!.messages[oldIndex];
|
final oldMessage = state!.messages[oldIndex];
|
||||||
state!.updateChannelState(state!._channelState.copyWith(
|
state!.updateChannelState(state!._channelState.copyWith(
|
||||||
messages: state?.messages?..remove(oldMessage),
|
messages: state?.messages?..remove(oldMessage),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
oldMessage = state!.threads.values
|
// remove thread message if present
|
||||||
|
// also reduces total reply count
|
||||||
|
final oldMessage = state!.threads.values
|
||||||
.expand((messages) => messages)
|
.expand((messages) => messages)
|
||||||
.firstWhereOrNull((m) => m.id == messageId);
|
.firstWhereOrNull((m) => m.id == messageId);
|
||||||
if (oldMessage?.parentId != null) {
|
if (oldMessage?.parentId != null) {
|
||||||
@@ -858,18 +863,11 @@ class Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the initial channel state and watches for changes
|
/// Loads the initial channel state and watches for changes
|
||||||
Future<ChannelState> watch([Map<String, dynamic> options = const {}]) async {
|
Future<ChannelState> watch() async {
|
||||||
final watchOptions = Map<String, dynamic>.from({
|
|
||||||
'state': true,
|
|
||||||
'watch': true,
|
|
||||||
'presence': false,
|
|
||||||
})
|
|
||||||
..addAll(options);
|
|
||||||
|
|
||||||
ChannelState response;
|
ChannelState response;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await query(options: watchOptions);
|
response = await query(watch: true);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
if (!_initializedCompleter.isCompleted) {
|
if (!_initializedCompleter.isCompleted) {
|
||||||
_initializedCompleter.completeError(error, stackTrace);
|
_initializedCompleter.completeError(error, stackTrace);
|
||||||
@@ -956,17 +954,15 @@ class Channel {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Creates a new channel
|
/// Creates a new channel
|
||||||
Future<ChannelState> create() async => query(options: {
|
Future<ChannelState> create() async => query(state: false);
|
||||||
'watch': false,
|
|
||||||
'state': false,
|
|
||||||
'presence': false,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Query the API, get messages, members or other channel fields
|
/// Query the API, get messages, members or other channel fields
|
||||||
/// Set [preferOffline] to true to avoid the api call if the data is already
|
/// Set [preferOffline] to true to avoid the api call if the data is already
|
||||||
/// in the offline storage
|
/// in the offline storage
|
||||||
Future<ChannelState> query({
|
Future<ChannelState> query({
|
||||||
Map<String, dynamic> options = const {},
|
bool state = true,
|
||||||
|
bool watch = false,
|
||||||
|
bool presence = false,
|
||||||
PaginationParams? messagesPagination,
|
PaginationParams? messagesPagination,
|
||||||
PaginationParams? membersPagination,
|
PaginationParams? membersPagination,
|
||||||
PaginationParams? watchersPagination,
|
PaginationParams? watchersPagination,
|
||||||
@@ -976,10 +972,10 @@ class Channel {
|
|||||||
final updatedState = await _client.chatPersistenceClient
|
final updatedState = await _client.chatPersistenceClient
|
||||||
?.getChannelStateByCid(cid!, messagePagination: messagesPagination);
|
?.getChannelStateByCid(cid!, messagePagination: messagesPagination);
|
||||||
if (updatedState != null && updatedState.messages.isNotEmpty) {
|
if (updatedState != null && updatedState.messages.isNotEmpty) {
|
||||||
if (state == null) {
|
if (this.state == null) {
|
||||||
_initState(updatedState);
|
_initState(updatedState);
|
||||||
} else {
|
} else {
|
||||||
state?.updateChannelState(updatedState);
|
this.state?.updateChannelState(updatedState);
|
||||||
}
|
}
|
||||||
return updatedState;
|
return updatedState;
|
||||||
}
|
}
|
||||||
@@ -990,6 +986,9 @@ class Channel {
|
|||||||
type,
|
type,
|
||||||
channelId: id,
|
channelId: id,
|
||||||
channelData: _extraData,
|
channelData: _extraData,
|
||||||
|
state: state,
|
||||||
|
watch: watch,
|
||||||
|
presence: presence,
|
||||||
messagesPagination: messagesPagination,
|
messagesPagination: messagesPagination,
|
||||||
membersPagination: membersPagination,
|
membersPagination: membersPagination,
|
||||||
watchersPagination: watchersPagination,
|
watchersPagination: watchersPagination,
|
||||||
@@ -1000,7 +999,7 @@ class Channel {
|
|||||||
_cid = updatedState.channel!.cid;
|
_cid = updatedState.channel!.cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
state?.updateChannelState(updatedState);
|
this.state?.updateChannelState(updatedState);
|
||||||
return updatedState;
|
return updatedState;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!_client.persistenceEnabled) {
|
if (!_client.persistenceEnabled) {
|
||||||
@@ -1775,7 +1774,7 @@ class ChannelClientState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
late Timer _cleaningTimer;
|
Timer? _cleaningTimer;
|
||||||
|
|
||||||
void _startCleaning() {
|
void _startCleaning() {
|
||||||
if (_channelState.channel?.config.typingEvents == false) {
|
if (_channelState.channel?.config.typingEvents == false) {
|
||||||
@@ -1842,7 +1841,7 @@ class ChannelClientState {
|
|||||||
_channelStateController.close();
|
_channelStateController.close();
|
||||||
_isUpToDateController.close();
|
_isUpToDateController.close();
|
||||||
_threadsController.close();
|
_threadsController.close();
|
||||||
_cleaningTimer.cancel();
|
_cleaningTimer?.cancel();
|
||||||
_pinnedMessagesTimer.cancel();
|
_pinnedMessagesTimer.cancel();
|
||||||
_typingEventsController.close();
|
_typingEventsController.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -757,7 +757,7 @@ class StreamChatClient {
|
|||||||
Future<UpdateChannelResponse> updateChannel(
|
Future<UpdateChannelResponse> updateChannel(
|
||||||
String channelId,
|
String channelId,
|
||||||
String channelType,
|
String channelType,
|
||||||
Map<String, dynamic> data, {
|
Map<String, Object?> data, {
|
||||||
Message? message,
|
Message? message,
|
||||||
}) =>
|
}) =>
|
||||||
_chatApi.channel.updateChannel(
|
_chatApi.channel.updateChannel(
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class ChannelApi {
|
|||||||
Future<UpdateChannelResponse> updateChannel(
|
Future<UpdateChannelResponse> updateChannel(
|
||||||
String channelId,
|
String channelId,
|
||||||
String channelType,
|
String channelType,
|
||||||
Map<String, dynamic> data, {
|
Map<String, Object?> data, {
|
||||||
Message? message,
|
Message? message,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await _client.post(
|
final response = await _client.post(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -82,3 +82,24 @@ class FakeChatApi extends Fake implements StreamChatApi {
|
|||||||
AttachmentFileUploader get fileUploader =>
|
AttachmentFileUploader get fileUploader =>
|
||||||
_fileUploader ??= MockAttachmentFileUploader();
|
_fileUploader ??= MockAttachmentFileUploader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FakeClientState extends Fake implements ClientState {
|
||||||
|
@override
|
||||||
|
OwnUser? get user => OwnUser(id: 'test-user-id');
|
||||||
|
|
||||||
|
var _totalUnreadCount = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? get totalUnreadCount => _totalUnreadCount;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set totalUnreadCount(int? unreadCount) {
|
||||||
|
_totalUnreadCount += unreadCount ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeMessage extends Fake implements Message {}
|
||||||
|
|
||||||
|
class FakeAttachmentFile extends Fake implements AttachmentFile {}
|
||||||
|
|
||||||
|
class FakeEvent extends Fake implements Event {}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:dio/dio.dart' show MultipartFile;
|
import 'package:dio/dio.dart' show MultipartFile;
|
||||||
|
import 'package:stream_chat/src/core/models/event.dart';
|
||||||
|
import 'package:stream_chat/src/core/models/message.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
Matcher isSameMultipartFileAs(MultipartFile targetFile) =>
|
Matcher isSameMultipartFileAs(MultipartFile targetFile) =>
|
||||||
@@ -17,3 +20,72 @@ class _IsSameMultipartFileAs extends Matcher {
|
|||||||
bool matches(covariant MultipartFile file, Map matchState) =>
|
bool matches(covariant MultipartFile file, Map matchState) =>
|
||||||
file.length == targetFile.length;
|
file.length == targetFile.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matcher isSameEventAs(Event targetEvent) =>
|
||||||
|
_IsSameEventAs(targetEvent: targetEvent);
|
||||||
|
|
||||||
|
class _IsSameEventAs extends Matcher {
|
||||||
|
const _IsSameEventAs({required this.targetEvent});
|
||||||
|
|
||||||
|
final Event targetEvent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Description describe(Description description) =>
|
||||||
|
description.add('is same event as $targetEvent');
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool matches(covariant Event event, Map matchState) =>
|
||||||
|
event.type == targetEvent.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher isSameMessageAs(
|
||||||
|
Message targetMessage, {
|
||||||
|
bool matchReactions = false,
|
||||||
|
bool matchSendingStatus = false,
|
||||||
|
}) =>
|
||||||
|
_IsSameMessageAs(
|
||||||
|
targetMessage: targetMessage,
|
||||||
|
matchReactions: matchReactions,
|
||||||
|
matchSendingStatus: matchSendingStatus,
|
||||||
|
);
|
||||||
|
|
||||||
|
class _IsSameMessageAs extends Matcher {
|
||||||
|
const _IsSameMessageAs({
|
||||||
|
required this.targetMessage,
|
||||||
|
this.matchReactions = false,
|
||||||
|
this.matchSendingStatus = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Message targetMessage;
|
||||||
|
final bool matchReactions;
|
||||||
|
final bool matchSendingStatus;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Description describe(Description description) =>
|
||||||
|
description.add('is same message as $targetMessage');
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool matches(covariant Message message, Map matchState) {
|
||||||
|
var matches = message.id == targetMessage.id;
|
||||||
|
if (matchSendingStatus) {
|
||||||
|
matches &= message.status == targetMessage.status;
|
||||||
|
}
|
||||||
|
if (matchReactions) {
|
||||||
|
matches &= const ListEquality().equals(
|
||||||
|
message.ownReactions
|
||||||
|
?.map((it) => '${it.type}-${it.messageId}')
|
||||||
|
.toList(),
|
||||||
|
targetMessage.ownReactions
|
||||||
|
?.map((it) => '${it.type}-${it.messageId}')
|
||||||
|
.toList());
|
||||||
|
matches &= const ListEquality().equals(
|
||||||
|
message.latestReactions
|
||||||
|
?.map((it) => '${it.type}-${it.messageId}')
|
||||||
|
.toList(),
|
||||||
|
targetMessage.latestReactions
|
||||||
|
?.map((it) => '${it.type}-${it.messageId}')
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:stream_chat/src/client/client.dart';
|
||||||
import 'package:stream_chat/src/core/api/attachment_file_uploader.dart';
|
import 'package:stream_chat/src/core/api/attachment_file_uploader.dart';
|
||||||
import 'package:stream_chat/src/core/api/channel_api.dart';
|
import 'package:stream_chat/src/core/api/channel_api.dart';
|
||||||
import 'package:stream_chat/src/core/api/device_api.dart';
|
import 'package:stream_chat/src/core/api/device_api.dart';
|
||||||
@@ -12,8 +13,13 @@ import 'package:stream_chat/src/core/api/user_api.dart';
|
|||||||
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
|
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
|
||||||
import 'package:stream_chat/src/core/http/stream_http_client.dart';
|
import 'package:stream_chat/src/core/http/stream_http_client.dart';
|
||||||
import 'package:stream_chat/src/core/http/token_manager.dart';
|
import 'package:stream_chat/src/core/http/token_manager.dart';
|
||||||
|
import 'package:stream_chat/src/core/models/channel_config.dart';
|
||||||
|
import 'package:stream_chat/src/core/models/channel_model.dart';
|
||||||
|
import 'package:stream_chat/src/db/chat_persistence_client.dart';
|
||||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
|
|
||||||
|
import 'db/chat_persistence_client_test.dart';
|
||||||
|
|
||||||
class MockWebSocketChannel extends Mock implements WebSocketChannel {}
|
class MockWebSocketChannel extends Mock implements WebSocketChannel {}
|
||||||
|
|
||||||
class MockWebSocketSink extends Mock implements WebSocketSink {}
|
class MockWebSocketSink extends Mock implements WebSocketSink {}
|
||||||
@@ -57,3 +63,24 @@ class MockGeneralApi extends Mock implements GeneralApi {}
|
|||||||
|
|
||||||
class MockAttachmentFileUploader extends Mock
|
class MockAttachmentFileUploader extends Mock
|
||||||
implements AttachmentFileUploader {}
|
implements AttachmentFileUploader {}
|
||||||
|
|
||||||
|
class MockPersistenceClient extends Mock implements ChatPersistenceClient {}
|
||||||
|
|
||||||
|
class MockStreamChatClient extends Mock implements StreamChatClient {
|
||||||
|
@override
|
||||||
|
bool get persistenceEnabled => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockStreamChatClientWithPersistence extends Mock
|
||||||
|
implements StreamChatClient {
|
||||||
|
ChatPersistenceClient? _persistenceClient;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChatPersistenceClient get chatPersistenceClient =>
|
||||||
|
_persistenceClient ??= MockPersistenceClient();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get persistenceEnabled => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockChannelConfig extends Mock implements ChannelConfig {}
|
||||||
|
|||||||
Reference in New Issue
Block a user