-
Notifications
You must be signed in to change notification settings - Fork 134
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
REPLAY-1330 Support UIDatePicker
elements in SR (date & time selection)
#1204
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work really!
It's easy to follow the solution and learn about the edge cases.
Left some minor comments 🙌
@@ -439,6 +443,7 @@ | |||
INFOPLIST_KEY_UIMainStoryboardFile = Main; | |||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; | |||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; | |||
IPHONEOS_DEPLOYMENT_TARGET = 13.4; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! Is there a hard constraint on having 13.0 here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought there is some, but turned out there is not 🙂. Changed to 13.0
👍
@@ -63,6 +63,14 @@ internal class SnapshotTestCase: XCTestCase { | |||
return createSideBySideImage(appImage, wireframesImage) | |||
} | |||
|
|||
func wait(seconds: TimeInterval) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe could be a part of TestUtilities
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If only we will need it anywhere else, we can move it. I would add things to TestUtilities
only when we see opportunity - otherwise it would become bloated.
nodes = wheelsStyleRecorder.recordNodes(of: datePicker, with: attributes, in: context) | ||
} | ||
|
||
let isDisplayedInPopover: Bool = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably a style preference on my side, but it's a perfect candidate for nested function. IMO slightly more swiftly. Obviously not a blocker :)
borderColor: isDisplayedInPopover ? SystemColors.secondarySystemFill : nil, | ||
borderWidth: isDisplayedInPopover ? 1 : 0, | ||
backgroundColor: isDisplayedInPopover ? SystemColors.secondarySystemGroupedBackground : SystemColors.systemBackground, | ||
cornerRadius: 10, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe worth getting that from the layer? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't - if date picker is shown in a popover, the background comes from parent's _UIVisualEffectBackdropView
child, not the pickerView.layer
itself. Doing arbitrary parent tree traversal would be flaky and only work on certain OSes (where popover is displayed). To solve this complexity, we use 10
as approximation.
internal struct UIImageViewRecorder: NodeRecorder { | ||
internal class UIImageViewRecorder: NodeRecorder { | ||
/// An option for overriding default semantics from parent recorder. | ||
var semanticsOverride: (UIImageView, ViewAttributes) -> NodeSemantics? = { _, _ in nil } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
let className = "\(type(of: imageView))" | ||
// This gets effective on iOS 15.0+ which is the earliest version that displays some elements in popover views. | ||
// Here we explicitly ignore the "shadow" effect applied to popover. | ||
let isSystemShadow = className == "_UICutoutShadowView" | ||
return isSystemShadow ? IgnoredElement(subtreeStrategy: .ignore) : nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It almost sounds like it should be default value of the semanticsOverride
in the init.
We probably want to expand the coverage of non-essential images here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds fair 👍, moved this to default value on UIImageViewRecorder
.
What and why?
📦 This PR enhances the recording of
UIDatePicker
elements in session replay - in all modes (date, time, date & time) and all styles (compact, inline, wheels). Tested on iOS 13.7, 14.5, 15.5. Snapshots generated for 16.2:Date selection:
Time selection:
How?
At the highest level,
UIDatePickerRecorder
uses one of 3 private recorders depending on itsdatePickerStyle
:The
WheelsStyleDatePickerRecorder
usesUIPickerViewRecorder
(which is howUIKit
handles the.wheels
mode). I was able to reuse 90% of work done for picker views - but the strategy of choosing "selected labels" turned out to be flaky. I enhanced it by much better predicate that depends solely ontransform3D
and labels visibility:Other than this, I had to improve text obfuscation logic. While we want to obfuscate labels in
UIPickerViewRecorder
, according to product definition we don't want this if that recorder is ran forWheelsStyleDatePickerRecorder
subtree. What I propose in this PR is having 3 separate text obfuscators in thecontext
propagated during view-tree traversal. Parent recorders can now adjustselectionTextObfuscator
accordingly before passing it to child recorders 👌:Last, I did few changes to
SRSnapshotTests
project so it can be ran on iOS 13.4 and above. Snapshot testing is still limited to iOS 16.2, but it is possible to generate images manually for older ones.Review checklist
Custom CI job configuration (optional)