小部件测试 DropdownButton 发现重复的 DropdownMenuItems

Widget testing DropdownButton finds duplicate DropdownMenuItems

我正在尝试为我的应用程序中的 DropdownButton 编写小部件测试。我注意到在点击按钮将其打开后,对 find.byType(DropdownMenuItem) 的调用返回的 DropdownMenuItems 数量是预期数量的两倍。

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

enum MyColor {
  blue,
  green,
  red,
  yellow,
  black,
  pink
}

Future<void> main() async {
//   runApp(MyApp());
  
  // tests
  group('dropdown tests', () {
    testWidgets('how many elements should be found?', (tester) async {
      await tester.pumpWidget(MyApp());
      await tester.pumpAndSettle();
      
      expect(find.byType(DropdownButton<MyColor>), findsOneWidget);
      await tester.tap(find.byType(DropdownButton<MyColor>));
      await tester.pumpAndSettle();
      
      // fails
      // expect(find.byType(DropdownMenuItem<MyColor>), findsNWidgets(MyColor.values.length));
      
      // passes
      expect(find.byType(DropdownMenuItem<MyColor>), findsNWidgets(MyColor.values.length * 2));
    });
  });
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  MyColor selected = MyColor.blue;
  
  @override
  Widget build(BuildContext context) {
    return DropdownButton<MyColor>(
      value: selected,
      items: MyColor.values.map((col) {
        return DropdownMenuItem<MyColor>(
          child: Text(col.name),
          value: col,
        );
      }).toList(),
      onChanged: (value) {
        if (value == null) {
          return;
        }
        
        print('${value.name} selected');
        setState(() {
          selected = value;
        });
      }
    );
  } 
}

飞镖板:https://dartpad.dev/?id=ce3eadff6bd98e6005817c70883451a0

我怀疑这与Flutter渲染场景的方式有关。我查看了 widget tests for the dropdown in the Flutter repo,但没有发现我的设置与他们的有任何区别,而且我也没有看到对 find.byType(DropdownMenuItem) 的任何调用。有谁知道为什么会这样?还是我的代码有错误?

最初呈现 DropdownButton 时,所有项目都使用 IndexedStack 呈现,并且根据所选值,我们在顶部看到一个可见项目

  • 在那个阶段 find.byType(DropdownMenuItem<MyColor>) 会找到 6 项目

点击 DropdownButton 后,_DropdownRoute 路线为 pushed,其中包含所有项目

  • 在那个阶段 find.byType(DropdownMenuItem<MyColor>) 会找到 12 项(前 6 项来自 IndexedStack,后 6 项来自 IndexedStack 项目来自新路线) 因此,在这个阶段,项目的数量应该是 flutter 测试中记录的两倍

// Each item appears twice, once in the menu and once // in the dropdown button's IndexedStack.

https://github.com/flutter/flutter/blob/504e66920005937b6ffbc3ccd6b59d594b0e98c4/packages/flutter/test/material/dropdown_test.dart#L2230

点击 DropdownMenuItem 个项目后,找到的小部件数量将恢复为 6