import 'package:coves_flutter/utils/url_launcher.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
import '../test_helpers/mock_url_launcher_platform.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late MockUrlLauncherPlatform mockPlatform;
setUp(() {
mockPlatform = MockUrlLauncherPlatform();
UrlLauncherPlatform.instance = mockPlatform;
});
group('UrlLauncher', () {
group('Security Validation', () {
test('blocks javascript: scheme', () async {
final result = await UrlLauncher.launchExternalUrl(
'javascript:alert("xss")',
);
expect(result, false);
expect(mockPlatform.launchedUrls, isEmpty);
});
test('blocks file: scheme', () async {
final result = await UrlLauncher.launchExternalUrl(
'file:///etc/passwd',
);
expect(result, false);
expect(mockPlatform.launchedUrls, isEmpty);
});
test('blocks data: scheme', () async {
final result = await UrlLauncher.launchExternalUrl(
'data:text/html,
XSS
',
);
expect(result, false);
expect(mockPlatform.launchedUrls, isEmpty);
});
test('allows http scheme', () async {
final result = await UrlLauncher.launchExternalUrl(
'http://example.com',
);
expect(result, true);
expect(mockPlatform.launchedUrls, contains('http://example.com'));
});
test('allows https scheme', () async {
final result = await UrlLauncher.launchExternalUrl(
'https://example.com',
);
expect(result, true);
expect(mockPlatform.launchedUrls, contains('https://example.com'));
});
test('scheme check is case insensitive', () async {
final result = await UrlLauncher.launchExternalUrl(
'HTTPS://example.com',
);
expect(result, true);
// URL gets normalized to lowercase by url_launcher
expect(mockPlatform.launchedUrls, contains('https://example.com'));
});
});
group('Invalid URL Handling', () {
test('returns false for malformed URLs', () async {
final result = await UrlLauncher.launchExternalUrl('not a url');
expect(result, false);
});
test('returns false for empty string', () async {
final result = await UrlLauncher.launchExternalUrl('');
expect(result, false);
});
test('handles URLs with special characters', () async {
final result = await UrlLauncher.launchExternalUrl(
'https://example.com/path?query=value&other=123',
);
expect(result, true);
});
});
group('Error Snackbar Display', () {
testWidgets('shows snackbar when context provided and URL blocked', (
tester,
) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) {
return ElevatedButton(
onPressed: () async {
await UrlLauncher.launchExternalUrl(
'javascript:alert("xss")',
context: context,
);
},
child: const Text('Test'),
);
},
),
),
),
);
// Tap button to trigger URL launch
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
// Wait for snackbar animation
await tester.pumpAndSettle();
// Verify snackbar is displayed
expect(find.text('Invalid link format'), findsOneWidget);
});
testWidgets('shows snackbar when context provided and URL fails', (
tester,
) async {
// Configure platform to fail
mockPlatform.canLaunchResponse = false;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) {
return ElevatedButton(
onPressed: () async {
await UrlLauncher.launchExternalUrl(
'https://example.com',
context: context,
);
},
child: const Text('Test'),
);
},
),
),
),
);
// Tap button to trigger URL launch
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
// Wait for snackbar animation
await tester.pumpAndSettle();
// Verify snackbar is displayed
expect(find.text('Could not open link'), findsOneWidget);
});
test('does not crash when context is null', () async {
// Should not throw exception
expect(
() async => UrlLauncher.launchExternalUrl('javascript:alert("xss")'),
returnsNormally,
);
});
});
group('Successful Launches', () {
test('successfully launches valid https URL', () async {
final result = await UrlLauncher.launchExternalUrl(
'https://www.example.com/path',
);
expect(result, true);
expect(
mockPlatform.launchedUrls,
contains('https://www.example.com/path'),
);
});
test('uses external application mode', () async {
await UrlLauncher.launchExternalUrl('https://example.com');
expect(
mockPlatform.lastLaunchMode,
PreferredLaunchMode.externalApplication,
);
});
});
});
}