9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
358 lines
12 KiB
Dart
358 lines
12 KiB
Dart
import 'package:buzz/features/home/home_page.dart';
|
|
import 'package:buzz/features/channels/channels_page.dart';
|
|
import 'package:buzz/shared/theme/theme.dart';
|
|
import 'package:buzz/shared/l10n/l10n.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
void main() {
|
|
Future<Widget> buildHome({
|
|
int unreadInboxCount = 0,
|
|
bool disableAnimations = false,
|
|
Gradient? topSectionGradient,
|
|
}) async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
final prefs = await SharedPreferences.getInstance();
|
|
return ProviderScope(
|
|
overrides: [savedPrefsProvider.overrideWithValue(prefs)],
|
|
child: MaterialApp(
|
|
locale: const Locale('en'),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
theme: AppTheme.light(topSectionGradient: topSectionGradient),
|
|
builder: (context, child) => MediaQuery(
|
|
data: MediaQuery.of(
|
|
context,
|
|
).copyWith(disableAnimations: disableAnimations),
|
|
child: child!,
|
|
),
|
|
home: HomePage(
|
|
settingsPageBuilder: _buildSettingsPage,
|
|
hasUnreadInbox: unreadInboxCount > 0,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
testWidgets('shows icon-only navigation and an aligned quick action', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(await buildHome());
|
|
await tester.pump();
|
|
|
|
expect(find.text('Home'), findsNothing);
|
|
expect(find.text('Activity'), findsNothing);
|
|
expect(find.text('Search'), findsNothing);
|
|
expect(find.bySemanticsLabel('Home'), findsOneWidget);
|
|
expect(find.bySemanticsLabel('Activity'), findsOneWidget);
|
|
expect(find.bySemanticsLabel('Search'), findsOneWidget);
|
|
|
|
final quickAction = find.byTooltip('Create or start conversation');
|
|
expect(quickAction, findsOneWidget);
|
|
final launcherSize = tester.getSize(
|
|
find.byType(ChannelQuickActionsLauncher),
|
|
);
|
|
expect(launcherSize.width, 800);
|
|
expect(launcherSize.height, greaterThan(0));
|
|
final motionRect = tester.getRect(
|
|
find.byKey(const Key('channel-quick-actions-motion')),
|
|
);
|
|
expect(motionRect.width, const Size.square(56).width);
|
|
expect(motionRect.left, greaterThanOrEqualTo(0));
|
|
expect(tester.getSize(quickAction), const Size.square(56));
|
|
final quickActionRect = tester.getRect(quickAction);
|
|
expect(quickActionRect.left, greaterThanOrEqualTo(0));
|
|
expect(quickActionRect.top, greaterThanOrEqualTo(0));
|
|
expect(quickActionRect.right, lessThanOrEqualTo(800));
|
|
expect(quickActionRect.bottom, lessThanOrEqualTo(600));
|
|
final homeDestinationRect = tester.getRect(find.bySemanticsLabel('Home'));
|
|
expect(
|
|
quickActionRect.center.dy,
|
|
closeTo(homeDestinationRect.center.dy, 0.01),
|
|
);
|
|
});
|
|
|
|
testWidgets('keeps the Buzz backdrop behind the scalable Home screen', (
|
|
tester,
|
|
) async {
|
|
const gradient = LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Colors.yellow, Colors.blue],
|
|
);
|
|
await tester.pumpWidget(await buildHome(topSectionGradient: gradient));
|
|
await tester.pump();
|
|
|
|
final backdrop = find.byKey(
|
|
const ValueKey('home-settings-transition-backdrop'),
|
|
);
|
|
final decoration =
|
|
tester.widget<DecoratedBox>(backdrop).decoration as BoxDecoration;
|
|
expect(decoration.gradient, gradient);
|
|
expect(
|
|
find.byKey(const ValueKey('home-settings-transition-scale')),
|
|
findsOneWidget,
|
|
);
|
|
expect(
|
|
tester
|
|
.widget<Transform>(
|
|
find.byKey(const ValueKey('home-settings-transition-scale')),
|
|
)
|
|
.transform
|
|
.getMaxScaleOnAxis(),
|
|
1,
|
|
);
|
|
expect(
|
|
tester
|
|
.widget<Opacity>(
|
|
find.byKey(const ValueKey('home-settings-transition-opacity')),
|
|
)
|
|
.opacity,
|
|
1,
|
|
);
|
|
});
|
|
|
|
testWidgets('gives selection haptics only when the tab changes', (
|
|
tester,
|
|
) async {
|
|
final hapticCalls = <MethodCall>[];
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(SystemChannels.platform, (call) async {
|
|
if (call.method == 'HapticFeedback.vibrate') {
|
|
hapticCalls.add(call);
|
|
}
|
|
return null;
|
|
});
|
|
addTearDown(
|
|
() => TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(SystemChannels.platform, null),
|
|
);
|
|
|
|
await tester.pumpWidget(await buildHome());
|
|
await tester.pump();
|
|
|
|
await tester.tap(find.byTooltip('Home'));
|
|
await tester.pump();
|
|
expect(hapticCalls, isEmpty);
|
|
|
|
await tester.tap(find.byTooltip('Activity'));
|
|
await tester.pump();
|
|
expect(hapticCalls, hasLength(1));
|
|
expect(hapticCalls.single.arguments, 'HapticFeedbackType.selectionClick');
|
|
|
|
await tester.tap(find.byTooltip('Activity'));
|
|
await tester.pump();
|
|
expect(hapticCalls, hasLength(1));
|
|
|
|
await tester.tap(find.byTooltip('Search'));
|
|
await tester.pump();
|
|
expect(hapticCalls, hasLength(2));
|
|
});
|
|
|
|
testWidgets('gives a light impact when the Home quick action is pressed', (
|
|
tester,
|
|
) async {
|
|
final hapticCalls = <MethodCall>[];
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(SystemChannels.platform, (call) async {
|
|
if (call.method == 'HapticFeedback.vibrate') {
|
|
hapticCalls.add(call);
|
|
}
|
|
return null;
|
|
});
|
|
addTearDown(
|
|
() => TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(SystemChannels.platform, null),
|
|
);
|
|
|
|
await tester.pumpWidget(await buildHome());
|
|
await tester.pump();
|
|
|
|
await tester.tap(find.byTooltip('Create or start conversation'));
|
|
await tester.pump();
|
|
|
|
expect(hapticCalls, hasLength(1));
|
|
expect(hapticCalls.single.arguments, 'HapticFeedbackType.lightImpact');
|
|
});
|
|
|
|
testWidgets('badges the Inbox tab when it has unread rows', (tester) async {
|
|
await tester.pumpWidget(await buildHome(unreadInboxCount: 1));
|
|
await tester.pump();
|
|
|
|
expect(
|
|
find.byKey(const ValueKey('activity-tab-unread-dot')),
|
|
findsOneWidget,
|
|
);
|
|
final badge = tester.widget<Container>(
|
|
find.byKey(const ValueKey('activity-tab-unread-dot')),
|
|
);
|
|
expect(badge.constraints?.maxWidth, 12);
|
|
expect(badge.constraints?.maxHeight, 12);
|
|
expect(find.bySemanticsLabel('Activity, unread'), findsOneWidget);
|
|
AnimatedScale unreadDotScale() => tester.widget<AnimatedScale>(
|
|
find.byKey(const ValueKey('activity-tab-unread-dot-scale')),
|
|
);
|
|
expect(unreadDotScale().scale, 1);
|
|
expect(unreadDotScale().alignment, const Alignment(-0.5, 0.5));
|
|
expect(unreadDotScale().duration, const Duration(milliseconds: 220));
|
|
|
|
await tester.tap(find.byTooltip('Activity'));
|
|
await tester.pump();
|
|
|
|
expect(
|
|
find.byKey(const ValueKey('activity-tab-unread-dot')),
|
|
findsOneWidget,
|
|
);
|
|
expect(unreadDotScale().scale, 0);
|
|
expect(find.bySemanticsLabel('Activity, unread'), findsNothing);
|
|
|
|
await tester.tap(find.byTooltip('Home'));
|
|
await tester.pump();
|
|
|
|
expect(unreadDotScale().scale, 1);
|
|
});
|
|
|
|
testWidgets('fades and slides tab content in the selected direction', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(await buildHome());
|
|
await tester.pump();
|
|
|
|
Transform bodyTransform() => tester.widget<Transform>(
|
|
find.byKey(const ValueKey('frosted-scaffold-body-transition-transform')),
|
|
);
|
|
Opacity bodyOpacity() => tester.widget<Opacity>(
|
|
find.byKey(const ValueKey('frosted-scaffold-body-transition-opacity')),
|
|
);
|
|
Transform appBarTransform() => tester.widget<Transform>(
|
|
find.byKey(
|
|
const ValueKey('frosted-app-bar-content-transition-transform'),
|
|
),
|
|
);
|
|
Opacity appBarOpacity() => tester.widget<Opacity>(
|
|
find.byKey(const ValueKey('frosted-app-bar-content-transition-opacity')),
|
|
);
|
|
double bodyOffset() => bodyTransform().transform.getTranslation().x;
|
|
double appBarOffset() => appBarTransform().transform.getTranslation().x;
|
|
|
|
expect(bodyOffset(), closeTo(0, 0.001));
|
|
expect(appBarOffset(), closeTo(0, 0.001));
|
|
expect(bodyOpacity().opacity, closeTo(1, 0.001));
|
|
expect(appBarOpacity().opacity, closeTo(1, 0.001));
|
|
|
|
await tester.tap(find.byTooltip('Activity'));
|
|
await tester.pump();
|
|
|
|
expect(bodyOffset(), closeTo(24, 0.001));
|
|
expect(appBarOffset(), closeTo(24, 0.001));
|
|
expect(bodyOpacity().opacity, closeTo(0, 0.001));
|
|
expect(appBarOpacity().opacity, closeTo(0, 0.001));
|
|
expect(
|
|
find.descendant(
|
|
of: find.byKey(const ValueKey('frosted-app-bar-background')),
|
|
matching: find.byKey(
|
|
const ValueKey('frosted-app-bar-content-transition-transform'),
|
|
),
|
|
),
|
|
findsOneWidget,
|
|
);
|
|
|
|
await tester.pump(const Duration(milliseconds: 120));
|
|
|
|
expect(bodyOffset(), inExclusiveRange(0, 24));
|
|
expect(appBarOffset(), inExclusiveRange(0, 24));
|
|
expect(bodyOpacity().opacity, inExclusiveRange(0, 1));
|
|
expect(appBarOpacity().opacity, inExclusiveRange(0, 1));
|
|
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.byTooltip('Home'));
|
|
await tester.pump();
|
|
|
|
expect(bodyOffset(), closeTo(-24, 0.001));
|
|
expect(appBarOffset(), closeTo(-24, 0.001));
|
|
expect(bodyOpacity().opacity, closeTo(0, 0.001));
|
|
expect(appBarOpacity().opacity, closeTo(0, 0.001));
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(bodyOffset(), closeTo(0, 0.001));
|
|
expect(appBarOffset(), closeTo(0, 0.001));
|
|
expect(bodyOpacity().opacity, closeTo(1, 0.001));
|
|
expect(appBarOpacity().opacity, closeTo(1, 0.001));
|
|
});
|
|
|
|
testWidgets('switches tab content instantly with reduced motion', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(await buildHome(disableAnimations: true));
|
|
await tester.pump();
|
|
|
|
await tester.tap(find.byTooltip('Activity'));
|
|
await tester.pump();
|
|
|
|
final bodyTransform = tester.widget<Transform>(
|
|
find.byKey(const ValueKey('frosted-scaffold-body-transition-transform')),
|
|
);
|
|
final bodyOpacity = tester.widget<Opacity>(
|
|
find.byKey(const ValueKey('frosted-scaffold-body-transition-opacity')),
|
|
);
|
|
final appBarTransform = tester.widget<Transform>(
|
|
find.byKey(
|
|
const ValueKey('frosted-app-bar-content-transition-transform'),
|
|
),
|
|
);
|
|
final appBarOpacity = tester.widget<Opacity>(
|
|
find.byKey(const ValueKey('frosted-app-bar-content-transition-opacity')),
|
|
);
|
|
expect(bodyTransform.transform.getTranslation().x, closeTo(0, 0.001));
|
|
expect(appBarTransform.transform.getTranslation().x, closeTo(0, 0.001));
|
|
expect(bodyOpacity.opacity, closeTo(1, 0.001));
|
|
expect(appBarOpacity.opacity, closeTo(1, 0.001));
|
|
});
|
|
|
|
testWidgets('scales and fades the quick action as tabs change', (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(await buildHome());
|
|
await tester.pump();
|
|
|
|
double scale() => tester
|
|
.widget<Transform>(find.byKey(const Key('channel-quick-actions-scale')))
|
|
.transform
|
|
.storage
|
|
.first;
|
|
double opacity() => tester
|
|
.widget<Opacity>(find.byKey(const Key('channel-quick-actions-opacity')))
|
|
.opacity;
|
|
|
|
expect(scale(), closeTo(1, 0.001));
|
|
expect(opacity(), closeTo(1, 0.001));
|
|
|
|
await tester.tap(find.byTooltip('Activity'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 110));
|
|
|
|
expect(scale(), inExclusiveRange(0.8, 1));
|
|
expect(opacity(), inExclusiveRange(0, 1));
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(scale(), closeTo(0.8, 0.001));
|
|
expect(opacity(), closeTo(0, 0.001));
|
|
|
|
await tester.tap(find.byTooltip('Home'));
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 110));
|
|
|
|
expect(scale(), inExclusiveRange(0.8, 1));
|
|
expect(opacity(), inExclusiveRange(0, 1));
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(scale(), closeTo(1, 0.001));
|
|
expect(opacity(), closeTo(1, 0.001));
|
|
});
|
|
}
|
|
|
|
Widget _buildSettingsPage(BuildContext context) => const SizedBox.shrink();
|