Skip to content

EditableText crashes when text editing value changes between consecutive scrolls #179164

@Renzo-Olivares

Description

@Renzo-Olivares

Steps to reproduce

  1. Run the test below, it will crash with a type error, null check operator used on a null value.
testWidgets(
  'Does not crash when editing value changes between consecutive scrolls',
  (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/
    final controller = TextEditingController(text: 'text ' * 10000);
    addTearDown(controller.dispose);

    await tester.pumpWidget(
      MaterialApp(
        home: Material(child: TextField(controller: controller, maxLines: null)),
      ),
    );

    final Finder textField = find.byType(TextField);
    final EditableTextState editableTextState = tester.state<EditableTextState>(
      find.byType(EditableText),
    );
    // Long press to select the first word and show the toolbar.
    await tester.longPressAt(textOffsetToPosition(tester, 0));
    await tester.pumpAndSettle();
    expect(editableTextState.selectionOverlay?.toolbarIsVisible, true);
    expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4));

    // Scroll down so selection is not visible, and toolbar is scheduled to be shown
    // when the selection is once again visible.
    final TestGesture gesture = await tester.startGesture(tester.getCenter(textField));
    await gesture.moveBy(const Offset(0.0, -200.0));
    await tester.pump();
    await gesture.up();

    // Scroll again before the post-frame callback from the first scroll is run to invalidate
    // the data from the first scroll.
    controller.value = const TextEditingValue(text: 'a different value');

    await gesture.down(tester.getCenter(textField));
    await gesture.moveBy(const Offset(0.0, -100.0));
    await tester.pump();
    await gesture.up();
    await tester.pump();
    // This test should reach the end without crashing.
  },
  variant: TargetPlatformVariant.only(TargetPlatform.android),
);

Expected results

Running the test above should pass.

Actual results

Test above, crashes with a type error, null check operator used on a null value.

Root cause

If the text editing value changes between two scrolls, when the second scroll ends _dataWhenToolbarShowScheduled will be invalidated. If the second scroll ends before the post frame callback scheduled by the first scroll has a chance to execute, there will be a crash because _dataWhenToolbarShowScheduled is being accessed while null.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions