flutter_flutter/packages/flutter/test/widgets/html_element_view_test.dart
Mouad Debbar b0188cd182
[web] Pass creation params to the platform view factory (#128146)
This concludes step 1 of the `HtmlElementView` improvements. It's now possible to pass creation params to platform view factories directly from `HtmlElementView`.

Here's a sample app using a single factory to render platform views in different colors:

<details>
  <summary>Code sample</summary>
  
  ```dart
import 'dart:js_interop';
import 'dart:ui_web' as ui_web;
import 'package:flutter/material.dart';
import 'package:web/web.dart' as web;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Platform View Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Platform View Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              BoxWrapper('red'),
              BoxWrapper(null),
              BoxWrapper('blue'),
            ],
          ),
        ),
      ),
    );
  }
}

bool isRegistered = false;

class BoxWrapper extends StatelessWidget {
  const BoxWrapper(this.cssColor);

  final String? cssColor;

  void register() {
    if (isRegistered) return;
    isRegistered = true;

    ui_web.platformViewRegistry.registerViewFactory('my-platform-view', (
      id, {
      Object? params,
    }) {
      params as String?;

      final element = web.document.createElement('div'.toJS) as web.HTMLElement;
      element.textContent = 'Platform View'.toJS;
      element.style
        ..lineHeight = '100px'.toJS
        ..fontSize = '24px'.toJS
        ..backgroundColor = (params ?? 'pink').toJS
        ..textAlign = 'center'.toJS;
      return element;
    });
  }

  @override
  Widget build(BuildContext context) {
    register();
    return SizedBox(
      width: 200,
      height: 100,
      child: Card(
        child: HtmlElementView(
          viewType: 'my-platform-view',
          creationParams: cssColor,
        ),
      ),
    );
  }
}
  ```
</details>

![image](https://github.com/flutter/flutter/assets/1278212/4b62ed8b-2314-49d6-9b4a-5da849bf2a48)

Depends on https://github.com/flutter/engine/pull/42255

Part of https://github.com/flutter/flutter/issues/127030
2023-06-15 18:00:25 +00:00

282 lines
8.4 KiB
Dart

// Copyright 2014 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.
@TestOn('chrome')
library;
import 'dart:async';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import '../services/fake_platform_views.dart';
void main() {
group('HtmlElementView', () {
testWidgets('Create HTML view', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'webview'),
),
),
);
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 1, 'webview'),
]),
);
});
testWidgets('Create HTML view with PlatformViewCreatedCallback', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
bool hasPlatformViewCreated = false;
void onPlatformViewCreatedCallBack(int id) {
hasPlatformViewCreated = true;
}
await tester.pumpWidget(
Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(
viewType: 'webview',
onPlatformViewCreated: onPlatformViewCreatedCallBack,
),
),
),
);
// Check the onPlatformViewCreatedCallBack has been called.
expect(hasPlatformViewCreated, true);
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 1, 'webview'),
]),
);
});
testWidgets('Create HTML view with creation params', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
const Column(
children: <Widget>[
SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(
viewType: 'webview',
creationParams: 'foobar',
),
),
SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(
viewType: 'webview',
creationParams: 123,
),
),
],
),
);
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 1, 'webview', 'foobar'),
FakeHtmlPlatformView(currentViewId + 2, 'webview', 123),
]),
);
});
testWidgets('Resize HTML view', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'webview'),
),
),
);
viewsController.resizeCompleter = Completer<void>();
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 100.0,
height: 50.0,
child: HtmlElementView(viewType: 'webview'),
),
),
);
viewsController.resizeCompleter.complete();
await tester.pump();
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 1, 'webview'),
]),
);
});
testWidgets('Change HTML view type', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
viewsController.registerViewType('maps');
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'webview'),
),
),
);
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'maps'),
),
),
);
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 2, 'maps'),
]),
);
});
testWidgets('Dispose HTML view', (WidgetTester tester) async {
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'webview'),
),
),
);
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
),
),
);
expect(
viewsController.views,
isEmpty,
);
});
testWidgets('HTML view survives widget tree change', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
final GlobalKey key = GlobalKey();
await tester.pumpWidget(
Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'webview', key: key),
),
),
);
await tester.pumpWidget(
Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(viewType: 'webview', key: key),
),
),
);
expect(
viewsController.views,
unorderedEquals(<FakeHtmlPlatformView>[
FakeHtmlPlatformView(currentViewId + 1, 'webview'),
]),
);
});
testWidgets('HtmlElementView has correct semantics', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
expect(currentViewId, greaterThanOrEqualTo(0));
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
Semantics(
container: true,
child: const Align(
alignment: Alignment.bottomRight,
child: SizedBox(
width: 200.0,
height: 100.0,
child: HtmlElementView(
viewType: 'webview',
),
),
),
),
);
// First frame is before the platform view was created so the render object
// is not yet in the tree.
await tester.pump();
// The platform view ID is set on the child of the HtmlElementView render object.
final SemanticsNode semantics = tester.getSemantics(find.byType(PlatformViewSurface));
expect(semantics.platformViewId, currentViewId + 1);
expect(semantics.rect, const Rect.fromLTWH(0, 0, 200, 100));
// A 200x100 rect positioned at bottom right of a 800x600 box.
expect(semantics.transform, Matrix4.translationValues(600, 500, 0));
expect(semantics.childrenCount, 0);
handle.dispose();
});
});
}