Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Infrastructure] Fix widget tester tapping on block component (Resolves #2197) #2207

Merged
merged 1 commit into from
Aug 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions super_editor/lib/src/test/super_editor_test/supereditor_robot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 164,7 @@ extension SuperEditorRobot on WidgetTester {
/// {@macro supereditor_finder}
Future<void> tapAtDocumentPosition(DocumentPosition position, [Finder? superEditorFinder]) async {
final documentLayout = _findDocumentLayout(superEditorFinder);
final positionRectInDoc = documentLayout.getRectForPosition(position)!;
final positionRectInDoc = _getRectForDocumentPosition(position, documentLayout, superEditorFinder);
final globalTapOffset = documentLayout.getAncestorOffsetFromDocumentOffset(positionRectInDoc.center);

await tapAt(globalTapOffset);
Expand Down Expand Up @@ -436,17 436,67 @@ extension SuperEditorRobot on WidgetTester {
return textLayout.getOffsetForCaret(position) Offset(affinity == TextAffinity.upstream ? -1 : 1, 5);
}

/// Returns the bounding box around the given [position], within the associated component.
///
/// If the component is a block component, the returned [Rect] will be half of its width.
Rect _getRectForDocumentPosition(DocumentPosition position, DocumentLayout documentLayout,
[Finder? superEditorFinder]) {
final component = documentLayout.getComponentByNodeId(position.nodeId);
if (component == null) {
throw Exception('No component found for node ID: ${position.nodeId}');
}

if (component.getBeginningPosition() is UpstreamDownstreamNodePosition) {
// The component is a block component. Compute the rect manually, because
// `getRectForPosition` returns always the rect of the whole block.
// The returned rect will be half of the width of the component.
final componentBox = component.context.findRenderObject() as RenderBox;
final edge = component.getEdgeForPosition(position.nodePosition);

final positionRect = position.nodePosition == UpstreamDownstreamNodePosition.upstream()
// For upstream position, the edge is a zero width rect starting from the left.
? Rect.fromLTWH(
edge.left,
edge.top,
componentBox.size.width / 2,
componentBox.size.height,
)
// For downstream position, the edge is a zero width rect starting at the right.
// Subtract half of the width to make it start from the center.
: Rect.fromLTWH(
edge.left - componentBox.size.width / 2,
edge.top,
componentBox.size.width / 2,
componentBox.size.height,
);

// Translate the rect to global coordinates.
final documentLayoutElement = _findDocumentLayoutElement(superEditorFinder);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking that the need to access the document element isn't great. Does the DocumentLayout interface not offer any way to accomplish this goal as-is?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any method to allow that. The Rect returned by Component.getEdgeForPosition is in component space and I didn't find any other method to convert it to document space.

final docOffset = componentBox.localToGlobal(Offset.zero, ancestor: documentLayoutElement.findRenderObject());
return positionRect.translate(docOffset.dx, docOffset.dy);
}

// The component isn't a block node. Use the default implementation for getRectForPosition.
return documentLayout.getRectForPosition(position)!;
}

/// Finds and returns the [DocumentLayout] within the only [SuperEditor] in the
/// widget tree, or within the [SuperEditor] found via the optional [superEditorFinder].
DocumentLayout _findDocumentLayout([Finder? superEditorFinder]) {
final documentLayoutElement = _findDocumentLayoutElement(superEditorFinder);
return documentLayoutElement.state as DocumentLayout;
}

/// Finds and returns the document layout element within the only [SuperEditor] in the
/// widget tree, or within the [SuperEditor] found via the optional [superEditorFinder].
StatefulElement _findDocumentLayoutElement([Finder? superEditorFinder]) {
late final Finder layoutFinder;
if (superEditorFinder != null) {
layoutFinder = find.descendant(of: superEditorFinder, matching: find.byType(SingleColumnDocumentLayout));
} else {
layoutFinder = find.byType(SingleColumnDocumentLayout);
}
final documentLayoutElement = layoutFinder.evaluate().single as StatefulElement;
return documentLayoutElement.state as DocumentLayout;
return layoutFinder.evaluate().single as StatefulElement;
}

/// Finds the [GlobalKey] that's attached to the [TextComponent], which presents the
Expand Down
Loading