withDiagnosticProp<T> method

  1. @useResult
WidgetSelector<W> withDiagnosticProp<T>(
  1. String propName,
  2. MatchProp<T> match
)

Filters widgets by their DiagnosticsProperty with propName that matches match

Example usage:

spot<Container>().existsOnce()
  .withDiagnosticProp<double>('margin', (it) => it.equals(EdgeInsets.zero));

Auto-generated selectors

The official Flutter widgets already offer a lot of selectors based on their diagnostic properties. The Container example above can be written as:

spot<Container>().existsOnce().hasMargin(EdgeInsets.zero);

For non-supported Flutter widgets, use printMatchers to generate the selectors and matchers based on the existing diagnostic properties.

// print to console
spot<Container>().printMatchers();

// write the Dart file directly
spot<Container>().writeMatchersToFile(path: 'test/container.g.dart');

Implementation

@useResult
WidgetSelector<W> withDiagnosticProp<T>(
  String propName,
  MatchProp<T> match,
) {
  void condition(Subject<T?> subject) {
    subject.hideNullability().context.nest<T>(
          () => ['with prop "$propName"'],
          (value) => Extracted.value(value),
        );
    match(subject.hideNullability());
  }

  final name = describe(condition).map((it) => it.trim()).toList().join(' ');

  return whereElement(
    (element) {
      final diagnosticsNode = mapElementToWidget(element).toDiagnosticsNode();
      final DiagnosticsNode? prop = diagnosticsNode
          .getProperties()
          .firstOrNullWhere((e) => e.name == propName);

      final unconstrainedSelector =
          overrideQuantityConstraint(QuantityConstraint.unconstrained);
      final actual = prop?.value as T? ?? prop?.getDefaultValue<T>();

      void condition(Subject<T?> subject) {
        subject.context.nest<T>(
          () => [
            unconstrainedSelector.toStringBreadcrumb(),
            'with prop "$propName"',
          ],
          (value) {
            if (prop == null) {
              return Extracted.rejection(which: ['Has no prop "$propName"']);
            }
            if (value is! T) {
              return Extracted.rejection(
                which: [
                  'Has no prop "$propName" of type "$T", the type is "${prop.value.runtimeType}"',
                ],
              );
            }

            return Extracted.value(actual as T);
          },
        );
        match(subject.hideNullability());
      }

      final failure = softCheckHideNull(actual, condition);
      if (failure != null) {
        return false;
      }

      return true;
    },
    description: name,
  );
}