Skip to content

Commit

Permalink
Suppress error causing the service_extension_test to be flaky (flut…
Browse files Browse the repository at this point in the history
  • Loading branch information
elliette authored Jul 29, 2024
1 parent 0d7df6b commit 5d99c69
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,42 +35,53 @@ void main() {
await resetHistory();
});

testWidgets('can call services and service extensions', (tester) async {
await pumpAndConnectDevTools(tester, testApp);
await tester.pump(longDuration);

// TODO(kenz): re-work this integration test so that we do not have to be
// on the inspector screen for this to pass.
await switchToScreen(
tester,
tabIcon: ScreenMetaData.inspector.icon!,
screenId: ScreenMetaData.inspector.id,
);
await tester.pump(longDuration);

// Ensure all futures are completed before running checks.
await serviceConnection.serviceManager.service!.allFuturesCompleted;

logStatus('verify Flutter framework service extensions');
await _verifyBooleanExtension(tester);
await _verifyNumericExtension(tester);
await _verifyStringExtension(tester);

logStatus('verify Flutter engine service extensions');
expect(
await serviceConnection.queryDisplayRefreshRate,
equals(60),
);

logStatus('verify services that are registered to exactly one client');
await _verifyHotReloadAndHotRestart();
await expectLater(
serviceConnection.serviceManager.callService('fakeMethod'),
throwsException,
);

await disconnectFromTestApp(tester);
});
testWidgets(
'can call services and service extensions',
ignoreAllowedExceptions(
(tester) async {
await pumpAndConnectDevTools(tester, testApp);
await tester.pump(longDuration);

// TODO(kenz): re-work this integration test so that we do not have to be
// on the inspector screen for this to pass.
await switchToScreen(
tester,
tabIcon: ScreenMetaData.inspector.icon!,
screenId: ScreenMetaData.inspector.id,
);
await tester.pump(longDuration);

// Ensure all futures are completed before running checks.
await serviceConnection.serviceManager.service!.allFuturesCompleted;

logStatus('verify Flutter framework service extensions');
await _verifyBooleanExtension(tester);
await _verifyNumericExtension(tester);
await _verifyStringExtension(tester);

logStatus('verify Flutter engine service extensions');
expect(
await serviceConnection.queryDisplayRefreshRate,
equals(60),
);

logStatus('verify services that are registered to exactly one client');
await _verifyHotReloadAndHotRestart();
await expectLater(
serviceConnection.serviceManager.callService('fakeMethod'),
throwsException,
);

await disconnectFromTestApp(tester);
},
allowedExceptions: [
AllowedException(
msg: 'A SemanticsHandle was active at the end of the test.',
issue: 'https://github.com/flutter/devtools/issues/8107',
),
],
),
);

testWidgets('loads initial extension states from device', (tester) async {
await pumpAndConnectDevTools(tester, testApp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:ui' as ui;

import 'package:collection/collection.dart';
import 'package:devtools_app/devtools_app.dart';
import 'package:devtools_app/main.dart' as app;
import 'package:devtools_app_shared/ui.dart';
Expand Down Expand Up @@ -157,3 +159,37 @@ Future<void> verifyScreenshot(
},
);
}

class AllowedException {
AllowedException({required this.msg, required this.issue});

final String msg;
final String issue;
}

/// Wraps the callback to [testWidgets] in a new zone that will catch any
/// exceptions thrown during the test or after the test completes.
///
/// If the exception is included in [allowedExceptions], the exception will be
/// logged but ignored. Otherwise, the exception will be rethrown.
Future<void> Function(WidgetTester) ignoreAllowedExceptions(
Future<void> Function(WidgetTester) testCallback, {
required List<AllowedException> allowedExceptions,
}) {
return (WidgetTester tester) async {
await runZonedGuarded(
() async {
await testCallback(tester);
},
(e, st) {
final allowed = allowedExceptions
.firstWhereOrNull((allowed) => '$e'.contains(allowed.msg));
if (allowed == null) {
throw Error.throwWithStackTrace(e, st);
} else {
logStatus('Ignoring exception due to ${allowed.issue}: $e');
}
},
);
};
}

0 comments on commit 5d99c69

Please sign in to comment.