pk_view_test.dart 4.85 KB
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:doublefeel_flutter/app/modules/pk/models/pk_data.dart';
import 'package:doublefeel_flutter/app/modules/pk/views/pk_view.dart';
import 'package:doublefeel_flutter/l10n/gen/app_localizations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

PkData designData(PkResult result) {
  final leftScore = switch (result) {
    PkResult.win => 800,
    PkResult.loss => 100,
    PkResult.draw => 500,
  };
  final leftWins = switch (result) {
    PkResult.win => 20,
    PkResult.loss => 5,
    PkResult.draw => 12,
  };
  return PkData(
    month: DateTime(2023, 9),
    left: PkPlayer(
      name: '蓝胖子',
      subtitle: '(女朋友)',
      avatarAsset: 'assets/images/pk/preview_friend.png',
      score: leftScore,
      steps: 15843,
      calories: 200,
      standingHours: .8,
      winningDays: leftWins,
    ),
    right: PkPlayer(
      name: '哆啦A梦',
      subtitle: '(我)',
      avatarAsset: 'assets/images/pk/preview_self.png',
      score: 1000 - leftScore,
      steps: 285,
      calories: 183,
      standingHours: 3.4,
      winningDays: result == PkResult.draw ? 12 : 25 - leftWins,
    ),
    days: {
      for (var day = 1; day <= 25; day++)
        day: PkDay(
          [800, 400, 300, 800, 750, 400, 200][(day - 1) % 7],
          [200, 600, 700, 200, 250, 600, 800][(day - 1) % 7],
        ),
    },
  );
}

Widget app(PkData data, {VoidCallback? onSwitchFriend}) => MaterialApp(
  debugShowCheckedModeBanner: false,
  theme: ThemeData(
    fontFamily: Platform.environment['PK_FONT_PATH'] == null
        ? null
        : 'PkPreview',
  ),
  locale: const Locale('zh'),
  localizationsDelegates: AppLocalizations.localizationsDelegates,
  supportedLocales: AppLocalizations.supportedLocales,
  home: Scaffold(
    body: PkView(data: data, onPoke: (_) {}, onSwitchFriend: onSwitchFriend),
  ),
);

Future<void> loadImages(WidgetTester tester) async {
  await tester.runAsync(() async {
    final context = tester.element(find.byType(PkView));
    for (final name in [
      'left_banner',
      'right_banner',
      'crown',
      'preview_friend',
      'preview_self',
      'steps',
      'calories',
      'standing',
      'poke',
      'lightning',
      'score_stripes',
      'podium_winner',
      'podium_loser',
    ]) {
      await precacheImage(AssetImage('assets/images/pk/$name.png'), context);
    }
    await precacheImage(
      const AssetImage('assets/images/common/ic_replace.png'),
      context,
    );
    await precacheImage(
      const AssetImage(
        'assets/images/common/ic_bottom_slogan_double_feel.webp',
      ),
      context,
    );
  });
  await tester.pumpAndSettle();
}

void main() {
  setUpAll(() async {
    final path = Platform.environment['PK_FONT_PATH'];
    if (path != null) {
      final loader = FontLoader('PkPreview')
        ..addFont(
          Future.value(ByteData.sublistView(File(path).readAsBytesSync())),
        );
      await loader.load();
    }
  });
  test('missing data is not counted as a draw', () {
    expect(PkData.compare(null, null), isNull);
    expect(PkData.compare(0, 0), PkResult.draw);
    expect(PkData.compare(800, 200), PkResult.win);
    expect(PkData.compare(100, 900), PkResult.loss);
  });
  for (final result in PkResult.values) {
    testWidgets('${result.name} renders the complete design', (tester) async {
      tester.view.physicalSize = const Size(375, 1400);
      tester.view.devicePixelRatio = 1;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);
      await tester.pumpWidget(app(designData(result)));
      await loadImages(tester);
      expect(tester.takeException(), isNull);
      expect(find.text('今日健康PK'), findsOneWidget);
      expect(
        find.text('平局'),
        result == PkResult.draw ? findsOneWidget : findsNothing,
      );
      final captureDir = Platform.environment['PK_CAPTURE_DIR'];
      if (captureDir != null) {
        await expectLater(
          find.byType(MaterialApp),
          matchesGoldenFile('$captureDir/pk_${result.name}.png'),
        );
      }
    });
  }
  testWidgets('small screen scrolls and friend switch responds', (
    tester,
  ) async {
    tester.view.physicalSize = const Size(320, 640);
    tester.view.devicePixelRatio = 1;
    addTearDown(tester.view.resetPhysicalSize);
    addTearDown(tester.view.resetDevicePixelRatio);
    var switched = false;
    await tester.pumpWidget(
      app(designData(PkResult.draw), onSwitchFriend: () => switched = true),
    );
    await tester.pumpAndSettle();
    await tester.tap(find.byTooltip('切换好友'));
    expect(switched, isTrue);
    await tester.drag(find.byType(ListView), const Offset(0, -650));
    await tester.pumpAndSettle();
    expect(tester.takeException(), isNull);
    expect(find.text('30'), findsOneWidget);
  });
}