Skip to content

[flutter_tools] Web test run reports "did not complete" for every remaining test with no diagnostic when the browser connection drops #191920

Closed

Description

@gabrimatic

Summary

When the browser hangs up its WebSocket connection to the test host while flutter test --platform chrome still has suites running, the tool shuts the browser down and reports every remaining test as did not complete without printing anything that explains why. Even with -v, the only trace is Shutting down Chromium.

Expected results

An error naming the cause, the way the two existing browser-exit messages do.

Actual results

01:10 +755: window 1280×1440
[+71385 ms] Shutting down Chromium.
[   +4 ms] Test suite test/all_pages_smoke_test.dart finished.
01:10 +755: window 1280×1440 - did not complete [E]
01:10 +755: window 1440×320 - did not complete [E]
... 39 more

No error, no exit code, nothing on stderr. The browser was launched with --enable-logging=stderr; it emitted nothing at the moment of the disconnect, and the browser process itself did not exit unexpectedly (the tool closed it afterwards).

Root cause

BrowserManager ends the run silently when the channel closes, in packages/flutter_tools/lib/src/test/flutter_web_platform.dart:

_channel.stream.listen(_onMessage, onDone: close);

Two diagnostics already exist for a browser that goes away, but neither can fire on this path, because close() marks everything closed before the browser process exits:

  • BrowserManager's _browser.onExit handler is guarded by if (!_closed), and close() sets _closed = true first.
  • Chromium's process-exit handler is guarded by if (!_didClose && code != 0), and Chromium.close() sets _didClose = true.

So the one case where the browser stops serving the test host without its process dying is the only case with no message at all.

Impact

A run that loses its browser is indistinguishable from a run whose tests genuinely failed. On a large suite this prints hundreds of did not complete lines with no cause, and the natural next step (re-running, bisecting the suite, suspecting the tests) is wasted effort. It is intermittent, which makes the missing diagnostic the expensive part.

Version

Flutter 3.47.1 - channel stable (also present on master at 53c174684f2)
macOS 26.0 darwin-arm64, Chrome 151

