You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter测试问题:拖动SliverList后无法找到SliverAppBar标题文本

问题:拖动SliverList后测试找不到SliverAppBar标题文本?

我正在为自己的SliverAppBar示例应用编写测试,但测试中拖动SliverList的第一项后,无法找到flexibleSpace中的标题文本“SliverAppBar”。

应用代码

import 'package:flutter/material.dart';

void main() {
  runApp(const StretchableSliverAppBar());
}

class StretchableSliverAppBar extends StatefulWidget {
  const StretchableSliverAppBar({super.key});

  @override
  State<StretchableSliverAppBar> createState() =
      _StretchableSliverAppBarState();
}

class _StretchableSliverAppBarState extends State<StretchableSliverAppBar> {
  bool _stretch = true;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      body: CustomScrollView(
        physics: const BouncingScrollPhysics(),
        slivers: <Widget>[
          SliverAppBar(
            stretch: _stretch,
            onStretchTrigger: () async {},
            expandedHeight: 200.0,
            flexibleSpace: const FlexibleSpaceBar(
              title: Text('SliverAppBar'),
              background: FlutterLogo(),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  color: index.isOdd ? Colors.white : Colors.black12,
                  height: 100.0,
                  child: Center(
                    child: Text('$index', textScaleFactor: 5),
                  ),
                );
              },
              childCount: 20,
            ),
          ),
        ],
      ),
    ));
  }
}

测试代码

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_project/main.dart';

const Offset _kOffset = Offset(0.0, -200.0);

void main() {
  testWidgets('SliverAppbar can be stretched', (WidgetTester tester) async {
    await tester.pumpWidget(
      const StretchableSliverAppBar(),
    );

    expect(find.text('SliverAppBar'), findsOneWidget);
    expect(tester.getBottomLeft(find.text('SliverAppBar')).dy, 184.0);

    await tester.drag(find.text('0'), _kOffset,
        touchSlopY: 0, warnIfMissed: false);
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 500));
    // Failing to find this text "SliverAppBar"
    expect(find.text('SliverAppBar'), findsOneWidget);
 });
}

测试报错信息

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching node in the widget tree
  Actual: _TextFinder:<zero widgets with text "SliverAppBar" (ignoring offstage widgets)>
   Which: means none were found but one was expected

When the exception was thrown, this was the stack:
#4      main.<anonymous closure> (file:///D:/Flutter_Projects/test_project/test/widget_test.dart:56:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

This was caught by the test expectation on the following line:
  file:///D:/Flutter_Projects/test_project/test/widget_test.dart line 56
The test description was:
  SliverAppbar can be stretched
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: SliverAppbar can be stretched

✖ SliverAppbar can be stretched

问题原因及解决方法

原因

当向上拖动SliverList时,SliverAppBar会收缩,默认情况下FlexibleSpaceBar的标题会在AppBar收缩到阈值后被标记为offstage(非舞台可见区域)。而Flutter测试的find.text()方法默认参数skipOffstage: true,会自动忽略不在可见区域的widget,因此找不到该文本。

解决方法

有几种方式可以修复这个测试:

  1. 修改查找逻辑,不忽略offstage widget
    调整查找语句,显式设置skipOffstage: false,这样就能找到即使不在可见区域的文本widget:

    expect(find.text('SliverAppBar', skipOffstage: false), findsOneWidget);
    
  2. 调整拖动偏移量,避免标题隐藏
    减小拖动的垂直偏移,让SliverAppBar不会收缩到标题隐藏的程度,比如把_kOffset改为:

    const Offset _kOffset = Offset(0.0, -100.0);
    

    这样标题会保持在可见区域,默认的查找逻辑就能找到它。

  3. 验证标题的可见性变化(可选)
    如果测试目标是验证SliverAppBar收缩时标题的隐藏行为,可以分两步验证:

    // 默认忽略offstage,此时标题已隐藏,所以找不到
    expect(find.text('SliverAppBar'), findsNothing);
    // 不忽略offstage,确认widget依然存在
    expect(find.text('SliverAppBar', skipOffstage: false), findsOneWidget);
    

内容的提问来源于stack exchange,提问作者Istiak Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 02:22:54