Repository: flutter
Issue: [Web][Engine]: AssertionError when execute Tests with ListView on Headful Chrome
Labels: engine,platform-web,f: integration_test,has reproducible steps,P2,found in release: 2.8,found in release: 2.10,team-web,triaged-web

## Steps to Reproduce

<!-- Please include full steps to reproduce so that we can reproduce the problem. -->

1. Execute `flutter run test.dart -d chrome` on the code sample <!-- (see "Code sample" section below) -->
2. Following conditions must be fulfilled, all considered in the tests below:
    - Widget (stateful or via ValueListener) must be updated asynchronously (e.g. with a delay)
    - Must render a ListView (or other BoxScrollView with SliverChildListDelegate), Column works fine
    - List items must be reduced from test to test (increasing or equal number works fine)
    - Must be executed in Web (e.g. Chrome)
    - Must be executed Headful (a headless test is successfull)
  
  In order to be able to debug headful tests in Chrome I added the method `resetDebugOptions` and executed the file as a flutter app. Otherwise the test environment complains, that the debug values changed, I think by flutter. Here's the `.run` file for IntelliJ:
```
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="ListView Test" type="FlutterRunConfigurationType" factoryName="Flutter">
    <option name="additionalArgs" value="--purge-persistent-cache" />
    <option name="filePath" value="$PROJECT_DIR$/test/test.dart" />
    <method v="2" />
  </configuration>
</component>
```

**Expected results:** <!-- what did you want to see? -->
Test should be successful

**Actual results:** <!-- what did you see? -->
Test failed:
```
The following assertion was thrown during a scheduler callback:
Assertion failed: "Parent #9 has child #7. However, the child is attached to #8."
```
See Flutter Engine: https://github.com/flutter/engine/blob/802332a525246a031da14e59bb87394707d1bd95/lib/web_ui/lib/src/engine/semantics/semantics.dart#L1621-L1623

My guess is, that ListItems are not deleted properly between tests or some how cached by CanvasKit / Skia. Or more likely the test is interrupted and because of the async rendering, the items are stored in the wrong internal rendering list of web, and therefore not deleted on the widget.dispose() method.

<details>
<summary>Code sample</summary>

```dart
/// test.dart

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

// Set overall count of tests, equals item count of first test
// Can be also set to higher value, in order to execute tests with more items.
const maxTests = 2;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('test-async-listview', () {
    for (var testCount = maxTests; testCount > 0; testCount--) {
      testWidgets('Display $testCount items', (WidgetTester tester) async {
        await tester.pumpWidget(MaterialApp(home: TestScreen(testCount)));
        await tester.pumpAndSettle();

        await waitFor(find.byType(TestScreen), tester);

        for (var i = 0; i < testCount; i++) {
          await waitFor(find.text('item$i'), tester);
          print('\x1B[35m Found item$i in test $testCount \x1B[0m');
        }
        // Can be commented to execute in full speed:
        await tester.pump(const Duration(milliseconds: 2000));

        resetDebugOptions();
      });
    }
  });
}

class TestScreen extends StatefulWidget {
  final int testCount;

  const TestScreen(this.testCount, {Key? key}) : super(key: key);

  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  bool isLoading = true;

  List<String> getItems() {
    final data = <String>[];
    for (var i = 0; i < widget.testCount; i++) {
      data.add('item$i');
    }
    return data;
  }

  @override
  void initState() {
    Future.delayed(const Duration(microseconds: 1)).then((value) {
      if (mounted) {
        setState(() {
          isLoading = false;
        });
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    print('\x1B[37m Build new state in test ${widget.testCount} \x1B[0m');

    final data = getItems();

    return Scaffold(
      appBar: AppBar(
        title: const Text('TestScreen'),
      ),
      body: isLoading
          ? const CircularProgressIndicator()
          : ListView.builder(
              itemCount: data.length,
              itemBuilder: (context, index) {
                return Text(data[index]);
              },
            ),
          /// Uncomment to test with column, which works fine
          // : Column(children: data.map((e) => Text(e)).toList()),
    );
  }
}

Future<void> waitFor(Finder finder, WidgetTester tester) => waitUntil(
      () async {
    try {
      await tester.pumpAndSettle();
      expect(finder, findsOneWidget);
      return true;
    } on TestFailure {
      return false;
    }
  },
);

/// Waits until the [condition] returns true
/// Will raise a complete with a [TimeoutException] if the
/// condition does not return true with the timeout period.
/// Copied from: https://github.com/jonsamwell/flutter_gherkin/blob/02a4af91d7a2512e0a4540b9b1ab13e36d5c6f37/lib/src/flutter/utils/driver_utils.dart#L86
Future<void> waitUntil(
  Future<bool> Function() condition, {
  Duration? timeout = const Duration(seconds: 15),
  Duration? pollInterval = const Duration(milliseconds: 500),
}) async {
  return Future.microtask(
    () async {
      final completer = Completer<void>();
      var maxAttempts = (timeout!.inMilliseconds / pollInterval!.inMilliseconds).round();
      var attempts = 0;

      while (attempts < maxAttempts) {
        final result = await condition();
        if (result) {
          completer.complete();
          break;
        } else {
          await Future.delayed(pollInterval);
        }
      }
    },
  ).timeout(
    timeout!,
  );
}

resetDebugOptions() {
  debugPrint = debugPrintSynchronously;
  debugDefaultTargetPlatformOverride = null;
  debugDoublePrecision = null;
  debugBrightnessOverride = null;
}
```

