Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter_wkwebview] Fixes bug where an NSError not an NSErrorData was returned #5973

Merged
merged 4 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -351,4 +351,41 @@ - (void)testEvaluateJavaScript {
XCTAssertEqualObjects(returnValue, @"result");
XCTAssertNil(returnError);
}

- (void)testEvaluateJavaScriptReturnsNSErrorData {
FWFWebView *mockWebView = OCMClassMock([FWFWebView class]);

OCMStub([mockWebView
evaluateJavaScript:@"runJavaScript"
completionHandler:([OCMArg invokeBlockWithArgs:[NSNull null],
[NSError errorWithDomain:@"errorDomain"
code:0
userInfo:@{
NSLocalizedDescriptionKey :
@"description"
}],
nil])]);

FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
[instanceManager addDartCreatedInstance:mockWebView withIdentifier:0];

FWFWebViewHostApiImpl *hostAPI =
[[FWFWebViewHostApiImpl alloc] initWithInstanceManager:instanceManager];

NSString __block *returnValue;
FlutterError __block *returnError;
[hostAPI evaluateJavaScriptForWebViewWithIdentifier:@0
javaScriptString:@"runJavaScript"
completion:^(id result, FlutterError *error) {
returnValue = result;
returnError = error;
}];

XCTAssertNil(returnValue);
FWFNSErrorData *errorData = returnError.details;
XCTAssertTrue([errorData isKindOfClass:[FWFNSErrorData class]]);
XCTAssertEqualObjects(errorData.code, @0);
XCTAssertEqualObjects(errorData.domain, @"errorDomain");
XCTAssertEqualObjects(errorData.localizedDescription, @"description");
}
@end
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ - (void)evaluateJavaScriptForWebViewWithIdentifier:(nonnull NSNumber *)identifie
if (!result || [result isKindOfClass:[NSString class]] ||
[result isKindOfClass:[NSNumber class]]) {
returnValue = result;
} else {
} else if (![result isKindOfClass:[NSNull class]]) {
NSString *className = NSStringFromClass([result class]);
NSLog(@"Return type of evaluateJavaScript is not directly supported: %@. Returned "
@"description of value.",
Expand All @@ -151,7 +151,7 @@ - (void)evaluateJavaScriptForWebViewWithIdentifier:(nonnull NSNumber *)identifie
} else {
flutterError = [FlutterError errorWithCode:@"FWFEvaluateJavaScriptError"
message:@"Failed evaluating JavaScript."
details:error];
details:FWFNSErrorDataFromNSError(error)];
}

completion(returnValue, flutterError);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -908,11 +908,25 @@ class WKWebViewHostApiImpl extends WKWebViewHostApi {
Future<Object?> evaluateJavaScriptForInstances(
WKWebView instance,
String javaScriptString,
) {
return evaluateJavaScript(
instanceManager.getIdentifier(instance)!,
javaScriptString,
);
) async {
try {
final Object? result = await evaluateJavaScript(
instanceManager.getIdentifier(instance)!,
javaScriptString,
);
return result;
} on PlatformException catch (exception) {
if (exception.details is! NSErrorData) {
rethrow;
}

throw PlatformException(
code: exception.code,
message: exception.message,
stacktrace: exception.stacktrace,
details: (exception.details as NSErrorData).toNSError(),
);
}
}

/// Calls [setNavigationDelegate] with the ids of the provided object instances.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,10 @@ class WebKitWebViewPlatformController extends WebViewPlatformController {
return '"<null>"';
}
return '(null)';
} else if (value is bool) {
return value ? '1' : '0';
} else if (value is double && value.truncate() == value) {
return value.truncate().toString();
} else if (value is List) {
final List<String> stringValues = <String>[];
for (final Object? listValue in value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
Expand Down Expand Up @@ -815,6 +816,30 @@ void main() {
.thenAnswer((_) => Future<String>.value('stopstop'));
expect(webView.evaluateJavaScript('gogo'), completion('stopstop'));
});

test('evaluateJavaScript returns NSError', () {
when(mockPlatformHostApi.evaluateJavaScript(webViewInstanceId, 'gogo'))
.thenThrow(
PlatformException(
code: '',
details: NSErrorData(
code: 0,
domain: 'domain',
localizedDescription: 'desc',
),
),
);
expect(
webView.evaluateJavaScript('gogo'),
throwsA(
isA<PlatformException>().having(
(PlatformException exception) => exception.details,
'details',
isA<NSError>(),
),
),
);
});
});

group('WKUIDelegate', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,42 @@ void main() {
);
});

testWidgets('evaluateJavascript with bool return value',
(WidgetTester tester) async {
await buildWidget(tester);

when(mockWebView.evaluateJavaScript('runJavaScript')).thenAnswer(
(_) => Future<Object?>.value(true),
);
// The legacy implementation of webview_flutter_wkwebview would convert
// objects to strings before returning them to Dart. This verifies bool
// is represented the way it is in Objective-C.
// `NSNumber.description` converts bool values to a 1 or 0.
expect(
testController.evaluateJavascript('runJavaScript'),
completion('1'),
);
});

testWidgets('evaluateJavascript with double return value',
(WidgetTester tester) async {
await buildWidget(tester);

when(mockWebView.evaluateJavaScript('runJavaScript')).thenAnswer(
(_) => Future<Object?>.value(1.0),
);
// The legacy implementation of webview_flutter_wkwebview would convert
// objects to strings before returning them to Dart. This verifies
// double is represented the way it is in Objective-C. If a double
// doesn't contain any decimal values, it gets truncated to an int.
// This should be happenning because NSNumber convertes float values
// with no decimals to an int when using `NSNumber.description`.
expect(
testController.evaluateJavascript('runJavaScript'),
completion('1'),
);
});

testWidgets('evaluateJavascript with list return value',
(WidgetTester tester) async {
await buildWidget(tester);
Expand Down