Skip to content

[Widget Tests] - Unpredictable behavior when simulated keys specify different platforms #133955

@matthew-carroll

Description

@matthew-carroll

When simulating a key press, there's an optional "platform" parameter. That parameter defaults to "android". Due to the hard-coded default value, it's easy to end up with mismatched platform values, and it appears that mixing platform values results in unexpected behaviors.

Here's a minimal test repro:

testWidgets("bug repro", (widgetTester) async {
      debugDefaultTargetPlatformOverride = TargetPlatform.linux;

      await widgetTester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: Focus(
              onKey: (FocusNode node, RawKeyEvent keyEvent) {
                print("Key event");
                print("$keyEvent");
                print("Is shift pressed? ${keyEvent.isShiftPressed}");
                print("");

                return KeyEventResult.ignored;
              },
              autofocus: true,
              child: const SizedBox.expand(),
            ),
          ),
        ),
      );

      print("Pressing SHIFT down");
      await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.shift);

      await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.arrowLeft, platform: "linux");
      await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.arrowLeft, platform: "linux");

      print("Releasing SHIFT");
      await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.shift);

      debugDefaultTargetPlatformOverride = null;
    });

Here's the test output:

Pressing SHIFT down
Key event
RawKeyDownEvent#e1bcc(logicalKey: LogicalKeyboardKey#df100(keyId: "0x200000102", keyLabel: "Shift Left", debugName: "Shift Left"), physicalKey: PhysicalKeyboardKey#ed430(usbHidUsage: "0x000700e1", debugName: "Shift Left"), repeat: false)
Is shift pressed? true

Key event
RawKeyDownEvent#3d221(logicalKey: LogicalKeyboardKey#860f3(keyId: "0x100000302", keyLabel: "Arrow Left", debugName: "Arrow Left"), physicalKey: PhysicalKeyboardKey#52951(usbHidUsage: "0x00070050", debugName: "Arrow Left"), repeat: false)
Is shift pressed? true

Key event
RawKeyUpEvent#fc85a(logicalKey: LogicalKeyboardKey#860f3(keyId: "0x100000302", keyLabel: "Arrow Left", debugName: "Arrow Left"), physicalKey: PhysicalKeyboardKey#52951(usbHidUsage: "0x00070050", debugName: "Arrow Left"))
Is shift pressed? true

Releasing SHIFT
Key event
RawKeyUpEvent#14075(logicalKey: LogicalKeyboardKey#df100(keyId: "0x200000102", keyLabel: "Shift Left", debugName: "Shift Left"), physicalKey: PhysicalKeyboardKey#ed430(usbHidUsage: "0x000700e1", debugName: "Shift Left"))
Is shift pressed? true

Notice that the final "Is shift pressed" is true, when it should be false.

Switching the test to the following results in the correct shift recognition:

testWidgets("bug repro", (widgetTester) async {
      debugDefaultTargetPlatformOverride = TargetPlatform.linux;

      await widgetTester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: Focus(
              onKey: (FocusNode node, RawKeyEvent keyEvent) {
                print("Key event");
                print("$keyEvent");
                print("Is shift pressed? ${keyEvent.isShiftPressed}");
                print("");

                return KeyEventResult.ignored;
              },
              autofocus: true,
              child: const SizedBox.expand(),
            ),
          ),
        ),
      );

      print("Pressing SHIFT down");
      await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.shift, platform: "linux");

      await widgetTester.sendKeyDownEvent(LogicalKeyboardKey.arrowLeft, platform: "linux");
      await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.arrowLeft, platform: "linux");

      print("Releasing SHIFT");
      await widgetTester.sendKeyUpEvent(LogicalKeyboardKey.shift, platform: "linux");

      debugDefaultTargetPlatformOverride = null;
    });

The reason that this situation is a problem, is because sometimes a package is used to simulate key presses. This expectation that independent key calls all match their platform then requires knowledge about the internals of a package's selection, and also requires careful and consistent adherence through all simulation calls that one executes.

For example, this problem was originally found by way of the following snippet:

await tester.sendKeyDownEvent(LogicalKeyboardKey.shift);
await tester.pressCtlLeftArrow();
await tester.sendKeyUpEvent(LogicalKeyboardKey.shift);

The pressCtlLeftArrow() method chose its platform based on defaultTargetPlatform, which happened to be "linux". But the regular simulation calls around it used Flutter's default, which is always "android". Thus, the unexpected SHIFT result.

Metadata

Metadata

Labels

P2Important issues not at the top of the work lista: tests"flutter test", flutter_test, or one of our testsa: text inputEntering text in a text field or keyboard related problemsfound in release: 3.13Found to occur in 3.13found in release: 3.14Found to occur in 3.14frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

Status

Done (PR merged)

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions