Flutter Engine
The Flutter Engine
UnobstructedPlatformViewTests.m
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#import <XCTest/XCTest.h>
6
7static const CGFloat kCompareAccuracy = 0.001;
8
9@interface UnobstructedPlatformViewTests : XCTestCase
10
11@end
12
14
15- (void)setUp {
16 self.continueAfterFailure = NO;
17}
18
19// A is the layer, which z index is higher than the platform view.
20// +--------+
21// | PV | +---+
22// +--------+ | A |
23// +---+
24- (void)testNoOverlay {
25 XCUIApplication* app = [[XCUIApplication alloc] init];
26 app.launchArguments = @[ @"--platform-view-no-overlay-intersection" ];
27 [app launch];
28
29 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
30 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
31 XCTAssertEqual(platform_view.frame.origin.x, 0);
32 XCTAssertEqual(platform_view.frame.origin.y, 0);
33 XCTAssertEqual(platform_view.frame.size.width, 250);
34 XCTAssertEqual(platform_view.frame.size.height, 250);
35
36 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
37 XCTAssertFalse(overlay.exists);
38}
39
40// A is the layer above the platform view.
41// +-----------------+
42// | PV +---+ |
43// | | A | |
44// | +---+ |
45// +-----------------+
46- (void)testOneOverlay {
47 XCUIApplication* app = [[XCUIApplication alloc] init];
48 app.launchArguments = @[ @"--platform-view" ];
49 [app launch];
50
51 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
52 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
53 XCTAssertEqual(platform_view.frame.origin.x, 0);
54 XCTAssertEqual(platform_view.frame.origin.y, 0);
55 XCTAssertEqual(platform_view.frame.size.width, 250);
56 XCTAssertEqual(platform_view.frame.size.height, 250);
57
58 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
59 XCTAssertTrue(overlay.exists);
60 XCTAssertEqual(overlay.frame.origin.x, 150);
61 XCTAssertEqual(overlay.frame.origin.y, 150);
62 XCTAssertEqual(overlay.frame.size.width, 50);
63 XCTAssertEqual(overlay.frame.size.height, 50);
64
65 XCUIElement* overlayView = app.otherElements[@"platform_view[0].overlay_view[0]"];
66 XCTAssertTrue(overlayView.exists);
67 // Overlay should always be the same frame as the app.
68 XCTAssertEqualWithAccuracy(overlayView.frame.origin.x, app.frame.origin.x, kCompareAccuracy);
69 XCTAssertEqualWithAccuracy(overlayView.frame.origin.y, app.frame.origin.x, kCompareAccuracy);
70 XCTAssertEqualWithAccuracy(overlayView.frame.size.width, app.frame.size.width, kCompareAccuracy);
71 XCTAssertEqualWithAccuracy(overlayView.frame.size.height, app.frame.size.height,
73}
74
75// A is the layer above the platform view.
76// +-----------------+
77// | PV +---+ |
78// +-----------| A |-+
79// +---+
81 XCUIApplication* app = [[XCUIApplication alloc] init];
82 app.launchArguments = @[ @"--platform-view-partial-intersection" ];
83 [app launch];
84
85 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
86 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
87 XCTAssertEqual(platform_view.frame.origin.x, 0);
88 XCTAssertEqual(platform_view.frame.origin.y, 0);
89 XCTAssertEqual(platform_view.frame.size.width, 250);
90 XCTAssertEqual(platform_view.frame.size.height, 250);
91
92 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
93 XCTAssertTrue(overlay.exists);
94 XCTAssertEqual(overlay.frame.origin.x, 200);
95 XCTAssertEqual(overlay.frame.origin.y, 245);
96 XCTAssertEqual(overlay.frame.size.width, 50);
97 // Half the height of the overlay.
98 XCTAssertEqual(overlay.frame.size.height, 5);
99
100 XCUIElement* overlayView = app.otherElements[@"platform_view[0].overlay_view[0]"];
101 XCTAssertTrue(overlayView.exists);
102 // Overlay should always be the same frame as the app.
103 XCTAssertEqualWithAccuracy(overlayView.frame.origin.x, app.frame.origin.x, kCompareAccuracy);
104 XCTAssertEqualWithAccuracy(overlayView.frame.origin.y, app.frame.origin.x, kCompareAccuracy);
105 XCTAssertEqualWithAccuracy(overlayView.frame.size.width, app.frame.size.width, kCompareAccuracy);
106 XCTAssertEqualWithAccuracy(overlayView.frame.size.height, app.frame.size.height,
108}
109
110// A and B are the layers above the platform view.
111// +--------------------+
112// | PV +------------+ |
113// | | B +-----+ | |
114// | +---| A |-+ |
115// +----------| |---+
116// +-----+
118 XCUIApplication* app = [[XCUIApplication alloc] init];
119 app.launchArguments = @[ @"--platform-view-two-intersecting-overlays" ];
120 [app launch];
121
122 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
123 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
124 XCTAssertEqual(platform_view.frame.origin.x, 0);
125 XCTAssertEqual(platform_view.frame.origin.y, 0);
126 XCTAssertEqual(platform_view.frame.size.width, 250);
127 XCTAssertEqual(platform_view.frame.size.height, 250);
128
129 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
130 XCTAssertTrue(overlay.exists);
131 XCTAssertEqual(overlay.frame.origin.x, 150);
132 XCTAssertEqual(overlay.frame.origin.y, 150);
133 XCTAssertEqual(overlay.frame.size.width, 75);
134 XCTAssertEqual(overlay.frame.size.height, 75);
135
136 XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[1]"].exists);
137}
138
139// A, B, and C are the layers above the platform view.
140// +-------------------------+
141// | PV +-----------+ |
142// | +---+ | B +-----+ | |
143// | | C | +---| A |-+ |
144// | +---+ +-----+ |
145// +-------------------------+
147 XCUIApplication* app = [[XCUIApplication alloc] init];
148 app.launchArguments = @[ @"--platform-view-one-overlay-two-intersecting-overlays" ];
149 [app launch];
150
151 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
152 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
153 XCTAssertEqual(platform_view.frame.origin.x, 0);
154 XCTAssertEqual(platform_view.frame.origin.y, 0);
155 XCTAssertEqual(platform_view.frame.size.width, 250);
156 XCTAssertEqual(platform_view.frame.size.height, 250);
157
158 XCUIElement* overlay1 = app.otherElements[@"platform_view[0].overlay[0]"];
159 XCTAssertTrue(overlay1.exists);
160 XCTAssertEqual(overlay1.frame.origin.x, 75);
161 XCTAssertEqual(overlay1.frame.origin.y, 150);
162 XCTAssertEqual(overlay1.frame.size.width, 150);
163 XCTAssertEqual(overlay1.frame.size.height, 100);
164
165 // There are three non overlapping rects above platform view, which
166 // FlutterPlatformViewsController merges into one.
167 XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[1]"].exists);
168
169 XCUIElement* overlayView0 = app.otherElements[@"platform_view[0].overlay_view[0]"];
170 XCTAssertTrue(overlayView0.exists);
171 // Overlay should always be the same frame as the app.
172 XCTAssertEqualWithAccuracy(overlayView0.frame.origin.x, app.frame.origin.x, kCompareAccuracy);
173 XCTAssertEqualWithAccuracy(overlayView0.frame.origin.y, app.frame.origin.x, kCompareAccuracy);
174 XCTAssertEqualWithAccuracy(overlayView0.frame.size.width, app.frame.size.width, kCompareAccuracy);
175 XCTAssertEqualWithAccuracy(overlayView0.frame.size.height, app.frame.size.height,
177}
178
179// A is the layer, which z index is higher than the platform view.
180// +--------+
181// | PV | +---+
182// +--------+ | A |
183// +--------+ +---+
184// | PV |
185// +--------+
187 XCUIApplication* app = [[XCUIApplication alloc] init];
188 app.launchArguments = @[ @"--platform-view-multiple-without-overlays" ];
189 [app launch];
190
191 XCUIElement* platform_view1 = app.otherElements[@"platform_view[0]"];
192 XCTAssertTrue([platform_view1 waitForExistenceWithTimeout:1.0]);
193 XCTAssertEqual(platform_view1.frame.origin.x, 0);
194 XCTAssertEqual(platform_view1.frame.origin.y, 300);
195 XCTAssertEqual(platform_view1.frame.size.width, 250);
196 XCTAssertEqual(platform_view1.frame.size.height, 250);
197
198 XCUIElement* platform_view2 = app.otherElements[@"platform_view[1]"];
199 XCTAssertTrue(platform_view2.exists);
200 XCTAssertEqual(platform_view2.frame.origin.x, 0);
201 XCTAssertEqual(platform_view2.frame.origin.y, 0);
202 XCTAssertEqual(platform_view2.frame.size.width, 250);
203 XCTAssertEqual(platform_view2.frame.size.height, 250);
204
205 XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[0]"].exists);
206 XCTAssertFalse(app.otherElements[@"platform_view[1].overlay[0]"].exists);
207 XCTAssertFalse(app.otherElements[@"platform_view[0].overlay_view[0]"].exists);
208 XCTAssertFalse(app.otherElements[@"platform_view[1].overlay_view[0]"].exists);
209}
210
211// A is the layer above both platform view.
212// +------------+
213// | PV +----+ |
214// +-----| A |-+
215// +-----| |-+
216// | PV +----+ |
217// +------------+
219 XCUIApplication* app = [[XCUIApplication alloc] init];
220 app.launchArguments = @[ @"--platform-view-multiple-background-foreground" ];
221 [app launch];
222
223 XCUIElement* platform_view1 = app.otherElements[@"platform_view[0]"];
224 XCTAssertTrue([platform_view1 waitForExistenceWithTimeout:1.0]);
225 XCTAssertEqual(platform_view1.frame.origin.x, 25);
226 XCTAssertEqual(platform_view1.frame.origin.y, 300);
227 XCTAssertEqual(platform_view1.frame.size.width, 250);
228 XCTAssertEqual(platform_view1.frame.size.height, 250);
229
230 XCUIElement* platform_view2 = app.otherElements[@"platform_view[1]"];
231 XCTAssertTrue(platform_view2.exists);
232 XCTAssertEqual(platform_view2.frame.origin.x, 25);
233 XCTAssertEqual(platform_view2.frame.origin.y, 0);
234 XCTAssertEqual(platform_view2.frame.size.width, 250);
235 XCTAssertEqual(platform_view2.frame.size.height, 250);
236
237 XCUIElement* overlay1 = app.otherElements[@"platform_view[0].overlay[0]"];
238 XCTAssertTrue(overlay1.exists);
239 XCTAssertEqual(overlay1.frame.origin.x, 25);
240 XCTAssertEqual(overlay1.frame.origin.y, 300);
241 XCTAssertEqual(overlay1.frame.size.width, 225);
242 XCTAssertEqual(overlay1.frame.size.height, 200);
243
244 XCUIElement* overlay2 = app.otherElements[@"platform_view[1].overlay[0]"];
245 XCTAssertTrue(overlay2.exists);
246 XCTAssertEqual(overlay2.frame.origin.x, 25);
247 XCTAssertEqual(overlay2.frame.origin.y, 0);
248 XCTAssertEqual(overlay2.frame.size.width, 225);
249 XCTAssertEqual(overlay2.frame.size.height, 250);
250
251 XCUIElement* overlayView0 = app.otherElements[@"platform_view[0].overlay_view[0]"];
252 XCTAssertTrue(overlayView0.exists);
253 // Overlay should always be the same frame as the app.
254 XCTAssertEqualWithAccuracy(overlayView0.frame.origin.x, app.frame.origin.x, kCompareAccuracy);
255 XCTAssertEqualWithAccuracy(overlayView0.frame.origin.y, app.frame.origin.x, kCompareAccuracy);
256 XCTAssertEqualWithAccuracy(overlayView0.frame.size.width, app.frame.size.width, kCompareAccuracy);
257 XCTAssertEqualWithAccuracy(overlayView0.frame.size.height, app.frame.size.height,
259
260 XCUIElement* overlayView1 = app.otherElements[@"platform_view[1].overlay_view[0]"];
261 XCTAssertTrue(overlayView1.exists);
262 // Overlay should always be the same frame as the app.
263 XCTAssertEqualWithAccuracy(overlayView1.frame.origin.x, app.frame.origin.x, kCompareAccuracy);
264 XCTAssertEqualWithAccuracy(overlayView1.frame.origin.y, app.frame.origin.x, kCompareAccuracy);
265 XCTAssertEqualWithAccuracy(overlayView1.frame.size.width, app.frame.size.width, kCompareAccuracy);
266 XCTAssertEqualWithAccuracy(overlayView1.frame.size.height, app.frame.size.height,
268}
269
270// More then two overlays are merged into a single layer.
271// +---------------------+
272// | +---+ +---+ +---+ |
273// | | A | | B | | C | |
274// | +---+ +---+ +---+ |
275// | +-------+ |
276// +-| D |-----------+
277// +-------+
279 XCUIApplication* app = [[XCUIApplication alloc] init];
280 app.launchArguments = @[ @"--platform-view-max-overlays" ];
281 [app launch];
282
283 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
284 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
285 XCTAssertEqual(platform_view.frame.origin.x, 0);
286 XCTAssertEqual(platform_view.frame.origin.y, 0);
287 XCTAssertEqual(platform_view.frame.size.width, 250);
288 XCTAssertEqual(platform_view.frame.size.height, 250);
289
290 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
291 XCTAssertTrue(overlay.exists);
292 XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[1]"].exists);
293 XCTAssertTrue(CGRectContainsRect(platform_view.frame, overlay.frame));
294
295 XCUIElement* overlayView0 = app.otherElements[@"platform_view[0].overlay_view[0]"];
296 XCTAssertTrue(overlayView0.exists);
297 // Overlay should always be the same frame as the app.
298 XCTAssertEqualWithAccuracy(overlayView0.frame.origin.x, app.frame.origin.x, kCompareAccuracy);
299 XCTAssertEqualWithAccuracy(overlayView0.frame.origin.y, app.frame.origin.x, kCompareAccuracy);
300 XCTAssertEqualWithAccuracy(overlayView0.frame.size.width, app.frame.size.width, kCompareAccuracy);
301 XCTAssertEqualWithAccuracy(overlayView0.frame.size.height, app.frame.size.height,
303
304 XCUIElement* overlayView1 = app.otherElements[@"platform_view[0].overlay_view[1]"];
305 XCTAssertFalse(overlayView1.exists);
306}
307
308// Platform view surrounded by adjacent layers on each side should not create any overlays.
309// +----+
310// | B |
311// +---+----+---+
312// | A | PV | C |
313// +---+----+---+
314// | D |
315// +----+
317 XCUIApplication* app = [[XCUIApplication alloc] init];
318 app.launchArguments = @[ @"--platform-view-surrounding-layers-fractional-coordinate" ];
319 [app launch];
320
321 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
322 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
323
324 CGFloat scale = [UIScreen mainScreen].scale;
325 XCTAssertEqual(platform_view.frame.origin.x * scale, 100.5);
326 XCTAssertEqual(platform_view.frame.origin.y * scale, 100.5);
327 XCTAssertEqual(platform_view.frame.size.width * scale, 100);
328 XCTAssertEqual(platform_view.frame.size.height * scale, 100);
329
330 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
331 XCTAssertFalse(overlay.exists);
332}
333
334// Platform view partially intersect with a layer in fractional coordinate.
335// +-------+
336// | |
337// | PV +--+--+
338// | | |
339// +----+ A |
340// | |
341// +-----+
343 XCUIApplication* app = [[XCUIApplication alloc] init];
344 app.launchArguments = @[ @"--platform-view-partial-intersection-fractional-coordinate" ];
345 [app launch];
346
347 XCUIElement* platform_view = app.otherElements[@"platform_view[0]"];
348 XCTAssertTrue([platform_view waitForExistenceWithTimeout:1.0]);
349
350 CGFloat scale = [UIScreen mainScreen].scale;
351 XCTAssertEqual(platform_view.frame.origin.x * scale, 0.5);
352 XCTAssertEqual(platform_view.frame.origin.y * scale, 0.5);
353 XCTAssertEqual(platform_view.frame.size.width * scale, 100);
354 XCTAssertEqual(platform_view.frame.size.height * scale, 100);
355
356 XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
357 XCTAssert(overlay.exists);
358
359 // We want to make sure the overlay covers the edge (which is at 100.5).
360 XCTAssertEqual(CGRectGetMaxX(overlay.frame) * scale, 101);
361 XCTAssertEqual(CGRectGetMaxY(overlay.frame) * scale, 101);
362}
363@end
std::unique_ptr< flutter::PlatformViewIOS > platform_view
static const CGFloat kCompareAccuracy
const Scalar scale