2318 lines
75 KiB
Dart
2318 lines
75 KiB
Dart
import 'package:mocktail/mocktail.dart';
|
|
import 'package:stream_chat/src/client/client.dart';
|
|
import 'package:stream_chat/src/core/api/device_api.dart';
|
|
import 'package:stream_chat/src/core/api/requests.dart';
|
|
import 'package:stream_chat/src/core/api/responses.dart';
|
|
import 'package:stream_chat/src/core/error/error.dart';
|
|
import 'package:stream_chat/src/core/http/token.dart';
|
|
import 'package:stream_chat/src/core/models/channel_model.dart';
|
|
import 'package:stream_chat/src/core/models/event.dart';
|
|
import 'package:stream_chat/src/core/models/filter.dart';
|
|
import 'package:stream_chat/src/core/models/message.dart';
|
|
import 'package:stream_chat/src/core/models/own_user.dart';
|
|
import 'package:stream_chat/src/core/models/user.dart';
|
|
import 'package:stream_chat/src/event_type.dart';
|
|
import 'package:stream_chat/src/ws/connection_status.dart';
|
|
import 'package:stream_chat/stream_chat.dart';
|
|
import 'package:test/scaffolding.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../fakes.dart';
|
|
import '../matchers.dart';
|
|
import '../mocks.dart';
|
|
import '../utils.dart';
|
|
|
|
void main() {
|
|
group('Fake web-socket connection functions', () {
|
|
const apiKey = 'test-api-key';
|
|
late final api = FakeChatApi();
|
|
|
|
late StreamChatClient client;
|
|
|
|
setUpAll(() {
|
|
// fallback values
|
|
registerFallbackValue<User>(FakeUser());
|
|
});
|
|
|
|
setUp(() {
|
|
final ws = FakeWebSocket();
|
|
client = StreamChatClient(apiKey, ws: ws, chatApi: api);
|
|
});
|
|
|
|
tearDown(() {
|
|
client.dispose();
|
|
});
|
|
|
|
test('`.connectUser` should work fine', () async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
expectLater(
|
|
// skipping first seed status -> ConnectionStatus.disconnected
|
|
client.wsConnectionStatusStream.skip(1),
|
|
emitsInOrder([
|
|
ConnectionStatus.connecting,
|
|
ConnectionStatus.connected,
|
|
]),
|
|
);
|
|
|
|
final res = await client.connectUser(user, token);
|
|
expect(res, isNotNull);
|
|
expect(res, isSameUserAs(user));
|
|
});
|
|
|
|
test('`.connectUserWithProvider` should work fine', () async {
|
|
final user = User(id: 'test-user-id');
|
|
Future<String> tokenProvider(String userId) async {
|
|
expect(userId, user.id);
|
|
return Token.development(userId).rawValue;
|
|
}
|
|
|
|
expectLater(
|
|
// skipping first seed status -> ConnectionStatus.disconnected
|
|
client.wsConnectionStatusStream.skip(1),
|
|
emitsInOrder([
|
|
ConnectionStatus.connecting,
|
|
ConnectionStatus.connected,
|
|
]),
|
|
);
|
|
|
|
final res = await client.connectUserWithProvider(user, tokenProvider);
|
|
expect(res, isNotNull);
|
|
expect(res, isSameUserAs(user));
|
|
});
|
|
|
|
group('`.connectGuestUser`', () {
|
|
test('should work fine', () async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
when(() => api.guest.getGuestUser(any(that: isSameUserAs(user))))
|
|
.thenAnswer(
|
|
(_) async => ConnectGuestUserResponse()
|
|
..user = user
|
|
..accessToken = token,
|
|
);
|
|
|
|
expectLater(
|
|
// skipping first seed status -> ConnectionStatus.disconnected
|
|
client.wsConnectionStatusStream.skip(1),
|
|
emitsInOrder([
|
|
ConnectionStatus.connecting,
|
|
ConnectionStatus.connected,
|
|
]),
|
|
);
|
|
|
|
final res = await client.connectGuestUser(user);
|
|
expect(res, isNotNull);
|
|
expect(res, isSameUserAs(user));
|
|
|
|
verify(
|
|
() => api.guest.getGuestUser(any(that: isSameUserAs(user))),
|
|
).called(1);
|
|
});
|
|
|
|
test('should throw if `.getGuestUser` fails', () async {
|
|
final user = User(id: 'test-user-id');
|
|
|
|
when(() => api.guest.getGuestUser(any(that: isSameUserAs(user))))
|
|
.thenThrow(StreamChatNetworkError(ChatErrorCode.inputError));
|
|
|
|
expectLater(
|
|
client.wsConnectionStatusStream,
|
|
emitsInOrder([
|
|
// only emits the seed -> disconnected status
|
|
// as the call never reaches `ws.connect`
|
|
ConnectionStatus.disconnected,
|
|
]),
|
|
);
|
|
|
|
try {
|
|
await client.connectGuestUser(user);
|
|
} catch (e) {
|
|
expect(e, isA<StreamChatNetworkError>());
|
|
}
|
|
|
|
verify(
|
|
() => api.guest.getGuestUser(any(that: isSameUserAs(user))),
|
|
).called(1);
|
|
});
|
|
});
|
|
|
|
test('`.connectAnonymousUser` should work fine', () async {
|
|
expectLater(
|
|
// skipping first seed status -> ConnectionStatus.disconnected
|
|
client.wsConnectionStatusStream.skip(1),
|
|
emitsInOrder([
|
|
ConnectionStatus.connecting,
|
|
ConnectionStatus.connected,
|
|
]),
|
|
);
|
|
|
|
final res = await client.connectAnonymousUser();
|
|
expect(res, isNotNull);
|
|
});
|
|
|
|
group('`.openConnection`', () {
|
|
test('should throw if state does not contain user', () async {
|
|
expect(client.state.currentUser, isNull);
|
|
try {
|
|
await client.openConnection();
|
|
} catch (e) {
|
|
expect(e, isA<AssertionError>());
|
|
}
|
|
});
|
|
|
|
test('should throw if connection is already in progress', () async {
|
|
expect(client.state.currentUser, isNull);
|
|
try {
|
|
await client.connectAnonymousUser();
|
|
await client.openConnection();
|
|
} catch (e) {
|
|
expect(e, isA<StreamChatError>());
|
|
final err = e as StreamChatError;
|
|
expect(
|
|
err.message.contains('Connection already in progress for'),
|
|
isTrue,
|
|
);
|
|
}
|
|
});
|
|
|
|
test('should throw if connection is already available', () async {
|
|
expect(client.state.currentUser, isNull);
|
|
try {
|
|
await client.connectAnonymousUser();
|
|
// waiting 300ms for `wsConnectionStatusStream` to emit
|
|
await delay(300);
|
|
|
|
await client.openConnection();
|
|
} catch (e) {
|
|
expect(e, isA<StreamChatError>());
|
|
final err = e as StreamChatError;
|
|
expect(
|
|
err.message.contains('Connection already available for'),
|
|
isTrue,
|
|
);
|
|
}
|
|
});
|
|
|
|
test('should open connection for closed connection', () async {
|
|
expectLater(
|
|
client.wsConnectionStatusStream.skip(1),
|
|
emitsInOrder([
|
|
// initial connectUser
|
|
ConnectionStatus.connecting,
|
|
ConnectionStatus.connected,
|
|
// close connection
|
|
ConnectionStatus.disconnected,
|
|
// open connection
|
|
ConnectionStatus.connecting,
|
|
ConnectionStatus.connected,
|
|
]),
|
|
);
|
|
|
|
await client.connectAnonymousUser();
|
|
// waiting 300ms for `wsConnectionStatusStream` to emit
|
|
await delay(300);
|
|
|
|
client.closeConnection();
|
|
|
|
await client.openConnection();
|
|
});
|
|
});
|
|
});
|
|
|
|
group('Fake web-socket connection functions failure', () {
|
|
const apiKey = 'test-api-key';
|
|
late final api = FakeChatApi();
|
|
|
|
late StreamChatClient client;
|
|
|
|
setUpAll(() {
|
|
// fallback values
|
|
registerFallbackValue<User>(FakeUser());
|
|
});
|
|
|
|
setUp(() {
|
|
final ws = FakeWebSocketWithConnectionError();
|
|
client = StreamChatClient(apiKey, chatApi: api, ws: ws);
|
|
});
|
|
|
|
tearDown(() {
|
|
client.dispose();
|
|
});
|
|
|
|
test('`.connectUser` should throw if `ws.connect` fails', () async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
try {
|
|
await client.connectUser(user, token);
|
|
} catch (e) {
|
|
expect(e, isA<StreamWebSocketError>());
|
|
}
|
|
});
|
|
|
|
test(
|
|
'`.connectUserWithProvider` should throw if `ws.connect` fails',
|
|
() async {
|
|
final user = User(id: 'test-user-id');
|
|
Future<String> tokenProvider(String userId) async {
|
|
expect(userId, user.id);
|
|
return Token.development(userId).rawValue;
|
|
}
|
|
|
|
try {
|
|
await client.connectUserWithProvider(user, tokenProvider);
|
|
} catch (e) {
|
|
expect(e, isA<StreamWebSocketError>());
|
|
}
|
|
},
|
|
);
|
|
|
|
test('`.connectGuestUser` should throw if `ws.connect` fails', () async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
when(() => api.guest.getGuestUser(any(that: isSameUserAs(user))))
|
|
.thenAnswer(
|
|
(_) async => ConnectGuestUserResponse()
|
|
..user = user
|
|
..accessToken = token,
|
|
);
|
|
|
|
try {
|
|
await client.connectGuestUser(user);
|
|
} catch (e) {
|
|
expect(e, isA<StreamWebSocketError>());
|
|
}
|
|
verify(
|
|
() => api.guest.getGuestUser(any(that: isSameUserAs(user))),
|
|
).called(1);
|
|
});
|
|
|
|
test(
|
|
'`.connectAnonymousUser` should throw if `ws.connect` fails',
|
|
() async {
|
|
try {
|
|
await client.connectAnonymousUser();
|
|
} catch (e) {
|
|
expect(e, isA<StreamWebSocketError>());
|
|
}
|
|
},
|
|
);
|
|
});
|
|
|
|
group('Connect user calls with `connectWebSocket`: false', () {
|
|
const apiKey = 'test-api-key';
|
|
late final api = FakeChatApi();
|
|
|
|
late StreamChatClient client;
|
|
|
|
setUpAll(() {
|
|
// fallback values
|
|
registerFallbackValue<User>(FakeUser());
|
|
});
|
|
|
|
setUp(() {
|
|
client = StreamChatClient(apiKey, chatApi: api);
|
|
});
|
|
|
|
tearDown(() {
|
|
client.dispose();
|
|
});
|
|
|
|
test('`.connectUser` should succeed without connecting', () async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
final res = await client.connectUser(
|
|
user,
|
|
token,
|
|
connectWebSocket: false,
|
|
);
|
|
expect(res, isSameUserAs(user));
|
|
expect(client.wsConnectionStatus, ConnectionStatus.disconnected);
|
|
});
|
|
|
|
test(
|
|
'`.connectUserWithProvider` should succeed without connecting',
|
|
() async {
|
|
final user = User(id: 'test-user-id');
|
|
Future<String> tokenProvider(String userId) async {
|
|
expect(userId, user.id);
|
|
return Token.development(userId).rawValue;
|
|
}
|
|
|
|
final res = await client.connectUserWithProvider(
|
|
user,
|
|
tokenProvider,
|
|
connectWebSocket: false,
|
|
);
|
|
expect(res, isSameUserAs(user));
|
|
expect(client.wsConnectionStatus, ConnectionStatus.disconnected);
|
|
},
|
|
);
|
|
|
|
test('`.connectGuestUser` should succeed without connecting', () async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
when(() => api.guest.getGuestUser(any(that: isSameUserAs(user))))
|
|
.thenAnswer(
|
|
(_) async => ConnectGuestUserResponse()
|
|
..user = user
|
|
..accessToken = token,
|
|
);
|
|
|
|
final res = await client.connectGuestUser(
|
|
user,
|
|
connectWebSocket: false,
|
|
);
|
|
|
|
expect(res, isSameUserAs(user));
|
|
expect(client.wsConnectionStatus, ConnectionStatus.disconnected);
|
|
verify(
|
|
() => api.guest.getGuestUser(any(that: isSameUserAs(user))),
|
|
).called(1);
|
|
});
|
|
|
|
test(
|
|
'`.connectAnonymousUser` should succeed without connecting',
|
|
() async {
|
|
final res = await client.connectAnonymousUser(
|
|
connectWebSocket: false,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(client.wsConnectionStatus, ConnectionStatus.disconnected);
|
|
},
|
|
);
|
|
});
|
|
|
|
group('Fake web-socket connection function with failure and persistence', () {
|
|
const apiKey = 'test-api-key';
|
|
late final api = FakeChatApi();
|
|
late final persistence = MockPersistenceClient();
|
|
|
|
late StreamChatClient client;
|
|
|
|
setUpAll(() {
|
|
// fallback values
|
|
registerFallbackValue<User>(FakeUser());
|
|
});
|
|
|
|
setUp(() {
|
|
final ws = FakeWebSocketWithConnectionError();
|
|
client = StreamChatClient(apiKey, chatApi: api, ws: ws)
|
|
..chatPersistenceClient = persistence;
|
|
});
|
|
|
|
tearDown(() {
|
|
client.dispose();
|
|
});
|
|
|
|
test(
|
|
'''`.connectUser` should connect successfully if persistence contains event''',
|
|
() async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
final event = Event(
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user));
|
|
when(persistence.getConnectionInfo).thenAnswer((_) async => event);
|
|
|
|
final res = await client.connectUser(user, token);
|
|
expect(res, isNotNull);
|
|
expect(res, isSameUserAs(user));
|
|
|
|
verify(persistence.getConnectionInfo).called(1);
|
|
verifyNoMoreInteractions(persistence);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'''`.connectUserWithProvider` should connect successfully if persistence contains event''',
|
|
() async {
|
|
final user = User(id: 'test-user-id');
|
|
Future<String> tokenProvider(String userId) async {
|
|
expect(userId, user.id);
|
|
return Token.development(userId).rawValue;
|
|
}
|
|
|
|
final event = Event(
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user));
|
|
when(persistence.getConnectionInfo).thenAnswer((_) async => event);
|
|
|
|
final res = await client.connectUserWithProvider(user, tokenProvider);
|
|
expect(res, isNotNull);
|
|
expect(res, isSameUserAs(user));
|
|
|
|
verify(persistence.getConnectionInfo).called(1);
|
|
verifyNoMoreInteractions(persistence);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'''`.connectGuestUser` should connect successfully if persistence contains event''',
|
|
() async {
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
final event = Event(
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user));
|
|
when(persistence.getConnectionInfo).thenAnswer((_) async => event);
|
|
|
|
when(() => api.guest.getGuestUser(any(that: isSameUserAs(user))))
|
|
.thenAnswer(
|
|
(_) async => ConnectGuestUserResponse()
|
|
..user = user
|
|
..accessToken = token,
|
|
);
|
|
|
|
final res = await client.connectGuestUser(user);
|
|
expect(res, isNotNull);
|
|
expect(res, isSameUserAs(user));
|
|
|
|
verify(persistence.getConnectionInfo).called(1);
|
|
verifyNoMoreInteractions(persistence);
|
|
verify(() => api.guest.getGuestUser(any(that: isSameUserAs(user))))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.guest);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'''`.connectAnonymousUser` should connect successfully if persistence contains event''',
|
|
() async {
|
|
final user = User(id: 'test-user-id');
|
|
|
|
when(persistence.getConnectionInfo).thenAnswer(
|
|
(invocation) async => Event(
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user),
|
|
),
|
|
);
|
|
|
|
final res = await client.connectAnonymousUser();
|
|
expect(res, isNotNull);
|
|
|
|
verify(persistence.getConnectionInfo).called(1);
|
|
verifyNoMoreInteractions(persistence);
|
|
},
|
|
);
|
|
});
|
|
|
|
group('Client with connected user with persistence', () {
|
|
const apiKey = 'test-api-key';
|
|
late final api = FakeChatApi();
|
|
late final ws = FakeWebSocket();
|
|
late final persistence = MockPersistenceClient();
|
|
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
late StreamChatClient client;
|
|
|
|
setUpAll(() {
|
|
// fallback values
|
|
registerFallbackValue<Event>(FakeEvent());
|
|
registerFallbackValue<PaginationParams>(const PaginationParams());
|
|
registerFallbackValue<ChannelState>(FakeChannelState());
|
|
});
|
|
|
|
setUp(() async {
|
|
client = StreamChatClient(apiKey, chatApi: api, ws: ws)
|
|
..chatPersistenceClient = persistence;
|
|
await client.connectUser(user, token);
|
|
await delay(300);
|
|
expect(client.persistenceEnabled, isTrue);
|
|
expect(client.wsConnectionStatus, ConnectionStatus.connected);
|
|
});
|
|
|
|
tearDown(() {
|
|
client.dispose();
|
|
});
|
|
|
|
group('`.sync`', () {
|
|
test(
|
|
'''should update persistence connectionInfo and lastSync when sync succeeds''',
|
|
() async {
|
|
const cids = ['test-cid-1', 'test-cid-2', 'test-cid-3'];
|
|
final lastSyncAt = DateTime.now();
|
|
|
|
when(() => api.general.sync(cids, lastSyncAt))
|
|
.thenAnswer((_) async => SyncResponse()
|
|
..events = [
|
|
Event(
|
|
isLocal: false,
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user),
|
|
),
|
|
Event(
|
|
isLocal: false,
|
|
type: EventType.messageDeleted,
|
|
message: Message(id: 'test-message-id'),
|
|
),
|
|
]);
|
|
|
|
when(() => persistence.updateConnectionInfo(any()))
|
|
.thenAnswer((_) => Future.value());
|
|
when(() => persistence.updateLastSyncAt(any()))
|
|
.thenAnswer((_) => Future.value());
|
|
|
|
await client.sync(cids: cids, lastSyncAt: lastSyncAt);
|
|
|
|
verify(() => persistence.updateConnectionInfo(any())).called(1);
|
|
verify(() => persistence.updateLastSyncAt(any())).called(1);
|
|
verify(() => api.general.sync(cids, lastSyncAt)).called(1);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'should work fine if persistence contains sync params',
|
|
() async {
|
|
const cids = ['test-cid-1', 'test-cid-2', 'test-cid-3'];
|
|
final lastSyncAt = DateTime.now();
|
|
|
|
when(persistence.getChannelCids).thenAnswer((_) async => cids);
|
|
when(persistence.getLastSyncAt).thenAnswer((_) async => lastSyncAt);
|
|
|
|
when(() => api.general.sync(cids, lastSyncAt))
|
|
.thenAnswer((_) async => SyncResponse()
|
|
..events = [
|
|
Event(
|
|
isLocal: false,
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user),
|
|
),
|
|
Event(
|
|
isLocal: false,
|
|
type: EventType.messageDeleted,
|
|
message: Message(id: 'test-message-id', text: 'Hey!'),
|
|
),
|
|
]);
|
|
|
|
when(() => persistence.updateConnectionInfo(any()))
|
|
.thenAnswer((_) => Future.value());
|
|
when(() => persistence.updateLastSyncAt(any()))
|
|
.thenAnswer((_) => Future.value());
|
|
|
|
await client.sync();
|
|
|
|
verify(() => persistence.updateConnectionInfo(any())).called(1);
|
|
verify(() => persistence.updateLastSyncAt(any())).called(1);
|
|
verify(() => api.general.sync(cids, lastSyncAt)).called(1);
|
|
verify(persistence.getChannelCids).called(1);
|
|
verify(persistence.getLastSyncAt).called(1);
|
|
},
|
|
);
|
|
});
|
|
|
|
group('`.queryChannels`', () {
|
|
test(
|
|
'should emit channels twice if persistence contains some channels',
|
|
() async {
|
|
final persistentChannelStates = List.generate(
|
|
3,
|
|
(index) => ChannelState(
|
|
channel: ChannelModel(cid: 'p-test-type-$index:p-test-id-$index'),
|
|
),
|
|
);
|
|
|
|
when(() => persistence.getChannelStates(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).thenAnswer((_) async => persistentChannelStates);
|
|
|
|
final channelStates = List.generate(
|
|
3,
|
|
(index) => ChannelState(
|
|
channel: ChannelModel(cid: 'test-type-$index:test-id-$index'),
|
|
),
|
|
);
|
|
|
|
when(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).thenAnswer(
|
|
(_) async => QueryChannelsResponse()..channels = channelStates,
|
|
);
|
|
|
|
when(() => persistence.getChannelThreads(any()))
|
|
.thenAnswer((_) async => {});
|
|
when(() => persistence.updateMessages(any(), any()))
|
|
.thenAnswer((_) => Future.value());
|
|
when(() => persistence.getChannelStateByCid(any(),
|
|
messagePagination: any(named: 'messagePagination'),
|
|
pinnedMessagePagination:
|
|
any(named: 'pinnedMessagePagination'))).thenAnswer(
|
|
(invocation) async => ChannelState(
|
|
channel: ChannelModel(cid: invocation.positionalArguments.first),
|
|
),
|
|
);
|
|
when(() => persistence.updateChannelQueries(any(), any(),
|
|
clearQueryCache: any(named: 'clearQueryCache')))
|
|
.thenAnswer((_) => Future.value());
|
|
|
|
expectLater(
|
|
client.queryChannels(),
|
|
emitsInOrder([
|
|
// emits persistent channels first
|
|
persistentChannelStates.map(isCorrectChannelFor),
|
|
// makes api call and emits network fetched channels
|
|
channelStates.map(isCorrectChannelFor),
|
|
]),
|
|
);
|
|
|
|
// Hack as `teardown` gets called even
|
|
// before our stream starts emitting data
|
|
await delay(300);
|
|
|
|
verify(() => persistence.getChannelStates(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).called(1);
|
|
|
|
verify(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).called(1);
|
|
|
|
verify(() => persistence.getChannelThreads(any()))
|
|
.called((persistentChannelStates + channelStates).length);
|
|
verify(() => persistence.updateMessages(any(), any()))
|
|
.called((persistentChannelStates + channelStates).length);
|
|
verify(
|
|
() => persistence.getChannelStateByCid(any(),
|
|
messagePagination: any(named: 'messagePagination'),
|
|
pinnedMessagePagination: any(named: 'pinnedMessagePagination')),
|
|
).called((persistentChannelStates + channelStates).length);
|
|
verify(() => persistence.updateChannelQueries(any(), any(),
|
|
clearQueryCache: any(named: 'clearQueryCache'))).called(1);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'''should never rethrow network call if persistence already emitted some channels''',
|
|
() async {
|
|
final persistentChannelStates = List.generate(
|
|
3,
|
|
(index) => ChannelState(
|
|
channel: ChannelModel(cid: 'p-test-type-$index:p-test-id-$index'),
|
|
),
|
|
);
|
|
|
|
when(() => persistence.getChannelStates(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).thenAnswer((_) async => persistentChannelStates);
|
|
|
|
when(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).thenThrow(StreamChatNetworkError(ChatErrorCode.inputError));
|
|
|
|
when(() => persistence.getChannelThreads(any()))
|
|
.thenAnswer((_) async => {});
|
|
when(() => persistence.updateMessages(any(), any()))
|
|
.thenAnswer((_) => Future.value());
|
|
when(() => persistence.getChannelStateByCid(any(),
|
|
messagePagination: any(named: 'messagePagination'),
|
|
pinnedMessagePagination:
|
|
any(named: 'pinnedMessagePagination'))).thenAnswer(
|
|
(invocation) async => ChannelState(
|
|
channel: ChannelModel(cid: invocation.positionalArguments.first),
|
|
),
|
|
);
|
|
|
|
expectLater(
|
|
client.queryChannels(),
|
|
emitsInOrder([
|
|
// emits persistent channels
|
|
persistentChannelStates.map(isCorrectChannelFor),
|
|
]),
|
|
);
|
|
|
|
// Hack as `teardown` gets called even
|
|
// before our stream starts emitting data
|
|
await delay(300);
|
|
|
|
verify(() => persistence.getChannelStates(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).called(1);
|
|
|
|
verify(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).called(1);
|
|
|
|
verify(() => persistence.getChannelThreads(any()))
|
|
.called(persistentChannelStates.length);
|
|
verify(() => persistence.updateMessages(any(), any()))
|
|
.called(persistentChannelStates.length);
|
|
verify(
|
|
() => persistence.getChannelStateByCid(any(),
|
|
messagePagination: any(named: 'messagePagination'),
|
|
pinnedMessagePagination: any(named: 'pinnedMessagePagination')),
|
|
).called(persistentChannelStates.length);
|
|
},
|
|
);
|
|
});
|
|
|
|
test('`.disconnectUser` should reset state and user', () async {
|
|
expect(client.state.currentUser, isNotNull);
|
|
expect(client.wsConnectionStatus, ConnectionStatus.connected);
|
|
|
|
expectLater(
|
|
// skipping initial connected value
|
|
client.wsConnectionStatusStream.skip(1),
|
|
emits(ConnectionStatus.disconnected),
|
|
);
|
|
|
|
await client.disconnectUser();
|
|
|
|
expect(client.state.currentUser, isNull);
|
|
expect(client.wsConnectionStatus, ConnectionStatus.disconnected);
|
|
});
|
|
});
|
|
|
|
group('Client with connected user without persistence', () {
|
|
const apiKey = 'test-api-key';
|
|
late final api = FakeChatApi();
|
|
late final ws = FakeWebSocket();
|
|
|
|
final user = User(id: 'test-user-id');
|
|
final token = Token.development(user.id).rawValue;
|
|
|
|
late StreamChatClient client;
|
|
|
|
setUpAll(() {
|
|
// fallback values
|
|
registerFallbackValue<Event>(FakeEvent());
|
|
registerFallbackValue<Message>(FakeMessage());
|
|
registerFallbackValue<PaginationParams>(const PaginationParams());
|
|
});
|
|
|
|
setUp(() async {
|
|
client = StreamChatClient(apiKey, chatApi: api, ws: ws);
|
|
await client.connectUser(user, token);
|
|
await delay(300);
|
|
expect(client.persistenceEnabled, isFalse);
|
|
expect(client.wsConnectionStatus, ConnectionStatus.connected);
|
|
});
|
|
|
|
tearDown(() {
|
|
client.dispose();
|
|
});
|
|
|
|
group('`.sync`', () {
|
|
test('should work fine', () async {
|
|
const cids = ['test-cid-1', 'test-cid-2', 'test-cid-3'];
|
|
final lastSyncAt = DateTime.now();
|
|
|
|
when(() => api.general.sync(cids, lastSyncAt))
|
|
.thenAnswer((_) async => SyncResponse()
|
|
..events = [
|
|
Event(
|
|
isLocal: false,
|
|
type: EventType.healthCheck,
|
|
connectionId: 'test-connection-id',
|
|
me: OwnUser.fromUser(user),
|
|
),
|
|
Event(
|
|
isLocal: false,
|
|
type: EventType.messageDeleted,
|
|
message: Message(id: 'test-message-id'),
|
|
),
|
|
]);
|
|
|
|
await client.sync(cids: cids, lastSyncAt: lastSyncAt);
|
|
|
|
verify(() => api.general.sync(cids, lastSyncAt)).called(1);
|
|
});
|
|
|
|
test('should return if `cids` is not available', () async {
|
|
expect(client.sync, returnsNormally);
|
|
verifyNever(() => api.general.sync(any(), any()));
|
|
});
|
|
|
|
test('should return if `lastSyncAt` is not available', () async {
|
|
expect(() => client.sync(cids: ['test-cid-1']), returnsNormally);
|
|
verifyNever(() => api.general.sync(any(), any()));
|
|
});
|
|
});
|
|
|
|
group('`.queryChannels`', () {
|
|
test('should work fine without persistent channels', () async {
|
|
final channelStates = List.generate(
|
|
3,
|
|
(index) => ChannelState(
|
|
channel: ChannelModel(cid: 'test-type-$index:test-id-$index'),
|
|
),
|
|
);
|
|
|
|
when(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).thenAnswer(
|
|
(_) async => QueryChannelsResponse()..channels = channelStates,
|
|
);
|
|
|
|
expectLater(
|
|
client.queryChannels(),
|
|
emitsInOrder([channelStates.map(isCorrectChannelFor)]),
|
|
);
|
|
|
|
// Hack as `teardown` gets called even
|
|
// before our stream starts emitting data
|
|
await delay(300);
|
|
|
|
verify(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).called(1);
|
|
});
|
|
|
|
test(
|
|
'''should rethrow if `.queryChannelsOnline` throws and persistence channels are empty''',
|
|
() async {
|
|
when(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).thenThrow(StreamChatNetworkError(ChatErrorCode.inputError));
|
|
|
|
expectLater(
|
|
client.queryChannels(),
|
|
emitsError(isA<StreamChatNetworkError>()),
|
|
);
|
|
|
|
// Hack as `teardown` gets called even
|
|
// before our stream starts emitting data
|
|
await delay(300);
|
|
|
|
verify(() => api.channel.queryChannels(
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
memberLimit: any(named: 'memberLimit'),
|
|
messageLimit: any(named: 'messageLimit'),
|
|
paginationParams: any(named: 'paginationParams'),
|
|
)).called(1);
|
|
},
|
|
);
|
|
});
|
|
|
|
test('`.queryUsers`', () async {
|
|
final users = List.generate(
|
|
3,
|
|
(index) => User(id: 'test-user-id-$index'),
|
|
);
|
|
|
|
when(() => api.user.queryUsers(
|
|
presence: any(named: 'presence'),
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
pagination: any(named: 'pagination'),
|
|
)).thenAnswer((_) async => QueryUsersResponse()..users = users);
|
|
|
|
expectLater(
|
|
// skipping initial seed event -> {} users
|
|
client.state.usersStream.skip(1),
|
|
emitsInOrder([
|
|
{for (var user in users) user.id: user},
|
|
]),
|
|
);
|
|
|
|
final res = await client.queryUsers();
|
|
expect(res, isNotNull);
|
|
expect(res.users.length, users.length);
|
|
|
|
verify(() => api.user.queryUsers(
|
|
presence: any(named: 'presence'),
|
|
filter: any(named: 'filter'),
|
|
sort: any(named: 'sort'),
|
|
pagination: any(named: 'pagination'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.user);
|
|
});
|
|
|
|
test('`.search`', () async {
|
|
const cid = 'test-type:test-id';
|
|
final filter = Filter.in_('cid', const [cid]);
|
|
|
|
final messages = List.generate(
|
|
3,
|
|
(index) => GetMessageResponse()
|
|
..channel = ChannelModel(cid: cid)
|
|
..message = Message(id: 'test-message-id-$index'),
|
|
);
|
|
|
|
when(() => api.general.searchMessages(filter,
|
|
query: any(named: 'query'),
|
|
sort: any(named: 'sort'),
|
|
pagination: any(named: 'pagination'),
|
|
messageFilters: any(named: 'messageFilters')))
|
|
.thenAnswer(
|
|
(_) async => SearchMessagesResponse()..results = messages);
|
|
|
|
final res = await client.search(filter);
|
|
expect(res, isNotNull);
|
|
expect(res.results.length, messages.length);
|
|
|
|
verify(() => api.general.searchMessages(filter,
|
|
query: any(named: 'query'),
|
|
sort: any(named: 'sort'),
|
|
pagination: any(named: 'pagination'),
|
|
messageFilters: any(named: 'messageFilters'))).called(1);
|
|
verifyNoMoreInteractions(api.general);
|
|
});
|
|
|
|
test('`.sendFile`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
final file = AttachmentFile(size: 33, path: 'test-file-path');
|
|
|
|
const fileUrl = 'test-file-url';
|
|
|
|
when(() => api.fileUploader.sendFile(file, channelId, channelType))
|
|
.thenAnswer((_) async => SendFileResponse()..file = fileUrl);
|
|
|
|
final res = await client.sendFile(file, channelId, channelType);
|
|
expect(res, isNotNull);
|
|
expect(res.file, fileUrl);
|
|
|
|
verify(() => api.fileUploader.sendFile(file, channelId, channelType))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.fileUploader);
|
|
});
|
|
|
|
test('`.sendImage`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
final image = AttachmentFile(size: 33, path: 'test-image-path');
|
|
|
|
const fileUrl = 'test-image-url';
|
|
|
|
when(() => api.fileUploader.sendImage(image, channelId, channelType))
|
|
.thenAnswer((_) async => SendImageResponse()..file = fileUrl);
|
|
|
|
final res = await client.sendImage(image, channelId, channelType);
|
|
expect(res, isNotNull);
|
|
expect(res.file, fileUrl);
|
|
|
|
verify(() => api.fileUploader.sendImage(image, channelId, channelType))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.fileUploader);
|
|
});
|
|
|
|
test('`.deleteFile`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
const fileUrl = 'test-file-url';
|
|
|
|
when(() => api.fileUploader.deleteFile(fileUrl, channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.deleteFile(fileUrl, channelId, channelType);
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.fileUploader.deleteFile(fileUrl, channelId, channelType))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.fileUploader);
|
|
});
|
|
|
|
test('`.deleteImage`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
const imageUrl = 'test-image-url';
|
|
|
|
when(() => api.fileUploader.deleteImage(imageUrl, channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.deleteImage(imageUrl, channelId, channelType);
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.fileUploader.deleteImage(imageUrl, channelId, channelType),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.fileUploader);
|
|
});
|
|
|
|
test('`.updateChannel`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
const data = {'name': 'test-channel'};
|
|
|
|
when(() => api.channel.updateChannel(channelId, channelType, data))
|
|
.thenAnswer((invocation) async => UpdateChannelResponse()
|
|
..channel = ChannelModel(
|
|
id: channelId,
|
|
type: channelType,
|
|
extraData: {...data},
|
|
));
|
|
|
|
final res = await client.updateChannel(channelId, channelType, data);
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, '$channelType:$channelId');
|
|
expect(res.channel.extraData['name'], 'test-channel');
|
|
|
|
verify(() => api.channel.updateChannel(channelId, channelType, data))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.updateChannelPartial`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
const set = {
|
|
'name': 'Stream Team',
|
|
'profile_image': 'test-profile-image',
|
|
};
|
|
const unset = ['tag', 'last_name'];
|
|
|
|
when(() => api.channel.updateChannelPartial(channelId, channelType,
|
|
set: set, unset: unset))
|
|
.thenAnswer((invocation) async => PartialUpdateChannelResponse()
|
|
..channel = ChannelModel(
|
|
id: channelId,
|
|
type: channelType,
|
|
extraData: {...set},
|
|
));
|
|
|
|
final res = await client.updateChannelPartial(
|
|
channelId,
|
|
channelType,
|
|
set: set,
|
|
unset: unset,
|
|
);
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, '$channelType:$channelId');
|
|
expect(res.channel.extraData, set);
|
|
|
|
verify(() => api.channel.updateChannelPartial(channelId, channelType,
|
|
set: set, unset: unset)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.addDevice`', () async {
|
|
const id = 'test-device-id';
|
|
const provider = PushProvider.firebase;
|
|
|
|
when(() => api.device.addDevice(id, provider))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.addDevice(id, provider);
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.device.addDevice(id, provider)).called(1);
|
|
verifyNoMoreInteractions(api.device);
|
|
});
|
|
|
|
test('`.getDevices`', () async {
|
|
final devices = List.generate(
|
|
3,
|
|
(index) => Device(
|
|
id: 'test-device-id-$index',
|
|
pushProvider: PushProvider.firebase.name,
|
|
),
|
|
);
|
|
|
|
when(() => api.device.getDevices())
|
|
.thenAnswer((_) async => ListDevicesResponse()..devices = devices);
|
|
|
|
final res = await client.getDevices();
|
|
expect(res, isNotNull);
|
|
expect(res.devices.length, devices.length);
|
|
|
|
verify(() => api.device.getDevices()).called(1);
|
|
verifyNoMoreInteractions(api.device);
|
|
});
|
|
|
|
test('`.removeDevice`', () async {
|
|
const deviceId = 'test-device-id';
|
|
|
|
when(() => api.device.removeDevice(deviceId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.removeDevice(deviceId);
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.device.removeDevice(deviceId)).called(1);
|
|
verifyNoMoreInteractions(api.device);
|
|
});
|
|
|
|
test('`.devToken`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
final token = client.devToken(userId);
|
|
|
|
expect(token, isNotNull);
|
|
expect(token.userId, userId);
|
|
expect(token.authType, AuthType.jwt);
|
|
});
|
|
|
|
group('`.channel`', () {
|
|
test('should return back a new channel instance', () {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelData = {'name': 'test-channel-name'};
|
|
|
|
final channel = client.channel(
|
|
channelType,
|
|
id: channelId,
|
|
extraData: channelData,
|
|
);
|
|
|
|
expect(channel, isNotNull);
|
|
expect(channel.type, channelType);
|
|
expect(channel.id, channelId);
|
|
expect(channel.cid, '$channelType:$channelId');
|
|
expect(channel.extraData, channelData);
|
|
});
|
|
|
|
test('should return back in memory channel instance if available',
|
|
() async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelData = {'name': 'test-channel-name'};
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final channel = client.channel(
|
|
channelType,
|
|
id: channelId,
|
|
extraData: channelData,
|
|
);
|
|
|
|
final channelState = ChannelState(
|
|
channel: ChannelModel(cid: channelCid),
|
|
);
|
|
|
|
when(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).thenAnswer((_) async => channelState);
|
|
|
|
expectLater(
|
|
client.state.channelsStream.skip(1),
|
|
emitsInOrder([
|
|
{channelCid: isCorrectChannelFor(channelState)}
|
|
]),
|
|
);
|
|
|
|
await channel.watch();
|
|
|
|
final newChannel = client.channel(channelType, id: channelId);
|
|
expect(newChannel, channel);
|
|
|
|
verify(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).called(1);
|
|
});
|
|
});
|
|
|
|
test('`.createChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelData = {'name': 'test-channel-name'};
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final channelState = ChannelState(
|
|
channel: ChannelModel(cid: channelCid, extraData: channelData),
|
|
);
|
|
|
|
when(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).thenAnswer((_) async => channelState);
|
|
|
|
final res = await client.createChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.channel, isNotNull);
|
|
final channel = res.channel!;
|
|
expect(channel.type, channelType);
|
|
expect(channel.id, channelId);
|
|
expect(channel.cid, '$channelType:$channelId');
|
|
expect(channel.extraData, channelData);
|
|
|
|
verify(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.watchChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelData = {'name': 'test-channel-name'};
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final channelState = ChannelState(
|
|
channel: ChannelModel(cid: channelCid, extraData: channelData),
|
|
);
|
|
|
|
when(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).thenAnswer((_) async => channelState);
|
|
|
|
final res = await client.watchChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.channel, isNotNull);
|
|
final channel = res.channel!;
|
|
expect(channel.type, channelType);
|
|
expect(channel.id, channelId);
|
|
expect(channel.cid, '$channelType:$channelId');
|
|
expect(channel.extraData, channelData);
|
|
|
|
verify(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.queryChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelData = {'name': 'test-channel-name'};
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final channelState = ChannelState(
|
|
channel: ChannelModel(cid: channelCid, extraData: channelData),
|
|
);
|
|
|
|
when(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).thenAnswer((_) async => channelState);
|
|
|
|
final res = await client.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.channel, isNotNull);
|
|
final channel = res.channel!;
|
|
expect(channel.type, channelType);
|
|
expect(channel.id, channelId);
|
|
expect(channel.cid, '$channelType:$channelId');
|
|
expect(channel.extraData, channelData);
|
|
|
|
verify(() => api.channel.queryChannel(
|
|
channelType,
|
|
channelId: channelId,
|
|
channelData: channelData,
|
|
state: any(named: 'state'),
|
|
watch: any(named: 'watch'),
|
|
presence: any(named: 'presence'),
|
|
messagesPagination: any(named: 'messagesPagination'),
|
|
membersPagination: any(named: 'membersPagination'),
|
|
watchersPagination: any(named: 'watchersPagination'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.queryMembers`', () async {
|
|
const channelType = 'test-channel-type';
|
|
|
|
final members = List.generate(
|
|
3,
|
|
(index) => Member(userId: 'test-user-id-$index'),
|
|
);
|
|
|
|
when(() => api.general.queryMembers(channelType)).thenAnswer(
|
|
(_) async => QueryMembersResponse()..members = members,
|
|
);
|
|
|
|
final res = await client.queryMembers(channelType);
|
|
expect(res, isNotNull);
|
|
expect(res.members.length, members.length);
|
|
|
|
verify(() => api.general.queryMembers(channelType)).called(1);
|
|
verifyNoMoreInteractions(api.general);
|
|
});
|
|
|
|
test('`.hideChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
|
|
when(() => api.channel.hideChannel(channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.hideChannel(channelId, channelType);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.hideChannel(channelId, channelType)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.showChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
|
|
when(() => api.channel.showChannel(channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.showChannel(channelId, channelType);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.showChannel(channelId, channelType)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.deleteChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
|
|
when(() => api.channel.deleteChannel(channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.deleteChannel(channelId, channelType);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.deleteChannel(channelId, channelType)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.truncateChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
|
|
when(() => api.channel.truncateChannel(channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.truncateChannel(channelId, channelType);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.channel.truncateChannel(channelId, channelType),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.muteChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
when(() => api.moderation.muteChannel(channelCid))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.muteChannel(channelCid);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.muteChannel(channelCid)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.unmuteChannel`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
when(() => api.moderation.unmuteChannel(channelCid))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.unmuteChannel(channelCid);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.unmuteChannel(channelCid)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.acceptChannelInvite`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
when(() => api.channel.acceptChannelInvite(channelId, channelType))
|
|
.thenAnswer((_) async =>
|
|
AcceptInviteResponse()..channel = ChannelModel(cid: channelCid));
|
|
|
|
final res = await client.acceptChannelInvite(channelId, channelType);
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, channelCid);
|
|
|
|
verify(() => api.channel.acceptChannelInvite(channelId, channelType))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.rejectChannelInvite`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
when(() => api.channel.rejectChannelInvite(channelId, channelType))
|
|
.thenAnswer((_) async =>
|
|
RejectInviteResponse()..channel = ChannelModel(cid: channelCid));
|
|
|
|
final res = await client.rejectChannelInvite(channelId, channelType);
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, channelCid);
|
|
|
|
verify(() => api.channel.rejectChannelInvite(channelId, channelType))
|
|
.called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.addChannelMembers`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final members = List.generate(
|
|
3,
|
|
(index) => Member(userId: 'test-user-id-$index'),
|
|
);
|
|
|
|
final memberIds = members.map((e) => e.userId!).toList(growable: false);
|
|
|
|
when(() => api.channel.addMembers(channelId, channelType, memberIds))
|
|
.thenAnswer((_) async => AddMembersResponse()
|
|
..channel = ChannelModel(cid: channelCid)
|
|
..members = members);
|
|
|
|
final res = await client.addChannelMembers(
|
|
channelId,
|
|
channelType,
|
|
memberIds,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, channelCid);
|
|
expect(res.members.length, memberIds.length);
|
|
|
|
verify(
|
|
() => api.channel.addMembers(channelId, channelType, memberIds),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.removeChannelMembers`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final members = List.generate(
|
|
3,
|
|
(index) => Member(userId: 'test-user-id-$index'),
|
|
);
|
|
|
|
final memberIds = members.map((e) => e.userId!).toList(growable: false);
|
|
|
|
when(() => api.channel.removeMembers(channelId, channelType, memberIds))
|
|
.thenAnswer((_) async => RemoveMembersResponse()
|
|
..channel = ChannelModel(cid: channelCid)
|
|
..members = members);
|
|
|
|
final res = await client.removeChannelMembers(
|
|
channelId,
|
|
channelType,
|
|
memberIds,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, channelCid);
|
|
expect(res.members.length, memberIds.length);
|
|
|
|
verify(
|
|
() => api.channel.removeMembers(channelId, channelType, memberIds),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.inviteChannelMembers`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const channelCid = '$channelType:$channelId';
|
|
|
|
final members = List.generate(
|
|
3,
|
|
(index) => Member(userId: 'test-user-id-$index'),
|
|
);
|
|
|
|
final memberIds = members.map((e) => e.userId!).toList(growable: false);
|
|
|
|
when(() => api.channel
|
|
.inviteChannelMembers(channelId, channelType, memberIds))
|
|
.thenAnswer((_) async => InviteMembersResponse()
|
|
..channel = ChannelModel(cid: channelCid)
|
|
..members = members);
|
|
|
|
final res = await client.inviteChannelMembers(
|
|
channelId,
|
|
channelType,
|
|
memberIds,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.channel.cid, channelCid);
|
|
expect(res.members.length, memberIds.length);
|
|
|
|
verify(() => api.channel
|
|
.inviteChannelMembers(channelId, channelType, memberIds)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.stopChannelWatching`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
|
|
when(() => api.channel.stopWatching(channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.stopChannelWatching(channelId, channelType);
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.stopWatching(channelId, channelType)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.sendAction`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
const messageId = 'test-message-id';
|
|
const formData = {'key': 'value'};
|
|
|
|
when(() => api.message
|
|
.sendAction(channelId, channelType, messageId, formData))
|
|
.thenAnswer((_) async => SendActionResponse());
|
|
|
|
final res = await client.sendAction(
|
|
channelId,
|
|
channelType,
|
|
messageId,
|
|
formData,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.message
|
|
.sendAction(channelId, channelType, messageId, formData)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.markChannelRead`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
|
|
when(() => api.channel.markRead(channelId, channelType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.markChannelRead(channelId, channelType);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.markRead(channelId, channelType)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.updateUser`', () async {
|
|
final user = User(
|
|
id: 'test-user-id',
|
|
extraData: const {'name': 'test-user'},
|
|
);
|
|
|
|
when(() => api.user.updateUsers([user])).thenAnswer(
|
|
(_) async => UpdateUsersResponse()..users = {user.id: user});
|
|
|
|
final res = await client.updateUser(user);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.users, {user.id: user});
|
|
|
|
verify(() => api.user.updateUsers([user])).called(1);
|
|
verifyNoMoreInteractions(api.user);
|
|
});
|
|
|
|
test('`.banUser`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
when(() => api.moderation.banUser(userId, options: any(named: 'options')))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.banUser(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.moderation.banUser(userId, options: any(named: 'options')),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.unbanUser`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
when(() =>
|
|
api.moderation.unbanUser(userId, options: any(named: 'options')))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.unbanUser(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.moderation.unbanUser(userId, options: any(named: 'options')),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.shadowBan`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
when(() => api.moderation.banUser(userId, options: {'shadow': true}))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.shadowBan(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.moderation.banUser(userId, options: {'shadow': true}),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.removeShadowBan`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
when(() => api.moderation.unbanUser(userId, options: {'shadow': true}))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.removeShadowBan(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.moderation.unbanUser(userId, options: {'shadow': true}),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.muteUser`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
when(() => api.moderation.muteUser(userId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.muteUser(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.muteUser(userId)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.unmuteUser`', () async {
|
|
const userId = 'test-user-id';
|
|
|
|
when(() => api.moderation.unmuteUser(userId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.unmuteUser(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.unmuteUser(userId)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.flagMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
|
|
when(() => api.moderation.flagMessage(messageId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.flagMessage(messageId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.flagMessage(messageId)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.unflagMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
|
|
when(() => api.moderation.unflagMessage(messageId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.unflagMessage(messageId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.unflagMessage(messageId)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.flagUser`', () async {
|
|
const userId = 'test-message-id';
|
|
|
|
when(() => api.moderation.flagUser(userId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.flagUser(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.flagUser(userId)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.unflagUser`', () async {
|
|
const userId = 'test-message-id';
|
|
|
|
when(() => api.moderation.unflagUser(userId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.unflagUser(userId);
|
|
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.moderation.unflagUser(userId)).called(1);
|
|
verifyNoMoreInteractions(api.moderation);
|
|
});
|
|
|
|
test('`.markAllRead`', () async {
|
|
when(() => api.channel.markAllRead())
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.markAllRead();
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.markAllRead()).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.sendEvent`', () async {
|
|
const channelType = 'test-channel-type';
|
|
const channelId = 'test-channel-id';
|
|
final event = Event(type: EventType.any);
|
|
|
|
when(
|
|
() => api.channel.sendEvent(
|
|
channelId,
|
|
channelType,
|
|
any(that: isSameEventAs(event)),
|
|
),
|
|
).thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.sendEvent(channelId, channelType, event);
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.channel.sendEvent(
|
|
channelId,
|
|
channelType,
|
|
any(that: isSameEventAs(event)),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.channel);
|
|
});
|
|
|
|
test('`.sendReaction`', () async {
|
|
const messageId = 'test-message-id';
|
|
const reactionType = 'like';
|
|
|
|
when(() => api.message.sendReaction(messageId, reactionType))
|
|
.thenAnswer((_) async => SendReactionResponse()
|
|
..message = Message(id: messageId)
|
|
..reaction = Reaction(type: reactionType, messageId: messageId));
|
|
|
|
final res = await client.sendReaction(messageId, reactionType);
|
|
expect(res, isNotNull);
|
|
expect(res.message.id, messageId);
|
|
expect(res.reaction.type, reactionType);
|
|
expect(res.reaction.messageId, messageId);
|
|
|
|
verify(() => api.message.sendReaction(messageId, reactionType)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.deleteReaction`', () async {
|
|
const messageId = 'test-message-id';
|
|
const reactionType = 'like';
|
|
|
|
when(() => api.message.deleteReaction(messageId, reactionType))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.deleteReaction(messageId, reactionType);
|
|
expect(res, isNotNull);
|
|
|
|
verify(
|
|
() => api.message.deleteReaction(messageId, reactionType),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.sendMessage`', () async {
|
|
final message = Message(id: 'test-message-id');
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
|
|
when(() => api.message.sendMessage(
|
|
channelId, channelType, any(that: isSameMessageAs(message))))
|
|
.thenAnswer((_) async => SendMessageResponse()..message = message);
|
|
|
|
final res = await client.sendMessage(message, channelId, channelType);
|
|
expect(res, isNotNull);
|
|
expect(res.message, isSameMessageAs(message));
|
|
|
|
verify(() => api.message.sendMessage(
|
|
channelId,
|
|
channelType,
|
|
any(that: isSameMessageAs(message)),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.getReplies`', () async {
|
|
const parentId = 'test-parent-id';
|
|
|
|
final messages = List.generate(
|
|
3,
|
|
(index) => Message(id: 'test-message-id-$index'),
|
|
);
|
|
|
|
when(() => api.message.getReplies(parentId))
|
|
.thenAnswer((_) async => QueryRepliesResponse()..messages = messages);
|
|
|
|
final res = await client.getReplies(parentId);
|
|
expect(res, isNotNull);
|
|
expect(res.messages.length, messages.length);
|
|
|
|
verify(() => api.message.getReplies(parentId)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.getReactions`', () async {
|
|
const messageId = 'test-parent-id';
|
|
|
|
final reactions = List.generate(
|
|
3,
|
|
(index) => Reaction(
|
|
type: 'test-reactions-type-$index',
|
|
messageId: messageId,
|
|
),
|
|
);
|
|
|
|
when(() => api.message.getReactions(messageId)).thenAnswer(
|
|
(_) async => QueryReactionsResponse()..reactions = reactions);
|
|
|
|
final res = await client.getReactions(messageId);
|
|
expect(res, isNotNull);
|
|
expect(res.reactions.length, reactions.length);
|
|
expect(res.reactions.every((it) => it.messageId == messageId), isTrue);
|
|
|
|
verify(() => api.message.getReactions(messageId)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.updateMessage`', () async {
|
|
final message = Message(id: 'test-message-id', text: 'Hello!');
|
|
|
|
when(() => api.message.updateMessage(any(that: isSameMessageAs(message))))
|
|
.thenAnswer((_) async => UpdateMessageResponse()..message = message);
|
|
|
|
final res = await client.updateMessage(message);
|
|
expect(res, isNotNull);
|
|
expect(res.message, isSameMessageAs(message));
|
|
|
|
verify(
|
|
() => api.message.updateMessage(any(that: isSameMessageAs(message))),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.deleteMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
|
|
when(() => api.message.deleteMessage(messageId))
|
|
.thenAnswer((_) async => EmptyResponse());
|
|
|
|
final res = await client.deleteMessage(messageId);
|
|
expect(res, isNotNull);
|
|
|
|
verify(() => api.message.deleteMessage(messageId)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.getMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
final message = Message(id: messageId);
|
|
|
|
when(() => api.message.getMessage(messageId))
|
|
.thenAnswer((_) async => GetMessageResponse()..message = message);
|
|
|
|
final res = await client.getMessage(messageId);
|
|
expect(res, isNotNull);
|
|
expect(res.message.id, messageId);
|
|
|
|
verify(() => api.message.getMessage(messageId)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.getMessagesById`', () async {
|
|
const channelId = 'test-channel-id';
|
|
const channelType = 'test-channel-type';
|
|
const messageIds = ['test-message-id'];
|
|
|
|
final messages = messageIds.map((id) => Message(id: id)).toList();
|
|
|
|
when(
|
|
() => api.message.getMessagesById(channelId, channelType, messageIds),
|
|
).thenAnswer((_) async => GetMessagesByIdResponse()..messages = messages);
|
|
|
|
final res = await client.getMessagesById(
|
|
channelId,
|
|
channelType,
|
|
messageIds,
|
|
);
|
|
expect(res, isNotNull);
|
|
expect(res.messages.length, messageIds.length);
|
|
|
|
verify(
|
|
() => api.message.getMessagesById(channelId, channelType, messageIds),
|
|
).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.translateMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
const language = 'hi'; // Hindi
|
|
const translatedMessageText = 'नमस्ते';
|
|
final translatedMessage = Message(
|
|
i18n: const {
|
|
language: translatedMessageText,
|
|
},
|
|
);
|
|
|
|
when(() => api.message.translateMessage(messageId, language)).thenAnswer(
|
|
(_) async => TranslateMessageResponse()..message = translatedMessage,
|
|
);
|
|
|
|
final res = await client.translateMessage(messageId, language);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.message.i18n, translatedMessage.i18n);
|
|
|
|
verify(() => api.message.translateMessage(messageId, language)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test('`.partialUpdateMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
final message = Message(id: messageId);
|
|
|
|
const set = {'text': 'Update Message text'};
|
|
const unset = ['pinExpires'];
|
|
|
|
final updateMessageResponse = UpdateMessageResponse()
|
|
..message = message.copyWith(text: set['text'], pinExpires: null);
|
|
|
|
when(() => api.message.partialUpdateMessage(
|
|
message.id,
|
|
set: set,
|
|
unset: unset,
|
|
)).thenAnswer((_) async => updateMessageResponse);
|
|
|
|
final res = await client.partialUpdateMessage(
|
|
messageId,
|
|
set: set,
|
|
unset: unset,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.message.id, message.id);
|
|
expect(res.message.id, message.id);
|
|
expect(res.message.text, set['text']);
|
|
expect(res.message.pinExpires, isNull);
|
|
|
|
verify(() => api.message.partialUpdateMessage(
|
|
message.id,
|
|
set: set,
|
|
unset: unset,
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
group('`.pinMessage`', () {
|
|
test('should work fine without passing timeoutOrExpirationDate',
|
|
() async {
|
|
const messageId = 'test-message-id';
|
|
final message = Message(id: messageId);
|
|
|
|
when(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: any(named: 'set'),
|
|
unset: any(named: 'unset'),
|
|
)).thenAnswer((_) async => UpdateMessageResponse()
|
|
..message = message.copyWith(
|
|
pinned: true,
|
|
pinExpires: null,
|
|
status: MessageSendingStatus.sent,
|
|
));
|
|
|
|
final res = await client.pinMessage(messageId);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.message.pinned, isTrue);
|
|
expect(res.message.pinExpires, isNull);
|
|
|
|
verify(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: any(named: 'set'),
|
|
unset: any(named: 'unset'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
|
|
test(
|
|
'should work fine if passed timeoutOrExpirationDate as num(seconds)',
|
|
() async {
|
|
const messageId = 'test-message-id';
|
|
final message = Message(id: messageId);
|
|
const timeoutOrExpirationDate = 300; // 300 seconds
|
|
|
|
when(() => api.message.partialUpdateMessage(
|
|
message.id,
|
|
set: any(named: 'set'),
|
|
unset: any(named: 'unset'),
|
|
)).thenAnswer((_) async => UpdateMessageResponse()
|
|
..message = message.copyWith(
|
|
pinned: true,
|
|
pinExpires: DateTime.now().add(
|
|
const Duration(seconds: timeoutOrExpirationDate),
|
|
),
|
|
status: MessageSendingStatus.sent,
|
|
));
|
|
|
|
final res = await client.pinMessage(
|
|
messageId,
|
|
timeoutOrExpirationDate: timeoutOrExpirationDate,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.message.pinned, isTrue);
|
|
expect(res.message.pinExpires, isNotNull);
|
|
|
|
verify(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: any(named: 'set'),
|
|
unset: any(named: 'unset'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'should work fine if passed timeoutOrExpirationDate as DateTime',
|
|
() async {
|
|
const messageId = 'test-message-id';
|
|
final message = Message(id: messageId);
|
|
final timeoutOrExpirationDate =
|
|
DateTime.now().add(const Duration(days: 3)); // 3 days
|
|
|
|
when(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: any(named: 'set'),
|
|
unset: any(named: 'unset'),
|
|
)).thenAnswer((_) async => UpdateMessageResponse()
|
|
..message = message.copyWith(
|
|
pinned: true,
|
|
pinExpires: timeoutOrExpirationDate,
|
|
status: MessageSendingStatus.sent,
|
|
));
|
|
|
|
final res = await client.pinMessage(
|
|
messageId,
|
|
timeoutOrExpirationDate: timeoutOrExpirationDate,
|
|
);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.message.pinned, isTrue);
|
|
expect(res.message.pinExpires, isNotNull);
|
|
expect(res.message.pinExpires, timeoutOrExpirationDate.toUtc());
|
|
|
|
verify(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: any(named: 'set'),
|
|
unset: any(named: 'unset'),
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'should throw if invalid timeoutOrExpirationDate is passed',
|
|
() async {
|
|
const messageId = 'test-message-id';
|
|
const timeoutOrExpirationDate = 'invalid-value';
|
|
|
|
try {
|
|
await client.pinMessage(
|
|
messageId,
|
|
timeoutOrExpirationDate: timeoutOrExpirationDate,
|
|
);
|
|
} catch (e) {
|
|
expect(e, isA<ArgumentError>());
|
|
}
|
|
},
|
|
);
|
|
});
|
|
|
|
test('`.unpinMessage`', () async {
|
|
const messageId = 'test-message-id';
|
|
final message = Message(id: messageId, pinned: true);
|
|
|
|
when(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: {'pinned': false},
|
|
)).thenAnswer((_) async => UpdateMessageResponse()
|
|
..message = message.copyWith(
|
|
pinned: false,
|
|
status: MessageSendingStatus.sent,
|
|
));
|
|
|
|
final res = await client.unpinMessage(messageId);
|
|
|
|
expect(res, isNotNull);
|
|
expect(res.message.pinned, isFalse);
|
|
|
|
verify(() => api.message.partialUpdateMessage(
|
|
messageId,
|
|
set: {'pinned': false},
|
|
)).called(1);
|
|
verifyNoMoreInteractions(api.message);
|
|
});
|
|
});
|
|
}
|