feat: import Chinese-localized Buzz source snapshot
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
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>
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
import 'package:buzz/shared/theme/theme.dart';
|
||||
import 'package:buzz/shared/widgets/skeleton.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
Widget buildShimmerTestable({
|
||||
bool disableAnimations = false,
|
||||
bool enabled = true,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: AppTheme.light(),
|
||||
builder: (context, child) => MediaQuery(
|
||||
data: MediaQuery.of(
|
||||
context,
|
||||
).copyWith(disableAnimations: disableAnimations),
|
||||
child: child!,
|
||||
),
|
||||
home: Scaffold(
|
||||
body: SkeletonShimmer(
|
||||
enabled: enabled,
|
||||
child: const SkeletonBar(width: 120, height: 16),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildRevealTestable({
|
||||
required ValueNotifier<bool> loading,
|
||||
bool disableAnimations = false,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: AppTheme.light(),
|
||||
builder: (context, child) => MediaQuery(
|
||||
data: MediaQuery.of(
|
||||
context,
|
||||
).copyWith(disableAnimations: disableAnimations),
|
||||
child: child!,
|
||||
),
|
||||
home: Scaffold(
|
||||
body: ValueListenableBuilder(
|
||||
valueListenable: loading,
|
||||
builder: (context, isLoading, _) => SkeletonReveal(
|
||||
loading: isLoading,
|
||||
skeleton: const SkeletonBar(width: 120, height: 16),
|
||||
content: const Text('Loaded content'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double layerOpacity(WidgetTester tester, String key) =>
|
||||
tester.widget<Opacity>(find.byKey(Key(key))).opacity;
|
||||
|
||||
bool contentFocusExcluded(WidgetTester tester) => tester
|
||||
.widget<ExcludeFocus>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('skeleton-reveal-content')),
|
||||
matching: find.byType(ExcludeFocus),
|
||||
),
|
||||
)
|
||||
.excluding;
|
||||
|
||||
testWidgets('sweeps a highlight across skeleton elements while loading', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(buildShimmerTestable());
|
||||
|
||||
final shimmer = find.byType(SkeletonShimmer);
|
||||
expect(find.byType(SkeletonBar), findsOneWidget);
|
||||
expect(
|
||||
find.descendant(of: shimmer, matching: find.byType(ShaderMask)),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
final boundary = tester.renderObject<RenderRepaintBoundary>(
|
||||
find
|
||||
.descendant(of: shimmer, matching: find.byType(RepaintBoundary))
|
||||
.first,
|
||||
);
|
||||
final beforeBytes = await tester.runAsync(() async {
|
||||
final image = await boundary.toImage();
|
||||
return image.toByteData();
|
||||
});
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 1000));
|
||||
final afterBytes = await tester.runAsync(() async {
|
||||
final image = await boundary.toImage();
|
||||
return image.toByteData();
|
||||
});
|
||||
|
||||
expect(
|
||||
beforeBytes!.buffer.asUint8List(),
|
||||
isNot(equals(afterBytes!.buffer.asUint8List())),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('keeps skeleton elements static for reduced motion', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(buildShimmerTestable(disableAnimations: true));
|
||||
|
||||
final shimmer = find.byType(SkeletonShimmer);
|
||||
expect(find.byType(SkeletonBar), findsOneWidget);
|
||||
expect(
|
||||
find.descendant(of: shimmer, matching: find.byType(ShaderMask)),
|
||||
findsNothing,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('keeps skeleton elements static when shimmer is disabled', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(buildShimmerTestable(enabled: false));
|
||||
|
||||
final shimmer = find.byType(SkeletonShimmer);
|
||||
expect(find.byType(SkeletonBar), findsOneWidget);
|
||||
expect(
|
||||
find.descendant(of: shimmer, matching: find.byType(ShaderMask)),
|
||||
findsNothing,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('reveals content in the same slot with a 400ms cross-fade', (
|
||||
tester,
|
||||
) async {
|
||||
final loading = ValueNotifier(true);
|
||||
await tester.pumpWidget(buildRevealTestable(loading: loading));
|
||||
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-placeholder'), 1);
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-content'), 0);
|
||||
expect(contentFocusExcluded(tester), isTrue);
|
||||
|
||||
loading.value = false;
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
expect(
|
||||
layerOpacity(tester, 'skeleton-reveal-placeholder'),
|
||||
closeTo(0.5, 0.01),
|
||||
);
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-content'), closeTo(0.5, 0.01));
|
||||
expect(contentFocusExcluded(tester), isTrue);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-placeholder'), 0);
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-content'), 1);
|
||||
expect(contentFocusExcluded(tester), isFalse);
|
||||
expect(find.text('Loaded content'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('resets to the skeleton without animating backwards', (
|
||||
tester,
|
||||
) async {
|
||||
final loading = ValueNotifier(false);
|
||||
await tester.pumpWidget(buildRevealTestable(loading: loading));
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-content'), 1);
|
||||
|
||||
loading.value = true;
|
||||
await tester.pump();
|
||||
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-placeholder'), 1);
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-content'), 0);
|
||||
});
|
||||
|
||||
testWidgets('reveals immediately for reduced motion', (tester) async {
|
||||
final loading = ValueNotifier(true);
|
||||
await tester.pumpWidget(
|
||||
buildRevealTestable(loading: loading, disableAnimations: true),
|
||||
);
|
||||
final reveal = find.byType(SkeletonReveal);
|
||||
expect(
|
||||
find.descendant(of: reveal, matching: find.byType(ShaderMask)),
|
||||
findsNothing,
|
||||
);
|
||||
|
||||
loading.value = false;
|
||||
await tester.pump();
|
||||
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-placeholder'), 0);
|
||||
expect(layerOpacity(tester, 'skeleton-reveal-content'), 1);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user