Files
clide/test/builtin/default_layout/widget_test.dart
T
jpmschweitzerandClaude Opus 4.8 6d0ebab721 chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)
Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).

Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
  - whole-tree `dart format` reformat (tall style)
  - `dart fix` for unnecessary_underscores + use_null_aware_elements

No runtime behaviour change; `make test` green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 12:11:53 +02:00

156 lines
7.1 KiB
Dart

import 'package:clide/builtin/default_layout/default_layout.dart';
import 'package:clide/extension/extension.dart';
import 'package:clide/kernel/kernel.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../helpers/kernel_fixture.dart';
void main() {
group('DefaultLayoutExtension', () {
late KernelFixture f;
setUp(() async => f = await KernelFixture.create());
tearDown(() async => f.dispose());
test('activates and applies the classic preset', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
expect(f.services.arrangement.positionOf(Slots.sidebar), SlotPosition.left);
expect(f.services.arrangement.sizeOf(Slots.sidebar), 400);
expect(f.services.arrangement.positionOf(Slots.workspace), SlotPosition.center);
expect(f.services.arrangement.positionOf(Slots.statusbar), SlotPosition.bottom);
});
test('contributes a layout.reset command', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
final reset = f.services.commands.get('layout.reset');
expect(reset, isNotNull);
});
test('layout.reset re-applies the preset', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
f.services.arrangement.setSize(Slots.sidebar, 300);
expect(f.services.arrangement.sizeOf(Slots.sidebar), 300);
final resp = await f.services.commands.execute('layout.reset');
expect(resp.ok, true);
expect(f.services.arrangement.sizeOf(Slots.sidebar), 400);
});
test('declares a layout preset contribution', () {
final ext = DefaultLayoutExtension();
expect(ext.contributions.whereType<LayoutPresetContribution>(), hasLength(1));
});
test('all commands return not-activated errors before activate', () async {
final ext = DefaultLayoutExtension();
final cmds = ext.contributions.whereType<CommandContribution>().toList();
// 12+ commands including the 5 sidebar.section.N variants.
expect(cmds.length, greaterThan(10));
for (final cmd in cmds) {
final r = await cmd.run(const []);
expect(r.ok, isFalse, reason: 'expected ${cmd.command} to fail pre-activate');
expect(r.error!.message, contains('not activated'));
}
});
test('palette.toggle flips palette open state', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
expect(f.services.palette.isOpen, isFalse);
final r1 = await f.services.commands.execute('palette.toggle');
expect(r1.ok, isTrue);
expect(r1.data['open'], isTrue);
expect(f.services.palette.isOpen, isTrue);
final r2 = await f.services.commands.execute('palette.toggle');
expect(r2.data['open'], isFalse);
});
test('sidebar.collapse + context.collapse toggle their respective slots', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isFalse);
await f.services.commands.execute('sidebar.collapse');
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isTrue);
await f.services.commands.execute('sidebar.collapse');
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isFalse);
await f.services.commands.execute('context.collapse');
expect(f.services.arrangement.isCollapsed(Slots.contextPanel), isTrue);
});
test('panel.focus.{left,middle,right} expand collapsed sides + set focus', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
// Collapse both side panels first.
f.services.arrangement.setCollapsed(Slots.sidebar, true);
f.services.arrangement.setCollapsed(Slots.contextPanel, true);
// Focus left: re-expands sidebar.
await f.services.commands.execute('panel.focus.left');
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isFalse);
// Focus right: re-expands context.
await f.services.commands.execute('panel.focus.right');
expect(f.services.arrangement.isCollapsed(Slots.contextPanel), isFalse);
// Focus middle: no expansion needed, just sets focus.
final r = await f.services.commands.execute('panel.focus.middle');
expect(r.ok, isTrue);
});
test('panel.focusMode toggles focus mode on the active slot', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
expect(f.services.arrangement.isInFocusMode, isFalse);
await f.services.commands.execute('panel.focusMode');
expect(f.services.arrangement.isInFocusMode, isTrue);
});
test('panel.focusMode.exit unwinds focus-mode → editor → palette', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
// Focus mode: exit clears it.
f.services.arrangement.toggleFocusMode(Slots.workspace);
expect(f.services.arrangement.isInFocusMode, isTrue);
await f.services.commands.execute('panel.focusMode.exit');
expect(f.services.arrangement.isInFocusMode, isFalse);
// Editor open: exit closes it.
f.services.arrangement.openEditor();
expect(f.services.arrangement.editorOpen, isTrue);
await f.services.commands.execute('panel.focusMode.exit');
expect(f.services.arrangement.editorOpen, isFalse);
// Palette open: exit closes it.
f.services.palette.toggle();
expect(f.services.palette.isOpen, isTrue);
await f.services.commands.execute('panel.focusMode.exit');
expect(f.services.palette.isOpen, isFalse);
// Nothing to exit: returns ok with empty data.
final noop = await f.services.commands.execute('panel.focusMode.exit');
expect(noop.ok, isTrue);
});
test('editor.open and editor.close toggle the editor split', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
expect(f.services.arrangement.editorOpen, isFalse);
await f.services.commands.execute('editor.open');
expect(f.services.arrangement.editorOpen, isTrue);
await f.services.commands.execute('editor.close');
expect(f.services.arrangement.editorOpen, isFalse);
// editor.close when already closed → ok no-op.
final noop = await f.services.commands.execute('editor.close');
expect(noop.ok, isTrue);
});
test('sidebar.section.N activates the Nth sidebar tab', () async {
f.services.extensions.register(DefaultLayoutExtension());
await f.services.extensions.activateAll();
// Collapse sidebar so we exercise the re-expand branch.
f.services.arrangement.setCollapsed(Slots.sidebar, true);
// No-op when no tabs are contributed.
final r = await f.services.commands.execute('sidebar.section.1');
expect(r.ok, isTrue);
// Sidebar auto-expanded.
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isFalse);
});
});
}