Activity

  1. gabrimatic commented on Aug 27, 2026

    @gabrimatic
    ContributorAuthor

    A fix is ready on the branch web-test-browser-disconnect.

    It reports the disconnect before BrowserManager tears itself down, and adds a regression test in test/commands.shard/hermetic/flutter_web_platform_test.dart.

    Verified end to end against a real run: killing the test browser's renderer mid-suite now prints

    The Chrome browser closed its connection to the test host unexpectedly, so any unfinished test suites are reported as "did not complete". The browser page or its renderer was most likely terminated, for example after running out of memory.

    where before it printed nothing at all and the run ended with only did not complete lines.

    I cannot open the pull request yet: contributors without write access are limited to two open pull requests, and I currently have two. I will open it as soon as one of them lands.

  2. saurabh-mirajkar commented on Aug 28, 2026

    @saurabh-mirajkar
    Contributor

    @gabrimatic Thanks for the detailed investigation. I haven't been able to reproduce the original failure yet.

    Could you provide the exact steps or command you use to cause the browser's WebSocket connection to the test host to drop while the tests are still running? In particular, what action/event triggers the disconnect in your repro?

    Also, provide a complete output of flutter doctor -v

    That will help us reproduce the issue locally.

  3. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    needs repro infoAutomated crash report whose cause isn't yet known
    and removed
    in triagePresently being triaged by the triage team
    on Aug 28, 2026
  4. gabrimatic commented on Aug 28, 2026

    @gabrimatic
    ContributorAuthor

    Thanks for looking. Here is a deterministic repro from a clean project.

    What triggers the disconnect. In the original occurrence nothing external did it: on a large suite (792 web tests in one tab) the page's renderer died on its own, intermittently, roughly half of runs. The renderer process dying is what closes the WebSocket while the browser process itself stays alive, and that is the path with no diagnostic. To make it deterministic you can kill that renderer yourself.

    Repro

    flutter create --platforms=web repro_app
    cd repro_app
    cat > test/disconnect_test.dart <<'DART'
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      test('slow enough to interrupt', () async {
        await Future<void>.delayed(const Duration(seconds: 25));
      });
      for (var i = 0; i < 5; i++) {
        test('queued after the slow one $i', () {
          expect(1, 1);
        });
      }
    }
    DART
    
    flutter test --platform chrome test/disconnect_test.dart &
    sleep 10
    
    # Kill only the renderer of the headless Chrome that flutter test launched.
    # The browser process stays alive, so this is not the process-exit path.
    BROWSER=$(ps -ax -o pid,command | grep -- --headless | grep flutter_tools_chrome_device \
      | grep -v 'type=' | grep -v grep | head -1 | awk '{print $1}')
    for p in $(pgrep -P "$BROWSER"); do
      ps -o command= -p "$p" | grep -q 'type=renderer' && kill -9 "$p"
    done
    wait

    Actual output

    00:00 +0: slow enough to interrupt
    00:23 +0: slow enough to interrupt - did not complete [E]
    00:23 +0: queued after the slow one 0 - did not complete [E]
    00:23 +0: queued after the slow one 1 - did not complete [E]
    00:23 +0: queued after the slow one 2 - did not complete [E]
    00:23 +0: queued after the slow one 3 - did not complete [E]
    00:23 +0: queued after the slow one 4 - did not complete [E]
    00:23 +0: Some tests failed.
    

    Nothing explains it, and -v adds only Shutting down Chromium. The exit code is 79 and the run ends with a misleading No tests were found.

    Why nothing is printed. BrowserManager ends the run on channel close:

    _channel.stream.listen(_onMessage, onDone: close);

    Both existing browser-exit messages are suppressed on this path, because close() sets _closed = true and Chromium.close() sets _didClose = true before the browser process exits, and those flags are exactly what the two messages check. So the one case where the browser stops serving the test host without its process dying is the only case with no message.

    The branch linked above adds that message; with it applied the same repro prints the disconnect instead of nothing.

    flutter doctor -v

    [✓] Flutter (Channel stable, 3.47.1, on macOS 27.0 26A5421a darwin-arm64, locale en-US) [126ms]
        • Flutter version 3.47.1 on channel stable at /Users/soroush/Developer/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 6655482ec0 (9 days ago), 2026-08-19 10:07:23 -0700
        • Engine revision 5d53178869
        • Dart version 3.13.1
        • DevTools version 2.60.0
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 37.0.0) [1,516ms]
        • Android SDK at /Users/soroush/Library/Android/sdk
        • Platform android-37.0, build-tools 37.0.0
        • Java version OpenJDK Runtime Environment (build 21.0.10+-117844308-b1163.108)
        • All Android licenses accepted.
    
    [!] Xcode - develop for iOS and macOS [862ms]
        ✗ Xcode installation is incomplete; a full installation is necessary for iOS and macOS development.
        • CocoaPods version 1.17.0
    
    [✓] Chrome - develop for the web [35ms]
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Connected device (2 available) [158ms]
        • macOS (desktop) • macos  • darwin-arm64   • macOS 27.0 26A5421a darwin-arm64
        • Chrome (web)    • chrome • web-javascript • Google Chrome 151.0.7922.175
    
    [✓] Network resources [639ms]
        • All expected network resources are available.
    

    Also reproduced on master at 53c1746; the code path is unchanged there.

  5. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Aug 28, 2026
  6. saurabh-mirajkar commented on Aug 28, 2026

    @saurabh-mirajkar
    Contributor

    Thanks for providing the repro details. I was able to reproduce the issue locally on master. Routing this to the team for further triage.

  7. added
    a: tests"flutter test", flutter_test, or one of our tests
    toolAffects the "flutter" command-line tool. See also t: labels.
    platform-webWeb applications specifically
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    team-webOwned by Web platform team
    and removed
    needs repro infoAutomated crash report whose cause isn't yet known
    on Aug 28, 2026
  8. added
    P2Important issues not at the top of the work list
    triaged-webTriaged by Web platform team
    on Sep 2, 2026
  9. gabrimatic commented on Sep 2, 2026

    @gabrimatic
    ContributorAuthor

    A slot freed up, so the fix is now open as #192198. The branch is rebased onto current master and carries the same change plus the regression test.

  10. gabrimatic commented on Sep 2, 2026

    @gabrimatic
    ContributorAuthor

    One more finding while verifying the fix: the process-exit path is silent too. With flutter test --platform chrome running the repro above, kill -9 the headless browser process itself (the parent, not its renderer) and the run ends with the same did not complete lines and nothing else, on 3.47.1 stable and on master. The two existing exit-code messages cannot fire because the connection closes before the exit code is delivered, and close() marks everything closed first.

    #192198 covers both paths: it reports the disconnect at once and lets the exit code arrive before closing, so a dead process is reported with its exit code and a dead page or renderer is reported as such.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: tests"flutter test", flutter_test, or one of our testshas reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyteam-webOwned by Web platform teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-webTriaged by Web platform team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions