Skip to content

πŸ”₯ A library based on Xcode Preview, for easy generation: Playbook view, Snapshot and Accessibility tests. SwiftUI and UIKit supported!

License

Notifications You must be signed in to change notification settings

BarredEwe/Prefire

Repository files navigation

Prefire

Release Platform Swift6 Swift Package Manager Swift Package Manager

πŸ”₯ What is Prefire?

Prefire transforms your #Preview blocks into:

  • βœ… Snapshot tests
  • βœ… Playbook views
  • βœ… Visual flows with states and user stories
  • βœ… Living documentation β€” fully automated

πŸš€ Key Features

Playbook

  • 🧠 Smart Preview Parsing β€” including #Preview, @Previewable
  • πŸ“Έ Snapshot Testing β€” automatic test generation from previews
  • πŸ“š Playbook View β€” auto-generated interactive component catalog
  • πŸƒ Flow-aware β€” build user stories from multiple preview steps
  • 🧩 UIKit Support β€” support for UIView and UIViewController
  • βš™οΈ SPM + Xcode Plugins β€” works in CLI, Xcode build phases, or CI
  • 🧠 Fast Caching β€” fingerprint-based AST and body caching avoids redundant work
  • ✍️ Stencil Templates β€” customize output with your own templates

Why Prefire?

  • πŸ”₯ Save Time - Generate tests and documentation automatically
  • πŸ”₯ Stay Consistent - Keep previews and tests always in sync
  • πŸ”₯ Improve Quality - Catch visual regressions before users do
  • πŸ”₯ Boost Collaboration - Share living documentation with your team


⚑️ Quick Start

πŸ“¦ Example project available at: Prefire Example

1. Add Prefire to Your Project

// Package.swift dependencies: [ .package(url: "https://github.com/BarredEwe/Prefire.git", from: "4.0.0") ], .testTarget( plugins: [ // For Snapshot Tests .plugin(name: "PrefireTestsPlugin", package: "Prefire") ] )

2. Write #Preview

#Preview { Button("Submit") }

3. Run tests

Just run the test target πŸš€ β€” Prefire will auto-generate snapshots based on your previews.

πŸ’‘ If your test target is empty, Prefire will still generate files and snapshot code during build.


πŸ“¦ Installation

Supports:

  • βœ… SPM Plugin (Package.swift)
  • βœ… Xcode Build Tool Plugin
  • βœ… CLI (brew install prefire)
  • βœ… GitHub Actions / CI

See detailed setup in the Installation guide

🧠 How It Works

πŸ” 1. Parses all source files

  • Finds all #Preview and PreviewProvider blocks
  • Supports modifiers: .prefireEnabled(), .prefireIgnored()

πŸ“‚ 2. Caches Types and PreviewBodies

  • Based on file modification date + SHA-256 of inputs
  • Avoids re-parsing if nothing changed

πŸ”’ 3. Generates Snapshot Tests

  • Uses Stencil templates
  • Respects .prefire.yml configuration

πŸ“˜ 4. Generates Playbook View

  • Groups by UserStory, State
  • Outputs PreviewModels.generated.swift

πŸ›  Advanced Usage

To generate tests and playbook, simply mark your preview using the PrefireProvider protocol:

struct Text_Previews: PreviewProvider, PrefireProvider { static var previews: some View { ... } }

If you use the #Preview macro, πŸ”₯Prefire will automatically find it!

If you don't need it, mark view - .prefireIgnored():

#Preview { Text("") .prefireIgnored() }

If you want to disable the automatic get of all previews, use the setting preview_default_enabled: false. Then to include preview in the test, you need to call the .prefireEnabled():

#Preview { Text("") .prefireEnabled() }

Playbook (Demo) View

To use Playbook, simply use PlaybookView

  • If you want to see a list of all the Views, use isComponent: true
  • If you want to sort by UserStory, use isComponent: false
import Prefire struct ContentView: View { var body: some View { PlaybookView(isComponent: true, previewModels: PreviewModels.models) } }

Snapshot tests

Just run generated tests πŸš€ All tests will be generated in the DerivedData folder.

Plugin PrefireTestsPlugin will handle everything for you πŸ› οΈ

For detailed instruction, check out swift-snapshot-testing or examine an example project.


API

Prefire provide new commands for previews:

  • You can set the delay, precision and perceptualPrecision parameters for the snapshot:

    .snapshot(delay: 0.3, precision: 0.95, perceptualPrecision: 0.98)
    static var previews: some View { TestView() .snapshot(delay: 0.3, precision: 0.95, perceptualPrecision: 0.98) }
  • Function for connecting preview together in one Flow:

    .previewUserStory(.auth)
    static var previews: some View { PrefireView() .previewUserStory(.auth) } static var previews: some View { AuthView() .previewUserStory(.auth) }

    For example Authorization flow: LoginView, OTPView and PincodeView


  • If a preview contains more than one View, you can mark State for these views.

    .previewState(.loading)
    static var previews: some View { TestView("Default") TestView("Loading") .previewState(.loading) }


🧰 API Summary

Feature Modifier
Include in snapshot .prefireEnabled()
Exclude from snapshot .prefireIgnored()
Group in a flow .previewUserStory(.auth)
Mark a UI state .previewState(.error)
Customize snapshot .snapshot(delay: 0.3, precision: 0.95)

πŸ’‘ Advanced: CLI Usage

# Generate snapshot tests prefire tests # Generate playbook models prefire playbook

Run prefire tests --help or prefire playbook --help for more options.


πŸ—‚ Configuration: .prefire.yml

See detailed configuration in the Configuration guide

test_configuration: target: MyApp playbook_configuration: preview_default_enabled: true

Distribution

When preparing for distribution, you may want to exclude your PreviewProvider and mock data from release builds. This can be achieved by wrapping them in #if DEBUG compiler directives. Alternatively, you can pass a compiler flag to exclude PreviewModels from release builds.

To exclude PreviewModels using Swift Package Manager, pass the PLAYBOOK_DISABLED swift setting in the package that links PrefirePlaybookPlugin:

swiftSettings: [ .define("PLAYBOOK_DISABLED", .when(configuration: .release)), ]

If you are using Xcode, you can pass the compiler flag in the Xcode build settings:

SWIFT_ACTIVE_COMPILATION_CONDITIONS = PLAYBOOK_DISABLED; 

🧠 Internal Architecture

  • PrefireCore β€” AST + preview parsing, caching, logic
  • PrefireGenerator β€” handles stencil templating + snapshot generation
  • PrefireCacheManager β€” unifies caching for Types and Previews
  • PrefireTestsPlugin / PrefirePlaybookPlugin β€” SPM/Xcode integrations
  • prefire β€” CLI entry point, calls shared generator code

Requirements

  • Swift 5.6 or higher
  • Xcode 14.0 or higher
  • iOS 14 or higher

Troubleshooting

NavigationView in Preview not supported for Playbook

  • Consider using other views or layouts for your Playbook needs.

Running Prefire via CI

  • To run Prefire via Continuous Integration (CI), you need to configure permissions: defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES

Xcode is unable to generate tests in a custom path.

  • To resolve this, you’ll need to disable the sandbox for file generation by running the following command in your terminal: defaults write com.apple.dt.Xcode IDEPackageSupportDisablePluginExecutionSandbox -bool YES

🀝 Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch
  3. Submit a Pull Request

πŸ“„ License

Prefire is released under the Apache License 2.0. See LICENSE for details.

About

πŸ”₯ A library based on Xcode Preview, for easy generation: Playbook view, Snapshot and Accessibility tests. SwiftUI and UIKit supported!

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

Contributors 17