Files
plezy/test/widgets/chapter_sheet_test.dart
edde746 61344f7862 test: extract shared fixtures and scaffolds
Collapse duplicated setup across the suite into six shared helpers under
test/test_helpers/ and rewrite the 28 suites that were open-coding it:

  http_fixtures.dart         jsonResponse() for http.Response JSON stubs
  library_tab_scaffold.dart  pumps library tabs under their required ancestors
  multi_server_fixtures.dart MultiServerProvider wiring for widget tests
  playback_report_fakes.dart PlaybackReportCall + fake report sinks
  profile_stack.dart         production-shaped profile dependency graph
  theme.dart                 testMonoTokens for fast-settling widget tests

Net -1245 lines with no change in coverage or assertions.
2026-07-26 06:09:47 +02:00

107 lines
3.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/i18n/strings.g.dart';
import 'package:plezy/media/media_source_info.dart';
import 'package:plezy/mpv/mpv.dart';
import 'package:plezy/widgets/overlay_sheet.dart';
import 'package:plezy/widgets/video_controls/sheets/chapter_sheet.dart';
import '../test_helpers/theme.dart';
void main() {
setUp(() => LocaleSettings.setLocaleSync(AppLocale.en));
testWidgets('denied chapter tile stays open and cannot seek by pointer or select', (tester) async {
final player = _FakePlayer();
await _pumpSheet(tester, player: player, canControl: false);
await tester.tap(find.text('Chapter One'));
await tester.sendKeyEvent(LogicalKeyboardKey.enter);
await tester.pump();
expect(player.seeks, isEmpty);
expect(find.text('Chapter One'), findsOneWidget);
});
testWidgets('authorized chapter seeks, reports completion, and closes', (tester) async {
final player = _FakePlayer();
final completions = <Duration>[];
await _pumpSheet(tester, player: player, canControl: true, onCompleted: completions.add);
await tester.tap(find.text('Chapter One'));
await tester.pumpAndSettle();
expect(player.seeks, [const Duration(seconds: 10)]);
expect(completions, [const Duration(seconds: 10)]);
expect(find.text('Chapter One'), findsNothing);
});
}
Future<void> _pumpSheet(
WidgetTester tester, {
required _FakePlayer player,
required bool canControl,
ValueChanged<Duration>? onCompleted,
}) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(extensions: const [testMonoTokens]),
home: OverlaySheetHost(
child: Scaffold(
body: Builder(
builder: (context) => ElevatedButton(
onPressed: () => OverlaySheetController.of(context).show<void>(
builder: (_) => ChapterSheet(
player: player,
chapters: [MediaChapter(id: 1, startTimeOffset: 10000, title: 'Chapter One')],
chaptersLoaded: true,
canControl: canControl,
onSeekCompleted: onCompleted,
),
),
child: const Text('Open'),
),
),
),
),
),
);
await tester.tap(find.text('Open'));
await tester.pumpAndSettle();
}
class _FakePlayer implements Player {
final List<Duration> seeks = [];
@override
PlayerState get state => PlayerState(duration: const Duration(minutes: 30));
@override
PlayerStreams get streams => const PlayerStreams(
playing: Stream<bool>.empty(),
completed: Stream<bool>.empty(),
buffering: Stream<bool>.empty(),
position: Stream<Duration>.empty(),
duration: Stream<Duration>.empty(),
seekable: Stream<bool>.empty(),
buffer: Stream<Duration>.empty(),
volume: Stream<double>.empty(),
rate: Stream<double>.empty(),
tracks: Stream<Tracks>.empty(),
track: Stream<TrackSelection>.empty(),
log: Stream<PlayerLog>.empty(),
error: Stream<PlayerError>.empty(),
audioDevice: Stream<AudioDevice>.empty(),
audioDevices: Stream<List<AudioDevice>>.empty(),
bufferRanges: Stream<List<BufferRange>>.empty(),
playbackRestart: Stream<void>.empty(),
backendSwitched: Stream<void>.empty(),
);
@override
Future<void> seek(Duration position) async => seeks.add(position);
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}