From 4275acd13302ce340f877e7f718c10ed7df1756c Mon Sep 17 00:00:00 2001 From: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com> Date: Thu, 2 Feb 2023 17:55:25 -0500 Subject: [PATCH 1/8] update --- .../webview_flutter_web/CHANGELOG.md | 4 ++- .../lib/src/web_webview_controller.dart | 36 +++++++++++-------- .../webview_flutter_web/pubspec.yaml | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md index 028e03d715ff..b6350b775786 100644 --- a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md @@ -1,6 +1,8 @@ -## NEXT +## 0.2.2 * Updates minimum Flutter version to 3.0. +* Updates `WebWebViewController.loadRequest` to only set the src of the iFrame when + `LoadRequestParams.headers` is empty and is using the HTTP GET request method. ## 0.2.1 diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart index 7ef72257999f..b33bd45ee0a9 100644 --- a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart @@ -72,21 +72,27 @@ class WebWebViewController extends PlatformWebViewController { throw ArgumentError( 'LoadRequestParams#uri is required to have a scheme.'); } - final HttpRequest httpReq = - await _webWebViewParams.httpRequestFactory.request( - params.uri.toString(), - method: params.method.serialize(), - requestHeaders: params.headers, - sendData: params.body, - ); - final String contentType = - httpReq.getResponseHeader('content-type') ?? 'text/html'; - // ignore: unsafe_html - _webWebViewParams.iFrame.src = Uri.dataFromString( - httpReq.responseText ?? '', - mimeType: contentType, - encoding: utf8, - ).toString(); + + if (params.headers.isEmpty && params.method == LoadRequestMethod.get) { + // ignore: unsafe_html + _webWebViewParams.iFrame.src = params.uri.toString(); + } else { + final HttpRequest httpReq = + await _webWebViewParams.httpRequestFactory.request( + params.uri.toString(), + method: params.method.serialize(), + requestHeaders: params.headers, + sendData: params.body, + ); + final String contentType = + httpReq.getResponseHeader('content-type') ?? 'text/html'; + // ignore: unsafe_html + _webWebViewParams.iFrame.src = Uri.dataFromString( + httpReq.responseText ?? '', + mimeType: contentType, + encoding: utf8, + ).toString(); + } } } diff --git a/packages/webview_flutter/webview_flutter_web/pubspec.yaml b/packages/webview_flutter/webview_flutter_web/pubspec.yaml index 66b67f4d67bd..f3ea67d68dad 100644 --- a/packages/webview_flutter/webview_flutter_web/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_web/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_web description: A Flutter plugin that provides a WebView widget on web. repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 0.2.1 +version: 0.2.2 environment: sdk: ">=2.14.0 <3.0.0" From 649e47736329932d014334bd8227182d44c74261 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 18:42:30 +0000 Subject: [PATCH 2/8] Request body must be empty too to skip XHR request. Add test. --- .../lib/src/web_webview_controller.dart | 8 ++- .../test/web_webview_controller_test.dart | 37 ++++++++++-- .../web_webview_controller_test.mocks.dart | 58 ++++++++++++++----- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart index b33bd45ee0a9..ca6e5fe1a831 100644 --- a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'dart:convert'; -import 'dart:html'; +import 'dart:html' as html; import 'package:flutter/cupertino.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; @@ -37,7 +37,7 @@ class WebWebViewControllerCreationParams /// The underlying element used as the WebView. @visibleForTesting - final IFrameElement iFrame = IFrameElement() + final html.IFrameElement iFrame = html.IFrameElement() ..id = 'webView${_nextIFrameId++}' ..width = '100%' ..height = '100%' @@ -73,7 +73,9 @@ class WebWebViewController extends PlatformWebViewController { 'LoadRequestParams#uri is required to have a scheme.'); } - if (params.headers.isEmpty && params.method == LoadRequestMethod.get) { + if (params.headers.isEmpty && + (params.body == null || params.body!.isEmpty) && + params.method == LoadRequestMethod.get) { // ignore: unsafe_html _webWebViewParams.iFrame.src = params.uri.toString(); } else { diff --git a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart index 6a8f73798107..15e9464077d2 100644 --- a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart +++ b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart @@ -17,9 +17,9 @@ import 'package:webview_flutter_web/webview_flutter_web.dart'; import 'web_webview_controller_test.mocks.dart'; -@GenerateMocks([ - HttpRequest, - HttpRequestFactory, +@GenerateMocks([], customMocks: >[ + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), ]) void main() { WidgetsFlutterBinding.ensureInitialized(); @@ -62,7 +62,7 @@ void main() { }); group('loadRequest', () { - test('loadRequest throws ArgumentError on missing scheme', () async { + test('throws ArgumentError on missing scheme', () async { final WebWebViewController controller = WebWebViewController(WebWebViewControllerCreationParams()); @@ -73,8 +73,33 @@ void main() { throwsA(const TypeMatcher())); }); - test('loadRequest makes request and loads response into iframe', - () async { + test('skips XHR for simple GETs (no headers, no data)', () async { + final MockHttpRequestFactory mockHttpRequestFactory = + MockHttpRequestFactory(); + final WebWebViewController controller = + WebWebViewController(WebWebViewControllerCreationParams( + httpRequestFactory: mockHttpRequestFactory, + )); + + when(mockHttpRequestFactory.request( + any, + method: anyNamed('method'), + requestHeaders: anyNamed('requestHeaders'), + sendData: anyNamed('sendData'), + )).thenThrow( + StateError('The `request` method should not have been called.')); + + await controller.loadRequest(LoadRequestParams( + uri: Uri.parse('https://flutter.dev'), + )); + + expect( + (controller.params as WebWebViewControllerCreationParams).iFrame.src, + 'https://flutter.dev/', + ); + }); + + test('makes request and loads response into iframe', () async { final MockHttpRequestFactory mockHttpRequestFactory = MockHttpRequestFactory(); final WebWebViewController controller = diff --git a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.mocks.dart index f74359aac431..5cb259a3f01a 100644 --- a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.mocks.dart +++ b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.mocks.dart @@ -55,24 +55,23 @@ class _FakeHttpRequest_2 extends _i1.SmartFake implements _i2.HttpRequest { /// /// See the documentation for Mockito's code generation for more information. class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { - MockHttpRequest() { - _i1.throwOnMissingStub(this); - } - @override Map get responseHeaders => (super.noSuchMethod( Invocation.getter(#responseHeaders), returnValue: {}, + returnValueForMissingStub: {}, ) as Map); @override int get readyState => (super.noSuchMethod( Invocation.getter(#readyState), returnValue: 0, + returnValueForMissingStub: 0, ) as int); @override String get responseType => (super.noSuchMethod( Invocation.getter(#responseType), returnValue: '', + returnValueForMissingStub: '', ) as String); @override set responseType(String? value) => super.noSuchMethod( @@ -97,6 +96,10 @@ class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { this, Invocation.getter(#upload), ), + returnValueForMissingStub: _FakeHttpRequestUpload_0( + this, + Invocation.getter(#upload), + ), ) as _i2.HttpRequestUpload); @override set withCredentials(bool? value) => super.noSuchMethod( @@ -110,41 +113,49 @@ class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { _i3.Stream<_i2.Event> get onReadyStateChange => (super.noSuchMethod( Invocation.getter(#onReadyStateChange), returnValue: _i3.Stream<_i2.Event>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.Event>.empty(), ) as _i3.Stream<_i2.Event>); @override _i3.Stream<_i2.ProgressEvent> get onAbort => (super.noSuchMethod( Invocation.getter(#onAbort), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i3.Stream<_i2.ProgressEvent> get onError => (super.noSuchMethod( Invocation.getter(#onError), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i3.Stream<_i2.ProgressEvent> get onLoad => (super.noSuchMethod( Invocation.getter(#onLoad), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i3.Stream<_i2.ProgressEvent> get onLoadEnd => (super.noSuchMethod( Invocation.getter(#onLoadEnd), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i3.Stream<_i2.ProgressEvent> get onLoadStart => (super.noSuchMethod( Invocation.getter(#onLoadStart), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i3.Stream<_i2.ProgressEvent> get onProgress => (super.noSuchMethod( Invocation.getter(#onProgress), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i3.Stream<_i2.ProgressEvent> get onTimeout => (super.noSuchMethod( Invocation.getter(#onTimeout), returnValue: _i3.Stream<_i2.ProgressEvent>.empty(), + returnValueForMissingStub: _i3.Stream<_i2.ProgressEvent>.empty(), ) as _i3.Stream<_i2.ProgressEvent>); @override _i2.Events get on => (super.noSuchMethod( @@ -153,6 +164,10 @@ class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { this, Invocation.getter(#on), ), + returnValueForMissingStub: _FakeEvents_1( + this, + Invocation.getter(#on), + ), ) as _i2.Events); @override void open( @@ -192,13 +207,16 @@ class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { [], ), returnValue: '', + returnValueForMissingStub: '', ) as String); @override - String? getResponseHeader(String? name) => - (super.noSuchMethod(Invocation.method( - #getResponseHeader, - [name], - )) as String?); + String? getResponseHeader(String? name) => (super.noSuchMethod( + Invocation.method( + #getResponseHeader, + [name], + ), + returnValueForMissingStub: null, + ) as String?); @override void overrideMimeType(String? mime) => super.noSuchMethod( Invocation.method( @@ -271,6 +289,7 @@ class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { [event], ), returnValue: false, + returnValueForMissingStub: false, ) as bool); } @@ -279,10 +298,6 @@ class MockHttpRequest extends _i1.Mock implements _i2.HttpRequest { /// See the documentation for Mockito's code generation for more information. class MockHttpRequestFactory extends _i1.Mock implements _i4.HttpRequestFactory { - MockHttpRequestFactory() { - _i1.throwOnMissingStub(this); - } - @override _i3.Future<_i2.HttpRequest> request( String? url, { @@ -324,5 +339,22 @@ class MockHttpRequestFactory extends _i1.Mock }, ), )), + returnValueForMissingStub: + _i3.Future<_i2.HttpRequest>.value(_FakeHttpRequest_2( + this, + Invocation.method( + #request, + [url], + { + #method: method, + #withCredentials: withCredentials, + #responseType: responseType, + #mimeType: mimeType, + #requestHeaders: requestHeaders, + #sendData: sendData, + #onProgress: onProgress, + }, + ), + )), ) as _i3.Future<_i2.HttpRequest>); } From 6e20ed126e957b6f7f10256aabd1e8e9a5c8d8ed Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 18:43:05 +0000 Subject: [PATCH 3/8] Add ContentType class to parse response headers. --- .../lib/src/content_type.dart | 48 ++++++++++++ .../test/content_type_test.dart | 77 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 packages/webview_flutter/webview_flutter_web/lib/src/content_type.dart create mode 100644 packages/webview_flutter/webview_flutter_web/test/content_type_test.dart diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/content_type.dart b/packages/webview_flutter/webview_flutter_web/lib/src/content_type.dart new file mode 100644 index 000000000000..0aa18ce2318a --- /dev/null +++ b/packages/webview_flutter/webview_flutter_web/lib/src/content_type.dart @@ -0,0 +1,48 @@ +// 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. + +/// Class to represent a content-type header value. +class ContentType { + /// Creates a [ContentType] instance by parsing a "content-type" response [header]. + /// + /// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + /// See: https://httpwg.org/specs/rfc9110.html#media.type + ContentType.parse(String header) { + final Iterable chunks = + header.split(';').map((String e) => e.trim().toLowerCase()); + + for (final String chunk in chunks) { + if (!chunk.contains('=')) { + _mimeType = chunk; + } else { + final List bits = + chunk.split('=').map((String e) => e.trim()).toList(); + assert(bits.length == 2); + switch (bits[0]) { + case 'charset': + _charset = bits[1]; + break; + case 'boundary': + _boundary = bits[1]; + break; + default: + throw StateError('Unable to parse "$chunk" in content-type.'); + } + } + } + } + + String? _mimeType; + String? _charset; + String? _boundary; + + /// The MIME-type of the resource or the data. + String? get mimeType => _mimeType; + + /// The character encoding standard. + String? get charset => _charset; + + /// The separation boundary for multipart entities. + String? get boundary => _boundary; +} diff --git a/packages/webview_flutter/webview_flutter_web/test/content_type_test.dart b/packages/webview_flutter/webview_flutter_web/test/content_type_test.dart new file mode 100644 index 000000000000..936eeae4f571 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_web/test/content_type_test.dart @@ -0,0 +1,77 @@ +// 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 'package:flutter_test/flutter_test.dart'; +import 'package:webview_flutter_web/src/content_type.dart'; + +void main() { + group('ContentType.parse', () { + test('basic content-type (lowers case)', () { + final ContentType contentType = ContentType.parse('text/pLaIn'); + + expect(contentType.mimeType, 'text/plain'); + expect(contentType.boundary, isNull); + expect(contentType.charset, isNull); + }); + + test('with charset', () { + final ContentType contentType = + ContentType.parse('text/pLaIn; charset=utf-8'); + + expect(contentType.mimeType, 'text/plain'); + expect(contentType.boundary, isNull); + expect(contentType.charset, 'utf-8'); + }); + + test('with boundary', () { + final ContentType contentType = + ContentType.parse('text/pLaIn; boundary=---xyz'); + + expect(contentType.mimeType, 'text/plain'); + expect(contentType.boundary, '---xyz'); + expect(contentType.charset, isNull); + }); + + test('with charset and boundary', () { + final ContentType contentType = + ContentType.parse('text/pLaIn; charset=utf-8; boundary=---xyz'); + + expect(contentType.mimeType, 'text/plain'); + expect(contentType.boundary, '---xyz'); + expect(contentType.charset, 'utf-8'); + }); + + test('with boundary and charset', () { + final ContentType contentType = + ContentType.parse('text/pLaIn; boundary=---xyz; charset=utf-8'); + + expect(contentType.mimeType, 'text/plain'); + expect(contentType.boundary, '---xyz'); + expect(contentType.charset, 'utf-8'); + }); + + test('with a bunch of whitespace, boundary and charset', () { + final ContentType contentType = ContentType.parse( + ' text/pLaIn ; boundary=---xyz; charset=utf-8 '); + + expect(contentType.mimeType, 'text/plain'); + expect(contentType.boundary, '---xyz'); + expect(contentType.charset, 'utf-8'); + }); + + test('empty string', () { + final ContentType contentType = ContentType.parse(''); + + expect(contentType.mimeType, ''); + expect(contentType.boundary, isNull); + expect(contentType.charset, isNull); + }); + + test('unknown parameter (throws)', () { + expect(() { + ContentType.parse('text/pLaIn; wrong=utf-8'); + }, throwsStateError); + }); + }); +} From 551da7291f3e20e513758febc39faf65f6207d3b Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 18:44:19 +0000 Subject: [PATCH 4/8] Use content-type in response to encode iframe contents. --- .../lib/src/web_webview_controller.dart | 40 ++++++++++++------- .../test/web_webview_controller_test.dart | 37 ++++++++++++++++- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart index ca6e5fe1a831..f62f1018956f 100644 --- a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart @@ -8,6 +8,7 @@ import 'dart:html' as html; import 'package:flutter/cupertino.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; +import 'content_type.dart'; import 'http_request_factory.dart'; import 'shims/dart_ui.dart' as ui; @@ -79,23 +80,32 @@ class WebWebViewController extends PlatformWebViewController { // ignore: unsafe_html _webWebViewParams.iFrame.src = params.uri.toString(); } else { - final HttpRequest httpReq = - await _webWebViewParams.httpRequestFactory.request( - params.uri.toString(), - method: params.method.serialize(), - requestHeaders: params.headers, - sendData: params.body, - ); - final String contentType = - httpReq.getResponseHeader('content-type') ?? 'text/html'; - // ignore: unsafe_html - _webWebViewParams.iFrame.src = Uri.dataFromString( - httpReq.responseText ?? '', - mimeType: contentType, - encoding: utf8, - ).toString(); + await _updateIFrameFromXhr(params); } } + + /// Performs an AJAX request defined by [params]. + Future _updateIFrameFromXhr(LoadRequestParams params) async { + final html.HttpRequest httpReq = + await _webWebViewParams.httpRequestFactory.request( + params.uri.toString(), + method: params.method.serialize(), + requestHeaders: params.headers, + sendData: params.body, + ); + + final String header = + httpReq.getResponseHeader('content-type') ?? 'text/html'; + final ContentType contentType = ContentType.parse(header); + final Encoding encoding = Encoding.getByName(contentType.charset) ?? utf8; + + // ignore: unsafe_html + _webWebViewParams.iFrame.src = Uri.dataFromString( + httpReq.responseText ?? '', + mimeType: contentType.mimeType, + encoding: encoding, + ).toString(); + } } /// An implementation of [PlatformWebViewWidget] using Flutter the for Web API. diff --git a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart index 15e9464077d2..b0be235bc2da 100644 --- a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart +++ b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:convert'; import 'dart:html'; // TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231) // ignore: unnecessary_import @@ -139,7 +140,41 @@ void main() { ); }); - test('loadRequest escapes "#" correctly', () async { + test('parses content-type response header correctly', () async { + final MockHttpRequestFactory mockHttpRequestFactory = + MockHttpRequestFactory(); + final WebWebViewController controller = + WebWebViewController(WebWebViewControllerCreationParams( + httpRequestFactory: mockHttpRequestFactory, + )); + + final Encoding iso = Encoding.getByName('latin1')!; + + final MockHttpRequest mockHttpRequest = MockHttpRequest(); + when(mockHttpRequest.responseText) + .thenReturn(String.fromCharCodes(iso.encode('EspaƱa'))); + when(mockHttpRequest.getResponseHeader('content-type')) + .thenReturn('Text/HTmL; charset=latin1'); + + when(mockHttpRequestFactory.request( + any, + method: anyNamed('method'), + requestHeaders: anyNamed('requestHeaders'), + sendData: anyNamed('sendData'), + )).thenAnswer((_) => Future.value(mockHttpRequest)); + + await controller.loadRequest(LoadRequestParams( + uri: Uri.parse('https://flutter.dev'), + method: LoadRequestMethod.post, + )); + + expect( + (controller.params as WebWebViewControllerCreationParams).iFrame.src, + 'data:text/html;charset=iso-8859-1,Espa%F1a', + ); + }); + + test('escapes "#" correctly', () async { final MockHttpRequestFactory mockHttpRequestFactory = MockHttpRequestFactory(); final WebWebViewController controller = From d97bf8c37d4dc693b27488bc01f5390d2354d788 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 18:44:48 +0000 Subject: [PATCH 5/8] Attempt to run integration_tests. Do they ever fail? --- .../webview_flutter_test.dart | 4 ++++ .../webview_flutter_web/example/run_test.sh | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100755 packages/webview_flutter/webview_flutter_web/example/run_test.sh diff --git a/packages/webview_flutter/webview_flutter_web/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_web/example/integration_test/webview_flutter_test.dart index 1736d47d39c8..f71d2d3c2bac 100644 --- a/packages/webview_flutter/webview_flutter_web/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_web/example/integration_test/webview_flutter_test.dart @@ -5,6 +5,10 @@ import 'dart:html' as html; import 'dart:io'; +// FIX (dit): Remove these integration tests, or make them run. They currently never fail. +// (They won't run because they use `dart:io`. If you remove all `dart:io` bits from +// this file, they start failing with `fail()`, for example.) + import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/packages/webview_flutter/webview_flutter_web/example/run_test.sh b/packages/webview_flutter/webview_flutter_web/example/run_test.sh new file mode 100755 index 000000000000..aa52974f310e --- /dev/null +++ b/packages/webview_flutter/webview_flutter_web/example/run_test.sh @@ -0,0 +1,22 @@ +#!/usr/bin/bash +# 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. + +if pgrep -lf chromedriver > /dev/null; then + echo "chromedriver is running." + + if [ $# -eq 0 ]; then + echo "No target specified, running all tests..." + find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' + else + echo "Running test target: $1..." + set -x + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1 + fi + + else + echo "chromedriver is not running." + echo "Please, check the README.md for instructions on how to use run_test.sh" +fi + From 744dcbbdc74a9e13d1acf4cd68cc8735a19b902c Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 18:46:59 +0000 Subject: [PATCH 6/8] Update docs. --- .../webview_flutter_web/CHANGELOG.md | 7 +++++-- .../webview_flutter_web/README.md | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md index b6350b775786..a9de8656a88b 100644 --- a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md @@ -1,8 +1,11 @@ ## 0.2.2 +* Updates `WebWebViewController.loadRequest` to only set the src of the iFrame + when `LoadRequestParams.headers` and `LoadRequestParams.body` are empty and is + using the HTTP GET request method. [#118573](https://github.com/flutter/flutter/issues/118573). +* Parses the `content-type` header of XHR responses to extract the correct + MIME-type and charset. [#118090](https://github.com/flutter/flutter/issues/118090). * Updates minimum Flutter version to 3.0. -* Updates `WebWebViewController.loadRequest` to only set the src of the iFrame when - `LoadRequestParams.headers` is empty and is using the HTTP GET request method. ## 0.2.1 diff --git a/packages/webview_flutter/webview_flutter_web/README.md b/packages/webview_flutter/webview_flutter_web/README.md index 51a0223696d0..1713cc9b5421 100644 --- a/packages/webview_flutter/webview_flutter_web/README.md +++ b/packages/webview_flutter/webview_flutter_web/README.md @@ -21,3 +21,19 @@ yet, so it currently requires extra setup to use: Once the step above is complete, the APIs from `webview_flutter` listed above can be used as normal on web. + +## Tests + +Tests are contained in the `test` directory. You can run all tests from the root +of the package with the following command: + +``` +$ flutter test --platform chrome +``` + +This package uses `package:mockito` in some tests. Mock files can be updated +from the root of the package like so: + +``` +$ flutter pub run build_runner build --delete-conflicting-outputs +``` From 1c2f1e789f73925972266cab22a7063af791ab99 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 18:55:11 +0000 Subject: [PATCH 7/8] Set Widget styles in a way the flutter engine likes. --- packages/webview_flutter/webview_flutter_web/CHANGELOG.md | 2 ++ .../webview_flutter_web/lib/src/web_webview_controller.dart | 4 ++-- .../webview_flutter_web/test/web_webview_controller_test.dart | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md index a9de8656a88b..3ada124fe7ce 100644 --- a/packages/webview_flutter/webview_flutter_web/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_web/CHANGELOG.md @@ -5,6 +5,8 @@ using the HTTP GET request method. [#118573](https://github.com/flutter/flutter/issues/118573). * Parses the `content-type` header of XHR responses to extract the correct MIME-type and charset. [#118090](https://github.com/flutter/flutter/issues/118090). +* Sets `width` and `height` of widget the way the Engine wants, to remove distracting + warnings from the development console. * Updates minimum Flutter version to 3.0. ## 0.2.1 diff --git a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart index f62f1018956f..52f93f911e40 100644 --- a/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_web/lib/src/web_webview_controller.dart @@ -40,8 +40,8 @@ class WebWebViewControllerCreationParams @visibleForTesting final html.IFrameElement iFrame = html.IFrameElement() ..id = 'webView${_nextIFrameId++}' - ..width = '100%' - ..height = '100%' + ..style.width = '100%' + ..style.height = '100%' ..style.border = 'none'; } diff --git a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart index b0be235bc2da..0a995cbb67e0 100644 --- a/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart +++ b/packages/webview_flutter/webview_flutter_web/test/web_webview_controller_test.dart @@ -32,8 +32,8 @@ void main() { WebWebViewControllerCreationParams(); expect(params.iFrame.id, contains('webView')); - expect(params.iFrame.width, '100%'); - expect(params.iFrame.height, '100%'); + expect(params.iFrame.style.width, '100%'); + expect(params.iFrame.style.height, '100%'); expect(params.iFrame.style.border, 'none'); }); }); From 267d2820448ceb8a18aba7d317008dfe7fa0cc6d Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 3 Feb 2023 19:10:05 +0000 Subject: [PATCH 8/8] Add bash to codeblocks in readme. --- packages/webview_flutter/webview_flutter_web/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_web/README.md b/packages/webview_flutter/webview_flutter_web/README.md index 1713cc9b5421..03bb6a89052e 100644 --- a/packages/webview_flutter/webview_flutter_web/README.md +++ b/packages/webview_flutter/webview_flutter_web/README.md @@ -27,13 +27,13 @@ above can be used as normal on web. Tests are contained in the `test` directory. You can run all tests from the root of the package with the following command: -``` +```bash $ flutter test --platform chrome ``` This package uses `package:mockito` in some tests. Mock files can be updated from the root of the package like so: -``` +```bash $ flutter pub run build_runner build --delete-conflicting-outputs ```