Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
4ec832b
[test] Add ActionTile widget tests
sharder996 Apr 18, 2026
2283133
[test] Register Flutter GUI tests with CTest
sharder996 Apr 19, 2026
2326e58
[build] Include Flutter coverage in covreport
sharder996 Apr 19, 2026
e022b9c
[test] Add catalogue tests
sharder996 Apr 20, 2026
e9287fa
[test] Add confirmation dialog tests
sharder996 Apr 20, 2026
29214eb
[test] Add copyable text and display field tests
sharder996 Apr 20, 2026
92bccd8
[test] Add CPU sparkline tests
sharder996 Apr 20, 2026
71aaeaf
[test] Add dropdown tests
sharder996 Apr 20, 2026
c4c4ca8
[test] Add extensions tests
sharder996 Apr 20, 2026
a192c19
[test] Add image card widget tests
sharder996 Apr 20, 2026
3fa96db
[test] Add IP addresses widget tests
sharder996 Apr 20, 2026
78fcc32
[test] Add launching VMs provider tests
sharder996 Apr 20, 2026
f3ef216
[test] Add mapping slider utility tests
sharder996 Apr 20, 2026
859de89
[test] Add memory usage widget tests
sharder996 Apr 20, 2026
c3d61f3
[test] Add name validator tests
sharder996 Apr 20, 2026
36fb6cc
[test] Add notifications provider tests
sharder996 Apr 20, 2026
44756b9
[test] Add providers logic tests
sharder996 Apr 20, 2026
7f194d7
[test] Add quit and terminal dialog tests
sharder996 Apr 20, 2026
6ad9bf5
[test] Add sidebar provider tests
sharder996 Apr 20, 2026
7df8794
[test] Add switch widget tests
sharder996 Apr 20, 2026
28cf316
[test] Add update notifier tests
sharder996 Apr 20, 2026
14178a2
[test] Add VM action and button tests
sharder996 Apr 20, 2026
49e613b
[test] Add VM details general tests
sharder996 Apr 20, 2026
84a6180
[test] Add VM details state tests
sharder996 Apr 20, 2026
32456dd
[test] Add VM status icon tests
sharder996 Apr 20, 2026
742ce5f
[test] Add VM table state tests
sharder996 Apr 20, 2026
5fd4640
[ci] Run tests with ctest in CI workflows
sharder996 Apr 21, 2026
967a336
[test] Add CatalogueScreen widget tests
sharder996 Apr 22, 2026
480a38a
[test] Add DeleteInstanceDialog widget tests
sharder996 Apr 22, 2026
ac2a4e1
[test] Add DisableSection widget tests
sharder996 Apr 22, 2026
d2768e6
[test] Add SVG asset stubs for widget tests
sharder996 Apr 22, 2026
367905f
[test] Add HeaderSelection widget tests
sharder996 Apr 22, 2026
298e0b0
[test] Add imageName function tests
sharder996 Apr 22, 2026
3eb296f
[test] Add NoVms widget tests
sharder996 Apr 22, 2026
34fb785
[test] Add notification entry widget tests
sharder996 Apr 23, 2026
f004794
[test] Add notifications list widget tests
sharder996 Apr 23, 2026
6d59254
[test] Add notifyError widget extension tests
sharder996 Apr 23, 2026
ede27e0
[test] Add SearchBox widget tests
sharder996 Apr 23, 2026
774c977
[test] Add Table widget tests
sharder996 Apr 23, 2026
d62d6f4
[test] Add VmActionButtons widget tests
sharder996 Apr 23, 2026
5feb9c5
[test] Add SelectedVms auto-removal test
sharder996 Apr 23, 2026
b625193
[test] Add checkForUpdate function tests
sharder996 Apr 23, 2026
ddc07a6
[test] Add GrpcClient integration tests
sharder996 Apr 23, 2026
24c126b
[test] Add VmTableHeaders widget tests
sharder996 Apr 23, 2026
9748acb
[test] Add SpecInput widget tests
sharder996 Apr 23, 2026
da95955
[refactor] Organize tests by component area
sharder996 Apr 23, 2026
20fadd7
[cmake] Inline Flutter coverage commands
sharder996 Apr 23, 2026
8cfe79b
[test] Exclude generated files from coverage
sharder996 Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ jobs:
ulimit -c unlimited && \
env CTEST_OUTPUT_ON_FAILURE=1 \
LD_LIBRARY_PATH=/root/stage/usr/lib/x86_64-linux-gnu/:/root/stage/lib/:/root/parts/multipass/build/lib/ \
/root/parts/multipass/build/bin/multipass_tests"
ctest -V"

