Unverified Commit 1155d271 authored by hellohuanlin's avatar hellohuanlin Committed by GitHub

[platform_view]integration test for platform view not tappable issue (#120844)

* [platform_view]integration test for platform view not tappable issue

* nit
parent 56a54d6d
......@@ -6,14 +6,26 @@
static const CGFloat kStandardTimeOut = 60.0;
@interface XCUIElement(KeyboardFocus)
@interface XCUIElement(Test)
@property (nonatomic, readonly) BOOL flt_hasKeyboardFocus;
- (void)flt_forceTap;
@end
@implementation XCUIElement(KeyboardFocus)
@implementation XCUIElement(Test)
- (BOOL)flt_hasKeyboardFocus {
return [[self valueForKey:@"hasKeyboardFocus"] boolValue];
}
- (void)flt_forceTap {
if (self.isHittable) {
[self tap];
} else {
XCUICoordinate *normalized = [self coordinateWithNormalizedOffset:CGVectorMake(0, 0)];
// The offset is in actual pixels. (1, 1) to make sure tap within the view boundary.
XCUICoordinate *coordinate = [normalized coordinateWithOffset:CGVectorMake(1, 1)];
[coordinate tap];
}
}
@end
@interface PlatformViewUITests : XCTestCase
......@@ -56,4 +68,31 @@ static const CGFloat kStandardTimeOut = 60.0;
XCTAssertFalse(flutterTextField.flt_hasKeyboardFocus);
}
- (void)testPlatformViewZOrder {
XCUIElement *entranceButton = self.app.buttons[@"platform view z order test"];
XCTAssertTrue([entranceButton waitForExistenceWithTimeout:kStandardTimeOut], @"The element tree is %@", self.app.debugDescription);
[entranceButton tap];
XCUIElement *showAlertButton = self.app.buttons[@"Show Alert"];
XCTAssertTrue([showAlertButton waitForExistenceWithTimeout:kStandardTimeOut]);
[showAlertButton tap];
XCUIElement *platformButton = self.app.buttons[@"platform_view[0]"];
XCTAssertTrue([platformButton waitForExistenceWithTimeout:kStandardTimeOut]);
XCTAssertTrue([platformButton.label isEqualToString:@"Initial Button Title"]);
// The `app.otherElements` query fails to query `platform_view[1]` (the background),
// because it is covered by a dialog prompt, which removes semantic nodes underneath.
// The workaround is to set a manual delay here (must be longer than the delay used to
// show the background view on the dart side).
[NSThread sleepForTimeInterval:3];
for (int i = 1; i <= 5; i++) {
[platformButton flt_forceTap];
NSString *expectedButtonTitle = [NSString stringWithFormat:@"Button Tapped %d", i];
XCTAssertTrue([platformButton.label isEqualToString:expectedButtonTitle]);
}
}
@end
......@@ -14,6 +14,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
E0440002299C782300D02513 /* ButtonFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = E0440001299C782300D02513 /* ButtonFactory.m */; };
E09898DE2853DBE800064317 /* ViewFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = E09898DD2853DBE800064317 /* ViewFactory.m */; };
E09898E12853DC3C00064317 /* TextFieldFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = E09898E02853DC3C00064317 /* TextFieldFactory.m */; };
E09898E92853E9F000064317 /* PlatformViewUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E09898E82853E9F000064317 /* PlatformViewUITests.m */; };
......@@ -57,6 +58,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E0440000299C782300D02513 /* ButtonFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ButtonFactory.h; sourceTree = "<group>"; };
E0440001299C782300D02513 /* ButtonFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ButtonFactory.m; sourceTree = "<group>"; };
E09898DC2853DBE800064317 /* ViewFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewFactory.h; sourceTree = "<group>"; };
E09898DD2853DBE800064317 /* ViewFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewFactory.m; sourceTree = "<group>"; };
E09898DF2853DC3C00064317 /* TextFieldFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextFieldFactory.h; sourceTree = "<group>"; };
......@@ -120,6 +123,8 @@
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
E09898DF2853DC3C00064317 /* TextFieldFactory.h */,
E09898E02853DC3C00064317 /* TextFieldFactory.m */,
E0440000299C782300D02513 /* ButtonFactory.h */,
E0440001299C782300D02513 /* ButtonFactory.m */,
E09898DC2853DBE800064317 /* ViewFactory.h */,
E09898DD2853DBE800064317 /* ViewFactory.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
......@@ -289,6 +294,7 @@
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
E0440002299C782300D02513 /* ButtonFactory.m in Sources */,
E09898E12853DC3C00064317 /* TextFieldFactory.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
E09898DE2853DBE800064317 /* ViewFactory.m in Sources */,
......
......@@ -6,6 +6,7 @@
#import "GeneratedPluginRegistrant.h"
#import "ViewFactory.h"
#import "TextFieldFactory.h"
#import "ButtonFactory.h"
@implementation AppDelegate
......@@ -16,6 +17,7 @@
id<FlutterPluginRegistrar> registrar = [self registrarForPlugin:@"flutter"];
[registrar registerViewFactory:[[ViewFactory alloc] init] withId:@"platform_view"];
[registrar registerViewFactory:[[TextFieldFactory alloc] init] withId:@"platform_text_field"];
[registrar registerViewFactory:[[ButtonFactory alloc] init] withId:@"platform_button"];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
......
// 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.
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ButtonFactory : NSObject<FlutterPlatformViewFactory>
@end
NS_ASSUME_NONNULL_END
// 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.
#import "ButtonFactory.h"
@interface PlatformButton: NSObject<FlutterPlatformView>
@property (strong, nonatomic) UIButton *button;
@property (assign, nonatomic) int counter;
@end
@implementation PlatformButton
- (instancetype)init
{
self = [super init];
if (self) {
_counter = 0;
_button = [[UIButton alloc] init];
[_button setTitle:@"Initial Button Title" forState:UIControlStateNormal];
[_button addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (UIView *)view {
return self.button;
}
- (void)buttonTapped {
self.counter += 1;
NSString *title = [NSString stringWithFormat:@"Button Tapped %d", self.counter];
[self.button setTitle:title forState:UIControlStateNormal];
}
@end
@implementation ButtonFactory
- (NSObject<FlutterPlatformView> *)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id)args {
return [[PlatformButton alloc] init];
}
@end
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_driver/driver_extension.dart';
void main() {
......@@ -78,6 +79,17 @@ class _MyHomePageState extends State<MyHomePage> {
);
},
),
TextButton(
key: const ValueKey<String>('platform_view_z_order_test'),
child: const Text('platform view z order test'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<ZOrderTestPage>(
builder: (BuildContext context) => const ZOrderTestPage()),
);
},
),
]),
);
}
......@@ -154,3 +166,68 @@ class _FocusTestPageState extends State<FocusTestPage> {
);
}
}
/// A page to test a platform view in an alert dialog prompt is still tappable.
/// See [this issue](https://github.com/flutter/flutter/issues/118366).
class ZOrderTestPage extends StatefulWidget {
const ZOrderTestPage({super.key});
@override
State<ZOrderTestPage> createState() => _ZOrderTestPageState();
}
class _ZOrderTestPageState extends State<ZOrderTestPage> {
bool _showBackground = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Platform view z order test'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Visibility(
visible: _showBackground,
child: const SizedBox(
width: 500,
height: 500,
child: UiKitView(
viewType: 'platform_view',
creationParamsCodec: StandardMessageCodec(),
),
)),
TextButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return const SizedBox(
width: 250,
height: 250,
child: UiKitView(
viewType: 'platform_button',
creationParamsCodec: StandardMessageCodec(),
),
);
});
// XCUITest fails to query the background platform view,
// Since it is covered by the dialog prompt, which removes
// semantic nodes underneath.
// As a workaround, we show the background with a delay.
Future<void>.delayed(const Duration(seconds: 1)).then((void value) {
setState(() {
_showBackground = true;
});
});
},
child: const Text('Show Alert')),
],
),
),
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment