generateTestFile function

String generateTestFile({
  1. required String packageName,
  2. required List<PreviewEntry> entries,
  3. required bool shell,
  4. required bool shots,
})

Implementation

String generateTestFile({
  required String packageName,
  required List<PreviewEntry> entries,
  required bool shell,
  required bool shots,
}) {
  final mountable = entries.where((e) => e.kind != 'missing').toList();
  final missing = entries.where((e) => e.kind == 'missing').toList();
  final markerRe = RegExp(r'\{\{([^}]+)\}\}');
  final uris = {
    for (final e in mountable) ...[
      e.importUri,
      if (e.annoCode != null)
        ...markerRe.allMatches(e.annoCode!).map((m) => m.group(1)!),
    ],
  }.toList()..sort();
  final prefixOf = {for (var i = 0; i < uris.length; i++) uris[i]: 'p$i'};

  final imports = [
    for (final uri in uris) "import '$uri' as ${prefixOf[uri]};",
    if (shell) "import 'package:$packageName/preview/shell.dart' as sh;",
  ].join('\n');
  final host = shell
      ? 'sh.shell(child)'
      : 'MaterialApp(debugShowCheckedModeBanner: false, '
            'home: Scaffold(body: child))';

  final tests = StringBuffer();
  for (final e in mountable) {
    final pfx = prefixOf[e.importUri];
    final desc = e.name == null ? e.id : '${e.id} — ${e.name}';
    final String previews;
    if (e.annoCode == null) {
      previews = 'const <Preview?>[null]';
    } else {
      final resolved = e.annoCode!.replaceAllMapped(
        markerRe,
        (m) => '${prefixOf[m.group(1)!]}.',
      );
      final instance = 'const $resolved.transform()';
      previews = e.isMulti ? instance : '[$instance]';
    }
    tests.writeln('''
  testWidgets(${jsonEncode(desc)}, (tester) async {
    final failure = await _mountPreviews(
      tester,
      id: ${jsonEncode(e.id)},
      previews: $previews,
      build: () => $pfx.${e.expr},
    );
    if (failure != null) fail(failure);
  });
''');
  }
  for (final e in missing) {
    final msg =
        "'${e.className}' (${e.id.split('::').first}) has required "
        'parameters and no @Preview entry — add one, e.g.  '
        "@Preview(name: '...')  static Widget preview() => "
        '${e.className}(...);';
    tests.writeln('''
  test(${jsonEncode('${e.className} needs a @Preview entry')}, () {
    _results.add({'id': ${jsonEncode(e.id)}, 'ok': false, 'error': ${jsonEncode(msg)}});
    fail(${jsonEncode(msg)});
  });
''');
  }

  final support = _supportTemplate
      .replaceAll('__PKG__', packageName)
      .replaceAll('__HOST__', host)
      .replaceAll('__SHOTS__', '$shots');

  return '''
// GENERATED by greenroom — regenerate with `dart run greenroom`.
// Self-contained on purpose: no runtime dependency on greenroom.
// CI recipe: `dart run greenroom --check && flutter test`.
// ignore_for_file: type=lint
import 'dart:convert';
import 'dart:io';
import 'dart:ui' as ui;

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widget_previews.dart';
import 'package:flutter_test/flutter_test.dart';

$imports

void main() {
  setUpAll(_loadRealFonts);
  tearDownAll(_writeVerdicts);
$tests}

$support''';
}