| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| import 'package:flutter/widgets.dart'; | |
| import 'package:flutter_test/flutter_test.dart'; | |
| extension FinderExtension on Finder { | |
| // TODO(alexeyinkin): Push to Flutter or wait for them to make their own, https://github.com/flutter/flutter/issues/117675 | |
| Finder and(Finder another) { | |
| return _AndFinder(this, another); | |
| } | |
| Finder or(Finder another) { | |
| return _OrFinder(this, another); | |
| } | |
| Finder getChildrenByType(Type childType) { | |
| final finders = evaluate(); | |
| final childElements = finders | |
| .map((e) => collectAllElementsFrom(e, skipOffstage: true)) | |
| .expand((e) => e) | |
| .where((e) => e.widget.runtimeType == childType); | |
| return find.byElementPredicate( | |
| (element) => childElements.contains(element), | |
| ); | |
| } | |
| Finder horizontallyAt(int index, WidgetTester wt) => | |
| _atIndexOnAxis(index, Axis.horizontal, wt); | |
| Finder verticallyAt(int index, WidgetTester wt) => | |
| _atIndexOnAxis(index, Axis.vertical, wt); | |
| Finder _atIndexOnAxis(int index, Axis axis, WidgetTester wt) { | |
| final finders = evaluate(); | |
| if (index > finders.length - 1) { | |
| throw IndexError(index, finders); | |
| } | |
| final offsets = <_IndexAndOffset>[]; | |
| for (int i = 0; i < finders.length; i++) { | |
| offsets.add(_IndexAndOffset(i, wt.getCenter(at(i)))); | |
| } | |
| offsets.sort( | |
| (a, b) => axis == Axis.vertical | |
| ? _compareDoubles(a.offset.dy, b.offset.dy) | |
| : _compareDoubles(a.offset.dx, b.offset.dx), | |
| ); | |
| return at(offsets[index].index); | |
| } | |
| int _compareDoubles(double a, double b) { | |
| return (a - b).sign.toInt(); | |
| } | |
| } | |
| class _AndFinder extends ChainedFinder { | |
| _AndFinder(super.parent, this.another); | |
| final Finder another; | |
| @override | |
| String get description => '${parent.description} AND ${another.description}'; | |
| @override | |
| Iterable<Element> filter(Iterable<Element> parentCandidates) { | |
| return another.apply(parentCandidates); | |
| } | |
| } | |
| class _OrFinder extends ChainedFinder { | |
| _OrFinder(super.parent, this.another); | |
| final Finder another; | |
| @override | |
| String get description => '(${parent.description} OR ${another.description})'; | |
| @override | |
| Iterable<Element> filter(Iterable<Element> parentCandidates) { | |
| return {...parentCandidates, ...another.evaluate()}; | |
| } | |
| } | |
| class _IndexAndOffset { | |
| final int index; | |
| final Offset offset; | |
| _IndexAndOffset(this.index, this.offset); | |
| } |