blob: 3640cb78871a806f39582bd68fe22c15ce99ac1b [file] [log] [blame]
// 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.
@TestOn('browser')
library;
import 'dart:async';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine/dom.dart';
import 'package:ui/src/engine/embedder.dart';
import 'package:ui/src/engine/pointer_binding/event_position_helper.dart';
import 'package:ui/ui.dart' as ui show Offset;
void main() {
internalBootstrapBrowserTest(() => doTests);
}
void doTests() {
ensureFlutterViewEmbedderInitialized();
late DomElement target;
late DomElement eventSource;
final StreamController<DomEvent> events = StreamController<DomEvent>.broadcast();
/// Dispatches an event `e` on `target`, and returns it after it's gone through the browser.
Future<DomPointerEvent> dispatchAndCatch(DomElement target, DomPointerEvent e) async {
final Future<DomEvent> nextEvent = events.stream.first;
target.dispatchEvent(e);
return (await nextEvent) as DomPointerEvent;
}
group('computeEventOffsetToTarget', () {
setUp(() {
target = createDomElement('div-target');
eventSource = createDomElement('div-event-source');
target.append(eventSource);
domDocument.body!.append(target);
// make containers known fixed sizes, absolutely positioned elements, so
// we can reason about screen coordinates relatively easily later!
target.style
..position = 'absolute'
..width = '320px'
..height = '240px'
..top = '0px'
..left = '0px';
eventSource.style
..position = 'absolute'
..width = '100px'
..height = '80px'
..top = '100px'
..left = '120px';
target.addEventListener('click', createDomEventListener((DomEvent e) {
events.add(e);
}));
});
tearDown(() {
target.remove();
});
test('Event dispatched by target returns offsetX, offsetY', () async {
// Fire an event contained within target...
final DomMouseEvent event = await dispatchAndCatch(target, createDomPointerEvent(
'click',
<String, Object>{
'bubbles': true,
'clientX': 10,
'clientY': 20,
}
));
expect(event.offsetX, 10);
expect(event.offsetY, 20);
final ui.Offset offset = computeEventOffsetToTarget(event, target);
expect(offset.dx, event.offsetX);
expect(offset.dy, event.offsetY);
});
test('Event dispatched on child re-computes offset (offsetX/Y invalid)', () async {
// Fire an event contained within target...
final DomMouseEvent event = await dispatchAndCatch(eventSource, createDomPointerEvent(
'click',
<String, Object>{
'bubbles': true, // So it can be caught in `target`
'clientX': 140, // x = 20px into `eventSource`.
'clientY': 110, // y = 10px into `eventSource`.
}
));
expect(event.offsetX, 20);
expect(event.offsetY, 10);
final ui.Offset offset = computeEventOffsetToTarget(event, target);
expect(offset.dx, 140);
expect(offset.dy, 110);
});
test('Event dispatched by TalkBack gets a computed offset', () async {
// Fill this in to test _computeOffsetForTalkbackEvent
}, skip: 'To be implemented!');
test('Event dispatched on text editing node computes offset with framework geometry', () async {
// Fill this in to test _computeOffsetForInputs
}, skip: 'To be implemented!');
});
}