Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Sources/SnapshotPreferences/ExcludeTrait.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import SwiftUI
import SnapshotSharedModels

@available(iOS 18.0, macOS 15.0, watchOS 11.0, tvOS 18.0, *)
extension PreviewTrait where T == Preview.ViewTraits {
public static func snapshotExcluded(_ excluded: Bool) -> Self {
.modifier(excluded ? SnapshotInclusionMode.excluded : .automatic)
}

public static var snapshotExcluded: Self {
.snapshotExcluded(true)
}
}

extension SnapshotInclusionMode: @retroactive PreviewModifier {
public func body(content: Content, context: Void) -> some View {
content
}
}
14 changes: 14 additions & 0 deletions Sources/SnapshotPreviewsCore/SnapshotPreviewsCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public struct Preview: Identifiable {
displayName = preview.displayName
device = preview.device
layout = preview.layout
_modifiers = []
_view = {
ViewSelectorTree(SnapshotViewModel(index: preview.id)) {
P.previews
Expand All @@ -26,10 +27,14 @@ public struct Preview: Identifiable {
let preview = Mirror(reflecting: preview)
let traits = preview.descendant("traits")! as! [Any]
var layout = PreviewLayout.device
var modifiers: [Any] = []
for t in traits {
if let value = Mirror(reflecting: t).descendant("value") {
if let value = value as? PreviewLayout {
layout = value
} else if #available(iOS 18.0, macOS 15.0, watchOS 11.0, tvOS 18.0, *),
let traitModifiers = value as? [any PreviewModifier] {
modifiers += traitModifiers
} else if String(describing: value).hasSuffix(".portraitUpsideDown") {
orientation = .portraitUpsideDown
} else if String(describing: value).hasSuffix(".landscapeLeft") {
Expand All @@ -39,6 +44,7 @@ public struct Preview: Identifiable {
}
}
}
self._modifiers = modifiers
self.orientation = orientation
self.layout = layout
displayName = preview.descendant("displayName") as? String
Expand Down Expand Up @@ -82,6 +88,14 @@ public struct Preview: Identifiable {
public let index: Int
public let device: PreviewDevice?
public let layout: PreviewLayout

// we can't store `[any PreviewModifier]` because it's unavailable before iOS 18 et al
private let _modifiers: [Any]
@available(iOS 18.0, macOS 15.0, watchOS 11.0, tvOS 18.0, *)
public var modifiers: [any PreviewModifier] {
_modifiers as? [any PreviewModifier] ?? []
Comment thread
kabiroberai marked this conversation as resolved.
}

private let _view: @MainActor () -> any View
@MainActor public func view() -> any View {
_view()
Expand Down
4 changes: 4 additions & 0 deletions Sources/SnapshotSharedModels/SnapshotInclusionMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public enum SnapshotInclusionMode: Sendable {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Is declaring this in SnapshotSharedModels safe? I'm not entirely sure I understand the motivation behind keeping certain APIs stringly/dynamically typed with ModifierFinder, vs placing concrete types in this module.

case excluded
case automatic
}
1 change: 1 addition & 0 deletions Sources/SnapshottingTests/PreviewLayoutTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ open class PreviewLayoutTest: PreviewBaseTest, PreviewFilters {
includedModules: Self.snapshotPreviewModules(),
excludedModules: Self.excludedSnapshotPreviewModules()
)
.filter(SnapshotPreviewInclusionFilter.shouldInclude)
return previews.map { DiscoveredPreview.from(previewType: $0) }
}

Expand Down
10 changes: 10 additions & 0 deletions Sources/SnapshottingTests/SnapshotPreviewInclusionFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@_implementationOnly import SnapshotPreviewsCore
import SnapshotSharedModels

enum SnapshotPreviewInclusionFilter {
static func shouldInclude(preview: PreviewType) -> Bool {
guard #available(iOS 18.0, macOS 15.0, watchOS 11.0, tvOS 18.0, *) else { return true }
guard preview.previews.count == 1 else { return true }
return !preview.previews[0].modifiers.contains { ($0 as? SnapshotInclusionMode) == .excluded }
}
}
2 changes: 2 additions & 0 deletions Sources/SnapshottingTests/SnapshotTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ open class SnapshotTest: PreviewBaseTest, PreviewFilters {
includedModules: Self.snapshotPreviewModules(),
excludedModules: Self.excludedSnapshotPreviewModules()
)
.filter(SnapshotPreviewInclusionFilter.shouldInclude)

fileNameResolver = FileNameResolver(previews: previews)

if let allSnapshotImageNamesWriter {
Expand Down