captureWidget function Capture

Future<TerminalCapture> captureWidget(
  1. Widget widget, {
  2. int columns = 80,
  3. int rows = 24,
  4. FutureOr<void> arrange(
    1. WidgetTester tester
    )?,
  5. WidgetCaptureMode mode = WidgetCaptureMode.view,
})

Captures widget after layout and optional deterministic interactions.

The widget runs through WidgetTester's real widget app and TEA runtime; its styled view is then drawn into UV cells. This captures the view rather than terminal transport bytes. Use TerminalCapture.fromBuffer when a native renderer buffer is already available.

Use arrange to send keys, change selection, or advance a manual clock. Async data should be awaited explicitly there rather than relying on sleeps. The tester is always disposed, including when setup or capture fails.

Implementation

Future<TerminalCapture> captureWidget(
  Widget widget, {
  int columns = 80,
  int rows = 24,
  FutureOr<void> Function(WidgetTester tester)? arrange,
  WidgetCaptureMode mode = WidgetCaptureMode.view,
}) async {
  if (columns <= 0 ||
      rows <= 0 ||
      columns > terminalCaptureMaxColumns ||
      rows > terminalCaptureMaxRows ||
      columns * rows > terminalCaptureMaxCells) {
    throw ArgumentError(
      'Widget capture dimensions must be positive and bounded.',
    );
  }
  final renderedFrame = mode == WidgetCaptureMode.renderedFrame;
  final tester = WidgetTester(
    screenWidth: columns,
    screenHeight: rows,
    enableRenderer: renderedFrame,
    enableNativeFrameCapture: renderedFrame,
  );
  try {
    await tester.pumpWidget(widget, width: columns, height: rows);
    if (arrange != null) await arrange(tester);
    tester.pump();
    if (renderedFrame) {
      final frame = tester.latestNativeFrame;
      if (frame == null) {
        throw StateError('rendered widget capture produced no native frame');
      }
      final buffer = frame.toBuffer();
      try {
        return TerminalCapture.fromBuffer(buffer);
      } finally {
        // TerminalCapture.fromBuffer copies the cells, so it does not consume
        // this owned intermediate buffer.
        buffer.dispose();
      }
    }
    return TerminalCapture.fromAnsi(tester.view, columns: columns, rows: rows);
  } finally {
    await tester.dispose();
  }
}