</details>

<details>
  <summary>Logs</summary>

```
Launching test\test2.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome...
This app is linked to the debug service: ws://127.0.0.1:55021/sP9LJ77_YbM=/ws
Debug service listening on ws://127.0.0.1:55021/sP9LJ77_YbM=/ws

 Running with sound null safety 
Debug service listening on ws://127.0.0.1:55021/sP9LJ77_YbM=/ws
00:00 +0: test-async-listview Display 2 items
 Build new state in test 2 
 Build new state in test 2 
 Found item0 in test 2 
 Found item1 in test 2 
00:04 +1: test-async-listview Display 1 items
00:04 +1: test-async-listview Display 2 items
 Build new state in test 1 
 Build new state in test 1 
00:05 +1: test-async-listview Display 1 items
 Found item0 in test 1 
══╡ EXCEPTION CAUGHT BY SCHEDULER LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during a scheduler callback:
Assertion failed: "Parent #9 has child #7. However, the child is attached to #8."

When the exception was thrown, this was the stack:
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49  throw_
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/semantics/semantics.dart 1601:15           <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13      forEach
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/semantics/semantics.dart 1585:22           <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/semantics/semantics.dart 1615:14           updateSemantics
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/platform_dispatcher.dart 630:35            updateSemantics
packages/flutter_test/src/window.dart 394:24                                                                               updateSemantics
packages/flutter/src/semantics/semantics.dart 3056:22                                                                      sendSemanticsUpdate
packages/flutter/src/rendering/object.dart 1098:7                                                                          flushSemantics
packages/flutter/src/rendering/binding.dart 502:21                                                                         drawFrame
packages/flutter/src/widgets/binding.dart 883:13                                                                           drawFrame
packages/flutter/src/rendering/binding.dart 363:5                                                                          [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1144:15                                                                        [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1081:9                                                                         handleDrawFrame
packages/flutter_test/src/binding.dart 1458:30                                                                             handleDrawFrame
packages/flutter/src/scheduler/binding.dart 995:5                                                                          [_handleDrawFrame]
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/platform_dispatcher.dart 1060:13           invoke
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/platform_dispatcher.dart 160:5             invokeOnDrawFrame
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/initialization.dart 128:45                 <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1442:13                                          _rootRunUnary
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1335:19                                          runUnary
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1244:7                                           runUnaryGuarded
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1281:26                                          <fn>
════════════════════════════════════════════════════════════════════════════════════════════════════
00:08 +1: test-async-listview Display 1 items [E]
  Test failed. See exception logs above.
  The test description was: Display 1 items

00:08 +1 -1: (tearDownAll)
00:08 +2 -1: Some tests failed.
```

<!-- Finally, paste the output of running `flutter doctor -v` here. -->

```
[√] Flutter (Channel master, 2.10.0-1.0.pre.359, on Microsoft Windows [Version 10.0.22000.466], locale
    en-US)
    • Flutter version 2.10.0-1.0.pre.359 at C:\src\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision d010a85476 (3 hours ago), 2022-02-01 14:55:07 -0500
    • Engine revision b0e6fe8e80
    • Dart version 2.17.0 (build 2.17.0-69.0.dev)
    • DevTools version 2.10.0-dev.1

[√] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at C:\src\android\Sdk
    • Platform android-31, build-tools 31.0.0
    • Java binary at: C:\Program Files\Java\jdk-15.0.2\bin\java
    • Java version OpenJDK Runtime Environment (build 15.0.2+7-27)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.11.8)
    • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
    • Visual Studio Community 2019 version 16.11.32002.261
    • Windows 10 SDK version 10.0.19041.0

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/windows#android-setup for detailed
      instructions).

[√] IntelliJ IDEA Ultimate Edition (version 2021.3)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA 2021.2
    • Flutter plugin version 63.2.4
    • Dart plugin version 213.5744.122

[√] VS Code (version 1.56.2)
    • VS Code at C:\Users\Gustl\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension can be installed from:
       https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22000.466]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 97.0.4692.99
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 96.0.1054.34

[√] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.
```

</details>