Flutter – How to select DropdownButton item in widget test

Issue

I tried selecting a DropdownButton item like this:

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

void main() {
  testWidgets('Select Dropdown item test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(const SampleApp());

    final dropdown = find.byKey(const ValueKey('dropdown'));

    await tester.tap(dropdown);
    await tester.pumpAndSettle();

    final dropdownItem = find.byKey(const ValueKey('First item key'));

    await tester.tap(dropdownItem);
    await tester.pumpAndSettle();
  });
}

But unfortunately, It throws this exception:
enter image description here

There seems to be something that keeps creating an identical DropdownButton item with the same key, thereby making the widget test fail because, tester.tap() cannot "tap" on two widgets at the same time.

Here’s the full implementation of the DropdownButton widget:

import 'package:flutter/material.dart';

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

class SampleApp extends StatelessWidget {
  const SampleApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dropdown Test Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const Home(),
    );
  }
}

class Home extends StatelessWidget {
  const Home({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: DummyDropdown(
          key: ValueKey('dropdown'),
        ),
      ),
    );
  }
}

class DummyDropdown extends StatefulWidget {
  const DummyDropdown({Key? key}) : super(key: key);

  @override
  State<DummyDropdown> createState() => _DummyDropdownState();
}

class _DummyDropdownState extends State<DummyDropdown> {
  String? text = 'Dropdown';
  String? textValue;

  @override
  Widget build(BuildContext context) {
    return DropdownButton<String>(
      value: textValue,
      underline: Container(),
      dropdownColor: Theme.of(context).cardColor,
      style: Theme.of(context).textTheme.bodyText2,
      hint: Text(
        text!,
      ),
      icon: const Icon(Icons.keyboard_arrow_down),
      onChanged: (newValue) {
        setState(
          () {
            textValue = newValue;
            text = newValue;
          },
        );
      },
      items: <String>['First item', 'Second item', 'Third item']
          .map<DropdownMenuItem<String>>(
        (value) {
          return DropdownMenuItem<String>(
            value: value,
            key: ValueKey('$value key'),
            child: Text(
              value,
            ),
          );
        },
      ).toList(),
    );
  }
}

Solution

Widget testing in drop down button is different than other widgets please see here for more. In this is case select the last element from the text "First Item".This will work.

    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    import 'package:testapp/main.dart';
    
    void main() {
  testWidgets('Select Dropdown item test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(const SampleApp());

    final dropdown = find.byKey(const ValueKey('dropdown'));

    await tester.tap(dropdown);
    await tester.pumpAndSettle();

    ///if you want to tap first item
    final dropdownItem = find.text('First item').last;

    await tester.tap(dropdownItem);
    await tester.pumpAndSettle();
  });

}

The issue is here. when we tap the drop down one was already selected and other one is not selected. So you can test that item using the text value.

final dropdownItem = find.text('First item').last;

Answered By – Dineth Prabashwara

Answer Checked By – Jay B. (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *