@@ -15,7 +15,7 @@ import 'webdriver_browser.dart';
1515/// Provides an environment for the desktop variant of Safari running on macOS.
1616class SafariMacOsEnvironment extends BrowserEnvironment {
1717 static const Duration _waitBetweenRetries = Duration (seconds: 1 );
18- static const int _maxRetryCount = 5 ;
18+ static const int _maxRetryCount = 10 ;
1919
2020 late int _portNumber;
2121 late Process _driverProcess;
@@ -88,16 +88,9 @@ $stackTrace
8888
8989 await _waitForSafariDriverServerReady ();
9090
91- // Smoke-test the web driver process by connecting to it and asking for a
92- // list of windows. It doesn't matter how many windows there are.
93- webDriver = await createDriver (
94- uri: _driverUri,
95- desired: < String , dynamic > {'browserName' : packageTestRuntime.identifier},
96- );
97-
98- await webDriver! .windows.toList ();
91+ webDriver = await _createDriverSessionWithRetry ();
9992 } catch (_) {
100- print ('safaridriver failed to start .' );
93+ print ('safaridriver failed to reach a healthy state .' );
10194
10295 final badDriver = webDriver;
10396 webDriver = null ; // let's not keep faulty driver around
@@ -141,6 +134,48 @@ $stackTrace
141134 }
142135 }
143136
137+ /// Creates a WebDriver session with a rety mechanism.
138+ ///
139+ /// The retry mechanism is used to combat intermittent errors of the form:
140+ ///
141+ /// > Could not create a session: The session timed out while connecting to a Safari instance.
142+ ///
143+ /// See also: https://github.com/flutter/flutter/issues/163790
144+ Future <WebDriver > _createDriverSessionWithRetry () async {
145+ const kSessionRetryCount = 10 ;
146+ int retryCount = 0 ;
147+ while (true ) {
148+ // Give Safari a chance to launch.
149+ //
150+ // 100ms seems enough in most cases, but feel free to revisit this.
151+ await Future <void >.delayed (const Duration (milliseconds: 100 ));
152+
153+ retryCount += 1 ;
154+ try {
155+ final candidateDriver = await createDriver (
156+ uri: _driverUri,
157+ desired: < String , dynamic > {'browserName' : packageTestRuntime.identifier},
158+ );
159+
160+ // Smoke-test the web driver process by asking for a list of windows. It
161+ // doesn't matter how many windows there are, only that the driver is
162+ // capable of answering the question.
163+ await candidateDriver.windows.toList ();
164+
165+ return candidateDriver;
166+ } catch (_) {
167+ if (retryCount < kSessionRetryCount) {
168+ print ('Failed to create a WebDriver session with Safari. Retrying...' );
169+ } else {
170+ print (
171+ 'Failed to create a WebDriver session with Safari after $kSessionRetryCount retries. Giving up.' ,
172+ );
173+ rethrow ;
174+ }
175+ }
176+ }
177+ }
178+
144179 /// The Safari Driver process cannot instantly spawn a server, so this function
145180 /// attempts to connect to the server in a loop until it succeeds.
146181 ///
0 commit comments