From 09c1f550c470c27444a89744002ef7ba6f65dbeb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:11:53 +0200 Subject: [PATCH 1/3] chore(deps): update Flutter SDK (metrics) to v3.24.3 (#2287) Co-authored-by: GitHub --- metrics/flutter.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics/flutter.properties b/metrics/flutter.properties index 70b1f7cd4..9a86225f5 100644 --- a/metrics/flutter.properties +++ b/metrics/flutter.properties @@ -1,2 +1,2 @@ -version = 3.24.2 +version = 3.24.3 repo = https://github.com/flutter/flutter From 7d5e695652556d2c9b46f3e78316841a831c77b5 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Fri, 13 Sep 2024 22:26:42 +0200 Subject: [PATCH 2/3] fix: event processor failed to stop processing (#2289) --- dart/lib/src/sentry_client.dart | 1 + dart/test/sentry_client_test.dart | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index e3809568d..65cf799d7 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -558,6 +558,7 @@ class SentryClient { count: spanCountBeforeEventProcessors + 1); } _options.logger(SentryLevel.debug, 'Event was dropped by a processor'); + break; } else if (event is SentryTransaction && processedEvent is SentryTransaction) { // If event processor removed only some spans we still report them as dropped diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index 07d5aab83..e58311169 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -1249,6 +1249,7 @@ void main() { }); test('thrown error is handled', () async { + fixture.options.automatedTestMode = false; final exception = Exception("before send exception"); final beforeSendTransactionCallback = (SentryTransaction event) { throw exception; @@ -1311,6 +1312,7 @@ void main() { }); test('thrown error is handled', () async { + fixture.options.automatedTestMode = false; final exception = Exception("before send exception"); final beforeSendCallback = (SentryEvent event, Hint hint) { throw exception; @@ -1604,7 +1606,13 @@ void main() { }); test('record event processor dropping event', () async { - final client = fixture.getSut(eventProcessor: DropAllEventProcessor()); + bool secondProcessorCalled = false; + fixture.options.addEventProcessor(DropAllEventProcessor()); + fixture.options.addEventProcessor(FunctionEventProcessor((event, hint) { + secondProcessorCalled = true; + return event; + })); + final client = fixture.getSut(); await client.captureEvent(fakeEvent); @@ -1612,6 +1620,7 @@ void main() { DiscardReason.eventProcessor); expect( fixture.recorder.discardedEvents.first.category, DataCategory.error); + expect(secondProcessorCalled, isFalse); }); test('record event processor dropping transaction', () async { @@ -1885,7 +1894,8 @@ class Fixture { final transport = MockTransport(); final options = SentryOptions(dsn: fakeDsn) - ..platformChecker = MockPlatformChecker(platform: MockPlatform.iOS()); + ..platformChecker = MockPlatformChecker(platform: MockPlatform.iOS()) + ..automatedTestMode = true; late SentryTransactionContext _context; late SentryTracer tracer; From fe6dcac6041d41f2b6ff38f507a75470ea94b2f4 Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:22:17 +0200 Subject: [PATCH 3/3] test: rethrow exceptions (#2290) * test: rethrow in native SDK integration * test: rethrow in automated test mode * fix event processor runner * test: use options.automatedTestMode everywhere * update failing tests * fix tests * formatting * fix tests * fix: tests * fix tests * update comments --- .../enricher/io_enricher_event_processor.dart | 3 + .../enricher/io_platform_memory.dart | 3 + .../io_exception_event_processor.dart | 3 + dart/lib/src/hub.dart | 27 ++ .../load_dart_debug_images_integration.dart | 3 + .../recursive_exception_cause_extractor.dart | 3 + dart/lib/src/sentry_baggage.dart | 1 + dart/lib/src/sentry_envelope_item.dart | 1 + dart/lib/src/transport/http_transport.dart | 3 + .../transport/spotlight_http_transport.dart | 3 + dart/test/debug_image_extractor_test.dart | 5 +- dart/test/diagnostic_logger_test.dart | 4 +- dart/test/environment_test.dart | 9 +- .../deduplication_event_processor_test.dart | 6 +- .../enricher/io_enricher_test.dart | 16 +- .../enricher/io_platform_memory_test.dart | 5 +- .../enricher/web_enricher_test.dart | 6 +- dart/test/exception_identifier_test.dart | 4 +- .../failed_request_client_test.dart | 3 +- .../http_client/io_client_provider_test.dart | 4 +- .../test/http_client/tracing_client_test.dart | 4 +- dart/test/hub_test.dart | 18 +- dart/test/initialization_test.dart | 5 +- ...ad_dart_debug_images_integration_test.dart | 3 +- .../test/metrics/metrics_aggregator_test.dart | 5 +- dart/test/metrics/metrics_api_test.dart | 4 +- dart/test/mocks/mock_hub.dart | 4 +- dart/test/protocol/rate_limiter_test.dart | 3 +- ...ursive_exception_cause_extractor_test.dart | 6 +- .../run_zoned_guarded_integration_test.dart | 4 +- dart/test/scope_test.dart | 28 +- dart/test/sentry_attachment_test.dart | 4 +- dart/test/sentry_client_test.dart | 8 +- dart/test/sentry_envelope_test.dart | 11 +- dart/test/sentry_envelope_vm_test.dart | 8 +- dart/test/sentry_exception_factory_test.dart | 4 +- dart/test/sentry_isolate_extension_test.dart | 5 +- dart/test/sentry_isolate_test.dart | 5 +- dart/test/sentry_options_test.dart | 44 +-- dart/test/sentry_test.dart | 50 ++-- dart/test/sentry_tracer_test.dart | 8 +- dart/test/sentry_traces_sampler_test.dart | 5 +- dart/test/sentry_transaction_test.dart | 3 +- dart/test/sentry_user_feedback_test.dart | 5 +- dart/test/stack_trace_test.dart | 6 +- dart/test/test_utils.dart | 26 +- dart/test/transport/http_transport_test.dart | 5 +- .../spotlight_http_transport_test.dart | 5 +- dart/test/transport/tesk_queue_test.dart | 5 +- dart/test/utils/tracing_utils_test.dart | 6 +- dio/test/dio_event_processor_test.dart | 2 +- dio/test/mocks.dart | 5 + dio/test/mocks/mock_hub.dart | 3 +- dio/test/sentry_transformer_test.dart | 2 +- dio/test/tracing_client_adapter_test.dart | 2 +- drift/test/sentry_database_test.dart | 3 +- drift/test/utils.dart | 8 + file/test/mock_sentry_client.dart | 5 + file/test/sentry_file_extension_test.dart | 2 +- file/test/sentry_file_test.dart | 2 +- .../sentry_io_overrides_integration_test.dart | 2 +- flutter/lib/src/binding_wrapper.dart | 3 + ...id_platform_exception_event_processor.dart | 3 + .../native_app_start_event_processor.dart | 3 + .../screenshot_event_processor.dart | 4 +- flutter/lib/src/file_system_transport.dart | 7 +- .../load_contexts_integration.dart | 3 + .../load_release_integration.dart | 3 + .../native_app_start_integration.dart | 3 + .../integrations/native_sdk_integration.dart | 6 + .../integrations/on_error_integration.dart | 3 + .../src/native/cocoa/sentry_native_cocoa.dart | 2 +- flutter/lib/src/native/factory_real.dart | 11 +- flutter/lib/src/native/factory_web.dart | 5 +- .../src/native/java/sentry_native_java.dart | 3 +- .../lib/src/native/sentry_native_channel.dart | 4 +- .../lib/src/native/sentry_native_invoker.dart | 2 - .../native/sentry_safe_method_channel.dart | 2 +- .../navigation/sentry_navigator_observer.dart | 6 + flutter/lib/src/replay/recorder.dart | 1 - flutter/lib/src/sentry_flutter.dart | 48 ++-- flutter/lib/src/sentry_flutter_options.dart | 15 ++ flutter/temp/native-test/dist/sentry.dll | Bin 0 -> 280064 bytes ...atform_exception_event_processor_test.dart | 3 +- ...flutter_enricher_event_processor_test.dart | 20 +- .../screenshot_event_processor_test.dart | 4 +- .../io_filter_event_processor_test.dart | 4 +- .../web_url_filter_event_processor_test.dart | 4 +- flutter/test/file_system_transport_test.dart | 3 +- flutter/test/initialization_test.dart | 52 +--- .../connectivity_integration_test.dart | 3 +- .../debug_print_integration_test.dart | 6 +- flutter/test/integrations/fixture.dart | 5 +- .../flutter_error_integration_test.dart | 10 +- .../integrations/init_native_sdk_test.dart | 11 +- .../load_contexts_integrations_test.dart | 3 +- .../load_release_integration_test.dart | 2 +- .../native_sdk_integration_test.dart | 15 +- ...ets_binding_on_error_integration_test.dart | 3 +- .../not_initialized_widgets_binding_test.dart | 4 +- .../on_error_integration_test.dart | 11 +- .../screenshot_integration_test.dart | 4 +- ...gets_flutter_binding_integration_test.dart | 4 +- flutter/test/mocks.dart | 27 +- flutter/test/mocks.mocks.dart | 251 ++++++++++++++++-- .../sentry_display_widget_test.dart | 3 +- .../time_to_display_tracker_test.dart | 2 +- .../time_to_full_display_tracker_test.dart | 2 +- .../time_to_initial_display_tracker_test.dart | 2 +- flutter/test/profiling_test.dart | 2 +- flutter/test/replay/recorder_test.dart | 3 +- flutter/test/replay/replay_native_test.dart | 15 +- .../test/replay/scheduled_recorder_test.dart | 3 +- .../sentry_screenshot_widget_test.dart | 2 +- flutter/test/sentry_asset_bundle_test.dart | 2 +- flutter/test/sentry_flutter_options_test.dart | 14 +- flutter/test/sentry_flutter_test.dart | 181 ++++++------- flutter/test/sentry_native_channel_test.dart | 9 +- .../test/sentry_navigator_observer_test.dart | 7 +- .../span_frame_metrics_collector_test.dart | 2 +- .../sentry_user_interaction_widget_test.dart | 2 +- .../sentry_tree_walker_test.dart | 6 +- .../view_hierarchy_event_processor_test.dart | 5 +- .../view_hierarchy_integration_test.dart | 4 +- .../test/widgets_binding_observer_test.dart | 4 +- hive/test/sentry_box_base_test.dart | 3 +- hive/test/sentry_box_collection_test.dart | 4 +- hive/test/sentry_hive_impl_test.dart | 3 +- hive/test/sentry_lazy_box_test.dart | 3 +- hive/test/utils.dart | 8 + isar/test/sentry_isar_collection_test.dart | 3 +- isar/test/sentry_isar_test.dart | 3 +- isar/test/utils.dart | 8 + logging/test/logging_integration_test.dart | 2 +- logging/test/mock_hub.dart | 7 +- sqflite/test/sentry_batch_test.dart | 2 +- sqflite/test/sentry_database_test.dart | 2 +- ...ry_sqflite_database_factory_dart_test.dart | 2 +- sqflite/test/sentry_sqflite_test.dart | 2 +- sqflite/test/utils.dart | 7 + 140 files changed, 846 insertions(+), 514 deletions(-) create mode 100644 drift/test/utils.dart create mode 100644 flutter/temp/native-test/dist/sentry.dll create mode 100644 hive/test/utils.dart create mode 100644 isar/test/utils.dart diff --git a/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart b/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart index 6c598b1ed..0bf4c218d 100644 --- a/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart +++ b/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart @@ -100,6 +100,9 @@ class IoEnricherEventProcessor implements EnricherEventProcessor { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } } diff --git a/dart/lib/src/event_processor/enricher/io_platform_memory.dart b/dart/lib/src/event_processor/enricher/io_platform_memory.dart index 4acde3f15..1f4a32987 100644 --- a/dart/lib/src/event_processor/enricher/io_platform_memory.dart +++ b/dart/lib/src/event_processor/enricher/io_platform_memory.dart @@ -75,6 +75,9 @@ class PlatformMemory { } } catch (e) { options.logger(SentryLevel.warning, "Failed to run process: $e"); + if (options.automatedTestMode) { + rethrow; + } } return null; } diff --git a/dart/lib/src/event_processor/exception/io_exception_event_processor.dart b/dart/lib/src/event_processor/exception/io_exception_event_processor.dart index bb4049c00..55677a938 100644 --- a/dart/lib/src/event_processor/exception/io_exception_event_processor.dart +++ b/dart/lib/src/event_processor/exception/io_exception_event_processor.dart @@ -69,6 +69,9 @@ class IoExceptionEventProcessor implements ExceptionEventProcessor { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } return event.copyWith( diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index b69bc5056..2626670a3 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -124,6 +124,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } finally { _lastEventId = sentryId; } @@ -183,6 +186,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } finally { _lastEventId = sentryId; } @@ -238,6 +244,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } finally { _lastEventId = sentryId; } @@ -271,6 +280,9 @@ class Hub { exception: exception, stackTrace: stacktrace, ); + if (_options.automatedTestMode) { + rethrow; + } } } @@ -364,6 +376,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } _isEnabled = false; @@ -565,6 +580,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } } } @@ -602,6 +620,9 @@ class Hub { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } } return sentryId; @@ -682,6 +703,9 @@ class _WeakMap { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } } @@ -699,6 +723,9 @@ class _WeakMap { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } return null; } diff --git a/dart/lib/src/load_dart_debug_images_integration.dart b/dart/lib/src/load_dart_debug_images_integration.dart index 81cf7cc67..0932cac9a 100644 --- a/dart/lib/src/load_dart_debug_images_integration.dart +++ b/dart/lib/src/load_dart_debug_images_integration.dart @@ -42,6 +42,9 @@ class _LoadImageIntegrationEventProcessor implements EventProcessor { exception: e, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } return event; } } diff --git a/dart/lib/src/recursive_exception_cause_extractor.dart b/dart/lib/src/recursive_exception_cause_extractor.dart index 7118d98c6..5636af84a 100644 --- a/dart/lib/src/recursive_exception_cause_extractor.dart +++ b/dart/lib/src/recursive_exception_cause_extractor.dart @@ -41,6 +41,9 @@ class RecursiveExceptionCauseExtractor { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } break; } } diff --git a/dart/lib/src/sentry_baggage.dart b/dart/lib/src/sentry_baggage.dart index b6fc8b7da..c47cd3762 100644 --- a/dart/lib/src/sentry_baggage.dart +++ b/dart/lib/src/sentry_baggage.dart @@ -55,6 +55,7 @@ class SentryBaggage { exception: exception, stackTrace: stackTrace, ); + // TODO rethrow in options.automatedTestMode (currently not available here to check) } } diff --git a/dart/lib/src/sentry_envelope_item.dart b/dart/lib/src/sentry_envelope_item.dart index b0f19cfcc..61463cdd8 100644 --- a/dart/lib/src/sentry_envelope_item.dart +++ b/dart/lib/src/sentry_envelope_item.dart @@ -132,6 +132,7 @@ class SentryEnvelopeItem { // TODO the data copy could be avoided - this would be most significant with attachments. return [...itemHeader, ...newLine, ...data]; } catch (e) { + // TODO rethrow in options.automatedTestMode (currently not available here to check) return []; } } diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index 68950948a..16cfed654 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -64,6 +64,9 @@ class HttpTransport implements Transport { return eventId != null ? SentryId.fromId(eventId) : null; } catch (e) { _options.logger(SentryLevel.error, 'Error parsing response: $e'); + if (_options.automatedTestMode) { + rethrow; + } return null; } } diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index 1889bb733..0dce69686 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -31,6 +31,9 @@ class SpotlightHttpTransport extends Transport { } catch (e) { _options.logger( SentryLevel.warning, 'Failed to send envelope to Spotlight: $e'); + if (_options.automatedTestMode) { + rethrow; + } } return _transport.send(envelope); } diff --git a/dart/test/debug_image_extractor_test.dart b/dart/test/debug_image_extractor_test.dart index 6218c726a..7a0ad7d12 100644 --- a/dart/test/debug_image_extractor_test.dart +++ b/dart/test/debug_image_extractor_test.dart @@ -1,9 +1,9 @@ import 'package:test/test.dart'; -import 'package:sentry/sentry.dart'; import 'package:sentry/src/debug_image_extractor.dart'; import 'mocks/mock_platform.dart'; import 'mocks/mock_platform_checker.dart'; +import 'test_utils.dart'; void main() { group(DebugImageExtractor, () { @@ -112,8 +112,7 @@ isolate_dso_base: 10000000 class Fixture { DebugImageExtractor getSut({required MockPlatform platform}) { - final options = SentryOptions(dsn: 'https://public@sentry.example.com/1') - ..platformChecker = MockPlatformChecker(platform: platform); + final options = defaultTestOptions(MockPlatformChecker(platform: platform)); return DebugImageExtractor(options); } } diff --git a/dart/test/diagnostic_logger_test.dart b/dart/test/diagnostic_logger_test.dart index ec53421e3..f33baa164 100644 --- a/dart/test/diagnostic_logger_test.dart +++ b/dart/test/diagnostic_logger_test.dart @@ -2,6 +2,8 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/diagnostic_logger.dart'; import 'package:test/test.dart'; +import 'test_utils.dart'; + void main() { late Fixture fixture; @@ -44,7 +46,7 @@ void main() { } class Fixture { - var options = SentryOptions(); + var options = defaultTestOptions(); Object? loggedMessage; diff --git a/dart/test/environment_test.dart b/dart/test/environment_test.dart index b16225d1d..d955f931e 100644 --- a/dart/test/environment_test.dart +++ b/dart/test/environment_test.dart @@ -3,6 +3,7 @@ import 'package:test/test.dart'; import 'mocks.dart'; import 'mocks/mock_environment_variables.dart'; +import 'test_utils.dart'; void main() { // See https://docs.sentry.io/platforms/dart/configuration/options/ @@ -13,7 +14,7 @@ void main() { }); test('SentryOptions are not overriden by environment', () async { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.release = 'release-1.2.3'; options.dist = 'foo'; options.environment = 'prod'; @@ -23,28 +24,26 @@ void main() { release: 'release-9.8.7', dist: 'bar', ); - options.automatedTestMode = true; await Sentry.init( (options) => options, options: options, ); - expect(options.dsn, fakeDsn); + expect(options.dsn, testDsn); expect(options.environment, 'prod'); expect(options.release, 'release-1.2.3'); expect(options.dist, 'foo'); }); test('SentryOptions are overriden by environment', () async { - final options = SentryOptions(); + final options = defaultTestOptions()..dsn = null; options.environmentVariables = MockEnvironmentVariables( dsn: fakeDsn, environment: 'staging', release: 'release-9.8.7', dist: 'bar', ); - options.automatedTestMode = true; await Sentry.init( (options) => options, diff --git a/dart/test/event_processor/deduplication_event_processor_test.dart b/dart/test/event_processor/deduplication_event_processor_test.dart index 3e17fe406..de576bafd 100644 --- a/dart/test/event_processor/deduplication_event_processor_test.dart +++ b/dart/test/event_processor/deduplication_event_processor_test.dart @@ -6,6 +6,7 @@ import 'package:test/test.dart'; import '../mocks.dart'; import '../mocks/mock_hub.dart'; import '../mocks/mock_transport.dart'; +import '../test_utils.dart'; void main() { group('$DeduplicationEventProcessor', () { @@ -77,14 +78,13 @@ void main() { final transport = MockTransport(); - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; await Sentry.init( (options) { options.dsn = fakeDsn; options.transport = transport; options.enableDeduplication = true; }, - options: options, + options: defaultTestOptions(), ); // The test doesn't work if `outerTestMethod` is passed as @@ -114,7 +114,7 @@ class Fixture { DeduplicationEventProcessor getSut(bool enabled, [int? maxDeduplicationItems]) { - final options = SentryOptions(dsn: fakeDsn) + final options = defaultTestOptions() ..enableDeduplication = enabled ..maxDeduplicationItems = maxDeduplicationItems ?? 5; diff --git a/dart/test/event_processor/enricher/io_enricher_test.dart b/dart/test/event_processor/enricher/io_enricher_test.dart index dad1a62f6..a48c8dfed 100644 --- a/dart/test/event_processor/enricher/io_enricher_test.dart +++ b/dart/test/event_processor/enricher/io_enricher_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import '../../mocks.dart'; import '../../mocks/mock_platform_checker.dart'; +import '../../test_utils.dart'; void main() { group('io_enricher', () { @@ -164,20 +165,17 @@ void main() { }); test('$IoEnricherEventProcessor gets added on init', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; - late SentryOptions configuredOptions; + final options = defaultTestOptions(); await Sentry.init( (options) { options.dsn = fakeDsn; - configuredOptions = options; }, options: options, ); await Sentry.close(); - final ioEnricherCount = configuredOptions.eventProcessors - .whereType() - .length; + final ioEnricherCount = + options.eventProcessors.whereType().length; expect(ioEnricherCount, 1); }); }); @@ -188,10 +186,8 @@ class Fixture { bool hasNativeIntegration = false, bool includePii = false, }) { - final options = SentryOptions( - dsn: fakeDsn, - checker: - MockPlatformChecker(hasNativeIntegration: hasNativeIntegration)) + final options = defaultTestOptions( + MockPlatformChecker(hasNativeIntegration: hasNativeIntegration)) ..sendDefaultPii = includePii; return IoEnricherEventProcessor(options); diff --git a/dart/test/event_processor/enricher/io_platform_memory_test.dart b/dart/test/event_processor/enricher/io_platform_memory_test.dart index 0f987b935..ce2c8474f 100644 --- a/dart/test/event_processor/enricher/io_platform_memory_test.dart +++ b/dart/test/event_processor/enricher/io_platform_memory_test.dart @@ -3,10 +3,11 @@ library dart_test; import 'dart:io'; -import 'package:sentry/sentry.dart'; import 'package:sentry/src/event_processor/enricher/io_platform_memory.dart'; import 'package:test/test.dart'; +import '../../test_utils.dart'; + void main() { late Fixture fixture; @@ -52,7 +53,7 @@ void main() { } class Fixture { - var options = SentryOptions(); + var options = defaultTestOptions(); PlatformMemory getSut() { return PlatformMemory(options); diff --git a/dart/test/event_processor/enricher/web_enricher_test.dart b/dart/test/event_processor/enricher/web_enricher_test.dart index d2590a09f..39502fc13 100644 --- a/dart/test/event_processor/enricher/web_enricher_test.dart +++ b/dart/test/event_processor/enricher/web_enricher_test.dart @@ -9,6 +9,7 @@ import 'package:test/test.dart'; import '../../mocks.dart'; import '../../mocks/mock_platform_checker.dart'; +import '../../test_utils.dart'; // can be tested on command line with // `dart test -p chrome --name web_enricher` @@ -201,9 +202,8 @@ void main() { class Fixture { WebEnricherEventProcessor getSut() { - final options = SentryOptions( - dsn: fakeDsn, - checker: MockPlatformChecker(hasNativeIntegration: false)); + final options = + defaultTestOptions(MockPlatformChecker(hasNativeIntegration: false)); return enricherEventProcessor(options) as WebEnricherEventProcessor; } } diff --git a/dart/test/exception_identifier_test.dart b/dart/test/exception_identifier_test.dart index b3014203d..29e2a4a73 100644 --- a/dart/test/exception_identifier_test.dart +++ b/dart/test/exception_identifier_test.dart @@ -4,10 +4,10 @@ import 'package:sentry/src/dart_exception_type_identifier.dart'; import 'package:sentry/src/sentry_exception_factory.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks.mocks.dart'; import 'mocks/mock_transport.dart'; import 'sentry_client_test.dart'; +import 'test_utils.dart'; void main() { late Fixture fixture; @@ -165,7 +165,7 @@ void main() { } class Fixture { - SentryOptions options = SentryOptions(dsn: fakeDsn); + SentryOptions options = defaultTestOptions(); } // We use this PlaceHolder exception to mimic an obfuscated runtimeType diff --git a/dart/test/http_client/failed_request_client_test.dart b/dart/test/http_client/failed_request_client_test.dart index 2ac9a74c8..b35dd2957 100644 --- a/dart/test/http_client/failed_request_client_test.dart +++ b/dart/test/http_client/failed_request_client_test.dart @@ -8,6 +8,7 @@ import 'package:test/test.dart'; import '../mocks.dart'; import '../mocks/mock_hub.dart'; import '../mocks/mock_transport.dart'; +import '../test_utils.dart'; final requestUri = Uri.parse('https://example.com?foo=bar#myFragment'); @@ -359,7 +360,7 @@ MockClient createThrowingClient() { class CloseableMockClient extends Mock implements BaseClient {} class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late Hub _hub; final transport = MockTransport(); Fixture() { diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart index 0672e84c0..81d05c154 100644 --- a/dart/test/http_client/io_client_provider_test.dart +++ b/dart/test/http_client/io_client_provider_test.dart @@ -7,7 +7,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/http_client/io_client_provider.dart'; import 'package:test/test.dart'; -import '../mocks.dart'; +import '../test_utils.dart'; void main() { group('getClient', () { @@ -77,7 +77,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final mockHttpClient = MockHttpClient(); String? mockUser; diff --git a/dart/test/http_client/tracing_client_test.dart b/dart/test/http_client/tracing_client_test.dart index 6cefe626b..4e052dc51 100644 --- a/dart/test/http_client/tracing_client_test.dart +++ b/dart/test/http_client/tracing_client_test.dart @@ -5,8 +5,8 @@ import 'package:sentry/src/http_client/tracing_client.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; -import '../mocks.dart'; import '../mocks/mock_transport.dart'; +import '../test_utils.dart'; final requestUri = Uri.parse('https://example.com?foo=bar#baz'); @@ -220,7 +220,7 @@ MockClient createThrowingClient() { } class Fixture { - final _options = SentryOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); late Hub _hub; final transport = MockTransport(); Fixture() { diff --git a/dart/test/hub_test.dart b/dart/test/hub_test.dart index c53ab74e4..564c59ff7 100644 --- a/dart/test/hub_test.dart +++ b/dart/test/hub_test.dart @@ -10,6 +10,7 @@ import 'mocks.dart'; import 'mocks.mocks.dart'; import 'mocks/mock_client_report_recorder.dart'; import 'mocks/mock_sentry_client.dart'; +import 'test_utils.dart'; void main() { bool scopeEquals(Scope? a, Scope b) { @@ -25,7 +26,7 @@ void main() { group('Hub instantiation', () { test('should instantiate with a dsn', () { - final hub = Hub(SentryOptions(dsn: fakeDsn)); + final hub = Hub(defaultTestOptions()); expect(hub.isEnabled, true); }); }); @@ -458,11 +459,11 @@ void main() { }); group('Hub scope', () { - var hub = Hub(SentryOptions(dsn: fakeDsn)); + var hub = Hub(defaultTestOptions()); var client = MockSentryClient(); setUp(() { - hub = Hub(SentryOptions(dsn: fakeDsn)); + hub = Hub(defaultTestOptions()); client = MockSentryClient(); hub.bindClient(client); }); @@ -487,7 +488,7 @@ void main() { expect(client.captureEventCalls.first.scope, isNotNull); final scope = client.captureEventCalls.first.scope; - final otherScope = Scope(SentryOptions(dsn: fakeDsn)) + final otherScope = Scope(defaultTestOptions()) ..level = SentryLevel.debug ..fingerprint = ['1', '2']; @@ -511,7 +512,7 @@ void main() { await hub.captureEvent(fakeEvent); final scope = client.captureEventCalls.first.scope; - final otherScope = Scope(SentryOptions(dsn: fakeDsn)); + final otherScope = Scope(defaultTestOptions()); await otherScope.setUser(fakeUser); expect( @@ -542,6 +543,7 @@ void main() { }); test('captureEvent should handle thrown error in scope callback', () async { + fixture.options.automatedTestMode = false; final hub = fixture.getSut(debug: true); final scopeCallbackException = Exception('error in scope callback'); @@ -557,6 +559,7 @@ void main() { test('captureException should handle thrown error in scope callback', () async { + fixture.options.automatedTestMode = false; final hub = fixture.getSut(debug: true); final scopeCallbackException = Exception('error in scope callback'); @@ -573,6 +576,7 @@ void main() { test('captureMessage should handle thrown error in scope callback', () async { + fixture.options.automatedTestMode = false; final hub = fixture.getSut(debug: true); final scopeCallbackException = Exception('error in scope callback'); @@ -593,7 +597,7 @@ void main() { SentryOptions options; setUp(() { - options = SentryOptions(dsn: fakeDsn); + options = defaultTestOptions(); hub = Hub(options); client = MockSentryClient(); hub.bindClient(client); @@ -756,7 +760,7 @@ class Fixture { final client = MockSentryClient(); final recorder = MockClientReportRecorder(); - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late SentryTransactionContext _context; late SentryTracer tracer; diff --git a/dart/test/initialization_test.dart b/dart/test/initialization_test.dart index e6f9ddea2..42766ac93 100644 --- a/dart/test/initialization_test.dart +++ b/dart/test/initialization_test.dart @@ -5,6 +5,7 @@ import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; import 'mocks.dart'; +import 'test_utils.dart'; // Tests for the following issue // https://github.com/getsentry/sentry-dart/issues/508 @@ -15,7 +16,7 @@ void main() { }); test('async re-initilization', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( (options) { options.dsn = fakeDsn; @@ -36,7 +37,7 @@ void main() { // This is the failure from // https://github.com/getsentry/sentry-dart/issues/508 test('re-initilization', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( (options) { options.dsn = fakeDsn; diff --git a/dart/test/load_dart_debug_images_integration_test.dart b/dart/test/load_dart_debug_images_integration_test.dart index 8b10a6232..e7f06525c 100644 --- a/dart/test/load_dart_debug_images_integration_test.dart +++ b/dart/test/load_dart_debug_images_integration_test.dart @@ -7,6 +7,7 @@ import 'package:test/test.dart'; import 'mocks/mock_platform.dart'; import 'mocks/mock_platform_checker.dart'; +import 'test_utils.dart'; void main() { group(LoadDartDebugImagesIntegration, () { @@ -92,7 +93,7 @@ isolate_dso_base: 10000000 } class Fixture { - final options = SentryOptions(dsn: 'https://public@sentry.example.com/1'); + final options = defaultTestOptions(); Fixture() { final integration = LoadDartDebugImagesIntegration(); diff --git a/dart/test/metrics/metrics_aggregator_test.dart b/dart/test/metrics/metrics_aggregator_test.dart index 5636e7ebf..19c6a9f18 100644 --- a/dart/test/metrics/metrics_aggregator_test.dart +++ b/dart/test/metrics/metrics_aggregator_test.dart @@ -3,8 +3,8 @@ import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/metrics/metrics_aggregator.dart'; import 'package:test/test.dart'; -import '../mocks.dart'; import '../mocks/mock_hub.dart'; +import '../test_utils.dart'; void main() { group('emit', () { @@ -402,6 +402,7 @@ void main() { }); test('emits if it throws', () async { + fixture.options.automatedTestMode = false; final MetricsAggregator sut = fixture.getSut(maxWeight: 4); fixture.options.beforeMetricCallback = (key, {tags}) => throw Exception(); sut.testEmit(key: 'key1'); @@ -455,7 +456,7 @@ const Map mockTags2 = {'tag1': 'val1'}; final DateTime mockTimestamp = DateTime.fromMillisecondsSinceEpoch(1); class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final mockHub = MockHub(); late final hub = Hub(options); diff --git a/dart/test/metrics/metrics_api_test.dart b/dart/test/metrics/metrics_api_test.dart index 8c53e6677..8e18d2199 100644 --- a/dart/test/metrics/metrics_api_test.dart +++ b/dart/test/metrics/metrics_api_test.dart @@ -6,8 +6,8 @@ import 'package:sentry/src/metrics/metrics_api.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; -import '../mocks.dart'; import '../mocks/mock_hub.dart'; +import '../test_utils.dart'; void main() { group('api', () { @@ -144,7 +144,7 @@ void main() { } class Fixture { - final _options = SentryOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); final mockHub = MockHub(); late final hub = Hub(_options); diff --git a/dart/test/mocks/mock_hub.dart b/dart/test/mocks/mock_hub.dart index c07625173..8fa7d3138 100644 --- a/dart/test/mocks/mock_hub.dart +++ b/dart/test/mocks/mock_hub.dart @@ -3,7 +3,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/metrics/metrics_aggregator.dart'; -import '../mocks.dart'; +import '../test_utils.dart'; import 'mock_sentry_client.dart'; import 'no_such_method_provider.dart'; @@ -21,7 +21,7 @@ class MockHub with NoSuchMethodProvider implements Hub { int spanContextCals = 0; int getSpanCalls = 0; - final _options = SentryOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); late final MetricsAggregator _metricsAggregator = MetricsAggregator(options: _options, hub: this); diff --git a/dart/test/protocol/rate_limiter_test.dart b/dart/test/protocol/rate_limiter_test.dart index b4364bcef..96d91ea68 100644 --- a/dart/test/protocol/rate_limiter_test.dart +++ b/dart/test/protocol/rate_limiter_test.dart @@ -10,6 +10,7 @@ import 'package:sentry/src/sentry_envelope_header.dart'; import '../mocks/mock_client_report_recorder.dart'; import '../mocks/mock_hub.dart'; +import '../test_utils.dart'; void main() { var fixture = Fixture(); @@ -368,7 +369,7 @@ class Fixture { late var mockRecorder = MockClientReportRecorder(); RateLimiter getSut() { - final options = SentryOptions(); + final options = defaultTestOptions(); options.clock = _currentDateTime; options.recorder = mockRecorder; diff --git a/dart/test/recursive_exception_cause_extractor_test.dart b/dart/test/recursive_exception_cause_extractor_test.dart index e32400b36..b2da69699 100644 --- a/dart/test/recursive_exception_cause_extractor_test.dart +++ b/dart/test/recursive_exception_cause_extractor_test.dart @@ -2,10 +2,9 @@ import 'package:sentry/src/exception_cause.dart'; import 'package:sentry/src/exception_cause_extractor.dart'; import 'package:sentry/src/recursive_exception_cause_extractor.dart'; import 'package:sentry/src/protocol/mechanism.dart'; -import 'package:sentry/src/sentry_options.dart'; import 'package:sentry/src/throwable_mechanism.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; +import 'test_utils.dart'; void main() { late Fixture fixture; @@ -91,6 +90,7 @@ void main() { ExceptionBCauseExtractor(), ); + fixture.options.automatedTestMode = false; final sut = fixture.getSut(); final flattened = sut.flatten(errorA, null); @@ -101,7 +101,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); RecursiveExceptionCauseExtractor getSut() { return RecursiveExceptionCauseExtractor(options); diff --git a/dart/test/run_zoned_guarded_integration_test.dart b/dart/test/run_zoned_guarded_integration_test.dart index dd3c2aa0f..71f87e9d1 100644 --- a/dart/test/run_zoned_guarded_integration_test.dart +++ b/dart/test/run_zoned_guarded_integration_test.dart @@ -4,9 +4,9 @@ library dart_test; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; import 'mocks/mock_sentry_client.dart'; +import 'test_utils.dart'; void main() { group(RunZonedGuardedIntegration, () { @@ -77,7 +77,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; RunZonedGuardedIntegration getSut( {required RunZonedGuardedRunner runner, diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index 0059a2e77..59b42e422 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -8,6 +8,7 @@ import 'package:test/test.dart'; import 'mocks.dart'; import 'mocks/mock_hub.dart'; import 'mocks/mock_scope_observer.dart'; +import 'test_utils.dart'; void main() { late Fixture fixture; @@ -426,7 +427,7 @@ void main() { tags: const {'etag': '987'}, extra: const {'e-infos': 'abc'}, ); - final scope = Scope(SentryOptions(dsn: fakeDsn)) + final scope = Scope(defaultTestOptions()) ..fingerprint = ['example-dart'] ..transaction = '/example/app' ..level = SentryLevel.warning @@ -454,8 +455,7 @@ void main() { test('apply trace context to event', () async { final event = SentryEvent(); - final scope = Scope(SentryOptions(dsn: fakeDsn)) - ..span = fixture.sentryTracer; + final scope = Scope(defaultTestOptions())..span = fixture.sentryTracer; final updatedEvent = await scope.applyToEvent(event, Hint()); @@ -473,7 +473,7 @@ void main() { fingerprint: ['event-fingerprint'], breadcrumbs: [eventBreadcrumb], ); - final scope = Scope(SentryOptions(dsn: fakeDsn)) + final scope = Scope(defaultTestOptions()) ..fingerprint = ['example-dart'] ..transaction = '/example/app'; @@ -502,7 +502,7 @@ void main() { operatingSystem: SentryOperatingSystem(name: 'event-os'), ), ); - final scope = Scope(SentryOptions(dsn: fakeDsn)); + final scope = Scope(defaultTestOptions()); await scope.setContexts( SentryDevice.type, SentryDevice(name: 'context-device'), @@ -542,7 +542,7 @@ void main() { test('should apply the scope.contexts values', () async { final event = SentryEvent(); - final scope = Scope(SentryOptions(dsn: fakeDsn)); + final scope = Scope(defaultTestOptions()); await scope.setContexts( SentryDevice.type, SentryDevice(name: 'context-device')); await scope.setContexts(SentryApp.type, SentryApp(name: 'context-app')); @@ -580,8 +580,7 @@ void main() { test('should apply the scope level', () async { final event = SentryEvent(level: SentryLevel.warning); - final scope = Scope(SentryOptions(dsn: fakeDsn)) - ..level = SentryLevel.error; + final scope = Scope(defaultTestOptions())..level = SentryLevel.error; final updatedEvent = await scope.applyToEvent(event, Hint()); @@ -590,8 +589,7 @@ void main() { test('should apply the scope transaction from the span', () async { final event = SentryEvent(); - final scope = Scope(SentryOptions(dsn: fakeDsn)) - ..span = fixture.sentryTracer; + final scope = Scope(defaultTestOptions())..span = fixture.sentryTracer; final updatedEvent = await scope.applyToEvent(event, Hint()); @@ -612,7 +610,7 @@ void main() { test('should not apply fingerprint if transaction', () async { var tr = SentryTransaction(fixture.sentryTracer); - final scope = Scope(SentryOptions(dsn: fakeDsn))..fingerprint = ['test']; + final scope = Scope(defaultTestOptions())..fingerprint = ['test']; final updatedTr = await scope.applyToEvent(tr, Hint()); @@ -621,7 +619,7 @@ void main() { test('should not apply level if transaction', () async { var tr = SentryTransaction(fixture.sentryTracer); - final scope = Scope(SentryOptions(dsn: fakeDsn))..level = SentryLevel.error; + final scope = Scope(defaultTestOptions())..level = SentryLevel.error; final updatedTr = await scope.applyToEvent(tr, Hint()); @@ -630,7 +628,7 @@ void main() { test('apply sampled to trace', () async { var tr = SentryTransaction(fixture.sentryTracer); - final scope = Scope(SentryOptions(dsn: fakeDsn))..level = SentryLevel.error; + final scope = Scope(defaultTestOptions())..level = SentryLevel.error; final updatedTr = await scope.applyToEvent(tr, Hint()); @@ -720,6 +718,7 @@ void main() { test("addBreadcrumb with beforeBreadcrumb error handled ", () async { final exception = Exception("before breadcrumb exception"); + fixture.options.automatedTestMode = false; final sut = fixture.getSut( beforeBreadcrumbCallback: ( Breadcrumb? breadcrumb, @@ -744,6 +743,7 @@ void main() { var numberOfBeforeBreadcrumbCalls = 0; final exception = Exception("before breadcrumb exception"); + fixture.options.automatedTestMode = false; final sut = fixture.getSut( beforeBreadcrumbCallback: ( Breadcrumb? breadcrumb, @@ -776,7 +776,7 @@ void main() { class Fixture { final mockScopeObserver = MockScopeObserver(); - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final sentryTracer = SentryTracer( SentryTransactionContext( diff --git a/dart/test/sentry_attachment_test.dart b/dart/test/sentry_attachment_test.dart index 578cb5ad9..267ca6260 100644 --- a/dart/test/sentry_attachment_test.dart +++ b/dart/test/sentry_attachment_test.dart @@ -3,8 +3,8 @@ import 'dart:typed_data'; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_transport.dart'; +import 'test_utils.dart'; void main() { group('$SentryAttachment ctor', () { @@ -185,7 +185,7 @@ class Fixture { MockTransport transport = MockTransport(); Hub getSut() { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.transport = transport; return Hub(options); } diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index e58311169..cf3df91d1 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -24,6 +24,7 @@ import 'mocks/mock_hub.dart'; import 'mocks/mock_platform.dart'; import 'mocks/mock_platform_checker.dart'; import 'mocks/mock_transport.dart'; +import 'test_utils.dart'; void main() { group('SentryClient captures message', () { @@ -1255,6 +1256,7 @@ void main() { throw exception; }; + fixture.options.automatedTestMode = false; final client = fixture.getSut( beforeSendTransaction: beforeSendTransactionCallback, debug: true); final fakeTransaction = fixture.fakeTransaction(); @@ -1318,6 +1320,7 @@ void main() { throw exception; }; + fixture.options.automatedTestMode = false; final client = fixture.getSut(beforeSend: beforeSendCallback, debug: true); @@ -1893,9 +1896,8 @@ class Fixture { final recorder = MockClientReportRecorder(); final transport = MockTransport(); - final options = SentryOptions(dsn: fakeDsn) - ..platformChecker = MockPlatformChecker(platform: MockPlatform.iOS()) - ..automatedTestMode = true; + final options = + defaultTestOptions(MockPlatformChecker(platform: MockPlatform.iOS())); late SentryTransactionContext _context; late SentryTracer tracer; diff --git a/dart/test/sentry_envelope_test.dart b/dart/test/sentry_envelope_test.dart index a24cab20c..7fe59d099 100644 --- a/dart/test/sentry_envelope_test.dart +++ b/dart/test/sentry_envelope_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import 'mocks.dart'; import 'mocks/mock_hub.dart'; +import 'test_utils.dart'; void main() { group('SentryEnvelope', () { @@ -51,7 +52,9 @@ void main() { '$expectedHeaderJsonSerialized\n$expectedItemSerialized\n$expectedItemSerialized'); final envelopeData = []; - await sut.envelopeStream(SentryOptions()).forEach(envelopeData.addAll); + await sut + .envelopeStream(defaultTestOptions()) + .forEach(envelopeData.addAll); expect(envelopeData, expected); }); @@ -213,12 +216,12 @@ void main() { final sutEnvelopeData = []; await sut - .envelopeStream(SentryOptions()..maxAttachmentSize = 1) + .envelopeStream(defaultTestOptions()..maxAttachmentSize = 1) .forEach(sutEnvelopeData.addAll); final envelopeData = []; await expectedEnvelopeItem - .envelopeStream(SentryOptions()) + .envelopeStream(defaultTestOptions()) .forEach(envelopeData.addAll); expect(sutEnvelopeData, envelopeData); @@ -238,7 +241,7 @@ void main() { dsn: fakeDsn, ); - final _ = sut.envelopeStream(SentryOptions()).map((e) => e); + final _ = sut.envelopeStream(defaultTestOptions()).map((e) => e); }); }); } diff --git a/dart/test/sentry_envelope_vm_test.dart b/dart/test/sentry_envelope_vm_test.dart index 7854ffccb..e5f027670 100644 --- a/dart/test/sentry_envelope_vm_test.dart +++ b/dart/test/sentry_envelope_vm_test.dart @@ -10,6 +10,7 @@ import 'package:sentry/src/sentry_envelope_item_header.dart'; import 'package:test/test.dart'; import 'mocks.dart'; +import 'test_utils.dart'; void main() { group('SentryEnvelopeItem', () { @@ -37,7 +38,7 @@ void main() { final envelopeData = []; await envelope - .envelopeStream(SentryOptions()) + .envelopeStream(defaultTestOptions()) .forEach(envelopeData.addAll); final expectedEnvelopeFile = @@ -62,8 +63,9 @@ void main() { attachments: [attachment], ); - final data = (await envelope.envelopeStream(SentryOptions()).toList()) - .reduce((a, b) => a + b); + final data = + (await envelope.envelopeStream(defaultTestOptions()).toList()) + .reduce((a, b) => a + b); final file = File('test_resources/envelope-no-attachment.envelope'); final jsonStr = await file.readAsString(); diff --git a/dart/test/sentry_exception_factory_test.dart b/dart/test/sentry_exception_factory_test.dart index cca350f2b..a3129fb8f 100644 --- a/dart/test/sentry_exception_factory_test.dart +++ b/dart/test/sentry_exception_factory_test.dart @@ -2,7 +2,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_exception_factory.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; +import 'test_utils.dart'; void main() { final fixture = Fixture(); @@ -284,7 +284,7 @@ isolate_instructions: 7526344980, vm_instructions: 752633f000 } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); SentryExceptionFactory getSut({bool attachStacktrace = true}) { options.attachStacktrace = true; diff --git a/dart/test/sentry_isolate_extension_test.dart b/dart/test/sentry_isolate_extension_test.dart index 626d7e525..89c6a0fe4 100644 --- a/dart/test/sentry_isolate_extension_test.dart +++ b/dart/test/sentry_isolate_extension_test.dart @@ -4,11 +4,10 @@ library dart_test; import 'dart:isolate'; import 'package:sentry/src/sentry_isolate_extension.dart'; -import 'package:sentry/src/sentry_options.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; +import 'test_utils.dart'; void main() { group("SentryIsolate", () { @@ -53,7 +52,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; Isolate getSut() { return Isolate.current; diff --git a/dart/test/sentry_isolate_test.dart b/dart/test/sentry_isolate_test.dart index 6d4163630..07347d558 100644 --- a/dart/test/sentry_isolate_test.dart +++ b/dart/test/sentry_isolate_test.dart @@ -5,12 +5,11 @@ import 'package:sentry/src/hub.dart'; import 'package:sentry/src/protocol/sentry_level.dart'; import 'package:sentry/src/protocol/span_status.dart'; import 'package:sentry/src/sentry_isolate.dart'; -import 'package:sentry/src/sentry_options.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; import 'mocks/mock_sentry_client.dart'; +import 'test_utils.dart'; void main() { group("SentryIsolate", () { @@ -72,5 +71,5 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; } diff --git a/dart/test/sentry_options_test.dart b/dart/test/sentry_options_test.dart index bb2db9db2..be652ca91 100644 --- a/dart/test/sentry_options_test.dart +++ b/dart/test/sentry_options_test.dart @@ -4,16 +4,16 @@ import 'package:sentry/src/noop_client.dart'; import 'package:sentry/src/version.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; +import 'test_utils.dart'; void main() { test('$Client is NoOp', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(NoOpClient(), options.httpClient); }); test('$Client sets a custom client', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final client = Client(); options.httpClient = client; @@ -21,20 +21,20 @@ void main() { }); test('maxBreadcrumbs is 100 by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(100, options.maxBreadcrumbs); }); test('maxBreadcrumbs sets custom maxBreadcrumbs', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.maxBreadcrumbs = 200; expect(200, options.maxBreadcrumbs); }); test('SentryLogger sets a diagnostic logger', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); // ignore: deprecated_member_use_from_same_package expect(options.logger, noOpLogger); // ignore: deprecated_member_use_from_same_package @@ -45,32 +45,32 @@ void main() { }); test('tracesSampler is null by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.tracesSampler, isNull); }); test('tracesSampleRate is null by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.tracesSampleRate, isNull); }); test('isTracingEnabled is disabled', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.isTracingEnabled(), false); }); test('isTracingEnabled is enabled by theres rate', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.tracesSampleRate = 1.0; expect(options.isTracingEnabled(), true); }); test('isTracingEnabled is enabled by theres sampler', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); double? sampler(SentrySamplingContext samplingContext) => 0.0; @@ -98,7 +98,7 @@ void main() { }); test('SentryOptions has sentryClientName set', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.sentryClientName, '${sdkName(options.platformChecker.isWeb)}/$sdkVersion'); @@ -131,39 +131,39 @@ void main() { }); test('Spotlight is disabled by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.spotlight.enabled, false); }); test('metrics are disabled by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.enableMetrics, false); }); test('enableExceptionTypeIdentification is enabled by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.enableExceptionTypeIdentification, true); }); test('default tags for metrics are enabled by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.enableMetrics = true; expect(options.enableDefaultTagsForMetrics, true); }); test('default tags for metrics are disabled if metrics are disabled', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.enableMetrics = false; expect(options.enableDefaultTagsForMetrics, false); }); test('default tags for metrics are enabled if metrics are enabled, too', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.enableMetrics = true; options.enableDefaultTagsForMetrics = true; @@ -171,14 +171,14 @@ void main() { }); test('span local metric aggregation is enabled by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.enableMetrics = true; expect(options.enableSpanLocalMetricAggregation, true); }); test('span local metric aggregation is disabled if metrics are disabled', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.enableMetrics = false; expect(options.enableSpanLocalMetricAggregation, false); @@ -186,7 +186,7 @@ void main() { test('span local metric aggregation is enabled if metrics are enabled, too', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); options.enableMetrics = true; options.enableSpanLocalMetricAggregation = true; @@ -194,7 +194,7 @@ void main() { }); test('enablePureDartSymbolication is enabled by default', () { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); expect(options.enableDartSymbolication, true); }); diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart index 1b363b99a..201062ed5 100644 --- a/dart/test/sentry_test.dart +++ b/dart/test/sentry_test.dart @@ -9,6 +9,7 @@ import 'fake_platform_checker.dart'; import 'mocks.dart'; import 'mocks/mock_integration.dart'; import 'mocks/mock_sentry_client.dart'; +import 'test_utils.dart'; AppRunner appRunner = () {}; @@ -19,7 +20,7 @@ void main() { var anException = Exception(); setUp(() async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -142,7 +143,7 @@ void main() { }); test('null DSN', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); expect( () async => await Sentry.init( options: options, @@ -155,7 +156,7 @@ void main() { test('appRunner should be optional', () async { expect(Sentry.isEnabled, false); - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) => options.dsn = fakeDsn, @@ -164,7 +165,7 @@ void main() { }); test('empty DSN', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) => options.dsn = '', @@ -175,7 +176,7 @@ void main() { test('empty DSN disables the SDK but runs the integrations', () async { final integration = MockIntegration(); - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -188,7 +189,7 @@ void main() { }); test('close disables the SDK', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) => options.dsn = fakeDsn, @@ -212,7 +213,7 @@ void main() { test('should install integrations', () async { final integration = MockIntegration(); - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -226,7 +227,7 @@ void main() { test('should add default integrations', () async { late SentryOptions optionsReference; - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -250,7 +251,7 @@ void main() { }, onPlatform: {'browser': Skip()}); test('should add only web compatible default integrations', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -266,7 +267,7 @@ void main() { test('should close integrations', () async { final integration = MockIntegration(); - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -282,7 +283,7 @@ void main() { }); test('$DeduplicationEventProcessor is added on init', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -299,7 +300,7 @@ void main() { final completer = Completer(); var completed = false; - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); final init = Sentry.init( options: options, (options) { @@ -321,7 +322,7 @@ void main() { }); test('should add DartExceptionTypeIdentifier by default', () async { - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); await Sentry.init( options: options, (options) { @@ -348,7 +349,7 @@ void main() { final completer = Completer(); var completed = false; - final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; + final options = defaultTestOptions(); final init = Sentry.init( options: options, (options) { @@ -371,12 +372,7 @@ void main() { }); test('options.environment debug', () async { - final sentryOptions = SentryOptions(dsn: fakeDsn) - ..automatedTestMode = true - ..platformChecker = FakePlatformChecker.debugMode(); - - final options = SentryOptions(); - options.automatedTestMode = true; + final sentryOptions = defaultTestOptions(FakePlatformChecker.debugMode()); await Sentry.init( (options) { options.dsn = fakeDsn; @@ -388,9 +384,7 @@ void main() { }); test('options.environment profile', () async { - final sentryOptions = - SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.profileMode()) - ..automatedTestMode = true; + final sentryOptions = defaultTestOptions(FakePlatformChecker.profileMode()); await Sentry.init( (options) { @@ -403,9 +397,7 @@ void main() { }); test('options.environment production (defaultEnvironment)', () async { - final sentryOptions = - SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.releaseMode()) - ..automatedTestMode = true; + final sentryOptions = defaultTestOptions(FakePlatformChecker.releaseMode()); await Sentry.init( (options) { options.dsn = fakeDsn; @@ -417,9 +409,7 @@ void main() { }); test('options.logger is set by setting the debug flag', () async { - final sentryOptions = - SentryOptions(dsn: fakeDsn, checker: FakePlatformChecker.debugMode()) - ..automatedTestMode = true; + final sentryOptions = defaultTestOptions(FakePlatformChecker.debugMode()); await Sentry.init( (options) { @@ -443,7 +433,7 @@ void main() { final fixture = Fixture(); test('throw is handled and logged', () async { - final sentryOptions = SentryOptions(dsn: fakeDsn) + final sentryOptions = defaultTestOptions() ..automatedTestMode = false ..debug = true ..logger = fixture.mockLogger; diff --git a/dart/test/sentry_tracer_test.dart b/dart/test/sentry_tracer_test.dart index ba57aeb40..9bc641072 100644 --- a/dart/test/sentry_tracer_test.dart +++ b/dart/test/sentry_tracer_test.dart @@ -2,9 +2,9 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_hub.dart'; import 'mocks/mock_sentry_client.dart'; +import 'test_utils.dart'; void main() { group('$SentryTracer', () { @@ -521,7 +521,7 @@ void main() { final newBaggage = SentryBaggage.fromHeader(baggage.value); expect(newBaggage.get('sentry-trace_id'), sut.context.traceId.toString()); - expect(newBaggage.get('sentry-public_key'), 'abc'); + expect(newBaggage.get('sentry-public_key'), 'public'); expect(newBaggage.get('sentry-release'), 'release'); expect(newBaggage.get('sentry-environment'), 'environment'); expect(newBaggage.get('sentry-user_segment'), 'segment'); @@ -595,7 +595,7 @@ void main() { final context = sut.traceContext(); expect(context!.traceId, sut.context.traceId); - expect(context.publicKey, 'abc'); + expect(context.publicKey, 'public'); expect(context.release, 'release'); expect(context.environment, 'environment'); // ignore: deprecated_member_use_from_same_package @@ -608,7 +608,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn) + final options = defaultTestOptions() ..release = 'release' ..environment = 'environment'; diff --git a/dart/test/sentry_traces_sampler_test.dart b/dart/test/sentry_traces_sampler_test.dart index 276897e65..3fbcb8577 100644 --- a/dart/test/sentry_traces_sampler_test.dart +++ b/dart/test/sentry_traces_sampler_test.dart @@ -2,7 +2,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_traces_sampler.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; +import 'test_utils.dart'; void main() { late Fixture fixture; @@ -81,6 +81,7 @@ void main() { }); test('tracesSampler exception is handled', () { + fixture.options.automatedTestMode = false; final sut = fixture.getSut(debug: true); final exception = Exception("tracesSampler exception"); @@ -151,7 +152,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); SentryLevel? loggedLevel; Object? loggedException; diff --git a/dart/test/sentry_transaction_test.dart b/dart/test/sentry_transaction_test.dart index 7de0549a1..8457e6eb4 100644 --- a/dart/test/sentry_transaction_test.dart +++ b/dart/test/sentry_transaction_test.dart @@ -4,6 +4,7 @@ import 'package:test/test.dart'; import 'mocks.dart'; import 'mocks/mock_hub.dart'; +import 'test_utils.dart'; void main() { final fixture = Fixture(); @@ -108,7 +109,7 @@ void main() { } class Fixture { - final SentryOptions options = SentryOptions(dsn: fakeDsn); + final SentryOptions options = defaultTestOptions(); late final Hub hub = Hub(options); SentryTransaction getSut(SentryTracer tracer) { diff --git a/dart/test/sentry_user_feedback_test.dart b/dart/test/sentry_user_feedback_test.dart index cb406f65b..fec01ca5b 100644 --- a/dart/test/sentry_user_feedback_test.dart +++ b/dart/test/sentry_user_feedback_test.dart @@ -5,6 +5,7 @@ import 'package:test/test.dart'; import 'mocks.dart'; import 'mocks/mock_transport.dart'; +import 'test_utils.dart'; void main() { group('$SentryUserFeedback', () { @@ -141,7 +142,7 @@ void main() { }); test('captureUserFeedback does not throw', () async { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions()..automatedTestMode = false; final transport = ThrowingTransport(); options.transport = transport; final sut = Hub(options); @@ -158,7 +159,7 @@ class Fixture { late MockTransport transport; Hub getSut() { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); transport = MockTransport(); options.transport = transport; return Hub(options); diff --git a/dart/test/stack_trace_test.dart b/dart/test/stack_trace_test.dart index 3636d845a..f63bc0f22 100644 --- a/dart/test/stack_trace_test.dart +++ b/dart/test/stack_trace_test.dart @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:sentry/sentry.dart'; import 'package:sentry/src/origin.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:stack_trace/stack_trace.dart'; import 'package:test/test.dart'; -import 'mocks.dart'; import 'mocks/mock_platform_checker.dart'; +import 'test_utils.dart'; void main() { group('encodeStackTraceFrame', () { @@ -300,8 +299,7 @@ class Fixture { bool considerInAppFramesByDefault = true, bool isWeb = false, }) { - final options = SentryOptions( - dsn: fakeDsn, checker: MockPlatformChecker(isWebValue: isWeb)); + final options = defaultTestOptions(MockPlatformChecker(isWebValue: isWeb)); inAppIncludes.forEach(options.addInAppInclude); inAppExcludes.forEach(options.addInAppExclude); options.considerInAppFramesByDefault = considerInAppFramesByDefault; diff --git a/dart/test/test_utils.dart b/dart/test/test_utils.dart index c7a0138a7..ec25b32f8 100644 --- a/dart/test/test_utils.dart +++ b/dart/test/test_utils.dart @@ -18,6 +18,11 @@ const String _testDsnWithPath = const String _testDsnWithPort = 'https://public:secret@sentry.example.com:8888/1'; +SentryOptions defaultTestOptions([PlatformChecker? checker]) { + return SentryOptions(dsn: testDsn, checker: checker) + ..automatedTestMode = true; +} + void testHeaders( Map? headers, ClockProvider fakeClockProvider, { @@ -69,7 +74,7 @@ Future testCaptureException( fail('Unexpected request on ${request.method} ${request.url} in HttpMock'); }); - final options = SentryOptions(dsn: testDsn) + final options = defaultTestOptions() ..compressPayload = compressPayload ..clock = fakeClockProvider ..httpClient = httpMock @@ -196,7 +201,7 @@ Future testCaptureException( void runTest({Codec, List?>? gzip, bool isWeb = false}) { test('can parse DSN', () async { - final options = SentryOptions(dsn: testDsn); + final options = defaultTestOptions(); final client = SentryClient(options); final dsn = Dsn.parse(options.dsn!); @@ -213,7 +218,7 @@ void runTest({Codec, List?>? gzip, bool isWeb = false}) { }); test('can parse DSN without secret', () async { - final options = SentryOptions(dsn: _testDsnWithoutSecret); + final options = defaultTestOptions()..dsn = _testDsnWithoutSecret; final client = SentryClient(options); final dsn = Dsn.parse(options.dsn!); @@ -230,7 +235,7 @@ void runTest({Codec, List?>? gzip, bool isWeb = false}) { }); test('can parse DSN with path', () async { - final options = SentryOptions(dsn: _testDsnWithPath); + final options = defaultTestOptions()..dsn = _testDsnWithPath; final client = SentryClient(options); final dsn = Dsn.parse(options.dsn!); @@ -246,7 +251,7 @@ void runTest({Codec, List?>? gzip, bool isWeb = false}) { client.close(); }); test('can parse DSN with port', () async { - final options = SentryOptions(dsn: _testDsnWithPort); + final options = defaultTestOptions()..dsn = _testDsnWithPort; final client = SentryClient(options); final dsn = Dsn.parse(options.dsn!); @@ -277,7 +282,8 @@ void runTest({Codec, List?>? gzip, bool isWeb = false}) { }); final client = SentryClient( - SentryOptions(dsn: _testDsnWithoutSecret) + defaultTestOptions() + ..dsn = _testDsnWithoutSecret ..httpClient = httpMock ..clock = fakeClockProvider ..compressPayload = false @@ -331,9 +337,7 @@ void runTest({Codec, List?>? gzip, bool isWeb = false}) { }); final client = SentryClient( - SentryOptions( - dsn: testDsn, - ) + defaultTestOptions() ..httpClient = httpMock ..clock = fakeClockProvider ..compressPayload = false @@ -392,9 +396,7 @@ void runTest({Codec, List?>? gzip, bool isWeb = false}) { data: {'foo': 'bar'}, ); - final options = SentryOptions( - dsn: testDsn, - ) + final options = defaultTestOptions() ..httpClient = httpMock ..clock = fakeClockProvider ..compressPayload = false diff --git a/dart/test/transport/http_transport_test.dart b/dart/test/transport/http_transport_test.dart index 90065d89d..6546cd73e 100644 --- a/dart/test/transport/http_transport_test.dart +++ b/dart/test/transport/http_transport_test.dart @@ -17,6 +17,7 @@ import 'package:test/test.dart'; import '../mocks.dart'; import '../mocks/mock_client_report_recorder.dart'; import '../mocks/mock_hub.dart'; +import '../test_utils.dart'; void main() { SentryEnvelope givenEnvelope() { @@ -286,9 +287,7 @@ void main() { } class Fixture { - final options = SentryOptions( - dsn: 'https://public:secret@sentry.example.com/1', - ); + final options = defaultTestOptions(); late var clientReportRecorder = MockClientReportRecorder(); diff --git a/dart/test/transport/spotlight_http_transport_test.dart b/dart/test/transport/spotlight_http_transport_test.dart index b23f1fd87..3e9d742bb 100644 --- a/dart/test/transport/spotlight_http_transport_test.dart +++ b/dart/test/transport/spotlight_http_transport_test.dart @@ -9,6 +9,7 @@ import 'package:test/scaffolding.dart'; import '../mocks.dart'; import '../mocks/mock_client_report_recorder.dart'; +import '../test_utils.dart'; void main() { group('send to Sentry', () { @@ -52,9 +53,7 @@ void main() { } class Fixture { - final options = SentryOptions( - dsn: 'https://public:secret@sentry.example.com/1', - ); + final options = defaultTestOptions(); late var clientReportRecorder = MockClientReportRecorder(); diff --git a/dart/test/transport/tesk_queue_test.dart b/dart/test/transport/tesk_queue_test.dart index 80dc97161..af22672d9 100644 --- a/dart/test/transport/tesk_queue_test.dart +++ b/dart/test/transport/tesk_queue_test.dart @@ -1,10 +1,9 @@ import 'dart:async'; -import 'package:sentry/sentry.dart'; import 'package:sentry/src/transport/task_queue.dart'; import 'package:test/test.dart'; -import '../mocks.dart'; +import '../test_utils.dart'; void main() { group("called sync", () { @@ -110,7 +109,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); TaskQueue getSut({required int maxQueueSize}) { return TaskQueue(maxQueueSize, options.logger); diff --git a/dart/test/utils/tracing_utils_test.dart b/dart/test/utils/tracing_utils_test.dart index 96b26b55b..134997afa 100644 --- a/dart/test/utils/tracing_utils_test.dart +++ b/dart/test/utils/tracing_utils_test.dart @@ -2,8 +2,8 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; -import '../mocks.dart'; import '../mocks/mock_sentry_client.dart'; +import '../test_utils.dart'; void main() { group('$containsTargetOrMatchesRegExp', () { @@ -125,7 +125,7 @@ void main() { addBaggageHeaderFromSpan(sut, headers); expect(headers[baggage!.name], - 'other-vendor-value=foo,sentry-trace_id=${sut.context.traceId},sentry-public_key=abc,sentry-release=release,sentry-environment=environment,sentry-user_segment=segment,sentry-transaction=name,sentry-sample_rate=1,sentry-sampled=true'); + 'other-vendor-value=foo,sentry-trace_id=${sut.context.traceId},sentry-public_key=public,sentry-release=release,sentry-environment=environment,sentry-user_segment=segment,sentry-transaction=name,sentry-sample_rate=1,sentry-sampled=true'); }); }); @@ -167,7 +167,7 @@ class Fixture { ), ); - final _options = SentryOptions(dsn: fakeDsn) + final _options = defaultTestOptions() ..release = 'release' ..environment = 'environment'; diff --git a/dio/test/dio_event_processor_test.dart b/dio/test/dio_event_processor_test.dart index af4a94ab8..978682884 100644 --- a/dio/test/dio_event_processor_test.dart +++ b/dio/test/dio_event_processor_test.dart @@ -436,7 +436,7 @@ final requestOptions = RequestOptions( ); class Fixture { - final SentryOptions options = SentryOptions(dsn: fakeDsn); + final SentryOptions options = defaultTestOptions(); // ignore: invalid_use_of_internal_member SentryExceptionFactory get exceptionFactory => options.exceptionFactory; diff --git a/dio/test/mocks.dart b/dio/test/mocks.dart index 30e53c577..052ab8257 100644 --- a/dio/test/mocks.dart +++ b/dio/test/mocks.dart @@ -3,6 +3,11 @@ import 'package:sentry/src/transport/rate_limiter.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +} + final fakeException = Exception('Error'); final fakeMessage = SentryMessage( diff --git a/dio/test/mocks/mock_hub.dart b/dio/test/mocks/mock_hub.dart index 377e1efb7..5e896d58d 100644 --- a/dio/test/mocks/mock_hub.dart +++ b/dio/test/mocks/mock_hub.dart @@ -2,6 +2,7 @@ import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; +import '../mocks.dart'; import 'no_such_method_provider.dart'; class MockHub with NoSuchMethodProvider implements Hub { @@ -17,7 +18,7 @@ class MockHub with NoSuchMethodProvider implements Hub { int spanContextCals = 0; int getSpanCalls = 0; - final _options = SentryOptions(dsn: 'fixture-dsn'); + final _options = defaultTestOptions(); @override @internal diff --git a/dio/test/sentry_transformer_test.dart b/dio/test/sentry_transformer_test.dart index ffa793c79..93fd36f13 100644 --- a/dio/test/sentry_transformer_test.dart +++ b/dio/test/sentry_transformer_test.dart @@ -137,7 +137,7 @@ void main() { } class Fixture { - final _options = SentryOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); late Hub _hub; final transport = MockTransport(); Fixture() { diff --git a/dio/test/tracing_client_adapter_test.dart b/dio/test/tracing_client_adapter_test.dart index f67ec4c14..680825b34 100644 --- a/dio/test/tracing_client_adapter_test.dart +++ b/dio/test/tracing_client_adapter_test.dart @@ -183,7 +183,7 @@ MockHttpClientAdapter createThrowingClient() { } class Fixture { - final _options = SentryOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); late Hub _hub; final transport = MockTransport(); Fixture() { diff --git a/drift/test/sentry_database_test.dart b/drift/test/sentry_database_test.dart index 52b0c9ee2..902888963 100644 --- a/drift/test/sentry_database_test.dart +++ b/drift/test/sentry_database_test.dart @@ -15,6 +15,7 @@ import 'package:sqlite3/open.dart'; import 'mocks/mocks.mocks.dart'; import 'test_database.dart'; +import 'utils.dart'; import 'utils/windows_helper.dart'; void main() { @@ -643,7 +644,7 @@ void main() { } class Fixture { - final options = SentryOptions(); + final options = defaultTestOptions(); final hub = MockHub(); static final dbName = 'people-drift-impl'; final exception = Exception('fixture-exception'); diff --git a/drift/test/utils.dart b/drift/test/utils.dart new file mode 100644 index 000000000..7fb87861f --- /dev/null +++ b/drift/test/utils.dart @@ -0,0 +1,8 @@ +import 'package:sentry/sentry.dart'; + +final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; + +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +} diff --git a/file/test/mock_sentry_client.dart b/file/test/mock_sentry_client.dart index 4a4a28142..8fb4091cd 100644 --- a/file/test/mock_sentry_client.dart +++ b/file/test/mock_sentry_client.dart @@ -4,6 +4,11 @@ import 'no_such_method_provider.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +} + class MockSentryClient with NoSuchMethodProvider implements SentryClient { List captureTransactionCalls = []; diff --git a/file/test/sentry_file_extension_test.dart b/file/test/sentry_file_extension_test.dart index d6a0bff5b..843de9600 100644 --- a/file/test/sentry_file_extension_test.dart +++ b/file/test/sentry_file_extension_test.dart @@ -46,7 +46,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late Hub hub; File getSut({ diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index 48cf9b517..8a1731a96 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -662,7 +662,7 @@ void main() { class Fixture { final client = MockSentryClient(); - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late Hub hub; SentryFile getSut( diff --git a/file/test/sentry_io_overrides_integration_test.dart b/file/test/sentry_io_overrides_integration_test.dart index 86d5f25d7..5a0dcc23a 100644 --- a/file/test/sentry_io_overrides_integration_test.dart +++ b/file/test/sentry_io_overrides_integration_test.dart @@ -68,7 +68,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late final hub = Hub(options); SentryIOOverridesIntegration getSut() { diff --git a/flutter/lib/src/binding_wrapper.dart b/flutter/lib/src/binding_wrapper.dart index 4d6856861..862f55f8d 100644 --- a/flutter/lib/src/binding_wrapper.dart +++ b/flutter/lib/src/binding_wrapper.dart @@ -26,6 +26,9 @@ class BindingWrapper { stackTrace: s, logger: 'BindingWrapper', ); + if (_hub.options.automatedTestMode) { + rethrow; + } return null; } } diff --git a/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart b/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart index d939f4b90..edb5773bb 100644 --- a/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart @@ -58,6 +58,9 @@ class AndroidPlatformExceptionEventProcessor implements EventProcessor { exception: e, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } return event; } } diff --git a/flutter/lib/src/event_processor/native_app_start_event_processor.dart b/flutter/lib/src/event_processor/native_app_start_event_processor.dart index a0da42359..a5d67595b 100644 --- a/flutter/lib/src/event_processor/native_app_start_event_processor.dart +++ b/flutter/lib/src/event_processor/native_app_start_event_processor.dart @@ -123,6 +123,9 @@ class NativeAppStartEventProcessor implements EventProcessor { } catch (e) { _hub.options.logger(SentryLevel.warning, 'Failed to attach native span to app start transaction: $e'); + if (_hub.options.automatedTestMode) { + rethrow; + } } }); } diff --git a/flutter/lib/src/event_processor/screenshot_event_processor.dart b/flutter/lib/src/event_processor/screenshot_event_processor.dart index 8981afe7b..2b9c80dc0 100644 --- a/flutter/lib/src/event_processor/screenshot_event_processor.dart +++ b/flutter/lib/src/event_processor/screenshot_event_processor.dart @@ -50,7 +50,6 @@ class ScreenshotEventProcessor implements EventProcessor { exception: exception, stackTrace: stackTrace, ); - // ignore: invalid_use_of_internal_member if (_options.automatedTestMode) { rethrow; } @@ -138,6 +137,9 @@ class ScreenshotEventProcessor implements EventProcessor { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } return null; } diff --git a/flutter/lib/src/file_system_transport.dart b/flutter/lib/src/file_system_transport.dart index 85cc0947a..e28f81ae7 100644 --- a/flutter/lib/src/file_system_transport.dart +++ b/flutter/lib/src/file_system_transport.dart @@ -3,15 +3,15 @@ import 'dart:typed_data'; import 'package:flutter/services.dart'; -import 'package:sentry/sentry.dart'; +import '../sentry_flutter.dart'; import 'native/sentry_native_binding.dart'; class FileSystemTransport implements Transport { FileSystemTransport(this._native, this._options); final SentryNativeBinding _native; - final SentryOptions _options; + final SentryFlutterOptions _options; @override Future send(SentryEnvelope envelope) async { @@ -28,6 +28,9 @@ class FileSystemTransport implements Transport { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } return SentryId.empty(); } diff --git a/flutter/lib/src/integrations/load_contexts_integration.dart b/flutter/lib/src/integrations/load_contexts_integration.dart index a6ed4effc..679c7b0e3 100644 --- a/flutter/lib/src/integrations/load_contexts_integration.dart +++ b/flutter/lib/src/integrations/load_contexts_integration.dart @@ -212,6 +212,9 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor { exception: exception, stackTrace: stackTrace, ); + if (_options.automatedTestMode) { + rethrow; + } } return event; } diff --git a/flutter/lib/src/integrations/load_release_integration.dart b/flutter/lib/src/integrations/load_release_integration.dart index de44876e0..ca8a29d11 100644 --- a/flutter/lib/src/integrations/load_release_integration.dart +++ b/flutter/lib/src/integrations/load_release_integration.dart @@ -46,6 +46,9 @@ class LoadReleaseIntegration extends Integration { exception: exception, stackTrace: stackTrace, ); + if (options.automatedTestMode) { + rethrow; + } } options.sdk.addIntegration('loadReleaseIntegration'); diff --git a/flutter/lib/src/integrations/native_app_start_integration.dart b/flutter/lib/src/integrations/native_app_start_integration.dart index af747dbf3..2456dd452 100644 --- a/flutter/lib/src/integrations/native_app_start_integration.dart +++ b/flutter/lib/src/integrations/native_app_start_integration.dart @@ -155,6 +155,9 @@ class NativeAppStartIntegration extends Integration { } catch (e) { _hub.options.logger( SentryLevel.warning, 'Failed to parse native span times: $e'); + if (_hub.options.automatedTestMode) { + rethrow; + } continue; } } diff --git a/flutter/lib/src/integrations/native_sdk_integration.dart b/flutter/lib/src/integrations/native_sdk_integration.dart index ad77711b6..4c7c9a92a 100644 --- a/flutter/lib/src/integrations/native_sdk_integration.dart +++ b/flutter/lib/src/integrations/native_sdk_integration.dart @@ -29,6 +29,9 @@ class NativeSdkIntegration implements Integration { exception: exception, stackTrace: stackTrace, ); + if (_options?.automatedTestMode ?? false) { + rethrow; + } } } @@ -44,6 +47,9 @@ class NativeSdkIntegration implements Integration { exception: exception, stackTrace: stackTrace, ); + if (_options?.automatedTestMode ?? false) { + rethrow; + } } } } diff --git a/flutter/lib/src/integrations/on_error_integration.dart b/flutter/lib/src/integrations/on_error_integration.dart index d97f561d5..365a3067a 100644 --- a/flutter/lib/src/integrations/on_error_integration.dart +++ b/flutter/lib/src/integrations/on_error_integration.dart @@ -143,6 +143,9 @@ class PlatformDispatcherWrapper { exception: exception, stackTrace: stacktrace, ); + if (options.automatedTestMode) { + rethrow; + } return false; } return true; diff --git a/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart b/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart index 00728d511..3c956205a 100644 --- a/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart +++ b/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart @@ -17,7 +17,7 @@ class SentryNativeCocoa extends SentryNativeChannel { ScreenshotRecorder? _replayRecorder; SentryId? _replayId; - SentryNativeCocoa(super.options, super.channel); + SentryNativeCocoa(super.options); @override Future init(Hub hub) async { diff --git a/flutter/lib/src/native/factory_real.dart b/flutter/lib/src/native/factory_real.dart index 554279a8b..67af20e2e 100644 --- a/flutter/lib/src/native/factory_real.dart +++ b/flutter/lib/src/native/factory_real.dart @@ -1,19 +1,16 @@ -import 'package:flutter/services.dart'; - import '../../sentry_flutter.dart'; import 'cocoa/sentry_native_cocoa.dart'; import 'java/sentry_native_java.dart'; import 'sentry_native_binding.dart'; import 'sentry_native_channel.dart'; -SentryNativeBinding createBinding(SentryFlutterOptions options, - {MethodChannel channel = const MethodChannel('sentry_flutter')}) { +SentryNativeBinding createBinding(SentryFlutterOptions options) { final platform = options.platformChecker.platform; if (platform.isIOS || platform.isMacOS) { - return SentryNativeCocoa(options, channel); + return SentryNativeCocoa(options); } else if (platform.isAndroid) { - return SentryNativeJava(options, channel); + return SentryNativeJava(options); } else { - return SentryNativeChannel(options, channel); + return SentryNativeChannel(options); } } diff --git a/flutter/lib/src/native/factory_web.dart b/flutter/lib/src/native/factory_web.dart index a928271d1..17c3f5afe 100644 --- a/flutter/lib/src/native/factory_web.dart +++ b/flutter/lib/src/native/factory_web.dart @@ -1,10 +1,7 @@ -import 'package:flutter/services.dart'; - import '../../sentry_flutter.dart'; import 'sentry_native_binding.dart'; // This isn't actually called, see SentryFlutter.init() -SentryNativeBinding createBinding(SentryFlutterOptions options, - {MethodChannel channel = const MethodChannel('sentry_flutter')}) { +SentryNativeBinding createBinding(SentryFlutterOptions options) { throw UnsupportedError("Native binding is not supported on this platform."); } diff --git a/flutter/lib/src/native/java/sentry_native_java.dart b/flutter/lib/src/native/java/sentry_native_java.dart index 5890ca5db..94c29fca1 100644 --- a/flutter/lib/src/native/java/sentry_native_java.dart +++ b/flutter/lib/src/native/java/sentry_native_java.dart @@ -16,7 +16,7 @@ class SentryNativeJava extends SentryNativeChannel { ScheduledScreenshotRecorder? _replayRecorder; String? _replayCacheDir; _IdleFrameFiller? _idleFrameFiller; - SentryNativeJava(super.options, super.channel); + SentryNativeJava(super.options); @override Future init(Hub hub) async { @@ -139,7 +139,6 @@ class SentryNativeJava extends SentryNativeChannel { exception: error, stackTrace: stackTrace, ); - // ignore: invalid_use_of_internal_member if (options.automatedTestMode) { rethrow; } diff --git a/flutter/lib/src/native/sentry_native_channel.dart b/flutter/lib/src/native/sentry_native_channel.dart index 360290230..1e4faf449 100644 --- a/flutter/lib/src/native/sentry_native_channel.dart +++ b/flutter/lib/src/native/sentry_native_channel.dart @@ -25,8 +25,8 @@ class SentryNativeChannel @protected final SentrySafeMethodChannel channel; - SentryNativeChannel(this.options, MethodChannel channel) - : channel = SentrySafeMethodChannel(channel, options); + SentryNativeChannel(this.options) + : channel = SentrySafeMethodChannel(options); @override Future init(Hub hub) async { diff --git a/flutter/lib/src/native/sentry_native_invoker.dart b/flutter/lib/src/native/sentry_native_invoker.dart index dbda8c451..0c0a63760 100644 --- a/flutter/lib/src/native/sentry_native_invoker.dart +++ b/flutter/lib/src/native/sentry_native_invoker.dart @@ -15,7 +15,6 @@ mixin SentryNativeSafeInvoker { return await fn(); } catch (error, stackTrace) { _logError(nativeMethodName, error, stackTrace); - // ignore: invalid_use_of_internal_member if (options.automatedTestMode) { rethrow; } @@ -28,7 +27,6 @@ mixin SentryNativeSafeInvoker { return fn(); } catch (error, stackTrace) { _logError(nativeMethodName, error, stackTrace); - // ignore: invalid_use_of_internal_member if (options.automatedTestMode) { rethrow; } diff --git a/flutter/lib/src/native/sentry_safe_method_channel.dart b/flutter/lib/src/native/sentry_safe_method_channel.dart index 8cd258c8d..184843279 100644 --- a/flutter/lib/src/native/sentry_safe_method_channel.dart +++ b/flutter/lib/src/native/sentry_safe_method_channel.dart @@ -12,7 +12,7 @@ class SentrySafeMethodChannel with SentryNativeSafeInvoker { final MethodChannel _channel; - SentrySafeMethodChannel(this._channel, this.options); + SentrySafeMethodChannel(this.options) : _channel = options.methodChannel; void setMethodCallHandler( Future Function(MethodCall call)? handler) => diff --git a/flutter/lib/src/navigation/sentry_navigator_observer.dart b/flutter/lib/src/navigation/sentry_navigator_observer.dart index db9109840..48b105925 100644 --- a/flutter/lib/src/navigation/sentry_navigator_observer.dart +++ b/flutter/lib/src/navigation/sentry_navigator_observer.dart @@ -331,6 +331,9 @@ class SentryNavigatorObserver extends RouteObserver> { exception: exception, stackTrace: stacktrace, ); + if (_hub.options.automatedTestMode) { + rethrow; + } } finally { await transaction?.finish(); if (clearAfter) { @@ -379,6 +382,9 @@ class SentryNavigatorObserver extends RouteObserver> { exception: exception, stackTrace: stacktrace, ); + if (_hub.options.automatedTestMode) { + rethrow; + } } finally { _clear(); } diff --git a/flutter/lib/src/replay/recorder.dart b/flutter/lib/src/replay/recorder.dart index a1f4ea1a0..847c3a75f 100644 --- a/flutter/lib/src/replay/recorder.dart +++ b/flutter/lib/src/replay/recorder.dart @@ -103,7 +103,6 @@ class ScreenshotRecorder { } catch (e, stackTrace) { options.logger(SentryLevel.error, "Replay: failed to capture screenshot.", exception: e, stackTrace: stackTrace); - // ignore: invalid_use_of_internal_member if (options.automatedTestMode) { rethrow; } diff --git a/flutter/lib/src/sentry_flutter.dart b/flutter/lib/src/sentry_flutter.dart index 6d035b374..16e6d7a4d 100644 --- a/flutter/lib/src/sentry_flutter.dart +++ b/flutter/lib/src/sentry_flutter.dart @@ -51,23 +51,15 @@ mixin SentryFlutter { static Future init( FlutterOptionsConfiguration optionsConfiguration, { AppRunner? appRunner, - @internal PlatformChecker? platformChecker, - @internal RendererWrapper? rendererWrapper, + @internal SentryFlutterOptions? options, }) async { - final flutterOptions = SentryFlutterOptions(); + options ??= SentryFlutterOptions(); // ignore: invalid_use_of_internal_member - sentrySetupStartTime ??= flutterOptions.clock(); + sentrySetupStartTime ??= options.clock(); - if (platformChecker != null) { - flutterOptions.platformChecker = platformChecker; - } - if (rendererWrapper != null) { - flutterOptions.rendererWrapper = rendererWrapper; - } - - if (flutterOptions.platformChecker.hasNativeIntegration) { - _native = createBinding(flutterOptions); + if (options.platformChecker.hasNativeIntegration) { + _native = createBinding(options); } final platformDispatcher = PlatformDispatcher.instance; @@ -76,34 +68,31 @@ mixin SentryFlutter { // Flutter Web don't capture [Future] errors if using [PlatformDispatcher.onError] and not // the [runZonedGuarded]. // likely due to https://github.com/flutter/flutter/issues/100277 - final isOnErrorSupported = flutterOptions.platformChecker.isWeb + final isOnErrorSupported = options.platformChecker.isWeb ? false - : wrapper.isOnErrorSupported(flutterOptions); + : wrapper.isOnErrorSupported(options); - final runZonedGuardedOnError = flutterOptions.platformChecker.isWeb - ? _createRunZonedGuardedOnError() - : null; + final runZonedGuardedOnError = + options.platformChecker.isWeb ? _createRunZonedGuardedOnError() : null; // first step is to install the native integration and set default values, // so we are able to capture future errors. - final defaultIntegrations = _createDefaultIntegrations( - flutterOptions, - isOnErrorSupported, - ); + final defaultIntegrations = + _createDefaultIntegrations(options, isOnErrorSupported); for (final defaultIntegration in defaultIntegrations) { - flutterOptions.addIntegration(defaultIntegration); + options.addIntegration(defaultIntegration); } - await _initDefaultValues(flutterOptions); + await _initDefaultValues(options); await Sentry.init( - (options) { - assert(options == flutterOptions); - return optionsConfiguration(options as SentryFlutterOptions); + (o) { + assert(options == o); + return optionsConfiguration(o as SentryFlutterOptions); }, appRunner: appRunner, // ignore: invalid_use_of_internal_member - options: flutterOptions, + options: options, // ignore: invalid_use_of_internal_member callAppRunnerInRunZonedGuarded: !isOnErrorSupported, // ignore: invalid_use_of_internal_member @@ -117,8 +106,7 @@ mixin SentryFlutter { // Insert it at the start of the list, before the Dart Exceptions that are set in Sentry.init // so we can identify Flutter exceptions first. - flutterOptions - .prependExceptionTypeIdentifier(FlutterExceptionTypeIdentifier()); + options.prependExceptionTypeIdentifier(FlutterExceptionTypeIdentifier()); } static Future _initDefaultValues(SentryFlutterOptions options) async { diff --git a/flutter/lib/src/sentry_flutter_options.dart b/flutter/lib/src/sentry_flutter_options.dart index 18b9d8c91..8e533e438 100644 --- a/flutter/lib/src/sentry_flutter_options.dart +++ b/flutter/lib/src/sentry_flutter_options.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:file/file.dart'; import 'package:file/local.dart'; +import 'package:flutter/services.dart'; import 'package:meta/meta.dart' as meta; import 'package:sentry/sentry.dart'; import 'package:flutter/widgets.dart'; @@ -224,6 +225,9 @@ class SentryFlutterOptions extends SentryOptions { @meta.internal late RendererWrapper rendererWrapper = RendererWrapper(); + @meta.internal + late MethodChannel methodChannel = const MethodChannel('sentry_flutter'); + /// Enables the View Hierarchy feature. /// /// Renders an ASCII represention of the entire view hierarchy of the @@ -346,6 +350,17 @@ class SentryFlutterOptions extends SentryOptions { /// The [navigatorKey] is used to add information of the currently used locale to the contexts. GlobalKey? navigatorKey; + // Override so we don't have to add `ignore` on each use. + @meta.internal + @override + // ignore: invalid_use_of_internal_member + bool get automatedTestMode => super.automatedTestMode; + + @meta.internal + @override + // ignore: invalid_use_of_internal_member + set automatedTestMode(bool value) => super.automatedTestMode = value; + @meta.internal FileSystem fileSystem = LocalFileSystem(); diff --git a/flutter/temp/native-test/dist/sentry.dll b/flutter/temp/native-test/dist/sentry.dll new file mode 100644 index 0000000000000000000000000000000000000000..21615e9b7d335ff796f8ef03339c05780c9e36f6 GIT binary patch literal 280064 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�-0)E$fH{&iSTzR59+v^ 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%0A8d$Wr2cmF@b#M0vCDY7zCl!lXFw{tv-~4gCcV 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.delayed(Duration(milliseconds: 1)); @@ -180,7 +182,7 @@ void main() { class Fixture { late Hub hub; - SentryFlutterOptions options = SentryFlutterOptions(dsn: fakeDsn); + SentryFlutterOptions options = defaultTestOptions(); Fixture() { options.attachScreenshot = true; diff --git a/flutter/test/event_processor/url_filter/io_filter_event_processor_test.dart b/flutter/test/event_processor/url_filter/io_filter_event_processor_test.dart index 22708b95b..186858888 100644 --- a/flutter/test/event_processor/url_filter/io_filter_event_processor_test.dart +++ b/flutter/test/event_processor/url_filter/io_filter_event_processor_test.dart @@ -5,6 +5,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/event_processor/url_filter/url_filter_event_processor.dart'; +import '../../mocks.dart'; + void main() { group("ignore allowUrls and denyUrls for non Web", () { late Fixture fixture; @@ -32,7 +34,7 @@ void main() { } class Fixture { - SentryFlutterOptions options = SentryFlutterOptions(); + SentryFlutterOptions options = defaultTestOptions(); UrlFilterEventProcessor getSut() { return UrlFilterEventProcessor(options); } diff --git a/flutter/test/event_processor/url_filter/web_url_filter_event_processor_test.dart b/flutter/test/event_processor/url_filter/web_url_filter_event_processor_test.dart index 5fb5f7039..bc80d45e6 100644 --- a/flutter/test/event_processor/url_filter/web_url_filter_event_processor_test.dart +++ b/flutter/test/event_processor/url_filter/web_url_filter_event_processor_test.dart @@ -5,6 +5,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/event_processor/url_filter/url_filter_event_processor.dart'; +import '../../mocks.dart'; + // can be tested on command line with // `flutter test --platform=chrome test/event_processor/url_filter/web_url_filter_event_processor_test.dart` // The URL looks something like this: http://localhost:58551/event_processor/url_filter/web_url_filter_event_processor_test.html @@ -112,7 +114,7 @@ void main() { } class Fixture { - SentryFlutterOptions options = SentryFlutterOptions(); + SentryFlutterOptions options = defaultTestOptions(); UrlFilterEventProcessor getSut() { return UrlFilterEventProcessor(options); } diff --git a/flutter/test/file_system_transport_test.dart b/flutter/test/file_system_transport_test.dart index 5aa071318..84bef4bab 100644 --- a/flutter/test/file_system_transport_test.dart +++ b/flutter/test/file_system_transport_test.dart @@ -40,6 +40,7 @@ void main() { }); test('$FileSystemTransport returns emptyId if channel throws', () async { + fixture.options.automatedTestMode = false; when(fixture.binding.captureEnvelope(any, false)).thenThrow(Exception()); final transport = fixture.getSut(); @@ -155,7 +156,7 @@ void main() { } class Fixture { - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final binding = MockSentryNativeBinding(); FileSystemTransport getSut() { diff --git a/flutter/test/initialization_test.dart b/flutter/test/initialization_test.dart index 7b59c173b..d36e54933 100644 --- a/flutter/test/initialization_test.dart +++ b/flutter/test/initialization_test.dart @@ -10,52 +10,22 @@ import 'mocks.dart'; // https://github.com/getsentry/sentry-dart/issues/508 // There are no asserts, test are succesfull if no exceptions are thrown. void main() { - setUp(() async { - await Sentry.close(); - }); - - test('async re-initilization', () async { - await SentryFlutter.init( - (options) { - options.dsn = fakeDsn; - // ignore: invalid_use_of_internal_member - options.automatedTestMode = true; - }, - ); - - await Sentry.close(); + final native = NativeChannelFixture(); - await SentryFlutter.init( - (options) { - options.dsn = fakeDsn; - // ignore: invalid_use_of_internal_member - options.automatedTestMode = true; - }, - ); + void optionsInitializer(SentryFlutterOptions options) { + // LoadReleaseIntegration throws because package_info channel is not available + options.removeIntegration( + options.integrations.firstWhere((i) => i is LoadReleaseIntegration)); + } - await Sentry.close(); - }); - - // This is the failure from - // https://github.com/getsentry/sentry-dart/issues/508 - test('re-initilization', () async { - await SentryFlutter.init( - (options) { - options.dsn = fakeDsn; - // ignore: invalid_use_of_internal_member - options.automatedTestMode = true; - }, - ); + test('async re-initilization', () async { + await SentryFlutter.init(optionsInitializer, + options: defaultTestOptions()..methodChannel = native.channel); await Sentry.close(); - await SentryFlutter.init( - (options) { - options.dsn = fakeDsn; - // ignore: invalid_use_of_internal_member - options.automatedTestMode = true; - }, - ); + await SentryFlutter.init(optionsInitializer, + options: defaultTestOptions()..methodChannel = native.channel); await Sentry.close(); }); diff --git a/flutter/test/integrations/connectivity_integration_test.dart b/flutter/test/integrations/connectivity_integration_test.dart index 2f0781e9e..ed7ca8034 100644 --- a/flutter/test/integrations/connectivity_integration_test.dart +++ b/flutter/test/integrations/connectivity_integration_test.dart @@ -3,7 +3,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry_flutter/src/integrations/connectivity/connectivity_integration.dart'; -import 'package:sentry_flutter/src/sentry_flutter_options.dart'; import '../mocks.dart'; import '../mocks.mocks.dart'; @@ -48,7 +47,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(dsn: fakeDsn); + final options = defaultTestOptions(); ConnectivityIntegration getSut() { return ConnectivityIntegration(); diff --git a/flutter/test/integrations/debug_print_integration_test.dart b/flutter/test/integrations/debug_print_integration_test.dart index b7804abee..67359ade7 100644 --- a/flutter/test/integrations/debug_print_integration_test.dart +++ b/flutter/test/integrations/debug_print_integration_test.dart @@ -94,10 +94,8 @@ class Fixture { bool debug = false, bool enablePrintBreadcrumbs = true, }) { - return SentryFlutterOptions( - dsn: fakeDsn, - checker: MockPlatformChecker(isDebug: debug), - )..enablePrintBreadcrumbs = enablePrintBreadcrumbs; + return defaultTestOptions(MockPlatformChecker(isDebug: debug)) + ..enablePrintBreadcrumbs = enablePrintBreadcrumbs; } DebugPrintIntegration getSut() { diff --git a/flutter/test/integrations/fixture.dart b/flutter/test/integrations/fixture.dart index 19a5ed790..471c6e42b 100644 --- a/flutter/test/integrations/fixture.dart +++ b/flutter/test/integrations/fixture.dart @@ -9,13 +9,10 @@ import '../mocks.mocks.dart'; class IntegrationTestFixture { late T sut; late Hub hub; - final options = SentryFlutterOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final binding = MockSentryNativeBinding(); IntegrationTestFixture(T Function(SentryNativeBinding) factory) { - // ignore: invalid_use_of_internal_member - options.automatedTestMode = true; - hub = Hub(options); sut = factory(binding); } diff --git a/flutter/test/integrations/flutter_error_integration_test.dart b/flutter/test/integrations/flutter_error_integration_test.dart index 40a8ef7c3..4ec10025c 100644 --- a/flutter/test/integrations/flutter_error_integration_test.dart +++ b/flutter/test/integrations/flutter_error_integration_test.dart @@ -269,6 +269,14 @@ void main() { final hub = Hub(fixture.options); final client = MockSentryClient(); + when(client.captureEvent(any, + scope: anyNamed('scope'), + stackTrace: anyNamed('stackTrace'), + hint: anyNamed('hint'))) + .thenAnswer((_) => Future.value(SentryId.newId())); + when(client.captureTransaction(any, + scope: anyNamed('scope'), traceContext: anyNamed('traceContext'))) + .thenAnswer((_) => Future.value(SentryId.newId())); hub.bindClient(client); final sut = fixture.getSut(); @@ -307,7 +315,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; FlutterErrorIntegration getSut() { return FlutterErrorIntegration(); diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart index bfce621eb..6f84e946f 100644 --- a/flutter/test/integrations/init_native_sdk_test.dart +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -189,10 +189,7 @@ MethodChannel createChannelWithCallback( SentryFlutterOptions createOptions() { final mockPlatformChecker = MockPlatformChecker(hasNativeIntegration: true); - final options = SentryFlutterOptions( - dsn: fakeDsn, - checker: mockPlatformChecker, - ); + final options = defaultTestOptions(mockPlatformChecker); options.sdk = SdkVersion( name: sdkName, version: sdkVersion, @@ -203,8 +200,8 @@ SentryFlutterOptions createOptions() { class Fixture { late SentryFlutterOptions options; - SentryNativeChannel getSut(MethodChannel native) { - options = createOptions(); - return SentryNativeChannel(options, native); + SentryNativeChannel getSut(MethodChannel channel) { + options = createOptions()..methodChannel = channel; + return SentryNativeChannel(options); } } diff --git a/flutter/test/integrations/load_contexts_integrations_test.dart b/flutter/test/integrations/load_contexts_integrations_test.dart index a1490b821..7add3f792 100644 --- a/flutter/test/integrations/load_contexts_integrations_test.dart +++ b/flutter/test/integrations/load_contexts_integrations_test.dart @@ -6,6 +6,7 @@ import 'package:mockito/mockito.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/integrations/load_contexts_integration.dart'; +import '../mocks.dart'; import '../mocks.mocks.dart'; void main() { @@ -424,7 +425,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); final binding = MockSentryNativeBinding(); LoadContextsIntegration getSut( diff --git a/flutter/test/integrations/load_release_integration_test.dart b/flutter/test/integrations/load_release_integration_test.dart index 0af572bd8..3d089b03d 100644 --- a/flutter/test/integrations/load_release_integration_test.dart +++ b/flutter/test/integrations/load_release_integration_test.dart @@ -143,7 +143,7 @@ void main() { } class Fixture { - final options = SentryFlutterOptions(dsn: fakeDsn); + final options = defaultTestOptions(); LoadReleaseIntegration getIntegration({Function? loader}) { if (loader != null) { diff --git a/flutter/test/integrations/native_sdk_integration_test.dart b/flutter/test/integrations/native_sdk_integration_test.dart index 5c244b3d6..7c25cec7b 100644 --- a/flutter/test/integrations/native_sdk_integration_test.dart +++ b/flutter/test/integrations/native_sdk_integration_test.dart @@ -24,13 +24,22 @@ void main() { verify(fixture.binding.init(any)).called(1); }); - test('do not throw', () async { + test('does not throw', () async { + fixture.options.automatedTestMode = false; + fixture.sut = NativeSdkIntegration(_ThrowingMockSentryNative()); await fixture.registerIntegration(); expect(fixture.options.sdk.integrations.contains('nativeSdkIntegration'), false); }); + test('rethrows in tests', () async { + fixture.sut = NativeSdkIntegration(_ThrowingMockSentryNative()); + expect(fixture.registerIntegration, throwsException); + expect(fixture.options.sdk.integrations.contains('nativeSdkIntegration'), + false); + }); + test('closes native SDK', () async { await fixture.registerIntegration(); await fixture.sut.close(); @@ -50,9 +59,9 @@ void main() { verifyNever(fixture.binding.close()); }); - test(' is not added in case of an exception', () async { + test('is not added in case of an exception', () async { fixture.sut = NativeSdkIntegration(_ThrowingMockSentryNative()); - await fixture.registerIntegration(); + expect(fixture.registerIntegration, throwsException); expect(fixture.options.sdk.integrations, []); }); }); diff --git a/flutter/test/integrations/not_initialized_widgets_binding_on_error_integration_test.dart b/flutter/test/integrations/not_initialized_widgets_binding_on_error_integration_test.dart index 41de1e557..6df7df0d0 100644 --- a/flutter/test/integrations/not_initialized_widgets_binding_on_error_integration_test.dart +++ b/flutter/test/integrations/not_initialized_widgets_binding_on_error_integration_test.dart @@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry_flutter/src/integrations/on_error_integration.dart'; -import 'package:sentry_flutter/src/sentry_flutter_options.dart'; import '../mocks.dart'; import '../mocks.mocks.dart'; @@ -51,7 +50,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late final platformDispatcherWrapper = PlatformDispatcherWrapper(MockPlatformDispatcher()); diff --git a/flutter/test/integrations/not_initialized_widgets_binding_test.dart b/flutter/test/integrations/not_initialized_widgets_binding_test.dart index 50c8b22b4..702071d10 100644 --- a/flutter/test/integrations/not_initialized_widgets_binding_test.dart +++ b/flutter/test/integrations/not_initialized_widgets_binding_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/integrations/widgets_binding_integration.dart'; +import '../mocks.dart'; import '../mocks.mocks.dart'; /// Tests that require `WidgetsFlutterBinding.ensureInitialized();` not @@ -25,5 +25,5 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); } diff --git a/flutter/test/integrations/on_error_integration_test.dart b/flutter/test/integrations/on_error_integration_test.dart index fb08e68a9..f36791661 100644 --- a/flutter/test/integrations/on_error_integration_test.dart +++ b/flutter/test/integrations/on_error_integration_test.dart @@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry_flutter/src/integrations/on_error_integration.dart'; -import 'package:sentry_flutter/src/sentry_flutter_options.dart'; import '../mocks.dart'; import '../mocks.mocks.dart'; @@ -165,6 +164,14 @@ void main() { final hub = Hub(fixture.options); final client = MockSentryClient(); + when(client.captureEvent(any, + scope: anyNamed('scope'), + stackTrace: anyNamed('stackTrace'), + hint: anyNamed('hint'))) + .thenAnswer((_) => Future.value(SentryId.newId())); + when(client.captureTransaction(any, + scope: anyNamed('scope'), traceContext: anyNamed('traceContext'))) + .thenAnswer((_) => Future.value(SentryId.newId())); hub.bindClient(client); final sut = fixture.getSut(); @@ -187,7 +194,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; final platformDispatcherWrapper = PlatformDispatcherWrapper(MockPlatformDispatcher()); diff --git a/flutter/test/integrations/screenshot_integration_test.dart b/flutter/test/integrations/screenshot_integration_test.dart index 4bf225268..cedf8bca4 100644 --- a/flutter/test/integrations/screenshot_integration_test.dart +++ b/flutter/test/integrations/screenshot_integration_test.dart @@ -1,8 +1,8 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/event_processor/screenshot_event_processor.dart'; import 'package:sentry_flutter/src/integrations/screenshot_integration.dart'; +import '../mocks.dart'; import '../mocks.mocks.dart'; void main() { @@ -69,7 +69,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); ScreenshotIntegration getSut({bool attachScreenshot = true}) { options.attachScreenshot = attachScreenshot; diff --git a/flutter/test/integrations/widgets_flutter_binding_integration_test.dart b/flutter/test/integrations/widgets_flutter_binding_integration_test.dart index 72fb406ee..3ab2a8f89 100644 --- a/flutter/test/integrations/widgets_flutter_binding_integration_test.dart +++ b/flutter/test/integrations/widgets_flutter_binding_integration_test.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/integrations/widgets_flutter_binding_integration.dart'; import '../mocks.dart'; @@ -43,8 +42,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(dsn: fakeDsn) - ..bindingUtils = TestBindingWrapper(); + final options = defaultTestOptions()..bindingUtils = TestBindingWrapper(); TestBindingWrapper get testBindingUtils => options.bindingUtils as TestBindingWrapper; diff --git a/flutter/test/mocks.dart b/flutter/test/mocks.dart index ee7488987..b920578f0 100644 --- a/flutter/test/mocks.dart +++ b/flutter/test/mocks.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/src/widgets/binding.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; import 'package:sentry/src/platform/platform.dart'; import 'package:sentry/src/sentry_tracer.dart'; @@ -18,10 +19,9 @@ import 'no_such_method_provider.dart'; const fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; const fakeProguardUuid = '3457d982-65ef-576d-a6ad-65b5f30f49a5'; -// TODO use this everywhere in tests so that we don't get exceptions swallowed. -SentryFlutterOptions defaultTestOptions() { - // ignore: invalid_use_of_internal_member - return SentryFlutterOptions(dsn: fakeDsn)..automatedTestMode = true; +SentryFlutterOptions defaultTestOptions([PlatformChecker? checker]) { + return SentryFlutterOptions(dsn: fakeDsn, checker: checker) + ..automatedTestMode = true; } // https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#fallback-generators @@ -46,6 +46,7 @@ ISentrySpan startTransactionShim( SentryTracer, SentryTransaction, SentrySpan, + SentryClient, MethodChannel, SentryNativeBinding ], customMocks: [ @@ -168,8 +169,6 @@ class TestBindingWrapper implements BindingWrapper { } } -class MockSentryClient with NoSuchMethodProvider implements SentryClient {} - // All these values are based on the fakeFrameDurations list. // The expected total frames is also based on the span duration of 1000ms and the slow and frozen frames. const expectedTotalFrames = 17; @@ -201,6 +200,8 @@ class NativeChannelFixture { TestWidgetsFlutterBinding.ensureInitialized(); channel = MethodChannel('test.channel', StandardMethodCodec(), _messenger); handler = MockCallbacks().methodCallHandler; + when(handler('initNativeSdk', any)).thenAnswer((_) => Future.value()); + when(handler('closeNativeSdk', any)).thenAnswer((_) => Future.value()); _messenger.setMockMethodCallHandler( channel, (call) => handler(call.method, call.arguments)); } @@ -213,3 +214,17 @@ class NativeChannelFixture { channel.name, call, (ByteData? data) {}); } } + +typedef EventProcessorFunction = SentryEvent? Function( + SentryEvent event, Hint hint); + +class FunctionEventProcessor implements EventProcessor { + FunctionEventProcessor(this.applyFunction); + + final EventProcessorFunction applyFunction; + + @override + SentryEvent? apply(SentryEvent event, Hint hint) { + return applyFunction(event, hint); + } +} diff --git a/flutter/test/mocks.mocks.dart b/flutter/test/mocks.mocks.dart index feb97b592..3f94ca027 100644 --- a/flutter/test/mocks.mocks.dart +++ b/flutter/test/mocks.mocks.dart @@ -4,19 +4,19 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i7; -import 'dart:typed_data' as _i12; +import 'dart:typed_data' as _i13; import 'package:flutter/services.dart' as _i4; import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/src/dummies.dart' as _i8; -import 'package:sentry/src/metrics/metric.dart' as _i14; +import 'package:sentry/src/metrics/metric.dart' as _i10; import 'package:sentry/src/metrics/metrics_api.dart' as _i5; import 'package:sentry/src/profiling.dart' as _i9; import 'package:sentry/src/sentry_tracer.dart' as _i3; import 'package:sentry_flutter/sentry_flutter.dart' as _i2; -import 'package:sentry_flutter/src/native/native_app_start.dart' as _i11; -import 'package:sentry_flutter/src/native/native_frames.dart' as _i13; -import 'package:sentry_flutter/src/native/sentry_native_binding.dart' as _i10; +import 'package:sentry_flutter/src/native/native_app_start.dart' as _i12; +import 'package:sentry_flutter/src/native/native_frames.dart' as _i14; +import 'package:sentry_flutter/src/native/sentry_native_binding.dart' as _i11; import 'mocks.dart' as _i6; @@ -280,6 +280,12 @@ class MockSentryTracer extends _i1.Mock implements _i3.SentryTracer { returnValueForMissingStub: null, ); + @override + Map get measurements => (super.noSuchMethod( + Invocation.getter(#measurements), + returnValue: {}, + ) as Map); + @override _i2.SentrySpanContext get context => (super.noSuchMethod( Invocation.getter(#context), @@ -349,12 +355,6 @@ class MockSentryTracer extends _i1.Mock implements _i3.SentryTracer { returnValue: {}, ) as Map); - @override - Map get measurements => (super.noSuchMethod( - Invocation.getter(#measurements), - returnValue: {}, - ) as Map); - @override _i7.Future finish({ _i2.SpanStatus? status, @@ -519,6 +519,24 @@ class MockSentryTracer extends _i1.Mock implements _i3.SentryTracer { returnValueForMissingStub: null, ); + @override + void setMeasurementFromChild( + String? name, + num? value, { + _i2.SentryMeasurementUnit? unit, + }) => + super.noSuchMethod( + Invocation.method( + #setMeasurementFromChild, + [ + name, + value, + ], + {#unit: unit}, + ), + returnValueForMissingStub: null, + ); + @override void scheduleFinish() => super.noSuchMethod( Invocation.method( @@ -998,6 +1016,189 @@ class MockSentrySpan extends _i1.Mock implements _i2.SentrySpan { ); } +/// A class which mocks [SentryClient]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockSentryClient extends _i1.Mock implements _i2.SentryClient { + MockSentryClient() { + _i1.throwOnMissingStub(this); + } + + @override + _i7.Future<_i2.SentryId> captureEvent( + _i2.SentryEvent? event, { + _i2.Scope? scope, + dynamic stackTrace, + _i2.Hint? hint, + }) => + (super.noSuchMethod( + Invocation.method( + #captureEvent, + [event], + { + #scope: scope, + #stackTrace: stackTrace, + #hint: hint, + }, + ), + returnValue: _i7.Future<_i2.SentryId>.value(_FakeSentryId_5( + this, + Invocation.method( + #captureEvent, + [event], + { + #scope: scope, + #stackTrace: stackTrace, + #hint: hint, + }, + ), + )), + ) as _i7.Future<_i2.SentryId>); + + @override + _i7.Future<_i2.SentryId> captureException( + dynamic throwable, { + dynamic stackTrace, + _i2.Scope? scope, + _i2.Hint? hint, + }) => + (super.noSuchMethod( + Invocation.method( + #captureException, + [throwable], + { + #stackTrace: stackTrace, + #scope: scope, + #hint: hint, + }, + ), + returnValue: _i7.Future<_i2.SentryId>.value(_FakeSentryId_5( + this, + Invocation.method( + #captureException, + [throwable], + { + #stackTrace: stackTrace, + #scope: scope, + #hint: hint, + }, + ), + )), + ) as _i7.Future<_i2.SentryId>); + + @override + _i7.Future<_i2.SentryId> captureMessage( + String? formatted, { + _i2.SentryLevel? level, + String? template, + List? params, + _i2.Scope? scope, + _i2.Hint? hint, + }) => + (super.noSuchMethod( + Invocation.method( + #captureMessage, + [formatted], + { + #level: level, + #template: template, + #params: params, + #scope: scope, + #hint: hint, + }, + ), + returnValue: _i7.Future<_i2.SentryId>.value(_FakeSentryId_5( + this, + Invocation.method( + #captureMessage, + [formatted], + { + #level: level, + #template: template, + #params: params, + #scope: scope, + #hint: hint, + }, + ), + )), + ) as _i7.Future<_i2.SentryId>); + + @override + _i7.Future<_i2.SentryId> captureTransaction( + _i2.SentryTransaction? transaction, { + _i2.Scope? scope, + _i2.SentryTraceContextHeader? traceContext, + }) => + (super.noSuchMethod( + Invocation.method( + #captureTransaction, + [transaction], + { + #scope: scope, + #traceContext: traceContext, + }, + ), + returnValue: _i7.Future<_i2.SentryId>.value(_FakeSentryId_5( + this, + Invocation.method( + #captureTransaction, + [transaction], + { + #scope: scope, + #traceContext: traceContext, + }, + ), + )), + ) as _i7.Future<_i2.SentryId>); + + @override + _i7.Future<_i2.SentryId?> captureEnvelope(_i2.SentryEnvelope? envelope) => + (super.noSuchMethod( + Invocation.method( + #captureEnvelope, + [envelope], + ), + returnValue: _i7.Future<_i2.SentryId?>.value(), + ) as _i7.Future<_i2.SentryId?>); + + @override + _i7.Future captureUserFeedback(_i2.SentryUserFeedback? userFeedback) => + (super.noSuchMethod( + Invocation.method( + #captureUserFeedback, + [userFeedback], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future<_i2.SentryId> captureMetrics( + Map>? metricsBuckets) => + (super.noSuchMethod( + Invocation.method( + #captureMetrics, + [metricsBuckets], + ), + returnValue: _i7.Future<_i2.SentryId>.value(_FakeSentryId_5( + this, + Invocation.method( + #captureMetrics, + [metricsBuckets], + ), + )), + ) as _i7.Future<_i2.SentryId>); + + @override + void close() => super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValueForMissingStub: null, + ); +} + /// A class which mocks [MethodChannel]. /// /// See the documentation for Mockito's code generation for more information. @@ -1097,7 +1298,7 @@ class MockMethodChannel extends _i1.Mock implements _i4.MethodChannel { /// /// See the documentation for Mockito's code generation for more information. class MockSentryNativeBinding extends _i1.Mock - implements _i10.SentryNativeBinding { + implements _i11.SentryNativeBinding { MockSentryNativeBinding() { _i1.throwOnMissingStub(this); } @@ -1123,17 +1324,17 @@ class MockSentryNativeBinding extends _i1.Mock ) as _i7.Future); @override - _i7.Future<_i11.NativeAppStart?> fetchNativeAppStart() => (super.noSuchMethod( + _i7.Future<_i12.NativeAppStart?> fetchNativeAppStart() => (super.noSuchMethod( Invocation.method( #fetchNativeAppStart, [], ), - returnValue: _i7.Future<_i11.NativeAppStart?>.value(), - ) as _i7.Future<_i11.NativeAppStart?>); + returnValue: _i7.Future<_i12.NativeAppStart?>.value(), + ) as _i7.Future<_i12.NativeAppStart?>); @override _i7.Future captureEnvelope( - _i12.Uint8List? envelopeData, + _i13.Uint8List? envelopeData, bool? containsUnhandledException, ) => (super.noSuchMethod( @@ -1159,14 +1360,14 @@ class MockSentryNativeBinding extends _i1.Mock ) as _i7.Future); @override - _i7.Future<_i13.NativeFrames?> endNativeFrames(_i2.SentryId? id) => + _i7.Future<_i14.NativeFrames?> endNativeFrames(_i2.SentryId? id) => (super.noSuchMethod( Invocation.method( #endNativeFrames, [id], ), - returnValue: _i7.Future<_i13.NativeFrames?>.value(), - ) as _i7.Future<_i13.NativeFrames?>); + returnValue: _i7.Future<_i14.NativeFrames?>.value(), + ) as _i7.Future<_i14.NativeFrames?>); @override _i7.Future setUser(_i2.SentryUser? user) => (super.noSuchMethod( @@ -1363,6 +1564,16 @@ class MockSentryNativeBinding extends _i1.Mock returnValueForMissingStub: _i7.Future.value(), ) as _i7.Future); + @override + _i7.Future nativeCrash() => (super.noSuchMethod( + Invocation.method( + #nativeCrash, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override _i7.Future<_i2.SentryId> captureReplay(bool? isCrash) => (super.noSuchMethod( Invocation.method( @@ -1715,7 +1926,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { @override _i7.Future<_i2.SentryId> captureMetrics( - Map>? metricsBuckets) => + Map>? metricsBuckets) => (super.noSuchMethod( Invocation.method( #captureMetrics, diff --git a/flutter/test/navigation/sentry_display_widget_test.dart b/flutter/test/navigation/sentry_display_widget_test.dart index a0495bfe8..abbd6e70d 100644 --- a/flutter/test/navigation/sentry_display_widget_test.dart +++ b/flutter/test/navigation/sentry_display_widget_test.dart @@ -102,8 +102,7 @@ void main() { } class Fixture { - final Hub hub = - Hub(SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0); + final Hub hub = Hub(defaultTestOptions()..tracesSampleRate = 1.0); late final SentryNavigatorObserver navigatorObserver; final fakeFrameCallbackHandler = FakeFrameCallbackHandler(); diff --git a/flutter/test/navigation/time_to_display_tracker_test.dart b/flutter/test/navigation/time_to_display_tracker_test.dart index 975adb37f..6e074bac6 100644 --- a/flutter/test/navigation/time_to_display_tracker_test.dart +++ b/flutter/test/navigation/time_to_display_tracker_test.dart @@ -255,7 +255,7 @@ void main() { class Fixture { final startTimestamp = getUtcDateTime(); - final options = SentryFlutterOptions() + final options = defaultTestOptions() ..dsn = fakeDsn ..tracesSampleRate = 1.0; late final endTimeProvider = ttidEndTimestampProvider(); diff --git a/flutter/test/navigation/time_to_full_display_tracker_test.dart b/flutter/test/navigation/time_to_full_display_tracker_test.dart index 50609f269..95d5a3ee2 100644 --- a/flutter/test/navigation/time_to_full_display_tracker_test.dart +++ b/flutter/test/navigation/time_to_full_display_tracker_test.dart @@ -65,7 +65,7 @@ void main() { class Fixture { final startTimestamp = getUtcDateTime(); - final hub = Hub(SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0); + final hub = Hub(defaultTestOptions()..tracesSampleRate = 1.0); final autoFinishAfter = const Duration(seconds: 2); late final endTimestampProvider = fakeTTIDEndTimestampProvider(); diff --git a/flutter/test/navigation/time_to_initial_display_tracker_test.dart b/flutter/test/navigation/time_to_initial_display_tracker_test.dart index 6e5502957..1f85360f5 100644 --- a/flutter/test/navigation/time_to_initial_display_tracker_test.dart +++ b/flutter/test/navigation/time_to_initial_display_tracker_test.dart @@ -179,7 +179,7 @@ void main() { class Fixture { final startTimestamp = getUtcDateTime(); - final hub = Hub(SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0); + final hub = Hub(defaultTestOptions()..tracesSampleRate = 1.0); late final fakeFrameCallbackHandler = FakeFrameCallbackHandler(); ISentrySpan getTransaction({String? name = "Regular route"}) { diff --git a/flutter/test/profiling_test.dart b/flutter/test/profiling_test.dart index 04ff70d06..5ab944e53 100644 --- a/flutter/test/profiling_test.dart +++ b/flutter/test/profiling_test.dart @@ -19,7 +19,7 @@ void main() { group('$SentryNativeProfilerFactory', () { Hub hubWithSampleRate(double profilesSampleRate) { - final o = SentryFlutterOptions(dsn: fakeDsn); + final o = defaultTestOptions(); o.platformChecker = getPlatformChecker(platform: MockPlatform.iOs()); o.profilesSampleRate = profilesSampleRate; diff --git a/flutter/test/replay/recorder_test.dart b/flutter/test/replay/recorder_test.dart index 16db1513b..2df4334c5 100644 --- a/flutter/test/replay/recorder_test.dart +++ b/flutter/test/replay/recorder_test.dart @@ -6,7 +6,6 @@ library dart_test; import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/replay/recorder.dart'; import 'package:sentry_flutter/src/replay/recorder_config.dart'; @@ -28,7 +27,7 @@ class _Fixture { _Fixture._() { sut = ScreenshotRecorder( ScreenshotRecorderConfig(), - SentryFlutterOptions()..bindingUtils = TestBindingWrapper(), + defaultTestOptions()..bindingUtils = TestBindingWrapper(), ); } diff --git a/flutter/test/replay/replay_native_test.dart b/flutter/test/replay/replay_native_test.dart index e9b047d8b..c758cd300 100644 --- a/flutter/test/replay/replay_native_test.dart +++ b/flutter/test/replay/replay_native_test.dart @@ -57,17 +57,14 @@ void main() { replayDir = fs.directory(replayConfig['directory']) ..createSync(recursive: true); - options = defaultTestOptions() - ..platformChecker = MockPlatformChecker(mockPlatform: mockPlatform) - ..fileSystem = fs; - native = NativeChannelFixture(); - when(native.handler('initNativeSdk', any)) - .thenAnswer((_) => Future.value()); - when(native.handler('closeNativeSdk', any)) - .thenAnswer((_) => Future.value()); - sut = createBinding(options, channel: native.channel); + options = + defaultTestOptions(MockPlatformChecker(mockPlatform: mockPlatform)) + ..fileSystem = fs + ..methodChannel = native.channel; + + sut = createBinding(options); }); tearDown(() async { diff --git a/flutter/test/replay/scheduled_recorder_test.dart b/flutter/test/replay/scheduled_recorder_test.dart index f859b27d5..7ace54c18 100644 --- a/flutter/test/replay/scheduled_recorder_test.dart +++ b/flutter/test/replay/scheduled_recorder_test.dart @@ -6,7 +6,6 @@ library dart_test; import 'dart:ui'; import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/replay/scheduled_recorder.dart'; import 'package:sentry_flutter/src/replay/recorder_config.dart'; @@ -45,7 +44,7 @@ class _Fixture { (Image image) async { capturedImages.add("${image.width}x${image.height}"); }, - SentryFlutterOptions()..bindingUtils = TestBindingWrapper(), + defaultTestOptions()..bindingUtils = TestBindingWrapper(), ); } diff --git a/flutter/test/screenshot/sentry_screenshot_widget_test.dart b/flutter/test/screenshot/sentry_screenshot_widget_test.dart index 0b6df7ffa..bedbfe8f1 100644 --- a/flutter/test/screenshot/sentry_screenshot_widget_test.dart +++ b/flutter/test/screenshot/sentry_screenshot_widget_test.dart @@ -53,7 +53,7 @@ void main() { } class Fixture { - final _options = SentryFlutterOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); late Hub hub; SentryScreenshotWidget getSut({ diff --git a/flutter/test/sentry_asset_bundle_test.dart b/flutter/test/sentry_asset_bundle_test.dart index c5236f674..cd17f3e27 100644 --- a/flutter/test/sentry_asset_bundle_test.dart +++ b/flutter/test/sentry_asset_bundle_test.dart @@ -516,7 +516,7 @@ void main() { } class Fixture { - final _options = SentryOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); late Hub _hub; final transport = MockTransport(); final assetBundle = TestAssetBundle(); diff --git a/flutter/test/sentry_flutter_options_test.dart b/flutter/test/sentry_flutter_options_test.dart index ed4a3ea7f..7c4d2e79b 100644 --- a/flutter/test/sentry_flutter_options_test.dart +++ b/flutter/test/sentry_flutter_options_test.dart @@ -1,6 +1,4 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:sentry_flutter/src/sentry_flutter_options.dart'; import 'mocks.dart'; @@ -8,8 +6,8 @@ void main() { group('SentryFlutterOptions', () { testWidgets('auto breadcrumb tracking: has native integration', (WidgetTester tester) async { - final options = SentryFlutterOptions( - checker: MockPlatformChecker(hasNativeIntegration: true)); + final options = + defaultTestOptions(MockPlatformChecker(hasNativeIntegration: true)); expect(options.enableAppLifecycleBreadcrumbs, isFalse); expect(options.enableWindowMetricBreadcrumbs, isFalse); @@ -21,8 +19,8 @@ void main() { testWidgets('auto breadcrumb tracking: without native integration', (WidgetTester tester) async { - final options = SentryFlutterOptions( - checker: MockPlatformChecker(hasNativeIntegration: false)); + final options = + defaultTestOptions(MockPlatformChecker(hasNativeIntegration: false)); expect(options.enableAppLifecycleBreadcrumbs, isTrue); expect(options.enableWindowMetricBreadcrumbs, isTrue); @@ -33,7 +31,7 @@ void main() { }); testWidgets('useNativeBreadcrumbTracking', (WidgetTester tester) async { - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); options.useNativeBreadcrumbTracking(); expect(options.enableAppLifecycleBreadcrumbs, isFalse); @@ -45,7 +43,7 @@ void main() { }); testWidgets('useFlutterBreadcrumbTracking', (WidgetTester tester) async { - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); options.useFlutterBreadcrumbTracking(); expect(options.enableAppLifecycleBreadcrumbs, isTrue); diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 534dd6ac1..7cd379428 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -55,6 +55,11 @@ final nativeIntegrations = [ void main() { TestWidgetsFlutterBinding.ensureInitialized(); + late NativeChannelFixture native; + + setUp(() async { + native = NativeChannelFixture(); + }); group('Test platform integrations', () { setUp(() async { @@ -67,19 +72,19 @@ void main() { List integrations = []; Transport transport = MockTransport(); - SentryFlutterOptions? sentryFlutterOptions; + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.android())) + ..methodChannel = native.channel; await SentryFlutter.init( (options) async { options.dsn = fakeDsn; - options.automatedTestMode = true; options.profilesSampleRate = 1.0; integrations = options.integrations; transport = options.transport; - sentryFlutterOptions = options; }, appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.android()), + options: sentryFlutterOptions, ); testTransport( @@ -88,7 +93,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions!, expectedHasNativeScopeObserver: true); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: true); testConfiguration( integrations: integrations, @@ -121,19 +126,20 @@ void main() { test('iOS', () async { List integrations = []; Transport transport = MockTransport(); - SentryFlutterOptions? sentryFlutterOptions; + + final sentryFlutterOptions = + defaultTestOptions(getPlatformChecker(platform: MockPlatform.iOs())) + ..methodChannel = native.channel; await SentryFlutter.init( (options) async { options.dsn = fakeDsn; - options.automatedTestMode = true; options.profilesSampleRate = 1.0; integrations = options.integrations; transport = options.transport; - sentryFlutterOptions = options; }, appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.iOs()), + options: sentryFlutterOptions, ); testTransport( @@ -142,7 +148,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions!, expectedHasNativeScopeObserver: true); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: true); testConfiguration( integrations: integrations, @@ -173,19 +179,19 @@ void main() { test('macOS', () async { List integrations = []; Transport transport = MockTransport(); - SentryFlutterOptions? sentryFlutterOptions; + final sentryFlutterOptions = + defaultTestOptions(getPlatformChecker(platform: MockPlatform.macOs())) + ..methodChannel = native.channel; await SentryFlutter.init( (options) async { options.dsn = fakeDsn; - options.automatedTestMode = true; options.profilesSampleRate = 1.0; integrations = options.integrations; transport = options.transport; - sentryFlutterOptions = options; }, appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.macOs()), + options: sentryFlutterOptions, ); testTransport( @@ -194,7 +200,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions!, expectedHasNativeScopeObserver: true); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: true); testConfiguration(integrations: integrations, shouldHaveIntegrations: [ ...iOsAndMacOsIntegrations, @@ -221,19 +227,19 @@ void main() { test('Windows', () async { List integrations = []; Transport transport = MockTransport(); - SentryFlutterOptions? sentryFlutterOptions; + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.windows())) + ..methodChannel = native.channel; await SentryFlutter.init( (options) async { options.dsn = fakeDsn; - options.automatedTestMode = true; options.profilesSampleRate = 1.0; integrations = options.integrations; transport = options.transport; - sentryFlutterOptions = options; }, appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.windows()), + options: sentryFlutterOptions, ); testTransport( @@ -242,8 +248,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions!, - expectedHasNativeScopeObserver: false); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: false); testConfiguration( integrations: integrations, @@ -273,19 +278,19 @@ void main() { test('Linux', () async { List integrations = []; Transport transport = MockTransport(); - SentryFlutterOptions? sentryFlutterOptions; + final sentryFlutterOptions = + defaultTestOptions(getPlatformChecker(platform: MockPlatform.linux())) + ..methodChannel = native.channel; await SentryFlutter.init( (options) async { options.dsn = fakeDsn; - options.automatedTestMode = true; options.profilesSampleRate = 1.0; integrations = options.integrations; transport = options.transport; - sentryFlutterOptions = options; }, appRunner: appRunner, - platformChecker: getPlatformChecker(platform: MockPlatform.linux()), + options: sentryFlutterOptions, ); testTransport( @@ -294,8 +299,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions!, - expectedHasNativeScopeObserver: false); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: false); testConfiguration( integrations: integrations, @@ -325,22 +329,18 @@ void main() { test('Web', () async { List integrations = []; Transport transport = MockTransport(); - SentryFlutterOptions? sentryFlutterOptions; + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(isWeb: true, platform: MockPlatform.linux())) + ..methodChannel = native.channel; await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; options.profilesSampleRate = 1.0; integrations = options.integrations; transport = options.transport; - sentryFlutterOptions = options; }, appRunner: appRunner, - platformChecker: getPlatformChecker( - isWeb: true, - platform: MockPlatform.linux(), - ), + options: sentryFlutterOptions, ); testTransport( @@ -349,8 +349,7 @@ void main() { ); testScopeObserver( - options: sentryFlutterOptions!, - expectedHasNativeScopeObserver: false); + options: sentryFlutterOptions, expectedHasNativeScopeObserver: false); testConfiguration( integrations: integrations, @@ -380,21 +379,19 @@ void main() { test('Web && (iOS || macOS)', () async { List integrations = []; Transport transport = MockTransport(); + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(isWeb: true, platform: MockPlatform.iOs())) + ..methodChannel = native.channel; // Tests that iOS || macOS integrations aren't added on a browser which // runs on iOS or macOS await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; integrations = options.integrations; transport = options.transport; }, appRunner: appRunner, - platformChecker: getPlatformChecker( - isWeb: true, - platform: MockPlatform.iOs(), - ), + options: sentryFlutterOptions, ); testTransport( @@ -427,21 +424,19 @@ void main() { test('Web && (macOS)', () async { List integrations = []; Transport transport = MockTransport(); + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(isWeb: true, platform: MockPlatform.macOs())) + ..methodChannel = native.channel; // Tests that iOS || macOS integrations aren't added on a browser which // runs on iOS or macOS await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; integrations = options.integrations; transport = options.transport; }, appRunner: appRunner, - platformChecker: getPlatformChecker( - isWeb: true, - platform: MockPlatform.macOs(), - ), + options: sentryFlutterOptions, ); testTransport( @@ -476,20 +471,18 @@ void main() { test('Web && Android', () async { List integrations = []; Transport transport = MockTransport(); + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(isWeb: true, platform: MockPlatform.android())) + ..methodChannel = native.channel; // Tests that Android integrations aren't added on an Android browser await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; integrations = options.integrations; transport = options.transport; }, appRunner: appRunner, - platformChecker: getPlatformChecker( - isWeb: true, - platform: MockPlatform.android(), - ), + options: sentryFlutterOptions, ); testTransport( @@ -528,16 +521,19 @@ void main() { test('installed on io platforms', () async { List integrations = []; + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.iOs(), isWeb: false)) + ..methodChannel = native.channel + ..rendererWrapper = MockRendererWrapper(FlutterRenderer.skia) + ..release = '' + ..dist = ''; + await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; integrations = options.integrations; }, appRunner: appRunner, - platformChecker: - getPlatformChecker(platform: MockPlatform.iOs(), isWeb: false), - rendererWrapper: MockRendererWrapper(FlutterRenderer.skia), + options: sentryFlutterOptions, ); expect( @@ -552,16 +548,18 @@ void main() { test('installed with canvasKit renderer', () async { List integrations = []; + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.iOs(), isWeb: true)) + ..rendererWrapper = MockRendererWrapper(FlutterRenderer.canvasKit) + ..release = '' + ..dist = ''; + await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; integrations = options.integrations; }, appRunner: appRunner, - platformChecker: - getPlatformChecker(platform: MockPlatform.iOs(), isWeb: true), - rendererWrapper: MockRendererWrapper(FlutterRenderer.canvasKit), + options: sentryFlutterOptions, ); expect( @@ -576,16 +574,18 @@ void main() { test('not installed with html renderer', () async { List integrations = []; + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.iOs(), isWeb: true)) + ..rendererWrapper = MockRendererWrapper(FlutterRenderer.html) + ..release = '' + ..dist = ''; + await SentryFlutter.init( (options) async { - options.dsn = fakeDsn; - options.automatedTestMode = true; integrations = options.integrations; }, appRunner: appRunner, - platformChecker: - getPlatformChecker(platform: MockPlatform.iOs(), isWeb: true), - rendererWrapper: MockRendererWrapper(FlutterRenderer.html), + options: sentryFlutterOptions, ); expect( @@ -605,11 +605,11 @@ void main() { }); test('test that initial values are set correctly', () async { + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.android(), isWeb: true)); + await SentryFlutter.init( (options) { - options.dsn = fakeDsn; - options.automatedTestMode = true; - expect(false, options.debug); expect('debug', options.environment); expect(sdkName, options.sdk.name); @@ -618,10 +618,7 @@ void main() { expect(sdkVersion, options.sdk.packages.last.version); }, appRunner: appRunner, - platformChecker: getPlatformChecker( - platform: MockPlatform.android(), - isWeb: true, - ), + options: sentryFlutterOptions, ); await Sentry.close(); @@ -630,19 +627,15 @@ void main() { test( 'enablePureDartSymbolication is set to false during SentryFlutter init', () async { + final sentryFlutterOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.android(), isWeb: true)); SentryFlutter.native = MockSentryNativeBinding(); await SentryFlutter.init( (options) { - options.dsn = fakeDsn; - options.automatedTestMode = true; - expect(options.enableDartSymbolication, false); }, appRunner: appRunner, - platformChecker: getPlatformChecker( - platform: MockPlatform.android(), - isWeb: true, - ), + options: sentryFlutterOptions, ); await Sentry.close(); @@ -696,24 +689,18 @@ void main() { test( 'should add DartExceptionTypeIdentifier and FlutterExceptionTypeIdentifier by default', () async { - SentryOptions? actualOptions; + final actualOptions = defaultTestOptions( + getPlatformChecker(platform: MockPlatform.android(), isWeb: true)); await SentryFlutter.init( - (options) { - options.dsn = fakeDsn; - options.automatedTestMode = true; - actualOptions = options; - }, + (options) {}, appRunner: appRunner, - platformChecker: getPlatformChecker( - platform: MockPlatform.android(), - isWeb: true, - ), + options: actualOptions, ); - expect(actualOptions!.exceptionTypeIdentifiers.length, 2); + expect(actualOptions.exceptionTypeIdentifiers.length, 2); // Flutter identifier should be first as it's more specific expect( - actualOptions!.exceptionTypeIdentifiers.first, + actualOptions.exceptionTypeIdentifiers.first, isA().having( (c) => c.identifier, 'wrapped identifier', @@ -721,7 +708,7 @@ void main() { ), ); expect( - actualOptions!.exceptionTypeIdentifiers[1], + actualOptions.exceptionTypeIdentifiers[1], isA().having( (c) => c.identifier, 'wrapped identifier', diff --git a/flutter/test/sentry_native_channel_test.dart b/flutter/test/sentry_native_channel_test.dart index fb339b468..0428349d4 100644 --- a/flutter/test/sentry_native_channel_test.dart +++ b/flutter/test/sentry_native_channel_test.dart @@ -27,12 +27,11 @@ void main() { late MockMethodChannel channel; setUp(() { - final options = SentryFlutterOptions( - dsn: fakeDsn, checker: getPlatformChecker(platform: mockPlatform)) - // ignore: invalid_use_of_internal_member - ..automatedTestMode = true; channel = MockMethodChannel(); - sut = createBinding(options, channel: channel); + final options = + defaultTestOptions(getPlatformChecker(platform: mockPlatform)) + ..methodChannel = channel; + sut = createBinding(options); }); // TODO move other methods here, e.g. init_native_sdk_test.dart diff --git a/flutter/test/sentry_navigator_observer_test.dart b/flutter/test/sentry_navigator_observer_test.dart index 9a64d6541..524f3e2ec 100644 --- a/flutter/test/sentry_navigator_observer_test.dart +++ b/flutter/test/sentry_navigator_observer_test.dart @@ -83,6 +83,8 @@ void main() { final options = defaultTestOptions(); options.tracesSampleRate = 1; + // Drop events, otherwise sentry tries to send them to the test DSN. + options.addEventProcessor(FunctionEventProcessor((_, __) => null)); final hub = Hub(options); when(mockBinding.endNativeFrames(any)) @@ -598,6 +600,7 @@ void main() { const op = 'navigation'; final hub = _MockHub(); final span = getMockSentryTracer(name: oldRouteName); + when(span.children).thenReturn([]); when(span.context).thenReturn(SentrySpanContext(operation: op)); when(span.status).thenReturn(null); when(span.finished).thenReturn(false); @@ -982,6 +985,7 @@ void main() { final secondRoute = route(RouteSettings(name: 'testRoute')); final hub = _MockHub(); + _whenAnyStart(hub, NoOpSentrySpan()); final sut = fixture.getSut(hub: hub, ignoreRoutes: ["testRoute"]); @@ -1002,6 +1006,7 @@ void main() { final secondRoute = route(RouteSettings(name: 'testRoute')); final hub = _MockHub(); + _whenAnyStart(hub, NoOpSentrySpan()); final sut = fixture.getSut(hub: hub, ignoreRoutes: ["testRoute"]); @@ -1086,7 +1091,7 @@ class _MockHub extends MockHub { } } -ISentrySpan getMockSentryTracer({String? name, bool? finished}) { +MockSentryTracer getMockSentryTracer({String? name, bool? finished}) { final tracer = MockSentryTracer(); when(tracer.name).thenReturn(name ?? 'name'); when(tracer.finished).thenReturn(finished ?? true); diff --git a/flutter/test/span_frame_metrics_collector_test.dart b/flutter/test/span_frame_metrics_collector_test.dart index 70c334807..41cb56b6d 100644 --- a/flutter/test/span_frame_metrics_collector_test.dart +++ b/flutter/test/span_frame_metrics_collector_test.dart @@ -262,7 +262,7 @@ void main() { } class Fixture { - final options = SentryFlutterOptions(dsn: fakeDsn); + final options = defaultTestOptions(); late final hub = Hub(options); final fakeFrameCallbackHandler = FakeFrameCallbackHandler(); final mockSentryNative = MockSentryNativeBinding(); diff --git a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart index b0288729b..cdb27f927 100644 --- a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart +++ b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart @@ -524,7 +524,7 @@ Future tapMe( } class Fixture { - final _options = SentryFlutterOptions(dsn: fakeDsn); + final _options = defaultTestOptions(); final _transport = MockTransport(); late Hub hub; diff --git a/flutter/test/view_hierarchy/sentry_tree_walker_test.dart b/flutter/test/view_hierarchy/sentry_tree_walker_test.dart index 9fd41fc52..26a7c41a0 100644 --- a/flutter/test/view_hierarchy/sentry_tree_walker_test.dart +++ b/flutter/test/view_hierarchy/sentry_tree_walker_test.dart @@ -3,6 +3,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/view_hierarchy/sentry_tree_walker.dart'; +import '../mocks.dart'; + void main() { group('TreeWalker', () { late WidgetsBinding instance; @@ -17,7 +19,7 @@ void main() { await tester.pumpWidget(MyApp()); final sentryViewHierarchy = - walkWidgetTree(instance, SentryFlutterOptions()); + walkWidgetTree(instance, defaultTestOptions()); expect(sentryViewHierarchy!.renderingSystem, 'flutter'); }); @@ -148,7 +150,7 @@ void main() { SentryViewHierarchyElement _getFirstSentryViewHierarchy( WidgetsBinding instance) { - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); final sentryViewHierarchy = walkWidgetTree(instance, options); return sentryViewHierarchy!.windows.first; diff --git a/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart b/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart index 98487ab3a..9ba8a694f 100644 --- a/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart +++ b/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:sentry/sentry.dart'; import 'package:sentry_flutter/src/binding_wrapper.dart'; -import 'package:sentry_flutter/src/sentry_flutter_options.dart'; import 'package:sentry_flutter/src/view_hierarchy/view_hierarchy_event_processor.dart'; +import '../mocks.dart'; + void main() { group(SentryViewHierarchyEventProcessor, () { late Fixture fixture; @@ -124,7 +125,7 @@ class TestBindingWrapper implements BindingWrapper { class Fixture { SentryViewHierarchyEventProcessor getSut(WidgetsBinding instance, {bool reportViewHierarchyIdentifiers = true}) { - final options = SentryFlutterOptions() + final options = defaultTestOptions() ..bindingUtils = TestBindingWrapper(instance) ..reportViewHierarchyIdentifiers = reportViewHierarchyIdentifiers; return SentryViewHierarchyEventProcessor(options); diff --git a/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart b/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart index bef4050c6..c57fff8b5 100644 --- a/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart +++ b/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart @@ -2,10 +2,10 @@ library flutter_test; import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/src/view_hierarchy/view_hierarchy_event_processor.dart'; import 'package:sentry_flutter/src/view_hierarchy/view_hierarchy_integration.dart'; +import '../mocks.dart'; import '../mocks.mocks.dart'; void main() { @@ -74,7 +74,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryFlutterOptions(); + final options = defaultTestOptions(); SentryViewHierarchyIntegration getSut({bool attachViewHierarchy = true}) { options.attachViewHierarchy = attachViewHierarchy; diff --git a/flutter/test/widgets_binding_observer_test.dart b/flutter/test/widgets_binding_observer_test.dart index 86973ba91..ce44577db 100644 --- a/flutter/test/widgets_binding_observer_test.dart +++ b/flutter/test/widgets_binding_observer_test.dart @@ -17,11 +17,11 @@ void main() { setUp(() { TestWidgetsFlutterBinding.ensureInitialized(); - flutterTrackingEnabledOptions = SentryFlutterOptions() + flutterTrackingEnabledOptions = defaultTestOptions() ..bindingUtils = TestBindingWrapper(); flutterTrackingEnabledOptions.useFlutterBreadcrumbTracking(); - flutterTrackingDisabledOptions = SentryFlutterOptions() + flutterTrackingDisabledOptions = defaultTestOptions() ..bindingUtils = TestBindingWrapper(); flutterTrackingDisabledOptions.useNativeBreadcrumbTracking(); }); diff --git a/hive/test/sentry_box_base_test.dart b/hive/test/sentry_box_base_test.dart index 3821b8b34..e46564a3f 100644 --- a/hive/test/sentry_box_base_test.dart +++ b/hive/test/sentry_box_base_test.dart @@ -12,6 +12,7 @@ import 'package:sentry/src/sentry_tracer.dart'; import 'mocks/mocks.mocks.dart'; import 'person.dart'; +import 'utils.dart'; void main() { void verifySpan(String description, SentrySpan? span) { @@ -525,7 +526,7 @@ void main() { class Fixture { late final Box box; late final mockBox = MockBox(); - final options = SentryOptions(); + final options = defaultTestOptions(); final hub = MockHub(); final exception = Exception('fixture-exception'); diff --git a/hive/test/sentry_box_collection_test.dart b/hive/test/sentry_box_collection_test.dart index f13b95e1c..3f730be3c 100644 --- a/hive/test/sentry_box_collection_test.dart +++ b/hive/test/sentry_box_collection_test.dart @@ -15,6 +15,8 @@ import 'person.dart'; import 'package:hive/src/box_collection/box_collection_stub.dart' as stub; +import 'utils.dart'; + void main() { void verifySpan(String description, SentrySpan? span) { expect(span?.context.operation, SentryHiveImpl.dbOp); @@ -355,7 +357,7 @@ void main() { } class Fixture { - final options = SentryOptions(); + final options = defaultTestOptions(); final hub = MockHub(); final exception = Exception('fixture-exception'); diff --git a/hive/test/sentry_hive_impl_test.dart b/hive/test/sentry_hive_impl_test.dart index 521415d1e..a478c9f24 100644 --- a/hive/test/sentry_hive_impl_test.dart +++ b/hive/test/sentry_hive_impl_test.dart @@ -14,6 +14,7 @@ import 'package:test/test.dart'; import 'mocks/mocks.mocks.dart'; import 'person.dart'; +import 'utils.dart'; void main() { void verifySpan( @@ -583,7 +584,7 @@ void main() { } class Fixture { - final options = SentryOptions(); + final options = defaultTestOptions(); late final mockHive = MockHiveInterface(); final hub = MockHub(); static final dbName = 'people-hive-impl'; diff --git a/hive/test/sentry_lazy_box_test.dart b/hive/test/sentry_lazy_box_test.dart index 291dc3fc2..72282ada4 100644 --- a/hive/test/sentry_lazy_box_test.dart +++ b/hive/test/sentry_lazy_box_test.dart @@ -12,6 +12,7 @@ import 'package:test/test.dart'; import 'mocks/mocks.mocks.dart'; import 'person.dart'; +import 'utils.dart'; void main() { void verifySpan(String description, SentrySpan? span) { @@ -247,7 +248,7 @@ void main() { class Fixture { late final LazyBox box; late final mockBox = MockLazyBox(); - final options = SentryOptions(); + final options = defaultTestOptions(); final hub = MockHub(); final exception = Exception('fixture-exception'); diff --git a/hive/test/utils.dart b/hive/test/utils.dart new file mode 100644 index 000000000..7fb87861f --- /dev/null +++ b/hive/test/utils.dart @@ -0,0 +1,8 @@ +import 'package:sentry/sentry.dart'; + +final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; + +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +} diff --git a/isar/test/sentry_isar_collection_test.dart b/isar/test/sentry_isar_collection_test.dart index de55ac598..5cf06586e 100644 --- a/isar/test/sentry_isar_collection_test.dart +++ b/isar/test/sentry_isar_collection_test.dart @@ -12,6 +12,7 @@ import 'package:sentry/src/sentry_tracer.dart'; import 'mocks/mocks.mocks.dart'; import 'person.dart'; +import 'utils.dart'; void main() { void verifySpan( @@ -876,7 +877,7 @@ void main() { } class Fixture { - final options = SentryOptions(); + final options = defaultTestOptions(); final hub = MockHub(); final isarCollection = MockIsarCollection(); diff --git a/isar/test/sentry_isar_test.dart b/isar/test/sentry_isar_test.dart index 222226fa5..00bafb216 100644 --- a/isar/test/sentry_isar_test.dart +++ b/isar/test/sentry_isar_test.dart @@ -13,6 +13,7 @@ import 'package:sentry_isar/src/version.dart'; import 'mocks/mocks.mocks.dart'; import 'person.dart'; +import 'utils.dart'; void main() { void verifySpan(String description, SentrySpan? span) { @@ -416,7 +417,7 @@ void main() { } class Fixture { - final options = SentryOptions(); + final options = defaultTestOptions(); final hub = MockHub(); final isar = MockIsar(); diff --git a/isar/test/utils.dart b/isar/test/utils.dart new file mode 100644 index 000000000..7fb87861f --- /dev/null +++ b/isar/test/utils.dart @@ -0,0 +1,8 @@ +import 'package:sentry/sentry.dart'; + +final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; + +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +} diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index 5ddb50cf3..c5e78657a 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -203,7 +203,7 @@ void main() { } class Fixture { - SentryOptions options = SentryOptions(dsn: fakeDsn); + SentryOptions options = defaultTestOptions(); MockHub hub = MockHub(); LoggingIntegration createSut({ diff --git a/logging/test/mock_hub.dart b/logging/test/mock_hub.dart index 3dcb1d4fc..ec3d8b2af 100644 --- a/logging/test/mock_hub.dart +++ b/logging/test/mock_hub.dart @@ -6,10 +6,15 @@ import 'no_such_method_provider.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +} + class MockHub with NoSuchMethodProvider implements Hub { final List breadcrumbs = []; final List events = []; - final _options = SentryOptions(dsn: 'fixture-dsn'); + final _options = defaultTestOptions(); @override @internal diff --git a/sqflite/test/sentry_batch_test.dart b/sqflite/test/sentry_batch_test.dart index 4a5062f2a..50dc469ab 100644 --- a/sqflite/test/sentry_batch_test.dart +++ b/sqflite/test/sentry_batch_test.dart @@ -668,7 +668,7 @@ SELECT * FROM Product'''; class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); final batch = MockBatch(); diff --git a/sqflite/test/sentry_database_test.dart b/sqflite/test/sentry_database_test.dart index 93b258b20..b97f97784 100644 --- a/sqflite/test/sentry_database_test.dart +++ b/sqflite/test/sentry_database_test.dart @@ -1234,7 +1234,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn); + final options = defaultTestOptions(); final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); final database = MockDatabase(); diff --git a/sqflite/test/sentry_sqflite_database_factory_dart_test.dart b/sqflite/test/sentry_sqflite_database_factory_dart_test.dart index 061660884..38bc23d40 100644 --- a/sqflite/test/sentry_sqflite_database_factory_dart_test.dart +++ b/sqflite/test/sentry_sqflite_database_factory_dart_test.dart @@ -95,7 +95,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); late final scope = Scope(options); diff --git a/sqflite/test/sentry_sqflite_test.dart b/sqflite/test/sentry_sqflite_test.dart index 41aa3277b..f54cfda98 100644 --- a/sqflite/test/sentry_sqflite_test.dart +++ b/sqflite/test/sentry_sqflite_test.dart @@ -121,7 +121,7 @@ void main() { class Fixture { final hub = MockHub(); - final options = SentryOptions(dsn: fakeDsn)..tracesSampleRate = 1.0; + final options = defaultTestOptions()..tracesSampleRate = 1.0; final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); late final scope = Scope(options); diff --git a/sqflite/test/utils.dart b/sqflite/test/utils.dart index 5dbeee585..7fb87861f 100644 --- a/sqflite/test/utils.dart +++ b/sqflite/test/utils.dart @@ -1 +1,8 @@ +import 'package:sentry/sentry.dart'; + final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; + +SentryOptions defaultTestOptions() { + // ignore: invalid_use_of_internal_member + return SentryOptions(dsn: fakeDsn)..automatedTestMode = true; +}