Skip to content

Commit 92ef71f

Browse files
Merge pull request #2155 from DataDog/maxep/RUM-7484/swiftui-placeholder
RUM-7484 Add placeholder for unknown SwiftUI content Co-authored-by: maxep <maxime.epain@datadoghq.com>
2 parents 5a49e0f + 3780aec commit 92ef71f

File tree

4 files changed

+74
-6
lines changed

4 files changed

+74
-6
lines changed

Datadog/Datadog.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@
799799
D20FD9D12ACC02F9004D3569 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; };
800800
D20FD9D32ACC08D1004D3569 /* WebKitMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FD9D22ACC08D1004D3569 /* WebKitMocks.swift */; };
801801
D20FD9D62ACC0934004D3569 /* WebLogIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FD9D52ACC0934004D3569 /* WebLogIntegrationTests.swift */; };
802+
D21331C12D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21331C02D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift */; };
802803
D214DA8129DF2D5E004D0AE8 /* CrashReportingPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61DE333525C8278A008E3EC2 /* CrashReportingPlugin.swift */; };
803804
D214DA8229DF2D5E004D0AE8 /* CrashReportingPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61DE333525C8278A008E3EC2 /* CrashReportingPlugin.swift */; };
804805
D214DA8329DF2D5E004D0AE8 /* CrashReporting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6161247825CA9CA6009901BE /* CrashReporting.swift */; };
@@ -2869,6 +2870,7 @@
28692870
D20FD9CE2AC6FF42004D3569 /* WebViewLogReceiverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewLogReceiverTests.swift; sourceTree = "<group>"; };
28702871
D20FD9D22ACC08D1004D3569 /* WebKitMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebKitMocks.swift; sourceTree = "<group>"; };
28712872
D20FD9D52ACC0934004D3569 /* WebLogIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebLogIntegrationTests.swift; sourceTree = "<group>"; };
2873+
D21331C02D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIWireframesBuilderTests.swift; sourceTree = "<group>"; };
28722874
D213532F270CA722000315AD /* DataCompressionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataCompressionTests.swift; sourceTree = "<group>"; };
28732875
D214DAA429E072D7004D0AE8 /* MessageBus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBus.swift; sourceTree = "<group>"; };
28742876
D214DAA729E54CB4004D0AE8 /* TelemetryReceiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryReceiver.swift; sourceTree = "<group>"; };
@@ -5733,6 +5735,7 @@
57335735
960B26BA2D03541900D7196F /* SwiftUI */ = {
57345736
isa = PBXGroup;
57355737
children = (
5738+
D21331C02D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift */,
57365739
962D72C42CF7806300F86EF0 /* GraphicsImageReflectionTests.swift */,
57375740
96867B982D08826B004AE0BC /* TextReflectionTests.swift */,
57385741
96867B9A2D0883DD004AE0BC /* ColorReflectionTests.swift */,
@@ -8606,6 +8609,7 @@
86068609
61054FC72A6EE1BA00AAA894 /* SRDataModelsMocks.swift in Sources */,
86078610
D218B0482D072CF300E3F82C /* SessionReplayTelemetryTests.swift in Sources */,
86088611
61054FC82A6EE1BA00AAA894 /* SnapshotProcessorSpy.swift in Sources */,
8612+
D21331C12D132F0600E4A6A1 /* SwiftUIWireframesBuilderTests.swift in Sources */,
86098613
A74A72872B10CE4100771FEB /* ResourceMocks.swift in Sources */,
86108614
61054FA42A6EE1BA00AAA894 /* DiffTests.swift in Sources */,
86118615
61054FA02A6EE1BA00AAA894 /* SRCompressionTests.swift in Sources */,

DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/SwiftUI/SwiftUIWireframesBuilder.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ internal struct SwiftUIWireframesBuilder: NodeWireframesBuilder {
173173
case .platformView:
174174
return nil // Should be recorder by UIKit recorder
175175
case .unknown:
176-
return nil // Need a placeholder
176+
return context.builder.createPlaceholderWireframe(
177+
id: Int64(content.seed.value),
178+
frame: context.convert(frame: item.frame),
179+
clip: context.clip,
180+
label: "Unsupported SwiftUI component"
181+
)
177182
}
178183
}
179184
}

DatadogSessionReplay/Sources/Utilities/Reflector.swift

+7-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ internal struct Reflector {
2626

2727
/// A `Lazy` reflection allows reflecting the subject at a later time.
2828
struct Lazy<T> where T: Reflection {
29-
private let reflector: Reflector
29+
/// Relect to the type `T`.
30+
let reflect: () throws -> T
3031
}
3132

3233
private let mirror: ReflectionMirror
@@ -293,11 +294,12 @@ extension Reflection {
293294

294295
extension Reflector.Lazy: Reflection {
295296
init(from reflector: Reflector) throws {
296-
self.reflector = reflector
297+
reflect = { try T(from: reflector) }
297298
}
299+
}
298300

299-
/// Relect to the type `T`.
300-
func reflect() throws -> T {
301-
try T(from: reflector)
301+
extension Reflector.Lazy {
302+
init(_ reflection: T) {
303+
reflect = { reflection }
302304
}
303305
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2019-Present Datadog, Inc.
5+
*/
6+
7+
import XCTest
8+
9+
#if os(iOS)
10+
import XCTest
11+
import SwiftUI
12+
import DatadogInternal
13+
import TestUtilities
14+
15+
@_spi(Internal)
16+
@testable import DatadogSessionReplay
17+
18+
@available(iOS 13.0, tvOS 13.0, *)
19+
class SwiftUIWireframesBuilderTests: XCTestCase {
20+
func testDisplayListWithUnknownContent_itReturnsAPlaceholder() throws {
21+
// Given
22+
// - DisplayList with unknown content
23+
let renderer = DisplayList.ViewUpdater(
24+
viewCache: DisplayList.ViewUpdater.ViewCache(map: [:]),
25+
lastList: DisplayList.Lazy(
26+
DisplayList(items: [
27+
DisplayList.Item(
28+
identity: DisplayList.Identity(value: .mockRandom()),
29+
frame: .mockAny(),
30+
value: .content(DisplayList.Content(
31+
seed: DisplayList.Seed(value: .mockRandom()),
32+
value: .unknown
33+
))
34+
)
35+
])
36+
)
37+
)
38+
39+
let builder = SwiftUIWireframesBuilder(
40+
wireframeID: .mockRandom(),
41+
renderer: renderer,
42+
textObfuscator: TextObfuscatorMock(),
43+
fontScalingEnabled: true,
44+
imagePrivacyLevel: .maskNone,
45+
attributes: .mockRandom()
46+
)
47+
48+
// When
49+
let wireframes = builder.buildWireframes(with: WireframesBuilder())
50+
51+
// Then
52+
let wireframe = try XCTUnwrap(wireframes.last?.placeholderWireframe)
53+
XCTAssertEqual(wireframe.label, "Unsupported SwiftUI component")
54+
}
55+
}
56+
57+
#endif

0 commit comments

Comments
 (0)