waitUntilVisible method

Future<PatrolFinder> waitUntilVisible(
  1. Finder finder, {
  2. Duration? timeout,
  3. Alignment alignment = Alignment.center,
  4. bool enablePatrolLog = true,
})
inherited

Waits until finder finds at least one visible widget.

Throws a WaitUntilVisibleTimeoutException if more time than specified by the timeout passed and no widgets were found.

Timeout is globally set by PatrolTesterConfig.visibleTimeout inside PatrolTester.config. If you want to override this global setting, set timeout.

Provide alignment to fine tune the visibility check by calling Finder.hitTestable at this alignment of the Widget. This might be helpful in case the tested Widget is or contains a Row or a Column. The default Alignment.center might always be the best choice as the following example demonstrates:


/// This [Widget] will only be found when calling
///await $(Foo).waitUntilVisible(alignment: Alignment.topCenter)
class Foo extends StatelessWidget {
Foo({Key? key}) : super(key: key);
 @override
 Widget build(BuildContext context) {
   return const Column(
       children: [
         Text(
           'Foo',
         ),
         SizedBox(height: 48),
         Text('Bar'),
       ],
     )
 }
}

As there is an empty SizedBox in the center of the Column, calling await $(Foo).waitUntilVisible() will fail as the underlying Finder.hitTestable will not find any hit-testable widget. Changing the alignment parameter to Alignment.topCenter and calling await $(Foo).waitUntilVisible(alignment: Alignment.topCenter) will make the test pass as the underlying Finder.hitTestable will find the Text widget at the top of the Column.

Implementation

Future<PatrolFinder> waitUntilVisible(
  Finder finder, {
  Duration? timeout,
  Alignment alignment = Alignment.center,
  bool enablePatrolLog = true,
}) {
  return TestAsyncUtils.guard(
    () => wrapWithPatrolLog(
      action: 'waitUntilVisible',
      finder: finder,
      color: AnsiCodes.cyan,
      enablePatrolLog: enablePatrolLog,
      function: () async {
        final duration = timeout ?? config.visibleTimeout;
        final end = tester.binding.clock.now().add(duration);
        final hitTestableFinder = finder.hitTestable(at: alignment);
        while (hitTestableFinder.evaluate().isEmpty) {
          final now = tester.binding.clock.now();
          if (now.isAfter(end)) {
            throw WaitUntilVisibleTimeoutException(
              finder: finder,
              duration: duration,
            );
          }

          await tester.pump(const Duration(milliseconds: 100));
        }

        return PatrolFinder(finder: hitTestableFinder, tester: this);
      },
    ),
  );
}