feat: server discovery, tunnel fallback, and update configs

This commit is contained in:
ssbg04 committed 2026-10-09 01:31:10 +08:00
1 parent 59049f848d
commit 5abd5a812c
9 files changed
+610 -144

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:frontend/core/network/api_constants.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() async {
HttpOverrides.global = null;
SharedPreferences.setMockInitialValues({});
});
test('ApiConstants.extractErrorMessage cleans FormatException and HTML', () {
try {
const badBody = '<!DOCTYPE html><html><body>Error</body></html>';
jsonDecode(badBody);
} catch (e) {
final message = ApiConstants.extractErrorMessage(e);
expect(message.contains('FormatUnexpected'), isFalse);
expect(message.contains('Unexpected character'), isFalse);
expect(message, contains('invalid response'));
}
final dioHtmlError = DioException(
requestOptions: RequestOptions(path: '/auth/login'),
response: Response(
requestOptions: RequestOptions(path: '/auth/login'),
statusCode: 400,
data: '<!DOCTYPE html><html><pre>SyntaxError</pre></html>',
),
);
expect(
ApiConstants.extractErrorMessage(dioHtmlError),
'Invalid request. Please check credentials or server URL.',
);
final dio401Error = DioException(
requestOptions: RequestOptions(path: '/auth/login'),
response: Response(
requestOptions: RequestOptions(path: '/auth/login'),
statusCode: 401,
data: {'message': 'Invalid username or password'},
),
);
expect(
ApiConstants.extractErrorMessage(dio401Error),
'Invalid username or password',
);
});
}
+6 -9
View File
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
// Use a relative import to reliably find your main.dart file
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:frontend/main.dart';
void main() {
@@ -9,16 +9,13 @@ void main() {
WidgetTester tester,
) async {
// 1. Build our app and trigger a frame.
await tester.pumpWidget(const TisRmsApp());
await tester.pumpWidget(const ProviderScope(child: TisRmsApp()));
// 2. Verify that our branding text is present on the Splash Screen
expect(find.textContaining('TIS RMS'), findsWidgets);
expect(find.textContaining('Talisay Integrated School'), findsWidgets);
// 3. Verify that the loading spinner is present
expect(find.byType(CircularProgressIndicator), findsOneWidget);
// Note: We don't pump the timer here because the test environment
// shouldn't wait for the 2.5 second simulated delay. We just want
// to ensure the initial widget tree renders without crashing.
// Clean up active timers/animations in test harness
await tester.pumpWidget(const SizedBox());
await tester.pump(const Duration(seconds: 2));
});
}