From 17b2be4e39f4386db2d0199c2dfbbf88c799844a Mon Sep 17 00:00:00 2001 From: Noah Martin Date: Mon, 12 Aug 2024 09:42:40 -0700 Subject: [PATCH] New preview tests (#149) --- .../DemoWatchPreviewTest.swift | 13 + .../DemoWatchSnapshotTest.swift | 13 + DemoApp/DemoApp.xcodeproj/project.pbxproj | 282 +++++++++++++++++- DemoApp/DemoAppTests/DemoAppPreviewTest.swift | 19 ++ .../DemoAppTests/DemoAppSnapshotTest.swift | 19 ++ ... => DemoAppAccessibilityPreviewTest.swift} | 9 +- ...> DemoWatchAccessibilityPreviewTest.swift} | 4 +- .../SnapshotPreviewsCore.swift | 4 +- ...t.swift => AccessibilityPreviewTest.swift} | 22 +- .../EMGPreviewBaseTest+PreviewFilters.swift | 28 ++ .../SnapshottingTests/PreviewFilters.swift | 17 ++ .../SnapshottingTests/PreviewLayoutTest.swift | 54 ++++ Sources/SnapshottingTests/SnapshotTest.swift | 72 +++++ 13 files changed, 524 insertions(+), 32 deletions(-) create mode 100644 DemoApp/Demo Watch AppTests/DemoWatchPreviewTest.swift create mode 100644 DemoApp/Demo Watch AppTests/DemoWatchSnapshotTest.swift create mode 100644 DemoApp/DemoAppTests/DemoAppPreviewTest.swift create mode 100644 DemoApp/DemoAppTests/DemoAppSnapshotTest.swift rename DemoApp/DemoAppUITests/{MyPreviewTest.swift => DemoAppAccessibilityPreviewTest.swift} (74%) rename DemoApp/DemoWatchTests/{Demo.swift => DemoWatchAccessibilityPreviewTest.swift} (62%) rename Sources/SnapshottingTests/{PreviewTest.swift => AccessibilityPreviewTest.swift} (92%) create mode 100644 Sources/SnapshottingTests/EMGPreviewBaseTest+PreviewFilters.swift create mode 100644 Sources/SnapshottingTests/PreviewFilters.swift create mode 100644 Sources/SnapshottingTests/PreviewLayoutTest.swift create mode 100644 Sources/SnapshottingTests/SnapshotTest.swift diff --git a/DemoApp/Demo Watch AppTests/DemoWatchPreviewTest.swift b/DemoApp/Demo Watch AppTests/DemoWatchPreviewTest.swift new file mode 100644 index 0000000..24376aa --- /dev/null +++ b/DemoApp/Demo Watch AppTests/DemoWatchPreviewTest.swift @@ -0,0 +1,13 @@ +// +// DemoWatchPreviewTest.swift +// Demo Watch AppTests +// +// Created by Noah Martin on 8/10/24. +// + +import XCTest +import SnapshottingTests + +final class DemoWatchPreviewTest: PreviewLayoutTest { + +} diff --git a/DemoApp/Demo Watch AppTests/DemoWatchSnapshotTest.swift b/DemoApp/Demo Watch AppTests/DemoWatchSnapshotTest.swift new file mode 100644 index 0000000..f9a5a66 --- /dev/null +++ b/DemoApp/Demo Watch AppTests/DemoWatchSnapshotTest.swift @@ -0,0 +1,13 @@ +// +// DemoWatchSnapshotTest.swift +// Demo Watch AppTests +// +// Created by Noah Martin on 8/10/24. +// + +import Foundation +import SnapshottingTests + +final class DemoWatchSnapshotTest: SnapshotTest { + +} diff --git a/DemoApp/DemoApp.xcodeproj/project.pbxproj b/DemoApp/DemoApp.xcodeproj/project.pbxproj index 712476f..ae491db 100644 --- a/DemoApp/DemoApp.xcodeproj/project.pbxproj +++ b/DemoApp/DemoApp.xcodeproj/project.pbxproj @@ -39,24 +39,30 @@ FA309EE22C38D7A900C85FF4 /* Snapshotting in Frameworks */ = {isa = PBXBuildFile; productRef = FA309EE12C38D7A900C85FF4 /* Snapshotting */; }; FA309EE32C38D7A900C85FF4 /* Snapshotting in Embed Frameworks */ = {isa = PBXBuildFile; productRef = FA309EE12C38D7A900C85FF4 /* Snapshotting */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; FA309EE62C38D7AC00C85FF4 /* SnapshottingTests in Frameworks */ = {isa = PBXBuildFile; productRef = FA309EE52C38D7AC00C85FF4 /* SnapshottingTests */; }; - FA309EE72C38EB9B00C85FF4 /* Demo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA309ED82C38D77C00C85FF4 /* Demo.swift */; }; + FA309EE72C38EB9B00C85FF4 /* DemoWatchAccessibilityPreviewTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA309ED82C38D77C00C85FF4 /* DemoWatchAccessibilityPreviewTest.swift */; }; FA309EFE2C3EF68A00C85FF4 /* PreviewGallery in Frameworks */ = {isa = PBXBuildFile; productRef = FA309EFD2C3EF68A00C85FF4 /* PreviewGallery */; }; - FA3C0DE72A620E9A00278952 /* MyPreviewTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C0DE62A620E9A00278952 /* MyPreviewTest.swift */; }; + FA3C0DE72A620E9A00278952 /* DemoAppAccessibilityPreviewTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C0DE62A620E9A00278952 /* DemoAppAccessibilityPreviewTest.swift */; }; FA40515D2A95B587007A66D4 /* EmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA40515C2A95B587007A66D4 /* EmptyView.swift */; }; FA4F5AD92A7A3E7700B268FF /* Snapshotting in Frameworks */ = {isa = PBXBuildFile; productRef = FA4F5AD82A7A3E7700B268FF /* Snapshotting */; }; FA4F5ADA2A7A3E7700B268FF /* Snapshotting in Embed Frameworks */ = {isa = PBXBuildFile; productRef = FA4F5AD82A7A3E7700B268FF /* Snapshotting */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; FA5E82972A96448A008DE3F0 /* StateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5E82962A96448A008DE3F0 /* StateView.swift */; }; FA7EFE132B9235D100EF534F /* SnapshotPreferences in Frameworks */ = {isa = PBXBuildFile; productRef = FA7EFE122B9235D100EF534F /* SnapshotPreferences */; }; + FA8F8B7E2C66C4C4007CEA33 /* DemoAppPreviewTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8F8B7D2C66C4C4007CEA33 /* DemoAppPreviewTest.swift */; }; + FA8F8B852C66C4CA007CEA33 /* SnapshottingTests in Frameworks */ = {isa = PBXBuildFile; productRef = FA8F8B842C66C4CA007CEA33 /* SnapshottingTests */; }; FA9C8E442A56959300DC4574 /* RatingPreviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9C8E432A56959300DC4574 /* RatingPreviews.swift */; }; FAA4F4CF2B271D9C00127B63 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA4F4CE2B271D9C00127B63 /* Color.swift */; }; FABCCD932AC39081008F4D3A /* EMGTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABCCD922AC39081008F4D3A /* EMGTestHandler.swift */; }; FACA23792A55FBEE0080545A /* DemoModule.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA1671D72A5399F700A42DB0 /* DemoModule.framework */; }; + FACBADA32C67B8D60012D600 /* DemoWatchPreviewTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FACBADA22C67B8D60012D600 /* DemoWatchPreviewTest.swift */; }; + FACBADAA2C67B8ED0012D600 /* SnapshottingTests in Frameworks */ = {isa = PBXBuildFile; productRef = FACBADA92C67B8ED0012D600 /* SnapshottingTests */; }; + FACBADAC2C67B9A50012D600 /* DemoWatchSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FACBADAB2C67B9A50012D600 /* DemoWatchSnapshotTest.swift */; }; FAD0107B2AA29ABA007D1AF6 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAD0107A2AA29ABA007D1AF6 /* TextView.swift */; }; FAD52BF62A7B5EEA001F1832 /* ExpandingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAD52BF12A7B5EEA001F1832 /* ExpandingView.swift */; }; FAD52BF72A7B5EEA001F1832 /* CodeEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAD52BF22A7B5EEA001F1832 /* CodeEntryView.swift */; }; FAD52BF82A7B5EEA001F1832 /* RideDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAD52BF32A7B5EEA001F1832 /* RideDetailView.swift */; }; FAD52BF92A7B5EEA001F1832 /* RideShareButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAD52BF42A7B5EEA001F1832 /* RideShareButton.swift */; }; FAD52BFA2A7B5EEA001F1832 /* RideOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAD52BF52A7B5EEA001F1832 /* RideOptionsView.swift */; }; + FADB112C2C67A17500985C48 /* DemoAppSnapshotTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FADB112B2C67A17500985C48 /* DemoAppSnapshotTest.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -81,6 +87,13 @@ remoteGlobalIDString = FA309EBF2C38D71C00C85FF4; remoteInfo = "Demo Watch App"; }; + FA8F8B7F2C66C4C4007CEA33 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FA1671B72A5367A800A42DB0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FA1671BE2A5367A800A42DB0; + remoteInfo = DemoApp; + }; FAC167ED2A5F41C500D79C23 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = FA1671B72A5367A800A42DB0 /* Project object */; @@ -88,6 +101,13 @@ remoteGlobalIDString = FA1671BE2A5367A800A42DB0; remoteInfo = DemoApp; }; + FACBADA42C67B8D60012D600 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FA1671B72A5367A800A42DB0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FA309EBF2C38D71C00C85FF4; + remoteInfo = "Demo Watch App"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -168,22 +188,28 @@ FA309EC62C38D71D00C85FF4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; FA309EC92C38D71D00C85FF4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; FA309ED62C38D77C00C85FF4 /* DemoWatchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoWatchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - FA309ED82C38D77C00C85FF4 /* Demo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Demo.swift; sourceTree = ""; }; - FA3C0DE62A620E9A00278952 /* MyPreviewTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPreviewTest.swift; sourceTree = ""; }; + FA309ED82C38D77C00C85FF4 /* DemoWatchAccessibilityPreviewTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoWatchAccessibilityPreviewTest.swift; sourceTree = ""; }; + FA3C0DE62A620E9A00278952 /* DemoAppAccessibilityPreviewTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppAccessibilityPreviewTest.swift; sourceTree = ""; }; FA40515C2A95B587007A66D4 /* EmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyView.swift; sourceTree = ""; }; FA44246E2AAA5B27005BFCD9 /* DemoApp.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = DemoApp.xctestplan; sourceTree = ""; }; FA5E82962A96448A008DE3F0 /* StateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateView.swift; sourceTree = ""; }; + FA8F8B7B2C66C4C4007CEA33 /* DemoAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + FA8F8B7D2C66C4C4007CEA33 /* DemoAppPreviewTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppPreviewTest.swift; sourceTree = ""; }; FA9C8E432A56959300DC4574 /* RatingPreviews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingPreviews.swift; sourceTree = ""; }; FAA4F4CE2B271D9C00127B63 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; FABCCD922AC39081008F4D3A /* EMGTestHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EMGTestHandler.swift; sourceTree = ""; }; FAC167E72A5F41C500D79C23 /* DemoAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; FACA23752A55FB970080545A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + FACBADA02C67B8D60012D600 /* Demo Watch AppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Demo Watch AppTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + FACBADA22C67B8D60012D600 /* DemoWatchPreviewTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoWatchPreviewTest.swift; sourceTree = ""; }; + FACBADAB2C67B9A50012D600 /* DemoWatchSnapshotTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoWatchSnapshotTest.swift; sourceTree = ""; }; FAD0107A2AA29ABA007D1AF6 /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = ""; }; FAD52BF12A7B5EEA001F1832 /* ExpandingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpandingView.swift; sourceTree = ""; }; FAD52BF22A7B5EEA001F1832 /* CodeEntryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeEntryView.swift; sourceTree = ""; }; FAD52BF32A7B5EEA001F1832 /* RideDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RideDetailView.swift; sourceTree = ""; }; FAD52BF42A7B5EEA001F1832 /* RideShareButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RideShareButton.swift; sourceTree = ""; }; FAD52BF52A7B5EEA001F1832 /* RideOptionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RideOptionsView.swift; sourceTree = ""; }; + FADB112B2C67A17500985C48 /* DemoAppSnapshotTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppSnapshotTest.swift; sourceTree = ""; }; FAF1BA622A54934200AEBE1B /* .. */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ..; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ @@ -222,6 +248,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + FA8F8B782C66C4C4007CEA33 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FA8F8B852C66C4CA007CEA33 /* SnapshottingTests in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; FAC167E42A5F41C500D79C23 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -231,6 +265,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + FACBAD9D2C67B8D60012D600 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FACBADAA2C67B8ED0012D600 /* SnapshottingTests in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -243,6 +285,8 @@ FAC167E82A5F41C500D79C23 /* DemoAppUITests */, FA309EC12C38D71C00C85FF4 /* Demo Watch App */, FA309ED72C38D77C00C85FF4 /* DemoWatchTests */, + FA8F8B7C2C66C4C4007CEA33 /* DemoAppTests */, + FACBADA12C67B8D60012D600 /* Demo Watch AppTests */, FA1671C02A5367A800A42DB0 /* Products */, FA6E72BD2A54944800448463 /* Frameworks */, ); @@ -256,6 +300,8 @@ FAC167E72A5F41C500D79C23 /* DemoAppUITests.xctest */, FA309EC02C38D71C00C85FF4 /* Demo Watch App.app */, FA309ED62C38D77C00C85FF4 /* DemoWatchTests.xctest */, + FA8F8B7B2C66C4C4007CEA33 /* DemoAppTests.xctest */, + FACBADA02C67B8D60012D600 /* Demo Watch AppTests.xctest */, ); name = Products; sourceTree = ""; @@ -327,7 +373,7 @@ FA309ED72C38D77C00C85FF4 /* DemoWatchTests */ = { isa = PBXGroup; children = ( - FA309ED82C38D77C00C85FF4 /* Demo.swift */, + FA309ED82C38D77C00C85FF4 /* DemoWatchAccessibilityPreviewTest.swift */, ); path = DemoWatchTests; sourceTree = ""; @@ -340,14 +386,32 @@ name = Frameworks; sourceTree = ""; }; + FA8F8B7C2C66C4C4007CEA33 /* DemoAppTests */ = { + isa = PBXGroup; + children = ( + FA8F8B7D2C66C4C4007CEA33 /* DemoAppPreviewTest.swift */, + FADB112B2C67A17500985C48 /* DemoAppSnapshotTest.swift */, + ); + path = DemoAppTests; + sourceTree = ""; + }; FAC167E82A5F41C500D79C23 /* DemoAppUITests */ = { isa = PBXGroup; children = ( - FA3C0DE62A620E9A00278952 /* MyPreviewTest.swift */, + FA3C0DE62A620E9A00278952 /* DemoAppAccessibilityPreviewTest.swift */, ); path = DemoAppUITests; sourceTree = ""; }; + FACBADA12C67B8D60012D600 /* Demo Watch AppTests */ = { + isa = PBXGroup; + children = ( + FACBADA22C67B8D60012D600 /* DemoWatchPreviewTest.swift */, + FACBADAB2C67B9A50012D600 /* DemoWatchSnapshotTest.swift */, + ); + path = "Demo Watch AppTests"; + sourceTree = ""; + }; FAD52BF02A7B5EBB001F1832 /* TestViews */ = { isa = PBXGroup; children = ( @@ -469,6 +533,27 @@ productReference = FA309ED62C38D77C00C85FF4 /* DemoWatchTests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; + FA8F8B7A2C66C4C4007CEA33 /* DemoAppTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = FA8F8B832C66C4C4007CEA33 /* Build configuration list for PBXNativeTarget "DemoAppTests" */; + buildPhases = ( + FA8F8B772C66C4C4007CEA33 /* Sources */, + FA8F8B782C66C4C4007CEA33 /* Frameworks */, + FA8F8B792C66C4C4007CEA33 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + FA8F8B802C66C4C4007CEA33 /* PBXTargetDependency */, + ); + name = DemoAppTests; + packageProductDependencies = ( + FA8F8B842C66C4CA007CEA33 /* SnapshottingTests */, + ); + productName = DemoAppTests; + productReference = FA8F8B7B2C66C4C4007CEA33 /* DemoAppTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; FAC167E62A5F41C500D79C23 /* DemoAppUITests */ = { isa = PBXNativeTarget; buildConfigurationList = FAC167EF2A5F41C500D79C23 /* Build configuration list for PBXNativeTarget "DemoAppUITests" */; @@ -492,6 +577,27 @@ productReference = FAC167E72A5F41C500D79C23 /* DemoAppUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; + FACBAD9F2C67B8D60012D600 /* Demo Watch AppTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = FACBADA62C67B8D60012D600 /* Build configuration list for PBXNativeTarget "Demo Watch AppTests" */; + buildPhases = ( + FACBAD9C2C67B8D60012D600 /* Sources */, + FACBAD9D2C67B8D60012D600 /* Frameworks */, + FACBAD9E2C67B8D60012D600 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + FACBADA52C67B8D60012D600 /* PBXTargetDependency */, + ); + name = "Demo Watch AppTests"; + packageProductDependencies = ( + FACBADA92C67B8ED0012D600 /* SnapshottingTests */, + ); + productName = "Demo Watch AppTests"; + productReference = FACBADA02C67B8D60012D600 /* Demo Watch AppTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -516,11 +622,19 @@ CreatedOnToolsVersion = 15.4; TestTargetID = FA309EBF2C38D71C00C85FF4; }; + FA8F8B7A2C66C4C4007CEA33 = { + CreatedOnToolsVersion = 15.4; + TestTargetID = FA1671BE2A5367A800A42DB0; + }; FAC167E62A5F41C500D79C23 = { CreatedOnToolsVersion = 14.3.1; LastSwiftMigration = 1430; TestTargetID = FA1671BE2A5367A800A42DB0; }; + FACBAD9F2C67B8D60012D600 = { + CreatedOnToolsVersion = 15.4; + TestTargetID = FA309EBF2C38D71C00C85FF4; + }; }; }; buildConfigurationList = FA1671BA2A5367A800A42DB0 /* Build configuration list for PBXProject "DemoApp" */; @@ -543,6 +657,8 @@ FAC167E62A5F41C500D79C23 /* DemoAppUITests */, FA309EBF2C38D71C00C85FF4 /* Demo Watch App */, FA309ED52C38D77C00C85FF4 /* DemoWatchTests */, + FA8F8B7A2C66C4C4007CEA33 /* DemoAppTests */, + FACBAD9F2C67B8D60012D600 /* Demo Watch AppTests */, ); }; /* End PBXProject section */ @@ -580,6 +696,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + FA8F8B792C66C4C4007CEA33 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; FAC167E52A5F41C500D79C23 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -587,6 +710,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + FACBAD9E2C67B8D60012D600 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -646,7 +776,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - FA309EE72C38EB9B00C85FF4 /* Demo.swift in Sources */, + FA309EE72C38EB9B00C85FF4 /* DemoWatchAccessibilityPreviewTest.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FA8F8B772C66C4C4007CEA33 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FADB112C2C67A17500985C48 /* DemoAppSnapshotTest.swift in Sources */, + FA8F8B7E2C66C4C4007CEA33 /* DemoAppPreviewTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -654,7 +793,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - FA3C0DE72A620E9A00278952 /* MyPreviewTest.swift in Sources */, + FA3C0DE72A620E9A00278952 /* DemoAppAccessibilityPreviewTest.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FACBAD9C2C67B8D60012D600 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FACBADAC2C67B9A50012D600 /* DemoWatchSnapshotTest.swift in Sources */, + FACBADA32C67B8D60012D600 /* DemoWatchPreviewTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -677,6 +825,11 @@ target = FA309EBF2C38D71C00C85FF4 /* Demo Watch App */; targetProxy = FA309EDC2C38D77C00C85FF4 /* PBXContainerItemProxy */; }; + FA8F8B802C66C4C4007CEA33 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FA1671BE2A5367A800A42DB0 /* DemoApp */; + targetProxy = FA8F8B7F2C66C4C4007CEA33 /* PBXContainerItemProxy */; + }; FAC167EE2A5F41C500D79C23 /* PBXTargetDependency */ = { isa = PBXTargetDependency; platformFilters = ( @@ -686,6 +839,11 @@ target = FA1671BE2A5367A800A42DB0 /* DemoApp */; targetProxy = FAC167ED2A5F41C500D79C23 /* PBXContainerItemProxy */; }; + FACBADA52C67B8D60012D600 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FA309EBF2C38D71C00C85FF4 /* Demo Watch App */; + targetProxy = FACBADA42C67B8D60012D600 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -1072,6 +1230,47 @@ }; name = Release; }; + FA8F8B812C66C4C4007CEA33 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J9H72XH8P9; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.emerge.DemoAppTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/DemoApp"; + }; + name = Debug; + }; + FA8F8B822C66C4C4007CEA33 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J9H72XH8P9; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.emerge.DemoAppTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/DemoApp"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; FAC167F02A5F41C500D79C23 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1122,6 +1321,47 @@ }; name = Release; }; + FACBADA72C67B8D60012D600 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J9H72XH8P9; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.emerge.Demo-Watch-AppTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Demo Watch App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Demo Watch App"; + WATCHOS_DEPLOYMENT_TARGET = 10.5; + }; + name = Debug; + }; + FACBADA82C67B8D60012D600 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = J9H72XH8P9; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.emerge.Demo-Watch-AppTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Demo Watch App.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Demo Watch App"; + VALIDATE_PRODUCT = YES; + WATCHOS_DEPLOYMENT_TARGET = 10.5; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1170,6 +1410,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + FA8F8B832C66C4C4007CEA33 /* Build configuration list for PBXNativeTarget "DemoAppTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FA8F8B812C66C4C4007CEA33 /* Debug */, + FA8F8B822C66C4C4007CEA33 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; FAC167EF2A5F41C500D79C23 /* Build configuration list for PBXNativeTarget "DemoAppUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1179,6 +1428,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + FACBADA62C67B8D60012D600 /* Build configuration list for PBXNativeTarget "Demo Watch AppTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FACBADA72C67B8D60012D600 /* Debug */, + FACBADA82C67B8D60012D600 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1210,6 +1468,14 @@ isa = XCSwiftPackageProductDependency; productName = SnapshotPreferences; }; + FA8F8B842C66C4CA007CEA33 /* SnapshottingTests */ = { + isa = XCSwiftPackageProductDependency; + productName = SnapshottingTests; + }; + FACBADA92C67B8ED0012D600 /* SnapshottingTests */ = { + isa = XCSwiftPackageProductDependency; + productName = SnapshottingTests; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = FA1671B72A5367A800A42DB0 /* Project object */; diff --git a/DemoApp/DemoAppTests/DemoAppPreviewTest.swift b/DemoApp/DemoAppTests/DemoAppPreviewTest.swift new file mode 100644 index 0000000..e33bf34 --- /dev/null +++ b/DemoApp/DemoAppTests/DemoAppPreviewTest.swift @@ -0,0 +1,19 @@ +// +// DemoAppPreviewTest.swift +// DemoAppTests +// +// Created by Noah Martin on 8/9/24. +// + +import XCTest +import SnapshottingTests + +final class DemoAppPreviewTest: PreviewLayoutTest { + override func snapshotPreviews() -> [String]? { + return nil + } + + override func excludedSnapshotPreviews() -> [String]? { + return nil + } +} diff --git a/DemoApp/DemoAppTests/DemoAppSnapshotTest.swift b/DemoApp/DemoAppTests/DemoAppSnapshotTest.swift new file mode 100644 index 0000000..9e7daa7 --- /dev/null +++ b/DemoApp/DemoAppTests/DemoAppSnapshotTest.swift @@ -0,0 +1,19 @@ +// +// DemoAppSnapshotTest.swift +// DemoAppTests +// +// Created by Noah Martin on 8/10/24. +// + +import Foundation +import SnapshottingTests + +class DemoAppSnapshotTest: SnapshotTest { + override func snapshotPreviews() -> [String]? { + return nil + } + + override func excludedSnapshotPreviews() -> [String]? { + return nil + } +} diff --git a/DemoApp/DemoAppUITests/MyPreviewTest.swift b/DemoApp/DemoAppUITests/DemoAppAccessibilityPreviewTest.swift similarity index 74% rename from DemoApp/DemoAppUITests/MyPreviewTest.swift rename to DemoApp/DemoAppUITests/DemoAppAccessibilityPreviewTest.swift index 644c456..e372e11 100644 --- a/DemoApp/DemoAppUITests/MyPreviewTest.swift +++ b/DemoApp/DemoAppUITests/DemoAppAccessibilityPreviewTest.swift @@ -1,5 +1,5 @@ // -// MultipleTests.swift +// DemoAppAccessibilityPreviewTest.swift // DemoAppUITests // // Created by Noah Martin on 7/14/23. @@ -9,7 +9,8 @@ import Foundation import XCTest import SnapshottingTests -class MyPreviewTest: PreviewTest { +@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) +class DemoAppAccessibilityPreviewTest: AccessibilityPreviewTest { override func snapshotPreviews() -> [String]? { return nil @@ -19,10 +20,6 @@ class MyPreviewTest: PreviewTest { return nil } - override var enableAccessibilityAudit: Bool { - true - } - @available(iOS 17.0, *) override func auditType() -> XCUIAccessibilityAuditType { return .all diff --git a/DemoApp/DemoWatchTests/Demo.swift b/DemoApp/DemoWatchTests/DemoWatchAccessibilityPreviewTest.swift similarity index 62% rename from DemoApp/DemoWatchTests/Demo.swift rename to DemoApp/DemoWatchTests/DemoWatchAccessibilityPreviewTest.swift index 091441f..77bc6cd 100644 --- a/DemoApp/DemoWatchTests/Demo.swift +++ b/DemoApp/DemoWatchTests/DemoWatchAccessibilityPreviewTest.swift @@ -1,5 +1,5 @@ // -// Demo.swift +// DemoWatchAccessibilityPreviewTest.swift // Demo // // Created by Noah Martin on 7/5/24. @@ -9,7 +9,7 @@ import Snapshotting import SnapshottingTests import XCTest -final class Demo: PreviewTest { +final class DemoWatchAccessibilityPreviewTest: AccessibilityPreviewTest { override func getApp() -> XCUIApplication { return XCUIApplication() diff --git a/Sources/SnapshotPreviewsCore/SnapshotPreviewsCore.swift b/Sources/SnapshotPreviewsCore/SnapshotPreviewsCore.swift index edbeb66..49be4c0 100644 --- a/Sources/SnapshotPreviewsCore/SnapshotPreviewsCore.swift +++ b/Sources/SnapshotPreviewsCore/SnapshotPreviewsCore.swift @@ -177,8 +177,8 @@ public enum FindPreviews { @MainActor public static func findPreviews(included: [String]?, excluded: [String]?) -> [PreviewType] { - var previewsSet = included.map { Set($0) } - var excludedPreviewsSet = excluded.map { Set($0) } + let previewsSet = included.map { Set($0) } + let excludedPreviewsSet = excluded.map { Set($0) } let previewTypes = findPreviews { name, proto in guard #available(iOS 16.0, macOS 13.0, tvOS 16.0, *) else { return true } diff --git a/Sources/SnapshottingTests/PreviewTest.swift b/Sources/SnapshottingTests/AccessibilityPreviewTest.swift similarity index 92% rename from Sources/SnapshottingTests/PreviewTest.swift rename to Sources/SnapshottingTests/AccessibilityPreviewTest.swift index 795094c..a06c4e4 100644 --- a/Sources/SnapshottingTests/PreviewTest.swift +++ b/Sources/SnapshottingTests/AccessibilityPreviewTest.swift @@ -1,6 +1,6 @@ // -// PreviewTest.swift -// +// AccessibilityPreviewTest.swift +// // // Created by Noah Martin on 8/9/24. // @@ -9,7 +9,9 @@ import Foundation import SnapshottingTestsObjc import MachO -open class PreviewTest: EMGPreviewBaseTest { +// This is an XCUITest that uses XCUIApplication.performAccessibilityAudit to test previews +@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) +open class AccessibilityPreviewTest: EMGPreviewBaseTest { open func getApp() -> XCUIApplication { XCUIApplication() @@ -26,10 +28,6 @@ open class PreviewTest: EMGPreviewBaseTest { nil } - open var enableAccessibilityAudit: Bool { - true - } - @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) open func auditType() -> XCUIAccessibilityAuditType { .all } @@ -159,13 +157,9 @@ open class PreviewTest: EMGPreviewBaseTest { XCTFail("Failed to parse JSON: \(error)") } - if #available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) { - if enableAccessibilityAudit { - let app = getApp() - try? app.performAccessibilityAudit(for: auditType()) { [weak self] issue in - return self?.handle(issue: issue) ?? false - } - } + let app = getApp() + try? app.performAccessibilityAudit(for: auditType()) { [weak self] issue in + return self?.handle(issue: issue) ?? false } } } diff --git a/Sources/SnapshottingTests/EMGPreviewBaseTest+PreviewFilters.swift b/Sources/SnapshottingTests/EMGPreviewBaseTest+PreviewFilters.swift new file mode 100644 index 0000000..bad009b --- /dev/null +++ b/Sources/SnapshottingTests/EMGPreviewBaseTest+PreviewFilters.swift @@ -0,0 +1,28 @@ +// +// EMGPreviewBaseTest+PreviewFilters.swift +// +// +// Created by Noah Martin on 8/9/24. +// + +import Foundation +import SnapshotPreviewsCore +import SnapshottingTestsObjc + +extension PreviewFilters where Self: EMGPreviewBaseTest { + @MainActor + static func matchingPreviewTypes() -> [PreviewType] { + let instance = self.create() + return FindPreviews.findPreviews(included: instance.snapshotPreviews(), excluded: instance.excludedSnapshotPreviews()) + } +} + +extension EMGDiscoveredPreview { + static func from(previewType: PreviewType) -> EMGDiscoveredPreview { + let d = EMGDiscoveredPreview() + d.typeName = previewType.typeName + d.displayName = previewType.displayName + d.numberOfPreviews = NSNumber(value: previewType.previews.count) + return d + } +} diff --git a/Sources/SnapshottingTests/PreviewFilters.swift b/Sources/SnapshottingTests/PreviewFilters.swift new file mode 100644 index 0000000..1815d0b --- /dev/null +++ b/Sources/SnapshottingTests/PreviewFilters.swift @@ -0,0 +1,17 @@ +// +// PreviewFilters.swift +// +// +// Created by Noah Martin on 8/9/24. +// + +import Foundation + +public protocol PreviewFilters { + // Override to return a list of previews that should be snapshotted. + // The default is null, which snapshots all previews. + // Elements should be the type name of the preview, like "MyModule.MyView_Previews" + func snapshotPreviews() -> [String]? + + func excludedSnapshotPreviews() -> [String]? +} diff --git a/Sources/SnapshottingTests/PreviewLayoutTest.swift b/Sources/SnapshottingTests/PreviewLayoutTest.swift new file mode 100644 index 0000000..d9e3d62 --- /dev/null +++ b/Sources/SnapshottingTests/PreviewLayoutTest.swift @@ -0,0 +1,54 @@ +// +// PreviewLayoutTest.swift +// +// +// Created by Noah Martin on 8/9/24. +// + +import Foundation +import SnapshotPreviewsCore +import SnapshottingTestsObjc +import SwiftUI + +// Test Xcode previews by forcing a layout pass of each one +open class PreviewLayoutTest: EMGPreviewBaseTest, PreviewFilters { + + open func snapshotPreviews() -> [String]? { + nil + } + + open func excludedSnapshotPreviews() -> [String]? { + nil + } + + static private var previews: [PreviewType] = [] + + @MainActor + open override class func discoverPreviews() -> [EMGDiscoveredPreview] { + previews = matchingPreviewTypes() + return previews.map { EMGDiscoveredPreview.from(previewType: $0) } + } + + @MainActor + open override func test(_ preview: EMGPreview) { + let previewType = Self.previews.first { $0.typeName == preview.preview.typeName } + guard let preview = previewType?.previews[preview.index.intValue] else { + XCTFail("Preview not found") + return + } + + #if canImport(UIKit) && !os(watchOS) + let hostingVC = UIHostingController(rootView: AnyView(preview.view())) + #if os(visionOS) || os(watchOS) + hostingVC.view.sizeThatFits(CGSize(width: 100, height: CGFloat.greatestFiniteMagnitude)) + #else + hostingVC.view.sizeThatFits(UIScreen.main.bounds.size) + #endif + #elseif canImport(AppKit) + let hostingVC = NSHostingController(rootView: AnyView(preview.view())) + _ = hostingVC.sizeThatFits(in: NSScreen.main!.frame.size) + #else + _ = ImageRenderer(content: AnyView(preview.view())).uiImage + #endif + } +} diff --git a/Sources/SnapshottingTests/SnapshotTest.swift b/Sources/SnapshottingTests/SnapshotTest.swift new file mode 100644 index 0000000..b3db374 --- /dev/null +++ b/Sources/SnapshottingTests/SnapshotTest.swift @@ -0,0 +1,72 @@ +// +// SnapshotTest.swift +// +// +// Created by Noah Martin on 8/9/24. +// + +import Foundation +import SnapshotPreviewsCore +import SnapshottingTestsObjc + +// Generate snapshots of Xcode previews +open class SnapshotTest: EMGPreviewBaseTest, PreviewFilters { + + open func snapshotPreviews() -> [String]? { + nil + } + + open func excludedSnapshotPreviews() -> [String]? { + nil + } + + private static func getRenderingStrategy() -> RenderingStrategy { + #if canImport(UIKit) && !os(watchOS) && !os(visionOS) && !os(tvOS) + return UIKitRenderingStrategy() + #else + if #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, visionOS 1.0, *) { + SwiftUIRenderingStrategy() + } else { + preconditionFailure("Cannot snapshot on this device/os") + } + #endif + } + private let renderingStrategy = getRenderingStrategy() + + static private var previews: [SnapshotPreviewsCore.PreviewType] = [] + + @MainActor + open override class func discoverPreviews() -> [EMGDiscoveredPreview] { + previews = matchingPreviewTypes() + return previews.map { EMGDiscoveredPreview.from(previewType: $0) } + } + + @MainActor + open override func test(_ preview: EMGPreview) { + let previewType = Self.previews.first { $0.typeName == preview.preview.typeName } + guard let preview = previewType?.previews[preview.index.intValue] else { + XCTFail("Preview not found") + return + } + + var result: SnapshotResult? = nil + let expectation = XCTestExpectation() + renderingStrategy.render(preview: preview) { snapshotResult in + result = snapshotResult + expectation.fulfill() + } + wait(for: [expectation], timeout: 10) + guard let result else { + XCTFail("Did not render") + return + } + do { + let attachment = try XCTAttachment(image: result.image.get()) + attachment.name = preview.displayName + attachment.lifetime = .keepAlways + add(attachment) + } catch { + XCTFail("Error \(error)") + } + } +}