mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-29 21:02:09 +02:00
138 lines
4.6 KiB
Dart
138 lines
4.6 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:spotiflac_android/models/settings.dart';
|
|
import 'package:spotiflac_android/providers/settings_provider.dart';
|
|
import 'package:spotiflac_android/providers/track_provider.dart';
|
|
import 'package:spotiflac_android/services/platform_bridge.dart';
|
|
import 'package:spotiflac_android/utils/extension_auth_launcher.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
const channel = MethodChannel('plugins.flutter.io/url_launcher');
|
|
const backend = MethodChannel('com.zarz.spotiflac/backend');
|
|
final messenger =
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger;
|
|
final uri = Uri.parse('https://example.invalid/verify?state=sample');
|
|
|
|
tearDown(() {
|
|
messenger.setMockMethodCallHandler(channel, null);
|
|
messenger.setMockMethodCallHandler(backend, null);
|
|
});
|
|
|
|
for (final inAppFirst in [true, false]) {
|
|
final browserMode = inAppFirst ? 'in_app_first' : 'external_first';
|
|
for (final throwsError in [true, false]) {
|
|
test(
|
|
'browser fallback after launch failure: $browserMode, throws=$throwsError',
|
|
() async {
|
|
final modes = <bool>[];
|
|
messenger.setMockMethodCallHandler(channel, (call) async {
|
|
expect(call.method, 'launch');
|
|
final arguments = Map<String, dynamic>.from(call.arguments as Map);
|
|
expect(arguments['url'], uri.toString());
|
|
modes.add(arguments['useWebView'] as bool);
|
|
if (modes.length == 1) {
|
|
if (throwsError) {
|
|
throw PlatformException(code: 'ACTIVITY_NOT_FOUND');
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
expect(
|
|
await launchExtensionAuthUrl(uri, browserMode: browserMode),
|
|
isTrue,
|
|
);
|
|
expect(modes, [inAppFirst, !inAppFirst]);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
test(
|
|
'both browser failures return false so manual help can be shown',
|
|
() async {
|
|
var launches = 0;
|
|
messenger.setMockMethodCallHandler(channel, (_) async {
|
|
launches++;
|
|
throw PlatformException(code: 'ACTIVITY_NOT_FOUND');
|
|
});
|
|
expect(
|
|
await launchExtensionAuthUrl(uri, browserMode: 'in_app_first'),
|
|
isFalse,
|
|
);
|
|
expect(launches, 2);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'direct search verifies through the fallback browser and retries once',
|
|
() async {
|
|
var searches = 0;
|
|
var pendingLookups = 0;
|
|
var launches = 0;
|
|
messenger.setMockMethodCallHandler(backend, (call) async {
|
|
switch (call.method) {
|
|
case 'customSearchWithExtension':
|
|
searches++;
|
|
if (searches == 1) {
|
|
throw PlatformException(
|
|
code: 'ERROR',
|
|
message:
|
|
"verification_required: extension 'sample-provider' needs signed-session verification: Error: VERIFY_REQUIRED",
|
|
);
|
|
}
|
|
return [
|
|
{
|
|
'id': 'sample-track',
|
|
'name': 'Sample track',
|
|
'artist_name': 'Artist',
|
|
},
|
|
];
|
|
case 'getExtensionPendingAuth':
|
|
pendingLookups++;
|
|
expect(call.arguments, {'extension_id': 'sample-provider'});
|
|
return {'auth_url': uri.toString()};
|
|
case 'completeExtensionSessionGrant':
|
|
return true;
|
|
default:
|
|
fail('Unexpected backend call: ${call.method}');
|
|
}
|
|
});
|
|
messenger.setMockMethodCallHandler(channel, (call) async {
|
|
launches++;
|
|
if (launches == 1) throw PlatformException(code: 'ACTIVITY_NOT_FOUND');
|
|
unawaited(
|
|
PlatformBridge.completeExtensionSessionGrant(
|
|
'sample-provider',
|
|
'test-grant',
|
|
),
|
|
);
|
|
return true;
|
|
});
|
|
final container = ProviderContainer(
|
|
overrides: [settingsProvider.overrideWith(_Settings.new)],
|
|
);
|
|
addTearDown(container.dispose);
|
|
await container
|
|
.read(trackProvider.notifier)
|
|
.customSearch('sample-provider', 'fallback verification');
|
|
final state = container.read(trackProvider);
|
|
expect(state.error, isNull);
|
|
expect(state.isLoading, isFalse);
|
|
expect(state.tracks.single.id, 'sample-track');
|
|
expect(searches, 2);
|
|
expect(pendingLookups, 1);
|
|
expect(launches, 2);
|
|
},
|
|
);
|
|
}
|
|
|
|
class _Settings extends SettingsNotifier {
|
|
@override
|
|
AppSettings build() => const AppSettings();
|
|
}
|