- name: Measure coverage
id: measure-coverage
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ jobs:
trap 'echo "MULTIPASS_TESTS_EXIT_CODE=$?" >> $GITHUB_ENV' EXIT
# Set soft limit for the core file size (512MiB)
ulimit -c 1048576
bin/multipass_tests
ctest -V

- name: Upload test coredump
uses: actions/upload-artifact@v7
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ jobs:
- name: Test
working-directory: ${{ env.BUILD_DIR }}
run: |
bin/multipass_tests
ctest -V

- name: Package
id: cmake-package
Expand Down
25 changes: 24 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,22 @@ if(cmake_build_type_lower MATCHES "coverage")
${CMAKE_BINARY_DIR}'/*'
--output-file coverage.cleaned
COMMAND ${CMAKE_COMMAND} -E remove coverage.info
COMMAND ${GENHTML} -o coverage coverage.cleaned

# Merge Flutter test coverage with C++ coverage
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR}/src/client/gui
${FLUTTER_EXECUTABLE} test --coverage
COMMAND ${LCOV}
--remove ${CMAKE_SOURCE_DIR}/src/client/gui/coverage/lcov.info
--ignore-errors unused
'*/lib/generated/*'
'*/lib/l10n/*'
--output-file ${CMAKE_SOURCE_DIR}/src/client/gui/coverage/lcov.info
COMMAND ${LCOV}
--add-tracefile coverage.cleaned
--add-tracefile ${CMAKE_SOURCE_DIR}/src/client/gui/coverage/lcov.info
--output-file coverage.cleaned

COMMAND ${GENHTML} --source-directory ${CMAKE_SOURCE_DIR}/src/client/gui -o coverage coverage.cleaned
)
endif()
endif()
Expand All @@ -369,6 +384,14 @@ add_subdirectory(src)
if(MULTIPASS_ENABLE_TESTS)
enable_testing()
add_subdirectory(tests/unit)

if(MULTIPASS_ENABLE_FLUTTER_GUI)
add_test(
NAME multipass_gui_tests
COMMAND ${FLUTTER_EXECUTABLE} test
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/client/gui
)
endif()
endif()

include(packaging/cpack.cmake OPTIONAL)
Expand Down
91 changes: 91 additions & 0 deletions src/client/gui/test/catalogue/catalogue_screen_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import 'dart:async';

import 'package:flutter/material.dart' hide ImageInfo;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:multipass_gui/catalogue/catalogue.dart';
import 'package:multipass_gui/grpc_client.dart';
import 'package:multipass_gui/l10n/app_localizations.dart';

import '../helpers.dart';

Widget _scope(Widget child) {
return withFakeSvgAssetBundle(
MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: child,
),
);
}

void main() {
group('CatalogueScreen', () {
testWidgets('shows a loading indicator while images are fetching',
(tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
imagesProvider.overrideWith(
(ref) => Completer<List<ImageInfo>>().future,
),
],
child: _scope(const CatalogueScreen()),
),
);
// One pump to trigger the first build before the future resolves.
await tester.pump();

expect(find.byType(CircularProgressIndicator), findsOneWidget);
});

testWidgets('shows an error message when images fail to load',
(tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
imagesProvider.overrideWith((ref) async {
throw Exception('Connection failed');
}),
],
child: _scope(const CatalogueScreen()),
),
);
await tester.pumpAndSettle();

expect(find.textContaining('Connection failed'), findsOneWidget);
});

testWidgets('shows a refresh button when images fail to load',
(tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
imagesProvider.overrideWith((ref) async {
throw Exception('Load error');
}),
],
child: _scope(const CatalogueScreen()),
),
);
await tester.pumpAndSettle();

expect(find.text('Refresh'), findsOneWidget);
});

testWidgets('shows the welcome title when images are successfully loaded',
(tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
imagesProvider.overrideWith((ref) async => []),
],
child: _scope(const CatalogueScreen()),
),
);
await tester.pumpAndSettle();

expect(find.text('Welcome to Multipass'), findsOneWidget);
});
});
}
Loading
Loading