import 'dart:convert'; 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()), ); }); }); 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'); }); }); 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()), ); }); }); }