add core/api tests

Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
Sahil Kumar
2021-06-08 16:09:17 +05:30
parent bdfbc27917
commit 89f989003d
35 changed files with 1788 additions and 56 deletions
@@ -0,0 +1,136 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/attachment_file_uploader.dart';
import 'package:stream_chat/src/core/models/attachment_file.dart';
import 'package:test/test.dart';
import '../../fakes.dart';
import '../../matchers.dart';
import '../../mocks.dart';
import '../../utils.dart';
void main() {
late final client = MockHttpClient();
late StreamAttachmentFileUploader fileUploader;
setUp(() {
fileUploader = StreamAttachmentFileUploader(client);
registerFallbackValue<MultipartFile>(FakeMultiPartFile());
});
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
test('sendImage', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const path = '/channels/$channelType/$channelId/image';
final file = assetFile('test_image.jpeg');
final attachmentFile = AttachmentFile(
size: 333,
path: file.path,
bytes: file.readAsBytesSync(),
);
final multipartFile = await attachmentFile.toMultipartFile();
when(() => client.postFile(
path,
any(that: isSameMultipartFileAs(multipartFile)),
)).thenAnswer((_) async => successResponse(path, data: {
'file': 'test-file-url',
}));
final res = await fileUploader.sendImage(
attachmentFile,
channelId,
channelType,
);
expect(res, isNotNull);
expect(res.file, isNotNull);
expect(res.file, isNotEmpty);
verify(() => client.postFile(
path,
any(that: isSameMultipartFileAs(multipartFile)),
)).called(1);
verifyNoMoreInteractions(client);
});
test('sendFile', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const path = '/channels/$channelType/$channelId/file';
final file = assetFile('example.pdf');
final attachmentFile = AttachmentFile(
size: 333,
path: file.path,
bytes: file.readAsBytesSync(),
);
final multipartFile = await attachmentFile.toMultipartFile();
when(() => client.postFile(
path,
any(that: isSameMultipartFileAs(multipartFile)),
)).thenAnswer((_) async => successResponse(path, data: {
'file': 'test-file-url',
}));
final res = await fileUploader.sendFile(
attachmentFile,
channelId,
channelType,
);
expect(res, isNotNull);
expect(res.file, isNotNull);
expect(res.file, isNotEmpty);
verify(() => client.postFile(
path,
any(that: isSameMultipartFileAs(multipartFile)),
)).called(1);
verifyNoMoreInteractions(client);
});
test('deleteImage', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const path = '/channels/$channelType/$channelId/image';
const url = 'test-image-url';
when(() => client.delete(path, queryParameters: {'url': url})).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await fileUploader.deleteImage(url, channelId, channelType);
expect(res, isNotNull);
verify(() => client.delete(path, queryParameters: {'url': url})).called(1);
verifyNoMoreInteractions(client);
});
test('deleteFile', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const path = '/channels/$channelType/$channelId/file';
const url = 'test-file-url';
when(() => client.delete(path, queryParameters: {'url': url})).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await fileUploader.deleteFile(url, channelId, channelType);
expect(res, isNotNull);
verify(() => client.delete(path, queryParameters: {'url': url})).called(1);
verifyNoMoreInteractions(client);
});
}
@@ -0,0 +1,492 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/channel_api.dart';
import 'package:stream_chat/src/core/models/channel_model.dart';
import 'package:stream_chat/src/core/models/channel_state.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
String _getChannelUrl(String channelId, String channelType) =>
'/channels/$channelType/$channelId';
ChannelState _generateChannelState(
String channelId,
String channelType,
) {
final channel = ChannelModel(id: channelId, type: channelType);
final messages = List.generate(
3,
(index) => Message(
id: 'test-message-id-$index',
text: 'test-message-text-$index',
),
);
final members = List.generate(
3,
(index) => Member(userId: 'test-user-id-$index'),
);
final reads = List.generate(
3,
(index) => Read(
lastRead: DateTime.now(),
user: User(id: 'test-user-id-$index'),
),
);
final watchers = List.generate(
3,
(index) => User(id: 'test-user-id-$index'),
);
final state = ChannelState(
channel: channel,
messages: messages,
pinnedMessages: messages,
members: members,
read: reads,
watchers: watchers,
watcherCount: watchers.length,
);
return state;
}
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late ChannelApi channelApi;
setUp(() {
channelApi = ChannelApi(client);
});
test('queryChannel', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const channelData = <String, Object>{'name': 'test-channel'};
const messagePagination = PaginationParams();
const membersPagination = PaginationParams();
const watchersPagination = PaginationParams();
const channelPath = '/channels/$channelType/$channelId';
const path = '$channelPath/query';
final channelState = _generateChannelState(channelId, channelType);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(
path,
data: channelState.toJson(),
));
final res = await channelApi.queryChannel(
channelType,
channelId: channelId,
channelData: channelData,
messagesPagination: messagePagination,
membersPagination: membersPagination,
watchersPagination: watchersPagination,
);
expect(res, isNotNull);
expect(res.messages.length, channelState.messages.length);
expect(res.pinnedMessages.length, channelState.pinnedMessages.length);
expect(res.members.length, channelState.members.length);
expect(res.read.length, channelState.read.length);
expect(res.watchers.length, channelState.watchers.length);
expect(res.watcherCount, channelState.watcherCount);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('queryChannels', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final filter = Filter.in_('cid', const ['test-cid']);
const sort = [SortOption<ChannelModel>('test-field')];
const memberLimit = 33;
const messageLimit = 33;
const path = '/channels';
final channelState = _generateChannelState(channelId, channelType);
when(() => client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(
path,
data: {
'channels': [channelState.toJson()]
},
));
final res = await channelApi.queryChannels(
filter: filter,
sort: sort,
memberLimit: memberLimit,
messageLimit: messageLimit,
);
expect(res, isNotNull);
expect(res.channels, isNotEmpty);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
test('markAllRead', () async {
const path = 'channels/read';
when(() => client.post(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.markAllRead();
expect(res, isNotNull);
verify(() => client.post(path)).called(1);
verifyNoMoreInteractions(client);
});
test('updateChannel', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const data = {'name': 'test-channel-name'};
final message = Message(id: 'test-message-id', text: 'channel-updated');
final path = _getChannelUrl(channelId, channelType);
final channelModel = ChannelModel(
id: channelId,
type: channelType,
extraData: data,
);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
'message': message.toJson(),
}));
final res = await channelApi.updateChannel(
channelId,
channelType,
data,
message: message,
);
expect(res, isNotNull);
expect(res.channel.cid, channelModel.cid);
expect(res.message?.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('updateChannelPartial', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const data = {'name': 'test-channel-name'};
final path = _getChannelUrl(channelId, channelType);
final channelModel = ChannelModel(
id: channelId,
type: channelType,
extraData: data,
);
when(() => client.patch(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
}));
final res = await channelApi.updateChannelPartial(
channelId,
channelType,
data,
);
expect(res, isNotNull);
verify(() => client.patch(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('acceptChannelInvite', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final message = Message(id: 'test-message-id', text: 'channel-accepted');
final channelModel = ChannelModel(id: channelId, type: channelType);
final path = _getChannelUrl(channelId, channelType);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
'message': message.toJson(),
}));
final res = await channelApi.acceptChannelInvite(
channelId,
channelType,
message: message,
);
expect(res, isNotNull);
expect(res.channel.cid, channelModel.cid);
expect(res.message?.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('rejectChannelInvite', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final message = Message(id: 'test-message-id', text: 'channel-rejected');
final channelModel = ChannelModel(id: channelId, type: channelType);
final path = _getChannelUrl(channelId, channelType);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
'message': message.toJson(),
}));
final res = await channelApi.rejectChannelInvite(
channelId,
channelType,
message: message,
);
expect(res, isNotNull);
expect(res.channel.cid, channelModel.cid);
expect(res.message?.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('inviteChannelMembers', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const memberIds = ['test-member-id-1', 'test-member-id-2'];
final channelModel = ChannelModel(id: channelId, type: channelType);
final message = Message(id: 'test-message-id', text: 'members-invited');
final path = _getChannelUrl(channelId, channelType);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
'message': message.toJson(),
}));
final res = await channelApi.inviteChannelMembers(
channelId,
channelType,
memberIds,
message: message,
);
expect(res, isNotNull);
expect(res.channel.cid, channelModel.cid);
expect(res.message?.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('addMembers', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const memberIds = ['test-member-id-1', 'test-member-id-2'];
final channelModel = ChannelModel(id: channelId, type: channelType);
final message = Message(id: 'test-message-id', text: 'members-added');
final path = _getChannelUrl(channelId, channelType);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
'message': message.toJson(),
}));
final res = await channelApi.addMembers(
channelId,
channelType,
memberIds,
message: message,
);
expect(res, isNotNull);
expect(res.channel.cid, channelModel.cid);
expect(res.message?.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('removeMembers', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const memberIds = ['test-member-id-1', 'test-member-id-2'];
final channelModel = ChannelModel(id: channelId, type: channelType);
final message = Message(id: 'test-message-id', text: 'members-removed');
final path = _getChannelUrl(channelId, channelType);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'channel': channelModel.toJson(),
'message': message.toJson(),
}));
final res = await channelApi.removeMembers(
channelId,
channelType,
memberIds,
message: message,
);
expect(res, isNotNull);
expect(res.channel.cid, channelModel.cid);
expect(res.message?.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('sendEvent', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final event = Event(type: 'event.test');
final path = '${_getChannelUrl(channelId, channelType)}/event';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.sendEvent(channelId, channelType, event);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('deleteChannel', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final path = _getChannelUrl(channelId, channelType);
when(() => client.delete(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.deleteChannel(channelId, channelType);
expect(res, isNotNull);
verify(() => client.delete(path)).called(1);
verifyNoMoreInteractions(client);
});
test('truncateChannel', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final path = '${_getChannelUrl(channelId, channelType)}/truncate';
when(() => client.post(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.truncateChannel(channelId, channelType);
expect(res, isNotNull);
verify(() => client.post(path)).called(1);
verifyNoMoreInteractions(client);
});
test('hideChannel', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final path = '${_getChannelUrl(channelId, channelType)}/hide';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.hideChannel(channelId, channelType);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('showChannel', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final path = '${_getChannelUrl(channelId, channelType)}/show';
when(() => client.post(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.showChannel(channelId, channelType);
expect(res, isNotNull);
verify(() => client.post(path)).called(1);
verifyNoMoreInteractions(client);
});
test('markRead', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const messageId = 'test-message-id';
final path = '${_getChannelUrl(channelId, channelType)}/read';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.markRead(
channelId,
channelType,
messageId: messageId,
);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('stopWatching', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final path = '${_getChannelUrl(channelId, channelType)}/stop-watching';
when(() => client.post(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.stopWatching(channelId, channelType);
expect(res, isNotNull);
verify(() => client.post(path)).called(1);
verifyNoMoreInteractions(client);
});
}
@@ -0,0 +1,84 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/device_api.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late DeviceApi deviceApi;
setUp(() {
deviceApi = DeviceApi(client);
});
test('addDevice', () async {
const deviceId = 'test-device-id';
const pushProvider = PushProvider.firebase;
const path = '/devices';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await deviceApi.addDevice(deviceId, pushProvider);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('getDevices', () async {
const path = '/devices';
final devices = List.generate(
3,
(index) => Device(
id: 'test-device-id-$index',
pushProvider: PushProvider.firebase.name,
),
);
when(() => client.get(path)).thenAnswer(
(_) async => successResponse(path, data: {
'devices': [...devices.map((it) => it.toJson())]
}),
);
final res = await deviceApi.getDevices();
expect(res, isNotNull);
expect(res.devices.length, devices.length);
verify(() => client.get(path)).called(1);
verifyNoMoreInteractions(client);
});
test('removeDevice', () async {
const deviceId = 'test-device-id';
const path = '/devices';
when(
() => client.delete(path, queryParameters: any(named: 'queryParameters')),
).thenAnswer((_) async => successResponse(path, data: <String, dynamic>{}));
final res = await deviceApi.removeDevice(deviceId);
expect(res, isNotNull);
verify(
() => client.delete(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
}
@@ -0,0 +1,211 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/general_api.dart';
import 'package:stream_chat/src/core/api/requests.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/stream_chat.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late GeneralApi generalApi;
setUp(() {
generalApi = GeneralApi(client);
});
test('sync', () async {
const cids = ['test-cid-1', 'test-cid-2', 'test-cid-3'];
final lastSyncAt = DateTime.now();
const path = '/sync';
final events =
List.generate(3, (index) => Event(type: 'test-event-type-$index'));
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'events': [...events.map((it) => it.toJson())]
}));
final res = await generalApi.sync(cids, lastSyncAt);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
group('searchMessages', () {
test(
'should throw if `query` and `messageFilters` is not provided',
() async {
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
try {
await generalApi.searchMessages(filter);
} catch (e) {
expect(e, isA<ArgumentError>());
}
},
);
test(
'should throw if `query` and `messageFilters` both are provided',
() async {
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
const query = 'test-query';
final messageFilter = Filter.query('key', 'text');
try {
await generalApi.searchMessages(
filter,
query: query,
messageFilters: messageFilter,
);
} catch (e) {
expect(e, isA<ArgumentError>());
}
},
);
test('should run successfully with `query`', () async {
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
const query = 'test-query';
const sort = [SortOption<ChannelModel>('test-field')];
const pagination = PaginationParams();
const path = '/search';
when(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).thenAnswer((_) async => successResponse(path, data: {'results': []}));
final res = await generalApi.searchMessages(
filter,
query: query,
sort: sort,
pagination: pagination,
);
expect(res, isNotNull);
expect(res.results, isEmpty);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
test('should run successfully with `messageFilter`', () async {
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
const sort = [SortOption<ChannelModel>('test-field')];
final messageFilter = Filter.query('key', 'text');
const pagination = PaginationParams();
const path = '/search';
when(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).thenAnswer((_) async => successResponse(path, data: {'results': []}));
final res = await generalApi.searchMessages(
filter,
messageFilters: messageFilter,
sort: sort,
pagination: pagination,
);
expect(res, isNotNull);
expect(res.results, isEmpty);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
});
group('queryMembers', () {
test('with `channelId`', () async {
const channelType = 'test-channel-type';
const channelId = 'test-channel-id';
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
const pagination = PaginationParams();
const sort = [SortOption('test-field')];
const path = '/members';
final members = List.generate(
3,
(index) => Member(userId: 'test-user-id=$index'),
);
when(() =>
client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(path, data: {
'members': [...members.map((it) => it.toJson())]
}));
final res = await generalApi.queryMembers(
channelType,
channelId: channelId,
filter: filter,
pagination: pagination,
sort: sort,
);
expect(res, isNotNull);
expect(res.members.length, members.length);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
test('with `members`', () async {
const channelType = 'test-channel-type';
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
const pagination = PaginationParams();
const sort = [SortOption('test-field')];
const path = '/members';
final members = List.generate(
3,
(index) => Member(userId: 'test-user-id=$index'),
);
when(() =>
client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(path, data: {
'members': [...members.map((it) => it.toJson())]
}));
final res = await generalApi.queryMembers(
channelType,
filter: filter,
pagination: pagination,
sort: sort,
members: members,
);
expect(res, isNotNull);
expect(res.members.length, members.length);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
});
}
@@ -0,0 +1,44 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/guest_api.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late GuestApi guestApi;
setUp(() {
guestApi = GuestApi(client);
});
test('getGuestUser', () async {
const accessToken = 'test-guest-token';
final user = User(id: 'test-user-id');
const path = '/guest';
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'access_token': accessToken,
'user': user.toJson(),
}));
final res = await guestApi.getGuestUser(user);
expect(res, isNotNull);
expect(res.accessToken, accessToken);
expect(res.user.id, user.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
}
@@ -0,0 +1,291 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/message_api.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late MessageApi messageApi;
setUp(() {
messageApi = MessageApi(client);
});
test('sendMessage', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
final message = Message(id: 'test-message-id', text: 'test-message-text');
const path = '/channels/$channelType/$channelId/message';
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'message': message.toJson(),
}));
final res = await messageApi.sendMessage(channelId, channelType, message);
expect(res, isNotNull);
expect(res.message.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('getMessagesById', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const messageIds = ['test-message-id-1', 'test-message-id-2'];
const path = '/channels/$channelType/$channelId/messages';
final messages = List.generate(
3,
(index) => Message(id: 'test-message-id-$index'),
);
when(() => client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(path, data: {
'messages': [...messages.map((it) => it.toJson())],
}));
final res = await messageApi.getMessagesById(
channelId,
channelType,
messageIds,
);
expect(res, isNotNull);
expect(res.messages.length, messages.length);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
test('getMessage', () async {
const messageId = 'test-message-id';
const path = '/messages/$messageId';
final message = Message(id: messageId);
when(() => client.get(path)).thenAnswer((_) async =>
successResponse(path, data: {'message': message.toJson()}));
final res = await messageApi.getMessage(messageId);
expect(res, isNotNull);
expect(res.message.id, messageId);
verify(() => client.get(path)).called(1);
verifyNoMoreInteractions(client);
});
test('updateMessage', () async {
final message = Message(id: 'test-message-id');
final path = '/messages/${message.id}';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: {'message': message.toJson()}),
);
final res = await messageApi.updateMessage(message);
expect(res, isNotNull);
expect(res.message.id, message.id);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('deleteMessage', () async {
const messageId = 'test-message-id';
const path = '/messages/$messageId';
when(() => client.delete(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}),
);
final res = await messageApi.deleteMessage(messageId);
expect(res, isNotNull);
verify(() => client.delete(path)).called(1);
verifyNoMoreInteractions(client);
});
test('sendAction', () async {
const channelId = 'test-channel-id';
const channelType = 'test-channel-type';
const messageId = 'test-message-id';
const formData = {'test-key': 'test-data'};
const path = '/messages/$messageId/action';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await messageApi.sendAction(
channelId,
channelType,
messageId,
formData,
);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('sendReaction', () async {
const messageId = 'test-message-id';
const reactionType = 'test-reaction-type';
const extraData = {'test-key': 'test-data'};
const path = '/messages/$messageId/reaction';
final message = Message(id: messageId);
final reaction = Reaction(type: reactionType, messageId: messageId);
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'message': message.toJson(),
'reaction': reaction.toJson(),
}));
final res = await messageApi.sendReaction(
messageId,
reactionType,
extraData: extraData,
);
expect(res, isNotNull);
expect(res.message.id, messageId);
expect(res.reaction.messageId, messageId);
expect(res.reaction.type, reactionType);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('deleteReaction', () async {
const messageId = 'test-message-id';
const reactionType = 'test-reaction-type';
const path = '/messages/$messageId/reaction/$reactionType';
when(() => client.delete(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await messageApi.deleteReaction(messageId, reactionType);
expect(res, isNotNull);
verify(() => client.delete(path)).called(1);
verifyNoMoreInteractions(client);
});
test('getReactions', () async {
const messageId = 'test-message-id';
const options = PaginationParams();
const path = '/messages/$messageId/reactions';
final reactions = List.generate(
3,
(index) => Reaction(
type: 'test-reaction-type-$index',
messageId: messageId,
),
);
when(() => client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(path, data: {
'reactions': [...reactions.map((it) => it.toJson())]
}));
final res = await messageApi.getReactions(messageId, options);
expect(res, isNotNull);
expect(res.reactions.length, reactions.length);
expect(res.reactions.every((it) => it.messageId == messageId), isTrue);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
test('translateMessage', () async {
const messageId = 'test-message-id';
const messageText = 'hello';
const language = 'hi'; // Hindi
final message = Message(id: messageId, text: messageText);
final path = '/messages/${message.id}/translate';
const translatedMessageText = 'नमस्ते';
final translatedMessage = TranslatedMessage(const {
language: translatedMessageText,
});
when(() => client.post(path, data: any(named: 'data')))
.thenAnswer((_) async => successResponse(path, data: {
'message': translatedMessage.toJson(),
}));
final res = await messageApi.translateMessage(messageId, language);
expect(res, isNotNull);
expect(res.message.i18n?.containsKey(language), isTrue);
expect(res.message.i18n?[language], translatedMessageText);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('getReplies', () async {
const parentId = 'test-parent-id';
const options = PaginationParams();
const path = '/messages/$parentId/replies';
final messages = List.generate(
3,
(index) => Message(
id: 'test-message-id-$index',
parentId: parentId,
),
);
when(() => client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(path, data: {
'messages': [...messages.map((it) => it.toJson())]
}));
final res = await messageApi.getReplies(parentId, options);
expect(res, isNotNull);
expect(res.messages.length, messages.length);
expect(res.messages.every((it) => it.parentId == parentId), isTrue);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
}
@@ -0,0 +1,190 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/moderation_api.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late ModerationApi moderationApi;
setUp(() {
moderationApi = ModerationApi(client);
});
test('muteUser', () async {
const userId = 'test-user-id';
const path = '/moderation/mute';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.muteUser(userId);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('unmuteUser', () async {
const userId = 'test-user-id';
const path = '/moderation/unmute';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.unmuteUser(userId);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('muteChannel', () async {
const channelCid = 'test-channel-cid';
const expiration = Duration(days: 3);
const path = '/moderation/mute/channel';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.muteChannel(
channelCid,
expiration: expiration,
);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('unmuteChannel', () async {
const channelCid = 'test-channel-cid';
const path = '/moderation/unmute/channel';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.unmuteChannel(channelCid);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('flagMessage', () async {
const messageId = 'test-message-id';
const path = '/moderation/flag';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.flagMessage(messageId);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('unflagMessage', () async {
const messageId = 'test-message-id';
const path = '/moderation/unflag';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.unflagMessage(messageId);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('flagUser', () async {
const userId = 'test-message-id';
const path = '/moderation/flag';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.flagUser(userId);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('unflagUser', () async {
const userId = 'test-message-id';
const path = '/moderation/unflag';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.unflagUser(userId);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('banUser', () async {
const targetUserId = 'test-target-user-id';
const options = {'key': 'value'};
const path = '/moderation/ban';
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.banUser(targetUserId, options: options);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
test('unbanUser', () async {
const targetUserId = 'test-target-user-id';
const options = {'key': 'value'};
const path = '/moderation/ban';
when(
() => client.delete(path, queryParameters: any(named: 'queryParameters')),
).thenAnswer((_) async => successResponse(path, data: <String, dynamic>{}));
final res = await moderationApi.unbanUser(targetUserId, options: options);
expect(res, isNotNull);
verify(
() => client.delete(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
}
@@ -0,0 +1,49 @@
import 'package:stream_chat/src/core/api/stream_chat_api.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
const apiKey = 'test-api-key';
late final client = MockHttpClient();
late StreamChatApi streamChatApi;
setUp(() {
streamChatApi = StreamChatApi(
apiKey,
client: client,
);
});
test('`.user`', () {
expect(streamChatApi.user, isNotNull);
});
test('`.guest`', () {
expect(streamChatApi.guest, isNotNull);
});
test('`.message`', () {
expect(streamChatApi.message, isNotNull);
});
test('`.channel`', () {
expect(streamChatApi.channel, isNotNull);
});
test('`.device`', () {
expect(streamChatApi.device, isNotNull);
});
test('`.moderation`', () {
expect(streamChatApi.moderation, isNotNull);
});
test('`.general`', () {
expect(streamChatApi.general, isNotNull);
});
test('`.fileUploader`', () {
expect(streamChatApi.fileUploader, isNotNull);
});
}
@@ -0,0 +1,77 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/requests.dart';
import 'package:stream_chat/src/core/api/user_api.dart';
import 'package:stream_chat/src/core/models/filter.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:test/test.dart';
import '../../mocks.dart';
void main() {
Response successResponse(String path, {Object? data}) => Response(
data: data,
requestOptions: RequestOptions(path: path),
statusCode: 200,
);
late final client = MockHttpClient();
late UserApi userApi;
setUp(() {
userApi = UserApi(client);
});
test('queryUsers', () async {
const presence = true;
final filter = Filter.in_('cid', const ['test-cid-1', 'test-cid-2']);
const sort = [SortOption('test-field')];
const pagination = PaginationParams();
const path = '/users';
final users = List.generate(3, (index) => User(id: 'test-user-id-$index'));
when(() => client.get(path, queryParameters: any(named: 'queryParameters')))
.thenAnswer((_) async => successResponse(path, data: {
'users': [...users.map((it) => it.toJson())]
}));
final res = await userApi.queryUsers(
presence: presence,
filter: filter,
sort: sort,
pagination: pagination,
);
expect(res, isNotNull);
expect(res.users.length, users.length);
verify(
() => client.get(path, queryParameters: any(named: 'queryParameters')),
).called(1);
verifyNoMoreInteractions(client);
});
test('updateUsers', () async {
final users = List.generate(3, (index) => User(id: 'test-user-id-$index'));
const path = '/users';
final updatedUsers = {for (final user in users) user.id: user};
when(() => client.post(path, data: any(named: 'data'))).thenAnswer(
(_) async => successResponse(path, data: {
'users': updatedUsers
.map((key, value) => MapEntry(key, value.toJson()))
}));
final res = await userApi.updateUsers(users);
expect(res, isNotNull);
expect(res.users.length, updatedUsers.length);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client);
});
}
+57
View File
@@ -1,6 +1,18 @@
import 'package:dio/dio.dart';
import 'package:mocktail/mocktail.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/general_api.dart';
import 'package:stream_chat/src/core/api/message_api.dart';
import 'package:stream_chat/src/core/api/moderation_api.dart';
import 'package:stream_chat/src/core/api/stream_chat_api.dart';
import 'package:stream_chat/src/core/api/user_api.dart';
import 'package:stream_chat/src/core/api/guest_api.dart';
import 'package:stream_chat/src/core/http/token.dart';
import 'package:stream_chat/src/core/http/token_manager.dart';
import 'package:stream_chat/stream_chat.dart';
import 'mocks.dart';
class FakeTokenManager extends Fake implements TokenManager {
final token = Token.development('test-user-id');
@@ -25,3 +37,48 @@ class FakeTokenManager extends Fake implements TokenManager {
@override
void reset() {}
}
class FakeMultiPartFile extends Fake implements MultipartFile {}
class FakeChatApi extends Fake implements StreamChatApi {
UserApi? _user;
@override
UserApi get user => _user ??= MockUserApi();
GuestApi? _guest;
@override
GuestApi get guest => _guest ??= MockGuestApi();
MessageApi? _message;
@override
MessageApi get message => _message ??= MockMessageApi();
ChannelApi? _channel;
@override
ChannelApi get channel => _channel ??= MockChannelApi();
DeviceApi? _device;
@override
DeviceApi get device => _device ??= MockDeviceApi();
ModerationApi? _moderation;
@override
ModerationApi get moderation => _moderation ??= MockModerationApi();
GeneralApi? _general;
@override
GeneralApi get general => _general ??= MockGeneralApi();
AttachmentFileUploader? _fileUploader;
@override
AttachmentFileUploader get fileUploader =>
_fileUploader ??= MockAttachmentFileUploader();
}
@@ -0,0 +1,19 @@
import 'package:dio/dio.dart' show MultipartFile;
import 'package:test/test.dart';
Matcher isSameMultipartFileAs(MultipartFile targetFile) =>
_IsSameMultipartFileAs(targetFile: targetFile);
class _IsSameMultipartFileAs extends Matcher {
const _IsSameMultipartFileAs({required this.targetFile});
final MultipartFile targetFile;
@override
Description describe(Description description) =>
description.add('is same multipartFile as $targetFile');
@override
bool matches(covariant MultipartFile file, Map matchState) =>
file.length == targetFile.length;
}
+25
View File
@@ -1,6 +1,14 @@
import 'package:dio/dio.dart';
import 'package:logging/logging.dart';
import 'package:mocktail/mocktail.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/device_api.dart';
import 'package:stream_chat/src/core/api/general_api.dart';
import 'package:stream_chat/src/core/api/guest_api.dart';
import 'package:stream_chat/src/core/api/message_api.dart';
import 'package:stream_chat/src/core/api/moderation_api.dart';
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/stream_http_client.dart';
import 'package:stream_chat/src/core/http/token_manager.dart';
@@ -32,3 +40,20 @@ class MockHttpClient extends Mock implements StreamHttpClient {}
class MockTokenManager extends Mock implements TokenManager {}
class MockConnectionIdManager extends Mock implements ConnectionIdManager {}
class MockUserApi extends Mock implements UserApi {}
class MockGuestApi extends Mock implements GuestApi {}
class MockMessageApi extends Mock implements MessageApi {}
class MockChannelApi extends Mock implements ChannelApi {}
class MockDeviceApi extends Mock implements DeviceApi {}
class MockModerationApi extends Mock implements ModerationApi {}
class MockGeneralApi extends Mock implements GeneralApi {}
class MockAttachmentFileUploader extends Mock
implements AttachmentFileUploader {}
+15
View File
@@ -0,0 +1,15 @@
import 'dart:io';
File assetFile(String name) {
final dir = currentDirectory.path;
return File('$dir/test/assets/$name');
}
// https://github.com/flutter/flutter/issues/20907
Directory get currentDirectory {
var directory = Directory.current;
if (directory.path.endsWith('/test')) {
directory = directory.parent;
}
return directory;
}