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

[webview_flutter] Add platform interface method loadRequest. #4450

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
@@ -1,3 +1,7 @@
## 1.3.0

* Added `loadRequest` method to platform interface.

## 1.2.0

* Added `runJavascript` and `runJavascriptReturningResult` interface methods to supersede `evaluateJavascript`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController {
});
}

@override
Future<void> loadRequest(WebViewRequest request) async {
assert(request != null);
return _channel.invokeMethod<void>('loadRequest', <String, dynamic>{
'request': request.toJson(),
});
}

@override
Future<String?> currentUrl() => _channel.invokeMethod<String>('currentUrl');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ abstract class WebViewPlatformController {
"WebView loadUrl is not implemented on the current platform");
}

/// Makes a specific HTTP request ands loads the response in the webview.
///
/// [WebViewRequest.method] must be one of the supported HTTP methods
/// in [WebViewRequestMethod].
///
/// If [WebViewRequest.headers] is not empty, its key-value pairs will be
/// added as the headers for the request.
///
/// If [WebViewRequest.body] is not null, it will be added as the body
/// for the request.
///
/// Throws an ArgumentError if [WebViewRequest.uri] has empty scheme.
Future<void> loadRequest(
WebViewRequest request,
) {
throw UnimplementedError(
"WebView loadRequest is not implemented on the current platform");
}

/// Updates the webview settings.
///
/// Any non null field in `settings` will be set as the new setting value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export 'javascript_mode.dart';
export 'web_resource_error.dart';
export 'web_resource_error_type.dart';
export 'web_settings.dart';
export 'webview_request.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:typed_data';

/// Defines the supported HTTP methods for loading a page in [WebView].
enum WebViewRequestMethod {
/// HTTP GET method.
get,

/// HTTP POST method.
post,
}

/// Extension methods on the [WebViewRequestMethod] enum.
extension WebViewRequestMethodExtensions on WebViewRequestMethod {
/// Converts [WebViewRequestMethod] to [String] format.
String serialize() {
switch (this) {
case WebViewRequestMethod.get:
return 'get';
case WebViewRequestMethod.post:
return 'post';
}
}
}

/// Defines the parameters that can be used to load a page in the [WebView].
class WebViewRequest {
/// Creates the [WebViewRequest].
WebViewRequest({
required this.uri,
required this.method,
this.headers = const {},
this.body,
});

/// URI for the request.
final Uri uri;

/// HTTP method used to make the request.
final WebViewRequestMethod method;

/// Headers for the request.
final Map<String, String> headers;

/// HTTP body for the request.
final Uint8List? body;

/// Serializes the [WebViewRequest] to JSON.
Map<String, dynamic> toJson() => {
'uri': this.uri.toString(),
'method': this.method.serialize(),
'headers': this.headers,
'body': this.body,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/master/packages/webview_flut
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview_flutter%22
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 1.2.0
version: 1.3.0

environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@ void main() {
);
});

test('loadRequest', () async {
await webViewPlatform.loadRequest(WebViewRequest(
uri: Uri.parse('https://test.url'),
method: WebViewRequestMethod.get,
));

expect(
log,
<Matcher>[
isMethodCall(
'loadRequest',
arguments: <String, dynamic>{
'request': {
'uri': 'https://test.url',
'method': 'get',
'headers': {},
'body': null,
}
},
),
],
);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a second test that sets the optional parameters and ensures they come through as expected as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stuartmorgan Would that not just be testing WebViewRequest's toJson method? We can of course add a second test, but as that toJson is already being tested here, including the optional parameters, I feel like we would be testing for the same thing twice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you know that loadRequest calls WebViewRequest's toJson method? Or to be more precise: how do you know that it will continue to do so?

I guarantee you that I could write a PR that breaks the test I am asking you to write without changing WebViewRequest.toJson.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is indeed a fair point, I now see it wouldn't. I've added the test for the optional parameters.

Just for my own curiosity: Would it not be possible to avoid testing toJson by instead mocking the WebViewRequest and checking if the return value of toJson gets passed to invokeMethod?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests should assert the behavior you want to guarantee. Which is a better description of the thing you want to guarantee is true:

  1. "The method channel is sent the following specific keys with the expected values", or
  2. "The call to the method channel is implemented by calling toJson on invokeMethod"?

(As an example of why only one of these is a good description: if someone later decides that the JSON keys aren't very descriptive, and sends a PR that updates toJson and its test to use different keys, what do you want to happen?)


test('currentUrl', () async {
final String? currentUrl = await webViewPlatform.currentUrl();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:webview_flutter_platform_interface/src/types/types.dart';

void main() {
test('WebViewRequestMethod should serialize correctly', () {
expect(WebViewRequestMethod.get.serialize(), 'get');
expect(WebViewRequestMethod.post.serialize(), 'post');
});

test('WebViewRequest should serialize correctly', () {
WebViewRequest request;
Map<String, dynamic> serializedRequest;
// Test serialization without headers or a body
request = WebViewRequest(
uri: Uri.parse('https://flutter.dev'),
method: WebViewRequestMethod.get,
);
serializedRequest = request.toJson();
expect(serializedRequest['uri'], 'https://flutter.dev');
expect(serializedRequest['method'], 'get');
expect(serializedRequest['headers'], {});
expect(serializedRequest['body'], null);
// Test serialization of headers and body
request = WebViewRequest(
uri: Uri.parse('https://flutter.dev'),
method: WebViewRequestMethod.get,
headers: {'foo': 'bar'},
body: Uint8List.fromList('Example Body'.codeUnits),
);
serializedRequest = request.toJson();
expect(serializedRequest['headers'], {'foo': 'bar'});
expect(serializedRequest['body'], 'Example Body'.codeUnits);
});
}