Tests for the epic's new code so the 95% floor holds: ClideSettings.i18n string/interpolated null-safe + localizedCommandTitle; settings-renderer localization (section/field/help/select/file, project-scope tag, didUpdateWidget); extension-activation rollback + settings-contribution unregister; the Dutch gate check; RootShell applying app.locale on boot; and prompt/conversation tool-body + file-ref coverage. Also harden the menu toggle re-tap (capture the button point while stable, then tapAt) so it no longer throws getCenter under the serial coverage load. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
162 lines
5.6 KiB
Dart
162 lines
5.6 KiB
Dart
/// Widget tests for the application menu bar (T-48): open/close, command
|
|
/// execution, disabled rendering, and keyboard navigation (arrows, Enter, Esc,
|
|
/// Left/Right between menus).
|
|
library;
|
|
|
|
import 'package:clide/builtin/menubar/menubar.dart';
|
|
import 'package:clide/clide.dart' show IpcResponse, clideVersion;
|
|
import 'package:clide/extension/extension.dart';
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import '../../helpers/kernel_fixture.dart';
|
|
|
|
void main() {
|
|
late KernelFixture f;
|
|
late MenuBarController controller;
|
|
|
|
setUp(() async {
|
|
f = await KernelFixture.create();
|
|
f.services.extensions.register(MenuBarExtension(services: f.services));
|
|
await f.services.extensions.activateAll();
|
|
// A registered View command so the View menu has an enabled item.
|
|
f.services.commands.register(
|
|
CommandContribution(
|
|
id: 'view.zoomIn',
|
|
command: 'view.zoomIn',
|
|
title: 'View: Zoom In',
|
|
run: (_) async => IpcResponse.ok(id: '', data: const {}),
|
|
),
|
|
);
|
|
controller = MenuBarController();
|
|
});
|
|
|
|
tearDown(() async {
|
|
controller.dispose();
|
|
await f.dispose();
|
|
});
|
|
|
|
Widget harness() => Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: ClideKernel(
|
|
services: f.services,
|
|
child: ClideTheme(
|
|
controller: f.services.theme,
|
|
child: MediaQuery(
|
|
data: const MediaQueryData(),
|
|
child: Align(
|
|
alignment: Alignment.topLeft,
|
|
child: SizedBox(
|
|
width: 900,
|
|
height: 600,
|
|
child: DialogHost(
|
|
router: f.services.dialog,
|
|
child: Overlay(
|
|
initialEntries: [
|
|
OverlayEntry(
|
|
builder: (_) => Align(
|
|
alignment: Alignment.topLeft,
|
|
child: MenuBar(controller: controller),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Future<void> openMenu(WidgetTester tester, String title) async {
|
|
await tester.tap(find.text(title));
|
|
await tester.pump(); // toggle → overlay insert
|
|
await tester.pump(); // dropdown post-frame focus
|
|
}
|
|
|
|
testWidgets('renders File / View / Help buttons', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
expect(find.text('File'), findsOneWidget);
|
|
expect(find.text('View'), findsOneWidget);
|
|
expect(find.text('Help'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('opening File shows its items, incl. a disabled Close Project', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
await openMenu(tester, 'File');
|
|
expect(find.text('Open Folder…'), findsOneWidget);
|
|
expect(find.text('New Window'), findsOneWidget);
|
|
expect(find.text('Close Project'), findsOneWidget); // present but disabled (no project open)
|
|
});
|
|
|
|
testWidgets('tapping the same top button toggles the menu closed', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
// Capture the top button's point while the tree is stable (menu closed),
|
|
// then tapAt it to toggle closed — re-finding 'File' after the overlay opens
|
|
// can hit a transiently-relaid element and throw in getCenter under load.
|
|
final fileCenter = tester.getCenter(find.text('File'));
|
|
await openMenu(tester, 'File');
|
|
expect(find.text('Open Folder…'), findsOneWidget);
|
|
await tester.tapAt(fileCenter);
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 20)); // flush the close under load
|
|
expect(find.text('Open Folder…'), findsNothing);
|
|
});
|
|
|
|
testWidgets('Esc closes an open menu', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
await openMenu(tester, 'File');
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
|
await tester.pump();
|
|
expect(find.text('Open Folder…'), findsNothing);
|
|
});
|
|
|
|
testWidgets('clicking Help → About runs the command and opens the About dialog', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
await openMenu(tester, 'Help');
|
|
await tester.tap(find.text('About clide'));
|
|
await tester.pump();
|
|
await tester.pump();
|
|
// The dialog renders its build-info synchronously (licenses load async).
|
|
expect(find.text(clideVersion), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('keyboard: Down highlights, Enter activates (Help → About)', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
await openMenu(tester, 'Help');
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
|
|
await tester.pump();
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
|
|
await tester.pump();
|
|
await tester.pump();
|
|
expect(find.text(clideVersion), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('keyboard: Right/Left switch between top menus', (tester) async {
|
|
await tester.pumpWidget(harness());
|
|
await tester.pump();
|
|
await openMenu(tester, 'File');
|
|
expect(find.text('Open Folder…'), findsOneWidget);
|
|
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); // File → View
|
|
await tester.pump();
|
|
await tester.pump();
|
|
expect(find.text('Zoom In'), findsOneWidget);
|
|
expect(find.text('Open Folder…'), findsNothing);
|
|
|
|
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft); // View → File
|
|
await tester.pump();
|
|
await tester.pump();
|
|
expect(find.text('Open Folder…'), findsOneWidget);
|
|
});
|
|
}
|