Skip to content

Commit 00bb02a

Browse files
authored
feat: sentry web api (#2489)
* update * update * update test * update * update * update * update * update doc * update * update * update * update test * update * update tests * use tryCatchSync * formatting * fix sentry_flutter_test * fix analyze * update test * fix tests * update test * update test * update scripts * ignore sentry_web in coverage * update test * temporary * update * test * update tests * update test with mocks * fix analyze * update * update names * fix test * update * update integration * update comment * update flutter enricher * update test * update * update flag name * update * update binding creation condition * update * update integration test * fix tests
1 parent 7017668 commit 00bb02a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+908
-268
lines changed

.github/workflows/flutter_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,6 @@ jobs:
222222
223223
# Run the tests
224224
flutter drive \
225-
--driver=integration_test/test_driver/web_driver.dart \
225+
--driver=integration_test/test_driver/driver.dart \
226226
--target=integration_test/web_sdk_test.dart \
227227
-d chrome

dart/lib/src/platform_checker.dart

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,13 @@ class PlatformChecker {
4040
}
4141

4242
/// Indicates whether a native integration is available.
43-
bool get hasNativeIntegration {
44-
if (isWeb) {
45-
return false;
46-
}
47-
// We need to check the platform after we checked for web, because
48-
// the OS checks return true when the browser runs on the checked platform.
49-
// Example: platform.isAndroid return true if the browser is used on an
50-
// Android device.
51-
return platform.isAndroid ||
52-
platform.isIOS ||
53-
platform.isMacOS ||
54-
platform.isWindows ||
55-
platform.isLinux;
56-
}
43+
bool get hasNativeIntegration =>
44+
isWeb ||
45+
platform.isAndroid ||
46+
platform.isIOS ||
47+
platform.isMacOS ||
48+
platform.isWindows ||
49+
platform.isLinux;
5750

5851
static bool _isWebWithWasmSupport() {
5952
if (const bool.hasEnvironment(_jsUtil)) {

flutter/example/integration_test/test_driver/web_driver.dart

Lines changed: 0 additions & 3 deletions
This file was deleted.

flutter/example/integration_test/utils.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ FutureOr<void> restoreFlutterOnErrorAfter(FutureOr<void> Function() fn) async {
2020
originalOnError?.call(details);
2121
};
2222
}
23+
24+
const fakeDsn = 'https://[email protected]/1234567';

flutter/example/integration_test/web_sdk_test.dart

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
@TestOn('browser')
44
library flutter_test;
55

6-
import 'dart:async';
7-
import 'dart:js';
6+
import 'dart:js_interop';
7+
import 'dart:js_interop_unsafe';
88

99
import 'package:flutter_test/flutter_test.dart';
1010
import 'package:integration_test/integration_test.dart';
@@ -13,52 +13,56 @@ import 'package:sentry_flutter_example/main.dart' as app;
1313

1414
import 'utils.dart';
1515

16-
// We can use dart:html, this is meant to be tested on Flutter Web and not WASM
17-
// This integration test can be changed later when we actually do support WASM
16+
@JS('globalThis')
17+
external JSObject get globalThis;
18+
19+
@JS('Sentry.getClient')
20+
external JSObject? _getClient();
1821

1922
void main() {
2023
group('Web SDK Integration', () {
2124
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
2225

23-
tearDown(() async {
24-
await Sentry.close();
25-
});
26-
27-
testWidgets('Sentry JS SDK is callable', (tester) async {
28-
final completer = Completer();
29-
const expectedMessage = 'test message';
30-
String actualMessage = '';
31-
32-
await restoreFlutterOnErrorAfter(() async {
33-
await SentryFlutter.init((options) {
34-
options.dsn = app.exampleDsn;
35-
options.automatedTestMode = false;
36-
}, appRunner: () async {
37-
await tester.pumpWidget(const app.MyApp());
26+
group('enabled', () {
27+
testWidgets('Sentry JS SDK initialized', (tester) async {
28+
await restoreFlutterOnErrorAfter(() async {
29+
await SentryFlutter.init((options) {
30+
options.enableSentryJs = true;
31+
options.dsn = fakeDsn;
32+
}, appRunner: () async {
33+
await tester.pumpWidget(const app.MyApp());
34+
});
3835
});
3936

40-
final beforeSendFn = JsFunction.withThis((thisArg, event, hint) {
41-
actualMessage = event['message'];
42-
completer.complete();
43-
return event;
44-
});
37+
expect(globalThis['Sentry'], isNotNull);
4538

46-
final Map<String, dynamic> options = {
47-
'dsn': app.exampleDsn,
48-
'beforeSend': beforeSendFn,
49-
'defaultIntegrations': [],
50-
};
39+
final client = _getClient()!;
40+
final options = client.callMethod('getOptions'.toJS)! as JSObject;
5141

52-
final sentry = context['Sentry'] as JsObject;
53-
sentry.callMethod('init', [JsObject.jsify(options)]);
54-
sentry.callMethod('captureMessage', [expectedMessage]);
55-
});
42+
final dsn = options.getProperty('dsn'.toJS).toString();
43+
final defaultIntegrations = options
44+
.getProperty('defaultIntegrations'.toJS)
45+
.dartify() as List<Object?>;
5646

57-
await completer.future.timeout(const Duration(seconds: 5), onTimeout: () {
58-
fail('beforeSend was not triggered');
47+
expect(dsn, fakeDsn);
48+
expect(defaultIntegrations, isEmpty);
5949
});
50+
});
6051

61-
expect(actualMessage, equals(expectedMessage));
52+
group('disabled', () {
53+
testWidgets('Sentry JS SDK is not initialized', (tester) async {
54+
await restoreFlutterOnErrorAfter(() async {
55+
await SentryFlutter.init((options) {
56+
options.enableSentryJs = false;
57+
options.dsn = fakeDsn;
58+
}, appRunner: () async {
59+
await tester.pumpWidget(const app.MyApp());
60+
});
61+
});
62+
63+
expect(globalThis['Sentry'], isNull);
64+
expect(() => _getClient(), throwsA(anything));
65+
});
6266
});
6367
});
6468
}

flutter/example/lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Future<void> setupSentry(
8383
options.spotlight = Spotlight(enabled: true);
8484
options.enableTimeToFullDisplayTracing = true;
8585
options.enableMetrics = true;
86+
options.enableSentryJs = true;
8687

8788
options.maxRequestBodySize = MaxRequestBodySize.always;
8889
options.maxResponseBodySize = MaxResponseBodySize.always;

flutter/lib/src/event_processor/flutter_enricher_event_processor.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ class FlutterEnricherEventProcessor implements EventProcessor {
3737
) async {
3838
// If there's a native integration available, it probably has better
3939
// information available than Flutter.
40-
final device =
41-
_hasNativeIntegration ? null : _getDevice(event.contexts.device);
40+
// TODO: while we have a native integration with JS SDK, it's currently opt in and we dont gather contexts yet
41+
// so for web it's still better to rely on the information of Flutter.
42+
final device = _hasNativeIntegration && !_checker.isWeb
43+
? null
44+
: _getDevice(event.contexts.device);
4245

4346
final contexts = event.contexts.copyWith(
4447
device: device,

flutter/lib/src/integrations/integrations.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export 'load_contexts_integration.dart';
44
export 'load_image_list_integration.dart';
55
export 'load_release_integration.dart';
66
export 'native_app_start_integration.dart';
7-
export 'native_sdk_integration.dart';
87
export 'on_error_integration.dart';
8+
export 'sdk_integration.dart';
99
export 'widgets_binding_integration.dart';
1010
export 'widgets_flutter_binding_integration.dart';

flutter/lib/src/integrations/native_sdk_integration.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import 'dart:async';
22

33
import 'package:sentry/sentry.dart';
4+
45
import '../native/sentry_native_binding.dart';
56
import '../sentry_flutter_options.dart';
67

8+
Integration<SentryFlutterOptions> createSdkIntegration(
9+
SentryNativeBinding native) {
10+
return NativeSdkIntegration(native);
11+
}
12+
713
/// Enables Sentry's native SDKs (Android and iOS) with options.
814
class NativeSdkIntegration implements Integration<SentryFlutterOptions> {
915
NativeSdkIntegration(this._native);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export 'native_sdk_integration.dart'
2+
if (dart.library.html) 'web_sdk_integration.dart'
3+
if (dart.library.js_interop) 'web_sdk_integration.dart';

0 commit comments

Comments
 (0)