2026-10-07 07:32:16 +02:00
|
|
|
import 'dart:convert';
|
|
|
|
|
|
2026-10-07 03:06:05 +02:00
|
|
|
import 'package:dio/dio.dart';
|
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
|
import 'package:frosty/apis/base_api_client.dart';
|
|
|
|
|
import 'package:frosty/apis/twitch_gql_api.dart';
|
|
|
|
|
import 'package:http_mock_adapter/http_mock_adapter.dart';
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
late Dio dio;
|
|
|
|
|
late DioAdapter dioAdapter;
|
|
|
|
|
late TwitchGqlApi api;
|
|
|
|
|
|
|
|
|
|
setUp(() {
|
|
|
|
|
dio = Dio(BaseOptions());
|
|
|
|
|
dioAdapter = DioAdapter(dio: dio);
|
|
|
|
|
api = TwitchGqlApi(dio);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
group('followUser', () {
|
|
|
|
|
test('posts FollowButton_FollowUser persisted mutation', () async {
|
|
|
|
|
dioAdapter.onPost(
|
|
|
|
|
'https://gql.twitch.tv/gql',
|
|
|
|
|
(server) => server.reply(200, {
|
|
|
|
|
'data': {
|
|
|
|
|
'followUser': {
|
|
|
|
|
'follow': {
|
|
|
|
|
'user': {'id': '999', 'displayName': 'Streamer'},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
data: Matchers.any,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await api.followUser(targetId: '999', authToken: 'web-token');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('throws IntegrityCheckException on integrity errors', () async {
|
|
|
|
|
dioAdapter.onPost(
|
|
|
|
|
'https://gql.twitch.tv/gql',
|
|
|
|
|
(server) => server.reply(200, {
|
|
|
|
|
'errors': [
|
|
|
|
|
{'message': 'failed integrity check'},
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
data: Matchers.any,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await expectLater(
|
|
|
|
|
api.followUser(targetId: '999', authToken: 'web-token'),
|
|
|
|
|
throwsA(isA<IntegrityCheckException>()),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
group('unfollowUser', () {
|
|
|
|
|
test('posts FollowButton_UnfollowUser persisted mutation', () async {
|
|
|
|
|
dioAdapter.onPost(
|
|
|
|
|
'https://gql.twitch.tv/gql',
|
|
|
|
|
(server) => server.reply(200, {
|
|
|
|
|
'data': {
|
|
|
|
|
'unfollowUser': {
|
|
|
|
|
'follow': null,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
data: Matchers.any,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await api.unfollowUser(targetId: '999', authToken: 'web-token');
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-10-07 07:32:16 +02:00
|
|
|
|
|
|
|
|
group('fetchIntegrityToken', () {
|
|
|
|
|
test('rejects bad_bot tokens', () async {
|
|
|
|
|
final payload = base64Url.encode(
|
|
|
|
|
utf8.encode(
|
|
|
|
|
jsonEncode({
|
|
|
|
|
'is_bad_bot': 'true',
|
|
|
|
|
'device_id': 'dev',
|
|
|
|
|
'client_id': 'kimne78kx3ncx6brgo4mv6wki5h1ko',
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
dioAdapter.onPost(
|
|
|
|
|
'https://gql.twitch.tv/integrity',
|
|
|
|
|
(server) => server.reply(200, {
|
|
|
|
|
'token': 'v4.public.$payload.sig',
|
|
|
|
|
'expiration': DateTime.now().millisecondsSinceEpoch + 600000,
|
|
|
|
|
}),
|
|
|
|
|
data: Matchers.any,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await expectLater(
|
|
|
|
|
api.fetchIntegrityToken(authToken: 'web', deviceId: 'dev'),
|
|
|
|
|
throwsA(isA<IntegrityCheckException>()),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-10-07 03:06:05 +02:00
|
|
|
}
|