diff --git a/.github/workflows/flutter_test.yml b/.github/workflows/flutter_test.yml index f2c83cc..ea1a890 100644 --- a/.github/workflows/flutter_test.yml +++ b/.github/workflows/flutter_test.yml @@ -110,12 +110,12 @@ jobs: run: | export DISPLAY=:99 sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & - flutter test integration_test --coverage -d linux + flutter test integration_test/app_test.dart --coverage -d linux shell: bash - name: Run integration tests for macos/windows if: needs.changes.outputs.branch == 'dev' && matrix.os != 'ubuntu' - run: flutter test integration_test --coverage -d ${{ matrix.os }} + run: flutter test integration_test/app_test.dart --coverage -d ${{ matrix.os }} - name: Upload Coverage to CodeCov if: needs.changes.outputs.branch == 'dev' diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart index 4caf9e2..d860e4e 100644 --- a/integration_test/app_test.dart +++ b/integration_test/app_test.dart @@ -1,34 +1,16 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:network_tools_flutter/network_tools_flutter.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:vernet/injection.dart'; import 'package:vernet/main.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; -import 'package:vernet/values/globals.dart' as globals; -import 'package:vernet/values/keys.dart'; + +import 'dns/lookup/lookup_test.dart' as lookup_test; +import 'dns/reverse_lookup/reverse_lookup.dart' as reverse_lookup; +import 'network_troubleshooting_test/ping_test/ping_test.dart' as ping_test; +import 'wifi_test/wifi_test_runner.dart' as wifi_test_runner; void main() { - globals.testingActive = true; - late ServerSocket server; - int port = 0; IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - setUpAll(() async { - configureDependencies(Env.test); - final appDocDirectory = await getApplicationDocumentsDirectory(); - await configureNetworkToolsFlutter(appDocDirectory.path); - //open a port in shared way because of portscanner using same, - //if passed false then two hosts come up in search and breaks test. - server = - await ServerSocket.bind(InternetAddress.anyIPv4, port, shared: true); - port = server.port; - debugPrint("Opened port in this machine at $port"); - }); - - group('host scanner end-to-end test', () { + group('app launch test', () { testWidgets('just test if app is able to launch and display homepage', (tester) async { // Load app widget. @@ -38,59 +20,9 @@ void main() { // Verify that there are 4 widgets at homepage expect(find.bySubtype(), findsAtLeastNWidgets(4)); }); - - testWidgets('tap on the scan for devices button, verify device found', - (tester) async { - // Load app widget. - await tester.pumpWidget(const MyApp(true)); - await tester.pumpAndSettle(); - - // Verify that there are 4 widgets at homepage - expect(find.bySubtype(), findsAtLeastNWidgets(4)); - - // Finds the scan for devices button to tap on. - final devicesButton = find.byKey(WidgetKey.scanForDevicesButton.key); - - // Emulate a tap on the button. - await tester.tap(devicesButton); - await tester.pump(); - expect(find.byType(AdaptiveListTile), findsAny); - await tester.pumpAndSettle(const Duration(seconds: 10)); - await tester.pump(); - expect(find.byType(AdaptiveListTile), findsAtLeast(2)); - final routerIconButton = - find.byKey(WidgetKey.thisDeviceTileIconButton.key); - - await tester.scrollUntilVisible( - routerIconButton, - 500.0, - scrollable: find.byType(Scrollable), - ); - - expect(routerIconButton, findsOne); - await tester.tap(routerIconButton); - await tester.pumpAndSettle(); - expect(find.byType(AppBar), findsOne); - - final radioButton = find.byKey(WidgetKey.singlePortScanRadioButton.key); - await tester.tap(radioButton); - await tester.pumpAndSettle(); - - await tester.enterText( - find.byKey(WidgetKey.enterPortTextField.key), - port.toString(), - ); - await tester.pumpAndSettle(); - - final portScanButton = find.byKey(WidgetKey.portScanButton.key); - await tester.tap(portScanButton); - await tester.pumpAndSettle(); - await tester.pump(); - expect(find.byType(AdaptiveListTile), findsAny); - }); - }); - - tearDownAll(() { - server.close(); }); + wifi_test_runner.main(); + ping_test.main(); + lookup_test.main(); + reverse_lookup.main(); } diff --git a/integration_test/dns/lookup/lookup_test.dart b/integration_test/dns/lookup/lookup_test.dart new file mode 100644 index 0000000..11fcfde --- /dev/null +++ b/integration_test/dns/lookup/lookup_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:vernet/main.dart'; +import 'package:vernet/ui/adaptive/adaptive_list.dart'; +import 'package:vernet/values/keys.dart'; +import 'package:vernet/values/strings.dart'; + +void main() { + group('Dns lookup integration test', () { + testWidgets('tap on the DNS lookup button, verify lookup ended', + (tester) async { + // Load app widget. + await tester.pumpWidget(const MyApp(true)); + await tester.pumpAndSettle(); + + // Verify that there are 4 widgets at homepage + expect(find.bySubtype(), findsAtLeastNWidgets(4)); + + // Finds the scan for devices button to tap on. + final lookupButton = find.byKey(WidgetKey.dnsLookupButton.key); + + // Emulate a tap on the button. + await tester.tap(lookupButton); + await tester.pumpAndSettle(); + + expect(find.text(StringValue.dnsLookupEmptyPlaceholder), findsOneWidget); + + await tester.enterText( + find.byType(TextFormField), + 'google.com', + ); + await tester.pumpAndSettle(); + + final submitButton = find.byKey(WidgetKey.basePageSubmitButton.key); + await tester.tap(submitButton); + + await tester.pumpAndSettle(const Duration(seconds: 2)); + + expect(find.byType(AdaptiveListTile), findsExactly(3)); + }); + }); +} diff --git a/integration_test/dns/reverse_lookup/reverse_lookup.dart b/integration_test/dns/reverse_lookup/reverse_lookup.dart new file mode 100644 index 0000000..7fc85db --- /dev/null +++ b/integration_test/dns/reverse_lookup/reverse_lookup.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:vernet/main.dart'; +import 'package:vernet/ui/adaptive/adaptive_list.dart'; +import 'package:vernet/values/keys.dart'; +import 'package:vernet/values/strings.dart'; + +void main() { + group('Reverse DNS lookup integration test', () { + testWidgets('tap on the reverse DNS lookup button, verify lookup ended', + (tester) async { + // Load app widget. + await tester.pumpWidget(const MyApp(true)); + await tester.pumpAndSettle(); + + // Verify that there are 4 widgets at homepage + expect(find.bySubtype(), findsAtLeastNWidgets(4)); + + // Finds the scan for devices button to tap on. + final reverseDnsLookupButton = + find.byKey(WidgetKey.reverseDnsLookupButton.key); + + // Emulate a tap on the button. + await tester.tap(reverseDnsLookupButton); + await tester.pumpAndSettle(); + + expect( + find.text(StringValue.reverseDnsLookupEmptyPlaceholder), + findsOneWidget, + ); + + await tester.enterText( + find.byType(TextFormField), + '172.217.160.142', + ); + await tester.pumpAndSettle(); + + final submitButton = find.byKey(WidgetKey.basePageSubmitButton.key); + await tester.tap(submitButton); + + await tester.pumpAndSettle(const Duration(seconds: 2)); + + expect(find.text("maa03s29-in-f14.1e100.net"), findsOne); + }); + }); +} diff --git a/integration_test/network_troubleshooting_test/ping_test/ping_test.dart b/integration_test/network_troubleshooting_test/ping_test/ping_test.dart new file mode 100644 index 0000000..7b55ce5 --- /dev/null +++ b/integration_test/network_troubleshooting_test/ping_test/ping_test.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_tools_flutter/network_tools_flutter.dart'; +import 'package:vernet/main.dart'; +import 'package:vernet/ui/adaptive/adaptive_list.dart'; +import 'package:vernet/values/keys.dart'; + +void main() { + group('Ping integration test', () { + testWidgets('tap on the ping button, verify ping ended', (tester) async { + // Load app widget. + await tester.pumpWidget(const MyApp(true)); + await tester.pumpAndSettle(); + + // Verify that there are 4 widgets at homepage + expect(find.bySubtype(), findsAtLeastNWidgets(4)); + + // Finds the scan for devices button to tap on. + final pingButton = find.byKey(WidgetKey.ping.key); + + // Emulate a tap on the button. + await tester.tap(pingButton); + await tester.pumpAndSettle(); + final interface = await NetInterface.localInterface(); + + await tester.enterText( + find.byType(TextFormField), + interface?.ipAddress ?? '192.168.0.1', + ); + await tester.pumpAndSettle(); + + final submitButton = find.byKey(WidgetKey.basePageSubmitButton.key); + await tester.tap(submitButton); + + await tester.pumpAndSettle(const Duration(seconds: 5)); + + expect(find.byKey(WidgetKey.pingSummarySent.key), findsOneWidget); + expect(find.byKey(WidgetKey.pingSummaryReceived.key), findsOneWidget); + expect(find.byKey(WidgetKey.pingSummaryTotalTime.key), findsOneWidget); + + expect(find.text('Sent: 5'), findsOneWidget); + expect(find.text('Received : 5'), findsOneWidget); + expect(find.text('Total time: --'), findsOneWidget); + expect(find.byType(AdaptiveListTile), findsAtLeastNWidgets(5)); + }); + }); +} diff --git a/integration_test/wifi_test/host_scan_and_port_scan_test.dart b/integration_test/wifi_test/host_scan_and_port_scan_test.dart new file mode 100644 index 0000000..c51e5d1 --- /dev/null +++ b/integration_test/wifi_test/host_scan_and_port_scan_test.dart @@ -0,0 +1,84 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:network_tools_flutter/network_tools_flutter.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:vernet/injection.dart'; +import 'package:vernet/main.dart'; +import 'package:vernet/ui/adaptive/adaptive_list.dart'; +import 'package:vernet/values/globals.dart' as globals; +import 'package:vernet/values/keys.dart'; + +void main() { + globals.testingActive = true; + late ServerSocket server; + int port = 0; + setUpAll(() async { + configureDependencies(Env.test); + final appDocDirectory = await getApplicationDocumentsDirectory(); + await configureNetworkToolsFlutter(appDocDirectory.path); + //open a port in shared way because of portscanner using same, + //if passed false then two hosts come up in search and breaks test. + server = + await ServerSocket.bind(InternetAddress.anyIPv4, port, shared: true); + port = server.port; + debugPrint("Opened port in this machine at $port"); + }); + + group('host scanner end-to-end test', () { + testWidgets('tap on the scan for devices button, verify device found', + (tester) async { + // Load app widget. + await tester.pumpWidget(const MyApp(true)); + await tester.pumpAndSettle(); + + // Verify that there are 4 widgets at homepage + expect(find.bySubtype(), findsAtLeastNWidgets(4)); + + // Finds the scan for devices button to tap on. + final devicesButton = find.byKey(WidgetKey.scanForDevicesButton.key); + + // Emulate a tap on the button. + await tester.tap(devicesButton); + await tester.pump(); + expect(find.byType(AdaptiveListTile), findsAny); + await tester.pumpAndSettle(const Duration(seconds: 10)); + await tester.pump(); + expect(find.byType(AdaptiveListTile), findsAtLeast(2)); + final routerIconButton = + find.byKey(WidgetKey.thisDeviceTileIconButton.key); + + await tester.scrollUntilVisible( + routerIconButton, + 500.0, + scrollable: find.byType(Scrollable), + ); + + expect(routerIconButton, findsOne); + await tester.tap(routerIconButton); + await tester.pumpAndSettle(); + expect(find.byType(AppBar), findsOne); + + final radioButton = find.byKey(WidgetKey.singlePortScanRadioButton.key); + await tester.tap(radioButton); + await tester.pumpAndSettle(); + + await tester.enterText( + find.byKey(WidgetKey.enterPortTextField.key), + port.toString(), + ); + await tester.pumpAndSettle(); + + final portScanButton = find.byKey(WidgetKey.portScanButton.key); + await tester.tap(portScanButton); + await tester.pumpAndSettle(); + await tester.pump(); + expect(find.byType(AdaptiveListTile), findsAny); + }); + }); + + tearDownAll(() { + server.close(); + }); +} diff --git a/integration_test/wifi_test/wifi_test_runner.dart b/integration_test/wifi_test/wifi_test_runner.dart new file mode 100644 index 0000000..596b585 --- /dev/null +++ b/integration_test/wifi_test/wifi_test_runner.dart @@ -0,0 +1,5 @@ +import 'host_scan_and_port_scan_test.dart' as host_scan_and_port_scan; + +void main() { + host_scan_and_port_scan.main(); +} diff --git a/lib/pages/base_page.dart b/lib/pages/base_page.dart index 95c4a3d..c146704 100644 --- a/lib/pages/base_page.dart +++ b/lib/pages/base_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; import 'package:vernet/ui/popular_chip.dart'; +import 'package:vernet/values/keys.dart'; abstract class BasePage extends State { TextEditingController textEditingController = TextEditingController(); @@ -82,6 +83,7 @@ abstract class BasePage extends State { Padding( padding: const EdgeInsets.only(left: 10.0), child: ElevatedButton( + key: WidgetKey.basePageSubmitButton.key, onPressed: () { if (_formKey.currentState!.validate()) onPressed(); }, diff --git a/lib/pages/dns/dns_page.dart b/lib/pages/dns/dns_page.dart index ca09ab2..627eedc 100644 --- a/lib/pages/dns/dns_page.dart +++ b/lib/pages/dns/dns_page.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:vernet/pages/base_page.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; +import 'package:vernet/values/strings.dart'; class DNSPage extends StatefulWidget { const DNSPage({super.key}); @@ -20,7 +21,7 @@ class _DNSPageState extends BasePage { return _addresses.isEmpty ? const Center( child: Text( - 'No addresses found yet.\nAll addresses will appear here.', + StringValue.dnsLookupEmptyPlaceholder, textAlign: TextAlign.center, ), ) diff --git a/lib/pages/dns/reverse_dns_page.dart b/lib/pages/dns/reverse_dns_page.dart index 9c70bfc..1cbf75d 100644 --- a/lib/pages/dns/reverse_dns_page.dart +++ b/lib/pages/dns/reverse_dns_page.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:vernet/pages/base_page.dart'; +import 'package:vernet/values/strings.dart'; class ReverseDNSPage extends StatefulWidget { const ReverseDNSPage({super.key}); @@ -23,7 +24,7 @@ class _ReverseDNSPageState extends BasePage { if (_address == null) { return const Center( child: Text( - 'Host name not found yet.\nHost name will appear here.', + StringValue.reverseDnsLookupEmptyPlaceholder, textAlign: TextAlign.center, ), ); diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 284376f..9aa2329 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -216,6 +216,7 @@ class _WifiDetailState extends State { Row( children: [ ElevatedButton.icon( + key: WidgetKey.ping.key, onPressed: () { Navigator.push( context, @@ -258,6 +259,7 @@ class _WifiDetailState extends State { Row( children: [ ElevatedButton.icon( + key: WidgetKey.dnsLookupButton.key, onPressed: () { Navigator.push( context, @@ -271,6 +273,7 @@ class _WifiDetailState extends State { ), const SizedBox(width: 10), ElevatedButton.icon( + key: WidgetKey.reverseDnsLookupButton.key, onPressed: () { Navigator.push( context, diff --git a/lib/pages/ping_page/ping_page.dart b/lib/pages/ping_page/ping_page.dart index 00a0484..be90658 100644 --- a/lib/pages/ping_page/ping_page.dart +++ b/lib/pages/ping_page/ping_page.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:vernet/main.dart'; import 'package:vernet/pages/base_page.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; +import 'package:vernet/values/keys.dart'; class PingPage extends StatefulWidget { const PingPage({super.key}); @@ -123,9 +124,18 @@ class _PingPageState extends BasePage { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('Sent: ${_pingSummary?.transmitted ?? '--'}'), - Text('Received : ${_pingSummary?.transmitted ?? '--'}'), - Text('Total time: ${_getTime(_pingSummary?.time)}'), + Text( + key: WidgetKey.pingSummarySent.key, + 'Sent: ${_pingSummary?.transmitted ?? '--'}', + ), + Text( + key: WidgetKey.pingSummaryReceived.key, + 'Received : ${_pingSummary?.transmitted ?? '--'}', + ), + Text( + key: WidgetKey.pingSummaryTotalTime.key, + 'Total time: ${_getTime(_pingSummary?.time)}', + ), ], ); } diff --git a/lib/values/keys.dart b/lib/values/keys.dart index 22c6cb3..126db4f 100644 --- a/lib/values/keys.dart +++ b/lib/values/keys.dart @@ -5,10 +5,16 @@ enum WidgetKey implements Comparable { rangePortScanRadioButton('rangePortScanRadioButton'), singlePortScanRadioButton('singlePortScanRadioButton'), scanForOpenPortsButton('scanForOpenPortsButton'), + reverseDnsLookupButton('reverseDnsLookupButton'), + pingSummaryTotalTime('pingSummaryTotalTime'), scanForDevicesButton('scanForDevicesButton'), + basePageSubmitButton('basePageSubmitButton'), + pingSummaryReceived('pingSummaryReceived'), enterPortTextField('enterPortTextField'), veryShortPortChip('veryShortPortChip'), rescanIconButton('rescanIconButton'), + pingSummarySent('pingSummarySent'), + dnsLookupButton('dnsLookupButton'), portScanButton('portScanButton'), cloudflareChip('cloudflareChip'), knownPortChip('knownPortChip'), @@ -18,7 +24,8 @@ enum WidgetKey implements Comparable { localIpChip('localIpChip'), googleChip('googleChip'), amazonChip('amazonChip'), - appleChip('appleChip'); + appleChip('appleChip'), + ping('ping'); const WidgetKey(this.value); final String value; diff --git a/lib/values/strings.dart b/lib/values/strings.dart index d1328ed..afebcbf 100644 --- a/lib/values/strings.dart +++ b/lib/values/strings.dart @@ -22,4 +22,8 @@ class StringValue { static const String hostScanPageTitle = 'Scan for devices'; static const String loadingDevicesMessage = 'Searching for devices in your local network'; + static const String dnsLookupEmptyPlaceholder = + 'No addresses found yet.\nAll addresses will appear here.'; + static const String reverseDnsLookupEmptyPlaceholder = + 'Host name not found yet.\nHost name will appear here.'; }