diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c09c0fdd716..54ce5359355 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -66,7 +66,7 @@ jobs: raw-test-output.log unit-tests: - name: Unit ${{matrix.platform}} - Xcode ${{matrix.xcode}} - OS ${{matrix.test-destination-os}} + name: Unit ${{matrix.platform}} - Xcode ${{matrix.xcode}} - OS ${{matrix.test-destination-os}} ${{matrix.scheme}} runs-on: ${{matrix.runs-on}} timeout-minutes: 20 needs: build-test-server @@ -137,6 +137,14 @@ jobs: platform: "tvOS" xcode: "15.4" test-destination-os: "17.5" + + # iOS 17 + - runs-on: macos-14 + platform: "iOS" + xcode: "15.4" + test-destination-os: "17.2" + device: "iPhone 15" + scheme: "SentrySwiftUI" # tvOS 18 - runs-on: macos-15 @@ -168,14 +176,14 @@ jobs: # We split building and running tests in two steps so we know how long running the tests takes. - name: Build tests id: build_tests - run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME build-for-testing "${{matrix.device}}" TestCI + run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME build-for-testing "${{matrix.device}}" TestCI ${{matrix.scheme}} - name: Run tests # We call a script with the platform so the destination # passed to xcodebuild doesn't end up in the job name, # because GitHub Actions don't provide an easy way of # manipulating string in expressions. - run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME test-without-building "${{matrix.device}}" TestCI + run: ./scripts/xcode-test.sh ${{matrix.platform}} ${{matrix.test-destination-os}} $GITHUB_REF_NAME test-without-building "${{matrix.device}}" TestCI ${{matrix.scheme}} - name: Slowest Tests if: ${{ always() }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7932596db..f0065329a2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- SwiftUI time for initial display and time for full display (#4596) + ### Improvements - Improve compiler error message for missing Swift declarations due to APPLICATION_EXTENSION_API_ONLY (#4603) @@ -47,7 +51,6 @@ - Load integration from same binary (#4541) - Masking for fast animations #4574 - ### Improvements - impr: Speed up getBinaryImages V2 (#4539). Follow up on (#4435) diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI-UITests/LaunchUITests.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI-UITests/LaunchUITests.swift index 6b45f4a3dc1..822fa607e57 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI-UITests/LaunchUITests.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI-UITests/LaunchUITests.swift @@ -38,4 +38,12 @@ class LaunchUITests: XCTestCase { formScreenNavigationBar/*@START_MENU_TOKEN@*/.buttons["Test"]/*[[".otherElements[\"Test\"].buttons[\"Test\"]",".buttons[\"Test\"]"],[[[-1,1],[-1,0]]],[0]]@END_MENU_TOKEN@*/.tap() XCTAssertEqual(app.staticTexts["SPAN_ID"].label, "NO SPAN") } + + func testTTID_TTFD() { + let app = XCUIApplication() + app.launch() + app.buttons["Show TTD"].tap() + + XCTAssertEqual(app.staticTexts["TTDInfo"].label, "TTID and TTFD found") + } } diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI.xcodeproj/project.pbxproj b/Samples/iOS-SwiftUI/iOS-SwiftUI.xcodeproj/project.pbxproj index 1d1ef792ba6..3f480ed0958 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI.xcodeproj/project.pbxproj +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ D8199DCE29376FD90074249E /* SentrySwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D8BBD38B2901AE400011F850 /* SentrySwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D832FAF02982A908007A9A5F /* FormScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D832FAEF2982A908007A9A5F /* FormScreen.swift */; }; D85388D12980222500B63908 /* UIKitScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85388D02980222500B63908 /* UIKitScreen.swift */; }; + D8F0F3C02D0068A100826CE3 /* SentrySwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8BBD38B2901AE400011F850 /* SentrySwiftUI.framework */; }; + D8F0F3C12D0068A100826CE3 /* SentrySwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D8BBD38B2901AE400011F850 /* SentrySwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -108,6 +110,13 @@ remoteGlobalIDString = 63AA76651EB8CB2F00D153DE; remoteInfo = SentryTests; }; + D833D61A2D13216300961E7A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 84D4FEA828ECD52700EDAAFE /* Sentry.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = D833D60D2D1320B500961E7A; + remoteInfo = SentrySwiftUITests; + }; D8BBD38A2901AE400011F850 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 84D4FEA828ECD52700EDAAFE /* Sentry.xcodeproj */; @@ -130,6 +139,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + D8F0F3C22D0068A100826CE3 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + D8F0F3C12D0068A100826CE3 /* SentrySwiftUI.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -166,6 +186,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D8F0F3C02D0068A100826CE3 /* SentrySwiftUI.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -190,6 +211,7 @@ 8425DE232B52241000113FEF /* SentryProfilerTests.xctest */, 8425DE252B52241000113FEF /* libSentryTestUtils.a */, 8425DE272B52241000113FEF /* SentryTestUtilsDynamic.framework */, + D833D61B2D13216300961E7A /* libSentrySwiftUITests.a */, ); name = Products; sourceTree = ""; @@ -306,6 +328,7 @@ 7B64385326A6C0A6000D0F65 /* Sources */, 7B64385426A6C0A6000D0F65 /* Frameworks */, 7B64385526A6C0A6000D0F65 /* Resources */, + D8F0F3C22D0068A100826CE3 /* Embed Frameworks */, ); buildRules = ( ); @@ -462,6 +485,13 @@ remoteRef = 84D4FEB328ECD52E00EDAAFE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + D833D61B2D13216300961E7A /* libSentrySwiftUITests.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libSentrySwiftUITests.a; + remoteRef = D833D61A2D13216300961E7A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; D8BBD38B2901AE400011F850 /* SentrySwiftUI.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift index be7b0b0f7ff..1cf4df2a620 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift @@ -15,6 +15,8 @@ class DataBag { struct ContentView: View { + @State var TTDInfo: String = "" + var addBreadcrumbAction: () -> Void = { let crumb = Breadcrumb(level: SentryLevel.info, category: "Debug") crumb.message = "tapped addBreadcrumb" @@ -89,12 +91,34 @@ struct ContentView: View { } } + func showTTD() { + guard let tracer = getCurrentTracer() else { return } + + var log = [String]() + + if !hasTTID(tracer: tracer) { log.append("TTID not found") } + if !hasTTFD(tracer: tracer) { log.append("TTFD not found") } + + if log.isEmpty { + log.append("TTID and TTFD found") + } + TTDInfo = log.joined(separator: "\n") + } + func getCurrentTracer() -> SentryTracer? { if DataBag.shared.info["initialTransaction"] == nil { DataBag.shared.info["initialTransaction"] = SentrySDK.span as? SentryTracer } return DataBag.shared.info["initialTransaction"] as? SentryTracer } + + func hasTTID(tracer: SentryTracer?) -> Bool { + tracer?.children.contains { $0.spanDescription?.contains("initial display") == true } == true + } + + func hasTTFD(tracer: SentryTracer?) -> Bool { + tracer?.children.contains { $0.spanDescription?.contains("full display") == true } == true + } func getCurrentSpan() -> Span? { @@ -113,14 +137,14 @@ struct ContentView: View { return DataBag.shared.info["lastSpan"] as? Span } - + var body: some View { - return SentryTracedView("Content View Body") { - NavigationView { + return SentryTracedView("Content View Body", waitForFullDisplay: true) { NavigationView { VStack(alignment: HorizontalAlignment.center, spacing: 16) { Group { Text(getCurrentTracer()?.transactionContext.name ?? "NO SPAN") .accessibilityIdentifier("TRANSACTION_NAME") + Text(getCurrentTracer()?.transactionContext.spanId.sentrySpanIdString ?? "NO ID") .accessibilityIdentifier("TRANSACTION_ID") .sentryReplayMask() @@ -128,6 +152,9 @@ struct ContentView: View { Text(getCurrentTracer()?.transactionContext.origin ?? "NO ORIGIN") .accessibilityIdentifier("TRACE_ORIGIN") }.sentryReplayUnmask() + .onAppear { + SentrySDK.reportFullyDisplayed() + } SentryTracedView("Child Span") { VStack { Text(getCurrentSpan()?.spanDescription ?? "NO SPAN") @@ -165,6 +192,9 @@ struct ContentView: View { Button(action: captureTransactionAction) { Text("Capture Transaction") } + Button(action: showTTD) { + Text("Show TTD") + } } VStack(spacing: 16) { Button(action: { @@ -204,8 +234,11 @@ struct ContentView: View { .background(Color.white) } SecondView() + + Text(TTDInfo) + .accessibilityIdentifier("TTDInfo") } - } + } } } } diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 461568e8703..96f6768f258 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -818,6 +818,11 @@ D82915632C85EF0C00A6CDD4 /* SentryViewPhotographerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82915622C85EF0C00A6CDD4 /* SentryViewPhotographerTests.swift */; }; D8292D7D2A39A027009872F7 /* UrlSanitizedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8292D7C2A39A027009872F7 /* UrlSanitizedTests.swift */; }; D82DD1CD2BEEB1A0001AB556 /* SentrySRDefaultBreadcrumbConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D82DD1CC2BEEB1A0001AB556 /* SentrySRDefaultBreadcrumbConverterTests.swift */; }; + D833D72A2D1321C100961E7A /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 630C01951EC341D600C52CEF /* Resources */; }; + D833D73B2D1321FF00961E7A /* SentryRedactModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D833D6152D13215900961E7A /* SentryRedactModifierTests.swift */; }; + D833D73C2D13220500961E7A /* SentryTraceViewModelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D833D6162D13215900961E7A /* SentryTraceViewModelTest.swift */; }; + D833D7512D13263800961E7A /* SentrySwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; }; + D833D7522D13263800961E7A /* SentrySwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D833D57C2D10784800961E7A /* SentryRRWebOptionsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D833D57B2D10783D00961E7A /* SentryRRWebOptionsEvent.swift */; }; D8370B6A273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m in Sources */ = {isa = PBXBuildFile; fileRef = D8370B68273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m */; }; D8370B6C273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h in Headers */ = {isa = PBXBuildFile; fileRef = D8370B6B273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h */; }; @@ -837,9 +842,6 @@ D84F833E2A1CC401005828E0 /* SentrySwiftAsyncIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = D84F833C2A1CC401005828E0 /* SentrySwiftAsyncIntegration.m */; }; D851527F2C9971020070F669 /* SentryStringUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = D851527E2C9971020070F669 /* SentryStringUtils.h */; }; D85152832C997A280070F669 /* SentryStringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85152822C997A1F0070F669 /* SentryStringUtils.swift */; }; - D85153002CA2B5F60070F669 /* SentrySwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; }; - D85153012CA2B5F60070F669 /* SentrySwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D851530C2CA2B7B00070F669 /* SentryRedactModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D851530B2CA2B7A30070F669 /* SentryRedactModifierTests.swift */; }; D85596F3280580F10041FF8B /* SentryScreenshotIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = D85596F1280580F10041FF8B /* SentryScreenshotIntegration.m */; }; D855AD62286ED6A4002573E1 /* SentryCrashTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D855AD61286ED6A4002573E1 /* SentryCrashTests.m */; }; D855B3E827D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D855B3E727D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift */; }; @@ -977,23 +979,34 @@ remoteGlobalIDString = 63AA759A1EB8AEF500D153DE; remoteInfo = Sentry; }; - D84DAD5B2B1742C1003CF120 /* PBXContainerItemProxy */ = { + D833D7382D1321F700961E7A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 6327C5CA1EB8A783004E799B /* Project object */; proxyType = 1; - remoteGlobalIDString = D84DAD4C2B17428D003CF120; - remoteInfo = SentryTestUtilsDynamic; + remoteGlobalIDString = D8199DA929376E9B0074249E; + remoteInfo = SentrySwiftUI; }; - D85153022CA2B5F60070F669 /* PBXContainerItemProxy */ = { + D84DAD5B2B1742C1003CF120 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 6327C5CA1EB8A783004E799B /* Project object */; proxyType = 1; - remoteGlobalIDString = D8199DA929376E9B0074249E; - remoteInfo = SentrySwiftUI; + remoteGlobalIDString = D84DAD4C2B17428D003CF120; + remoteInfo = SentryTestUtilsDynamic; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + D833D7532D13263800961E7A /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + D833D7522D13263800961E7A /* SentrySwiftUI.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; D84DAD5D2B1742C1003CF120 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1001,7 +1014,6 @@ dstSubfolderSpec = 10; files = ( D84DAD5A2B1742C1003CF120 /* SentryTestUtilsDynamic.framework in Embed Frameworks */, - D85153012CA2B5F60070F669 /* SentrySwiftUI.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -1904,6 +1916,10 @@ D8292D7A2A38AF04009872F7 /* HTTPHeaderSanitizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPHeaderSanitizer.swift; sourceTree = ""; }; D8292D7C2A39A027009872F7 /* UrlSanitizedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlSanitizedTests.swift; sourceTree = ""; }; D82DD1CC2BEEB1A0001AB556 /* SentrySRDefaultBreadcrumbConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySRDefaultBreadcrumbConverterTests.swift; sourceTree = ""; }; + D833D6152D13215900961E7A /* SentryRedactModifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRedactModifierTests.swift; sourceTree = ""; }; + D833D6162D13215900961E7A /* SentryTraceViewModelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryTraceViewModelTest.swift; sourceTree = ""; }; + D833D7342D1321C100961E7A /* SentrySwiftUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SentrySwiftUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D833D74D2D1323F800961E7A /* SentryTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryTests-Bridging-Header.h"; sourceTree = ""; }; D833D57B2D10783D00961E7A /* SentryRRWebOptionsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRRWebOptionsEvent.swift; sourceTree = ""; }; D8370B68273DF1E900F66E2D /* SentryNSURLSessionTaskSearch.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSURLSessionTaskSearch.m; sourceTree = ""; }; D8370B6B273DF20F00F66E2D /* SentryNSURLSessionTaskSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryNSURLSessionTaskSearch.h; path = include/SentryNSURLSessionTaskSearch.h; sourceTree = ""; }; @@ -1923,7 +1939,6 @@ D8511F722BAC8F750015E6FD /* Sentry.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = Sentry.modulemap; sourceTree = ""; }; D851527E2C9971020070F669 /* SentryStringUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryStringUtils.h; sourceTree = ""; }; D85152822C997A1F0070F669 /* SentryStringUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryStringUtils.swift; sourceTree = ""; }; - D851530B2CA2B7A30070F669 /* SentryRedactModifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRedactModifierTests.swift; sourceTree = ""; }; D85596F1280580F10041FF8B /* SentryScreenshotIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryScreenshotIntegration.m; sourceTree = ""; }; D855AD61286ED6A4002573E1 /* SentryCrashTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashTests.m; sourceTree = ""; }; D855B3E727D652AF00BCED76 /* SentryCoreDataTrackingIntegrationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCoreDataTrackingIntegrationTest.swift; sourceTree = ""; }; @@ -2064,7 +2079,6 @@ 8431F01C29B2854200D8DC56 /* libSentryTestUtils.a in Frameworks */, D84DAD592B1742C1003CF120 /* SentryTestUtilsDynamic.framework in Frameworks */, 63AA766A1EB8CB2F00D153DE /* Sentry.framework in Frameworks */, - D85153002CA2B5F60070F669 /* SentrySwiftUI.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2092,6 +2106,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D833D7252D1321C100961E7A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D833D7512D13263800961E7A /* SentrySwiftUI.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D84DAD4A2B17428D003CF120 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2341,6 +2363,7 @@ 8431EFD929B27B1100D8DC56 /* SentryProfilerTests.xctest */, 8431F00A29B284F200D8DC56 /* libSentryTestUtils.a */, D84DAD4D2B17428D003CF120 /* SentryTestUtilsDynamic.framework */, + D833D7342D1321C100961E7A /* SentrySwiftUITests.xctest */, ); name = Products; sourceTree = ""; @@ -2516,6 +2539,7 @@ 63AA75931EB8AEDB00D153DE /* SentryTests */, 8431EFDB29B27B3D00D8DC56 /* SentryProfilerTests */, D8F01DE32A125D7B008F4996 /* HybridSDKTest */, + D833D60F2D1320DF00961E7A /* SentrySwiftUITests */, ); path = Tests; sourceTree = ""; @@ -2566,7 +2590,6 @@ 7BF536D224BEF240004FA6A2 /* TestUtils */, D81FDF0F280E9FEC0045E0E4 /* Tools */, 7B6C5ED4264E62B60010D138 /* Transaction */, - D851530A2CA2B7960070F669 /* SwiftUI */, ); path = SentryTests; sourceTree = ""; @@ -3746,21 +3769,23 @@ name = Tools; sourceTree = ""; }; - D84DAD4E2B17428D003CF120 /* SentryTestUtilsDynamic */ = { + D833D60F2D1320DF00961E7A /* SentrySwiftUITests */ = { isa = PBXGroup; children = ( - D84DAD4F2B17428D003CF120 /* SentryTestUtilsDynamic.h */, - D80C990A2B0DFE410052F311 /* ExternalUIViewController.swift */, + D833D6152D13215900961E7A /* SentryRedactModifierTests.swift */, + D833D6162D13215900961E7A /* SentryTraceViewModelTest.swift */, + D833D74D2D1323F800961E7A /* SentryTests-Bridging-Header.h */, ); - path = SentryTestUtilsDynamic; + path = SentrySwiftUITests; sourceTree = ""; }; - D851530A2CA2B7960070F669 /* SwiftUI */ = { + D84DAD4E2B17428D003CF120 /* SentryTestUtilsDynamic */ = { isa = PBXGroup; children = ( - D851530B2CA2B7A30070F669 /* SentryRedactModifierTests.swift */, + D84DAD4F2B17428D003CF120 /* SentryTestUtilsDynamic.h */, + D80C990A2B0DFE410052F311 /* ExternalUIViewController.swift */, ); - path = SwiftUI; + path = SentryTestUtilsDynamic; sourceTree = ""; }; D85596EF280580BE0041FF8B /* Screenshot */ = { @@ -4371,7 +4396,6 @@ dependencies = ( 63AA766C1EB8CB2F00D153DE /* PBXTargetDependency */, D84DAD5C2B1742C1003CF120 /* PBXTargetDependency */, - D85153032CA2B5F60070F669 /* PBXTargetDependency */, ); name = SentryTests; packageProductDependencies = ( @@ -4437,6 +4461,27 @@ productReference = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; productType = "com.apple.product-type.framework"; }; + D833D61E2D1321C100961E7A /* SentrySwiftUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D833D72D2D1321C100961E7A /* Build configuration list for PBXNativeTarget "SentrySwiftUITests" */; + buildPhases = ( + D833D6232D1321C100961E7A /* Sources */, + D833D7252D1321C100961E7A /* Frameworks */, + D833D7292D1321C100961E7A /* Resources */, + D833D7532D13263800961E7A /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + D833D7392D1321F700961E7A /* PBXTargetDependency */, + ); + name = SentrySwiftUITests; + packageProductDependencies = ( + ); + productName = "Tests-iOS"; + productReference = D833D7342D1321C100961E7A /* SentrySwiftUITests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; D84DAD4C2B17428D003CF120 /* SentryTestUtilsDynamic */ = { isa = PBXNativeTarget; buildConfigurationList = D84DAD512B17428D003CF120 /* Build configuration list for PBXNativeTarget "SentryTestUtilsDynamic" */; @@ -4512,6 +4557,7 @@ 8431EECF29B27B1100D8DC56 /* SentryProfilerTests */, 8431F00929B284F200D8DC56 /* SentryTestUtils */, D84DAD4C2B17428D003CF120 /* SentryTestUtilsDynamic */, + D833D61E2D1321C100961E7A /* SentrySwiftUITests */, ); }; /* End PBXProject section */ @@ -4548,6 +4594,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D833D7292D1321C100961E7A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D833D72A2D1321C100961E7A /* Resources in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D84DAD4B2B17428D003CF120 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -5074,7 +5128,6 @@ D8AE48C12C57B1550092A2A6 /* SentryLevelTests.swift in Sources */, 63FE721820DA66EC00CDBAE8 /* TestThread.m in Sources */, 7B4D308A26FC616B00C94DE9 /* SentryHttpTransportTests.swift in Sources */, - D851530C2CA2B7B00070F669 /* SentryRedactModifierTests.swift in Sources */, 7B4E23B6251A07BD00060D68 /* SentryDispatchQueueWrapperTests.swift in Sources */, 63FE720720DA66EC00CDBAE8 /* SentryCrashReportFilter_Tests.m in Sources */, 8F73BC312B02B87E00C3CEF4 /* SentryInstallationTests.swift in Sources */, @@ -5205,6 +5258,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D833D6232D1321C100961E7A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D833D73B2D1321FF00961E7A /* SentryRedactModifierTests.swift in Sources */, + D833D73C2D13220500961E7A /* SentryTraceViewModelTest.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D84DAD492B17428D003CF120 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -5236,16 +5298,16 @@ target = 63AA759A1EB8AEF500D153DE /* Sentry */; targetProxy = D8199DC429376FC10074249E /* PBXContainerItemProxy */; }; + D833D7392D1321F700961E7A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D8199DA929376E9B0074249E /* SentrySwiftUI */; + targetProxy = D833D7382D1321F700961E7A /* PBXContainerItemProxy */; + }; D84DAD5C2B1742C1003CF120 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D84DAD4C2B17428D003CF120 /* SentryTestUtilsDynamic */; targetProxy = D84DAD5B2B1742C1003CF120 /* PBXContainerItemProxy */; }; - D85153032CA2B5F60070F669 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D8199DA929376E9B0074249E /* SentrySwiftUI */; - targetProxy = D85153022CA2B5F60070F669 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -5377,6 +5439,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)"; MODULEMAP_PRIVATE_FILE = ""; + OTHER_SWIFT_FLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -5413,6 +5476,7 @@ "@loader_path/Frameworks", ); MODULEMAP_PRIVATE_FILE = ""; + OTHER_SWIFT_FLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; USE_HEADERMAP = YES; @@ -5569,6 +5633,7 @@ "@loader_path/Frameworks", ); MODULEMAP_PRIVATE_FILE = ""; + OTHER_SWIFT_FLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -5693,6 +5758,7 @@ "@loader_path/Frameworks", ); MODULEMAP_PRIVATE_FILE = ""; + OTHER_SWIFT_FLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -5785,7 +5851,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -5847,7 +5912,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -5878,7 +5942,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -5909,7 +5972,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -5940,7 +6002,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -6168,6 +6229,7 @@ "@loader_path/Frameworks", ); MODULEMAP_PRIVATE_FILE = ""; + OTHER_SWIFT_FLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; USE_HEADERMAP = YES; @@ -6258,7 +6320,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -6394,6 +6455,7 @@ "@loader_path/Frameworks", ); MODULEMAP_PRIVATE_FILE = ""; + OTHER_SWIFT_FLAGS = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -6622,6 +6684,219 @@ }; name = Release; }; + D833D72E2D1321C100961E7A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ""; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DSENTRY_USE_UIKIT"; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.Sentry.tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SWIFT_INCLUDE_PATHS = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h"; + SWIFT_OBJC_INTEROP_MODE = objc; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 5.0; + TVOS_DEPLOYMENT_TARGET = 13.0; + }; + name = Debug; + }; + D833D72F2D1321C100961E7A /* DebugWithoutUIKit */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ""; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.Sentry.tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SWIFT_INCLUDE_PATHS = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h"; + SWIFT_OBJC_INTEROP_MODE = objc; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 5.0; + TVOS_DEPLOYMENT_TARGET = 13.0; + }; + name = DebugWithoutUIKit; + }; + D833D7302D1321C100961E7A /* Test */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ""; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DSENTRY_USE_UIKIT"; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.Sentry.tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SWIFT_INCLUDE_PATHS = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h"; + SWIFT_OBJC_INTEROP_MODE = objc; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 5.0; + TVOS_DEPLOYMENT_TARGET = 13.0; + }; + name = Test; + }; + D833D7312D1321C100961E7A /* TestCI */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ""; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DSENTRY_USE_UIKIT"; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.Sentry.tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SWIFT_INCLUDE_PATHS = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h"; + SWIFT_OBJC_INTEROP_MODE = objc; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 5.0; + TVOS_DEPLOYMENT_TARGET = 13.0; + }; + name = TestCI; + }; + D833D7322D1321C100961E7A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ""; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DSENTRY_USE_UIKIT"; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.Sentry.tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SWIFT_INCLUDE_PATHS = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h"; + SWIFT_OBJC_INTEROP_MODE = objc; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 5.0; + TVOS_DEPLOYMENT_TARGET = 13.0; + }; + name = Release; + }; + D833D7332D1321C100961E7A /* ReleaseWithoutUIKit */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63AA76AE1EB9D5CD00D153DE /* SentryTests.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = ""; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DSENTRY_USE_UIKIT"; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.Sentry.tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SWIFT_INCLUDE_PATHS = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h"; + SWIFT_OBJC_INTEROP_MODE = objc; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; + SWIFT_VERSION = 5.0; + TVOS_DEPLOYMENT_TARGET = 13.0; + }; + name = ReleaseWithoutUIKit; + }; D84DAD522B17428D003CF120 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -7025,6 +7300,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D833D72D2D1321C100961E7A /* Build configuration list for PBXNativeTarget "SentrySwiftUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D833D72E2D1321C100961E7A /* Debug */, + D833D72F2D1321C100961E7A /* DebugWithoutUIKit */, + D833D7302D1321C100961E7A /* Test */, + D833D7312D1321C100961E7A /* TestCI */, + D833D7322D1321C100961E7A /* Release */, + D833D7332D1321C100961E7A /* ReleaseWithoutUIKit */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D84DAD512B17428D003CF120 /* Build configuration list for PBXNativeTarget "SentryTestUtilsDynamic" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Sentry.xcodeproj/xcshareddata/xcschemes/SentrySwiftUI.xcscheme b/Sentry.xcodeproj/xcshareddata/xcschemes/SentrySwiftUI.xcscheme index 8ed1c486c91..cc826bfbcc0 100644 --- a/Sentry.xcodeproj/xcshareddata/xcschemes/SentrySwiftUI.xcscheme +++ b/Sentry.xcodeproj/xcshareddata/xcschemes/SentrySwiftUI.xcscheme @@ -23,11 +23,21 @@ + + + + +#if __has_include() +# import +#elif __has_include("Sentry.h") +# import "Sentry.h" +#endif + +#if TEST +# import "SentrySpan.h" +# import "SentryTracer.h" +#else +@class SentrySpan; +@interface SentryTracer : NSObject +@end +#endif + NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSInteger, SentryTransactionNameSource); @class SentrySpanId; -@protocol SentrySpan; +@class SentryDispatchQueueWrapper; typedef NS_ENUM(NSUInteger, SentrySpanStatus); @@ -56,4 +71,46 @@ typedef NS_ENUM(NSUInteger, SentrySpanStatus); @end +@interface SentryTimeToDisplayTracker : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@property (nullable, nonatomic, weak, readonly) SentrySpan *initialDisplaySpan; + +@property (nullable, nonatomic, weak, readonly) SentrySpan *fullDisplaySpan; + +@property (nonatomic, readonly) BOOL waitForFullDisplay; + +- (instancetype)initWithName:(NSString *)name + waitForFullDisplay:(BOOL)waitForFullDisplay + dispatchQueueWrapper:(SentryDispatchQueueWrapper *)dispatchQueueWrapper; + +- (instancetype)initWithName:(NSString *)name waitForFullDisplay:(BOOL)waitForFullDisplay; + +- (BOOL)startForTracer:(SentryTracer *)tracer; + +- (void)reportInitialDisplay; + +- (void)reportFullyDisplayed; + +- (void)finishSpansIfNotFinished; + +@end + +@interface SentryUIViewControllerPerformanceTracker : NSObject + +@property (nonatomic, readonly, class) SentryUIViewControllerPerformanceTracker *shared; + +- (void)reportFullyDisplayed; + +- (nullable SentryTimeToDisplayTracker *)startTimeToDisplayTrackerForScreen:(NSString *)screenName + waitForFullDisplay:(BOOL)waitForFullDisplay + tracer:(SentryTracer *)tracer; + +@end + +@interface SentrySDK () +@property (nonatomic, nullable, readonly, class) SentryOptions *options; +@end + NS_ASSUME_NONNULL_END diff --git a/Sources/SentrySwiftUI/SentryTracedView.swift b/Sources/SentrySwiftUI/SentryTracedView.swift index 97e94ea9367..8a26792493e 100644 --- a/Sources/SentrySwiftUI/SentryTracedView.swift +++ b/Sources/SentrySwiftUI/SentryTracedView.swift @@ -1,14 +1,85 @@ #if canImport(SwiftUI) + import Foundation -#if SENTRY_NO_UIKIT -import SentryWithoutUIKit -#else import Sentry -#endif +import SwiftUI + #if CARTHAGE || SWIFT_PACKAGE @_implementationOnly import SentryInternal #endif -import SwiftUI + +class SentryTraceViewModel { + private var transactionId: SpanId? + private var viewAppeared: Bool = false + private var tracker: SentryTimeToDisplayTracker? + + let name: String + let nameSource: SentryTransactionNameSource + let waitForFullDisplay: Bool + let traceOrigin = "auto.ui.swift_ui" + + init(name: String, nameSource: SentryTransactionNameSource, waitForFullDisplay: Bool) { + self.name = name + self.nameSource = nameSource + self.waitForFullDisplay = waitForFullDisplay + } + + func startSpan() -> SpanId? { + guard !viewAppeared else { return nil } + + let trace = startRootTransaction() + let name = trace != nil ? "\(name) - body" : name + return createBodySpan(name: name) + } + + private func startRootTransaction() -> SentryTracer? { + guard SentryPerformanceTracker.shared.activeSpanId() == nil else { return nil } + + let transactionId = SentryPerformanceTracker.shared.startSpan( + withName: name, + nameSource: nameSource, + operation: "ui.load", + origin: traceOrigin + ) + SentryPerformanceTracker.shared.pushActiveSpan(transactionId) + self.transactionId = transactionId + + let tracer = SentryPerformanceTracker.shared.getSpan(transactionId) as? SentryTracer +#if canImport(SwiftUI) && canImport(UIKit) && os(iOS) || os(tvOS) + if let tracer = tracer { + tracker = SentryUIViewControllerPerformanceTracker.shared.startTimeToDisplay(forScreen: name, waitForFullDisplay: waitForFullDisplay, tracer: tracer) + } +#endif + return tracer + } + + private func createBodySpan(name: String) -> SpanId { + let spanId = SentryPerformanceTracker.shared.startSpan( + withName: name, + nameSource: nameSource, + operation: "ui.load", + origin: traceOrigin + ) + SentryPerformanceTracker.shared.pushActiveSpan(spanId) + return spanId + } + + func finishSpan(_ spanId: SpanId) { + SentryPerformanceTracker.shared.popActiveSpan() + SentryPerformanceTracker.shared.finishSpan(spanId) + } + + func viewDidAppear() { + guard !viewAppeared else { return } + viewAppeared = true + tracker?.reportInitialDisplay() + + if let transactionId = transactionId { + self.finishSpan(transactionId) + SentryPerformanceTracker.shared.popActiveSpan() + } + } +} /// A control to measure the performance of your views and send the result as a transaction to Sentry.io. /// @@ -38,62 +109,56 @@ import SwiftUI /// @available(iOS 13, macOS 10.15, tvOS 13, watchOS 6.0, *) public struct SentryTracedView: View { - @State var viewAppeared = false - + @State private var viewModel: SentryTraceViewModel let content: () -> Content - let name: String - let nameSource: SentryTransactionNameSource - let traceOrigin = "auto.ui.swift_ui" - - public init(_ viewName: String? = nil, content: @escaping () -> Content) { +#if canImport(SwiftUI) && canImport(UIKit) && os(iOS) || os(tvOS) + /// Creates a view that measures the performance of its `content`. + /// + /// - Parameter viewName: The name that will be used for the span, if nil we try to get the name of the content class. + /// - Parameter waitForFullDisplay: Indicates whether this view transaction should wait for `SentrySDK.reportFullyDisplayed()` + /// in case you need to track some asyncronous task. This is ignored for any `SentryTracedView` that is child of another `SentryTracedView` + /// - Parameter content: The content that you want to track the performance + public init(_ viewName: String? = nil, waitForFullDisplay: Bool? = nil, @ViewBuilder content: @escaping () -> Content) { self.content = content - self.name = viewName ?? SentryTracedView.extractName(content: Content.self) - self.nameSource = viewName == nil ? .component : .custom + let name = viewName ?? SentryTracedView.extractName(content: Content.self) + let nameSource = viewName == nil ? SentryTransactionNameSource.component : SentryTransactionNameSource.custom + let waitforFullDisplay = waitForFullDisplay ?? SentrySDK.options?.enableTimeToFullDisplayTracing ?? false + self.viewModel = SentryTraceViewModel(name: name, nameSource: nameSource, waitForFullDisplay: waitforFullDisplay) } - +#else + /// Creates a view that measures the performance of its `content`. + /// + /// - Parameter viewName: The name that will be used for the span, if nil we try to get the name of the content class. + /// - Parameter content: The content that you want to track the performance + public init(_ viewName: String? = nil, @ViewBuilder content: @escaping () -> Content) { + self.content = content + let name = viewName ?? SentryTracedView.extractName(content: Content.self) + let nameSource = viewName == nil ? SentryTransactionNameSource.component : SentryTransactionNameSource.custom + self.viewModel = SentryTraceViewModel(name: name, nameSource: nameSource, waitForFullDisplay: false) + } +#endif + private static func extractName(content: Any) -> String { var result = String(describing: content) - + if let index = result.firstIndex(of: "<") { result = String(result[result.startIndex ..< index]) } - + return result } - + public var body: some View { - if viewAppeared { - return self.content().onAppear() - } - - var transactionCreated = false - if SentryPerformanceTracker.shared.activeSpanId() == nil { - transactionCreated = true - let transactionId = SentryPerformanceTracker.shared.startSpan(withName: self.name, nameSource: nameSource, operation: "ui.load", origin: self.traceOrigin) - SentryPerformanceTracker.shared.pushActiveSpan(transactionId) - - //According to Apple's documentation, the call to `body` needs to be fast - //and can be made many times in one frame. Therefore they don't use async code to process the view. - //Scheduling to finish the transaction at the end of the main loop seems the least hack solution right now. - //'onAppear' is not a suitable place to do this because it may happen before other view `body` property get called. - DispatchQueue.main.async { - SentryPerformanceTracker.shared.popActiveSpan() - SentryPerformanceTracker.shared.finishSpan(transactionId) - } - } - - let id = SentryPerformanceTracker.shared.startSpan(withName: transactionCreated ? "\(self.name) - body" : self.name, nameSource: nameSource, operation: "ui.load", origin: self.traceOrigin) - - SentryPerformanceTracker.shared.pushActiveSpan(id) + let spanId = viewModel.startSpan() + defer { - SentryPerformanceTracker.shared.popActiveSpan() - SentryPerformanceTracker.shared.finishSpan(id) - } - - return self.content().onAppear { - self.viewAppeared = true + if let spanId = spanId { + viewModel.finishSpan(spanId) + } } + + return content().onAppear(perform: viewModel.viewDidAppear) } } diff --git a/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift b/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift index 8e165de7cd9..f3ff29ec503 100644 --- a/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift +++ b/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift @@ -36,7 +36,7 @@ final class SentryAppLaunchProfilingSwiftTests: XCTestCase { let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) SentrySDK.setAppStartMeasurement(appStartMeasurement) let tracer = try fixture.newTransaction(testingAppLaunchSpans: true, automaticTransaction: true) - let ttd = SentryTimeToDisplayTracker(for: UIViewController(nibName: nil, bundle: nil), waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) + let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) ttd.start(for: tracer) ttd.reportInitialDisplay() ttd.reportFullyDisplayed() @@ -55,7 +55,7 @@ final class SentryAppLaunchProfilingSwiftTests: XCTestCase { XCTAssert(try XCTUnwrap(SentryTraceProfiler.getCurrentProfiler()).isRunning()) SentrySDK.setStart(fixture.options) - let ttd = SentryTimeToDisplayTracker(for: UIViewController(nibName: nil, bundle: nil), waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) + let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) ttd.start(for: try XCTUnwrap(sentry_launchTracer)) ttd.reportInitialDisplay() ttd.reportFullyDisplayed() @@ -76,7 +76,7 @@ final class SentryAppLaunchProfilingSwiftTests: XCTestCase { let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) SentrySDK.setAppStartMeasurement(appStartMeasurement) let tracer = try fixture.newTransaction(testingAppLaunchSpans: true, automaticTransaction: true) - let ttd = SentryTimeToDisplayTracker(for: UIViewController(nibName: nil, bundle: nil), waitForFullDisplay: false, dispatchQueueWrapper: fixture.dispatchQueueWrapper) + let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: false, dispatchQueueWrapper: fixture.dispatchQueueWrapper) ttd.start(for: tracer) ttd.reportInitialDisplay() fixture.displayLinkWrapper.call() @@ -94,7 +94,7 @@ final class SentryAppLaunchProfilingSwiftTests: XCTestCase { XCTAssert(try XCTUnwrap(SentryTraceProfiler.getCurrentProfiler()).isRunning()) SentrySDK.setStart(fixture.options) - let ttd = SentryTimeToDisplayTracker(for: UIViewController(nibName: nil, bundle: nil), waitForFullDisplay: false, dispatchQueueWrapper: fixture.dispatchQueueWrapper) + let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: false, dispatchQueueWrapper: fixture.dispatchQueueWrapper) ttd.start(for: try XCTUnwrap(sentry_launchTracer)) ttd.reportInitialDisplay() fixture.displayLinkWrapper.call() diff --git a/Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift b/Tests/SentrySwiftUITests/SentryRedactModifierTests.swift similarity index 96% rename from Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift rename to Tests/SentrySwiftUITests/SentryRedactModifierTests.swift index 48caa3246a4..62a46640a57 100644 --- a/Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift +++ b/Tests/SentrySwiftUITests/SentryRedactModifierTests.swift @@ -5,21 +5,17 @@ import SwiftUI import XCTest class SentryRedactModifierTests: XCTestCase { - func testViewMask() throws { let text = Text("Hello, World!") let redactedText = text.sentryReplayMask() - XCTAssertTrue(redactedText is ModifiedContent) } func testViewUnmask() throws { let text = Text("Hello, World!") let redactedText = text.sentryReplayUnmask() - XCTAssertTrue(redactedText is ModifiedContent) } - } #endif diff --git a/Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h b/Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h new file mode 100644 index 00000000000..a8f1ccd050f --- /dev/null +++ b/Tests/SentrySwiftUITests/SentryTests-Bridging-Header.h @@ -0,0 +1,9 @@ +#import "SentryHub+Private.h" +#import "SentryPerformanceTracker.h" +#import "SentrySDK+Private.h" +#import "SentrySDK+Tests.h" +#import "SentryTracer.h" + +@interface SentryPerformanceTracker () +- (void)clear; +@end diff --git a/Tests/SentrySwiftUITests/SentryTraceViewModelTest.swift b/Tests/SentrySwiftUITests/SentryTraceViewModelTest.swift new file mode 100644 index 00000000000..8026bf1a1fa --- /dev/null +++ b/Tests/SentrySwiftUITests/SentryTraceViewModelTest.swift @@ -0,0 +1,90 @@ +#if canImport(UIKit) && canImport(SwiftUI) +@testable import Sentry +@testable import SentrySwiftUI +import XCTest + +class SentryTraceViewModelTestCase: XCTestCase { + + override func tearDown() { + super.tearDown() + SentryPerformanceTracker.shared.clear() + } + + func testCreateTransaction() throws { + let option = Options() + SentrySDK.setCurrentHub(SentryHub(client: SentryClient(options: option), andScope: nil)) + + let viewModel = SentryTraceViewModel(name: "TestView", nameSource: .component, waitForFullDisplay: false) + let spanId = viewModel.startSpan() + + let tracer = try XCTUnwrap(SentrySDK.span as? SentryTracer) + + XCTAssertEqual(tracer.transactionContext.name, "TestView") + XCTAssertEqual(tracer.children.first?.spanId, spanId) + XCTAssertEqual(tracer.children.first?.spanDescription, "TestView - body") + } + + func testRootTransactionStarted() throws { + let option = Options() + SentrySDK.setCurrentHub(SentryHub(client: SentryClient(options: option), andScope: nil)) + + let viewModel = SentryTraceViewModel(name: "RootTransactionTest", nameSource: .component, waitForFullDisplay: true) + _ = viewModel.startSpan() + + let tracer = try XCTUnwrap(SentrySDK.span as? SentryTracer) + XCTAssertEqual(tracer.transactionContext.name, "RootTransactionTest") + XCTAssertEqual(tracer.transactionContext.operation, "ui.load") + XCTAssertEqual(tracer.transactionContext.origin, "auto.ui.swift_ui") + } + + func testNoRootTransactionForCurrentTransactionRunning() throws { + let option = Options() + SentrySDK.setCurrentHub(SentryHub(client: SentryClient(options: option), andScope: nil)) + + let testSpan = SentryPerformanceTracker.shared.startSpan(withName: "Test Root", nameSource: .component, operation: "Testing", origin: "Test") + SentryPerformanceTracker.shared.pushActiveSpan(testSpan) + + let viewModel = SentryTraceViewModel(name: "ViewContent", + nameSource: .component, + waitForFullDisplay: true) + _ = viewModel.startSpan() + + let tracer = try XCTUnwrap(SentrySDK.span as? SentryTracer) + XCTAssertEqual(tracer.transactionContext.name, "Test Root") + XCTAssertEqual(tracer.children.count, 1) + XCTAssertEqual(tracer.children.first?.spanDescription, "ViewContent") + } + + func testNoTransactionWhenViewAppeared() { + let option = Options() + SentrySDK.setCurrentHub(SentryHub(client: SentryClient(options: option), andScope: nil)) + + let viewModel = SentryTraceViewModel(name: "TestView", nameSource: .component, waitForFullDisplay: false) + viewModel.viewDidAppear() + + let spanId = viewModel.startSpan() + XCTAssertNil(spanId, "Span should not be created if the view has already appeared.") + } + + func testFinishSpan() throws { + let option = Options() + SentrySDK.setCurrentHub(SentryHub(client: SentryClient(options: option), andScope: nil)) + + let viewModel = SentryTraceViewModel(name: "FinishSpanTest", nameSource: .component, waitForFullDisplay: false) + let spanId = try XCTUnwrap(viewModel.startSpan()) + XCTAssertNotNil(spanId, "Span should be created.") + + let tracer = try XCTUnwrap(SentrySDK.span as? SentryTracer) + + viewModel.finishSpan(spanId) + viewModel.viewDidAppear() + + // Verify that the span was popped and finished + XCTAssertNil(SentryPerformanceTracker.shared.activeSpanId(), "Active span should be nil after finishing the span.") + + XCTAssertTrue(tracer.isFinished, "The transaction should be finished.") + XCTAssertTrue(tracer.children.first?.isFinished == true, "The body span should be finished") + } +} + +#endif diff --git a/Tests/SentryTests/Integrations/Performance/SentryPerformanceTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/Performance/SentryPerformanceTrackingIntegrationTests.swift index 37376eabe95..35144a884f7 100644 --- a/Tests/SentryTests/Integrations/Performance/SentryPerformanceTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/Performance/SentryPerformanceTrackingIntegrationTests.swift @@ -74,7 +74,7 @@ class SentryPerformanceTrackingIntegrationTests: XCTestCase { options.enableTimeToFullDisplayTracing = true sut.install(with: options) - XCTAssertTrue(SentryUIViewControllerPerformanceTracker.shared.enableWaitForFullDisplay) + XCTAssertTrue(SentryUIViewControllerPerformanceTracker.shared.alwaysWaitForFullDisplay) } func testConfigure_dontWaitForDisplay() { @@ -85,7 +85,7 @@ class SentryPerformanceTrackingIntegrationTests: XCTestCase { options.enableTimeToFullDisplayTracing = false sut.install(with: options) - XCTAssertFalse(SentryUIViewControllerPerformanceTracker.shared.enableWaitForFullDisplay) + XCTAssertFalse(SentryUIViewControllerPerformanceTracker.shared.alwaysWaitForFullDisplay) } #endif diff --git a/Tests/SentryTests/Integrations/Performance/UIViewController/SentryTimeToDisplayTrackerTest.swift b/Tests/SentryTests/Integrations/Performance/UIViewController/SentryTimeToDisplayTrackerTest.swift index 077bf7479f4..865e5e45599 100644 --- a/Tests/SentryTests/Integrations/Performance/UIViewController/SentryTimeToDisplayTrackerTest.swift +++ b/Tests/SentryTests/Integrations/Performance/UIViewController/SentryTimeToDisplayTrackerTest.swift @@ -21,8 +21,8 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { framesTracker.start() } - func getSut(for controller: UIViewController, waitForFullDisplay: Bool) -> SentryTimeToDisplayTracker { - return SentryTimeToDisplayTracker(for: controller, waitForFullDisplay: waitForFullDisplay, dispatchQueueWrapper: SentryDispatchQueueWrapper()) + func getSut(name: String, waitForFullDisplay: Bool) -> SentryTimeToDisplayTracker { + return SentryTimeToDisplayTracker(name: name, waitForFullDisplay: waitForFullDisplay, dispatchQueueWrapper: SentryDispatchQueueWrapper()) } func getTracer() throws -> SentryTracer { @@ -52,7 +52,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testNoSpansCreated_WhenFramesTrackerNotRunning() throws { fixture.framesTracker.stop() - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: false) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: false) fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 7)) let tracer = try fixture.getTracer() @@ -67,7 +67,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { } func testReportInitialDisplay_notWaitingForFullDisplay() throws { - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: false) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: false) fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 7)) let tracer = try fixture.getTracer() @@ -101,7 +101,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testReportInitialDisplay_waitForFullDisplay() throws { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 7)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -130,7 +130,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { } func testReportFullDisplay_notWaitingForFullDisplay() throws { - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: false) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: false) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -150,7 +150,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testReportFullDisplay_waitingForFullDisplay() throws { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 9)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -184,7 +184,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testWaitingForFullDisplay_ReportFullDisplayBeforeInitialDisplay() throws { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 9)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -224,7 +224,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { } func testTracerFinishesBeforeReportInitialDisplay_FinishesInitialDisplaySpan() throws { - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: false) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: false) fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 7)) let tracer = try fixture.getTracer() @@ -254,7 +254,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 9)) fixture.dateProvider.driftTimeForEveryRead = true - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -269,7 +269,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { let tracer = try fixture.getTracer() - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) sut.start(for: tracer) @@ -305,7 +305,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testReportFullyDisplayed_GetsDispatchedOnMainQueue() { let dispatchQueueWrapper = TestSentryDispatchQueueWrapper() - let sut = SentryTimeToDisplayTracker(for: UIViewController(), waitForFullDisplay: true, dispatchQueueWrapper: dispatchQueueWrapper) + let sut = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: dispatchQueueWrapper) let invocationsBefore = dispatchQueueWrapper.blockOnMainInvocations.count sut.reportFullyDisplayed() @@ -319,7 +319,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { let tracer = try fixture.getTracer() - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: false) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: false) sut.start(for: tracer) @@ -351,7 +351,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 7)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: false) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: false) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -384,7 +384,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 7)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -416,7 +416,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testFinish_WithoutCallingReportFullyDisplayed() throws { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 9)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) @@ -451,7 +451,7 @@ class SentryTimeToDisplayTrackerTest: XCTestCase { func testFinish_WithoutTTID() throws { fixture.dateProvider.setDate(date: Date(timeIntervalSince1970: 9)) - let sut = fixture.getSut(for: UIViewController(), waitForFullDisplay: true) + let sut = fixture.getSut(name: "UIViewController", waitForFullDisplay: true) let tracer = try fixture.getTracer() sut.start(for: tracer) diff --git a/Tests/SentryTests/Integrations/Performance/UIViewController/SentryUIViewControllerPerformanceTrackerTests.swift b/Tests/SentryTests/Integrations/Performance/UIViewController/SentryUIViewControllerPerformanceTrackerTests.swift index 0358748c697..a27e04fe51e 100644 --- a/Tests/SentryTests/Integrations/Performance/UIViewController/SentryUIViewControllerPerformanceTrackerTests.swift +++ b/Tests/SentryTests/Integrations/Performance/UIViewController/SentryUIViewControllerPerformanceTrackerTests.swift @@ -356,7 +356,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { func testReportFullyDisplayed() throws { let sut = fixture.getSut() - sut.enableWaitForFullDisplay = true + sut.alwaysWaitForFullDisplay = true let viewController = fixture.viewController let tracker = fixture.tracker var tracer: SentryTracer? @@ -661,7 +661,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { var tracer: SentryTracer? - sut.enableWaitForFullDisplay = true + sut.alwaysWaitForFullDisplay = true sut.viewControllerLoadView(firstController) { tracer = self.getStack(tracker).first as? SentryTracer @@ -678,7 +678,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { var tracer: SentryTracer? - sut.enableWaitForFullDisplay = false + sut.alwaysWaitForFullDisplay = false sut.viewControllerLoadView(firstController) { tracer = self.getStack(tracker).first as? SentryTracer @@ -711,7 +711,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { func test_OnlyViewDidLoadTTFDEnabled_CreatesTTIDAndTTFDSpans() throws { let sut = fixture.getSut() - sut.enableWaitForFullDisplay = true + sut.alwaysWaitForFullDisplay = true let tracker = fixture.tracker var tracer: SentryTracer! @@ -776,7 +776,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { var firstTracer: SentryTracer? var secondTracer: SentryTracer? - sut.enableWaitForFullDisplay = true + sut.alwaysWaitForFullDisplay = true let expectedFirstTTFDStartTimestamp = fixture.dateProvider.date() @@ -823,7 +823,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { var firstTracer: SentryTracer? var secondTracer: SentryTracer? - sut.enableWaitForFullDisplay = true + sut.alwaysWaitForFullDisplay = true sut.viewControllerLoadView(firstController) { firstTracer = self.getStack(tracker).first as? SentryTracer @@ -863,7 +863,7 @@ class SentryUIViewControllerPerformanceTrackerTests: XCTestCase { var firstTracer: SentryTracer? var secondTracer: SentryTracer? - sut.enableWaitForFullDisplay = true + sut.alwaysWaitForFullDisplay = true let expectedFirstTTFDStartTimestamp = fixture.dateProvider.date() sut.viewControllerLoadView(firstController) { diff --git a/Tests/SentryTests/SentryHubTests.swift b/Tests/SentryTests/SentryHubTests.swift index 30a21d12f48..1643f77a099 100644 --- a/Tests/SentryTests/SentryHubTests.swift +++ b/Tests/SentryTests/SentryHubTests.swift @@ -893,24 +893,21 @@ class SentryHubTests: XCTestCase { #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) func test_reportFullyDisplayed_enableTimeToFullDisplay_YES() { - fixture.options.enableTimeToFullDisplayTracing = true let sut = fixture.getSut(fixture.options) - let testTTDTracker = TestTimeToDisplayTracker() + let testTTDTracker = TestTimeToDisplayTracker(waitForFullDisplay: true) Dynamic(SentryUIViewControllerPerformanceTracker.shared).currentTTDTracker = testTTDTracker sut.reportFullyDisplayed() XCTAssertTrue(testTTDTracker.registerFullDisplayCalled) - } func test_reportFullyDisplayed_enableTimeToFullDisplay_NO() { - fixture.options.enableTimeToFullDisplayTracing = false let sut = fixture.getSut(fixture.options) - let testTTDTracker = TestTimeToDisplayTracker() + let testTTDTracker = TestTimeToDisplayTracker(waitForFullDisplay: false) Dynamic(SentryUIViewControllerPerformanceTracker.shared).currentTTDTracker = testTTDTracker @@ -1189,8 +1186,8 @@ class SentryHubTests: XCTestCase { #if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) class TestTimeToDisplayTracker: SentryTimeToDisplayTracker { - init() { - super.init(for: UIViewController(), waitForFullDisplay: false, dispatchQueueWrapper: SentryDispatchQueueWrapper()) + init(waitForFullDisplay: Bool = false) { + super.init(name: "UIViewController", waitForFullDisplay: waitForFullDisplay, dispatchQueueWrapper: SentryDispatchQueueWrapper()) } var registerFullDisplayCalled = false diff --git a/Tests/SentryTests/SentrySDKTests.swift b/Tests/SentryTests/SentrySDKTests.swift index 75239a90d05..245a4f9f18e 100644 --- a/Tests/SentryTests/SentrySDKTests.swift +++ b/Tests/SentryTests/SentrySDKTests.swift @@ -688,8 +688,8 @@ class SentrySDKTests: XCTestCase { SentrySDK.start(options: fixture.options) - let testTTDTracker = TestTimeToDisplayTracker() - + let testTTDTracker = TestTimeToDisplayTracker(waitForFullDisplay: true) + Dynamic(SentryUIViewControllerPerformanceTracker.shared).currentTTDTracker = testTTDTracker SentrySDK.reportFullyDisplayed() diff --git a/scripts/xcode-test.sh b/scripts/xcode-test.sh index 0597b701d96..59e560d71ee 100755 --- a/scripts/xcode-test.sh +++ b/scripts/xcode-test.sh @@ -15,6 +15,7 @@ COMMAND="${4:-test}" DEVICE=${5:-iPhone 14} CONFIGURATION_OVERRIDE="${6:-}" DERIVED_DATA_PATH="${7:-}" +TEST_SCHEME="${8:Sentry}" case $PLATFORM in @@ -80,7 +81,7 @@ esac if [ $RUN_BUILD == true ]; then env NSUnbufferedIO=YES xcodebuild \ -workspace Sentry.xcworkspace \ - -scheme Sentry \ + -scheme "$TEST_SCHEME" \ -configuration "$CONFIGURATION" \ -destination "$DESTINATION" \ -derivedDataPath "$DERIVED_DATA_PATH" \ @@ -91,7 +92,7 @@ fi if [ $RUN_BUILD_FOR_TESTING == true ]; then env NSUnbufferedIO=YES xcodebuild \ -workspace Sentry.xcworkspace \ - -scheme Sentry \ + -scheme "$TEST_SCHEME" \ -configuration "$CONFIGURATION" \ -destination "$DESTINATION" -quiet \ build-for-testing @@ -100,7 +101,7 @@ fi if [ $RUN_TEST_WITHOUT_BUILDING == true ]; then env NSUnbufferedIO=YES && set -o pipefail && xcodebuild \ -workspace Sentry.xcworkspace \ - -scheme Sentry \ + -scheme "$TEST_SCHEME" \ -configuration "$CONFIGURATION" \ -destination "$DESTINATION" \ test-without-building |