GithubHelp home page GithubHelp logo

barredewe / prefire Goto Github PK

View Code? Open in Web Editor NEW
286.0 2.0 18.0 90.9 MB

๐Ÿ”ฅ A library based on SwiftUI Preview, for easy generation: Playbook view, Snapshot and Accessibility tests

License: Apache License 2.0

Swift 98.34% Makefile 1.66%
accesibility-tests component ios playbook preview screen snapshot-testing swift swiftui swiftui-previews

prefire's People

Contributors

alexey1312 avatar barredewe avatar codesmith-emmy avatar davidnext avatar markst avatar mgacy avatar stefanceriu avatar szymon-heetch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

prefire's Issues

Form Rows do not keep the continuity of their side edges in snapshot

How to reproduce

Just make a very simple form view like this:

static var previews: some View {
        Form {
            Section("Test") {
                Text("Row 1")
                Text("Row 2")
            }
        }
    }

The preview that SwiftUI Canvas shows is the following:
Screenshot 2023-09-22 at 11 04 41

The generated previews instead is:
test_compoundIcon Test

Is very subtle but if you check the edges on the sides of the two rows you will see that the rounding happens PER ROW in the preview snapshot, instead of happening only at the end and at the start of the row like in the SwiftUI preview.

These happens for all views that use the system rows.
Screenshot 2023-09-22 at 11 04 41

test_compoundIcon Test

Multiple command produce... when using the test plugin

Hello I just added the Test Plugin to my UnitTests as a Build Tool Plug-in.

However I get this error saying that multiple command produce the Unit Tests product.

Am I doing something wrong in the setup?
I have added in the project Prefire, incuded it in the base target, and then as a build tool plugin only for the tests (I do not need the Playbook)

Snapshots to use preview provider preview display name

Generated snapshots for a test name are numbered:

test_authView_Preview.1.png
test_authView_Preview.2.png
test_authView_Preview.3.png
test_authView_Preview.4.png

Would be better if we supply the preview provider display name so that generated png's have more context:

test_prefireView_Preview.PrefireView.png

How to use .prefire.yml with Xcode project?

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Hi! I am new to Prefire and it is very nice. But I got an issue when snapshot with environmentObject

Screenshot 2024-06-20 at 7 06 36โ€ฏPM

What ๐ŸŒฑ

I tried

  - imports:
      - SpeedManagerModule

but does not fixed the issue, seems like .prefire.yml is not read when building the test

how to custom snapshot image file name?

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

I would like to custom the snapshot image file name with custom prefix. e.g. with Swift snapshot testing, I can change the file name like test_snapshots.EU-staging-pt_PT

What ๐ŸŒฑ

I checked PreviewTests.stencil, and found the file name is created from preview.displayName. Here is my code to do it with swift snapshot testing

            .assertSnapshots(as: .image(precision: precision,
                                        layout: .device(config: config)),
                             named: LocaleHelper.deviceLanguage + "_" + LocaleHelper.regionCode,
                             record: recording,
                             snapshotDirectory: XCTestCase.snapshotDirectoryUrl(file: file, pathPrefix: pathPrefix).path,
                             file: file,
                             testName: testName,
                             line: line
            )

Proposal ๐ŸŽ‰

I am thinking about editing PreviewTests.stencil, or add a new option to allow custom prefix?

Wait before capturing a snapshot

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

While attempting to capture a view that includes AsyncImage or revealing a component after a specified duration, it's been noticed that the resulting snapshot doesn't include images loaded via URL or views that appear with a slight delay. Even when using .snapshot(delay: 1.0), there's no noticeable improvement in this scenario.

What ๐ŸŒฑ

To overcome this challenge, it would be helpful to incorporate an option to wait before taking the snapshot. This way, we can ensure that the snapshot accounts for the asynchronous loading of images and views that emerge after a delay.

Example of a view that isn't properly captured in the snapshot:

struct DummyView: View {
    @State var isButtonHidden = true
    var body: some View {
        VStack {
            Text("Some text")
            Text("Some text with delay")
                .opacity(isButtonHidden ? 0 : 1)

        }.onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.isButtonHidden = false
            }
        }
    }
}

Can't pass `mainTarget` to `PreviewModels.stencil`

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Inside PreviewModels.stencil we have a conditional import statement:

{% if argument.mainTarget %}
@testable import {{ argument.mainTarget }}
{% endif %}

What ๐ŸŒฑ

Where as the PrefireTestsPlugin can be provided with a mainTarget argument.
It seems the PrefirePlaybookPlugin has no support for passing the mainTarget?

Proposal ๐ŸŽ‰

Think this might be as simple as passing:

"--args",
"mainTarget=\(targetName)",

to the PrefireTestsPlugin.Command

Regression when specifying a `template_file_path`

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Setup the Prefire example project to use a - template_file_path: PreviewTests.stencil, where PreviewTests.stencil is just a copy of the default template next to PreFireExample.xcodeproj

What ๐ŸŒฑ

Specifying a template_file_path doesn't seem to be working anymore resulting in a does not exist or is not readable error

Proposal ๐ŸŽ‰

Let's try to fix it maybe ๐Ÿ˜

.prefire.yml file not picked up in SPM package?

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

We are using different local SPM packages and I added Prefire to one of them. PreviewTests is generated but it seems it doesn't use the .prefire.yml file to have a custom device and simulator version?

Specifying module defining PrefireProvider breaks snapshot-tests generation

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Specifying module like this struct FooPreviews: ModuleA.PrefierProvider { ... }

What ๐ŸŒฑ

I guess such specification (that can take place in multimodular projects) shouldn't affect snapshot tests generation

Proposal ๐ŸŽ‰

I suppose Prefire parses project files and collects previews marked with PrefireProvider, if that's the case โ€” then parser should use mask [space]*.PrefireProvider to avoid the issue

README specifies wrong command to run Prefire via CI

The README specifies the command to configure permissions on CI as

defaults write com.apple.dt.Xcode ideskippackagepluginfingerprintvalidationbool YES

but it should be:

defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES

#Preview only supports SwiftUI and not other view types

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

As per Apple's documentation - https://developer.apple.com/documentation/xcode/previewing-your-apps-interface-in-xcode #Preview supports other forms of views such as UIViewController, NSView, UIView. Right now, unless you exclude those the generated tests from the plugin won't compile.

What ๐ŸŒฑ

It would be amazing if we can add support for more view types other than just SwiftUI views.

Proposal ๐ŸŽ‰

In the PreviewLoader, it assumes that it's a SwiftUI view and always wraps it in AnyView

I wonder if we could add another function assertSnapshots to the stencil that takes in the other view types like:

private func assertSnapshots(matching view: UIView,
                                 name: String?, isScreen: Bool,
                                 device: ViewImageConfig,
                                 testName: String = #function,
                                 traits: UITraitCollection = .init()) -> String? {
    // ... 
}

private func assertSnapshots(matching view: UIViewController,
                                 name: String?, isScreen: Bool,
                                 device: ViewImageConfig,
                                 testName: String = #function,
                                 traits: UITraitCollection = .init()) -> String? {
    // ... 
}

And then instead of always casting to AnyView, use a more generic any View parameter for the assertSnapshots function and then allow it to dynamically call the appropriate function based on the classes implementation type?

Happy to help further with an implementation but I think this would be a great addition!

Circular dependency between modules 'ModuleTypes' and 'SnapshotTests'

Swift package:

let package = Package(
    name: "ModuleTypes",
    platforms: [.iOS(.v15)],
    products: [
        .library(
            name: "ModuleTypes",
            targets: ["ModuleTypes"]
        )
    ],
    dependencies: [
        .package(path: "../Asset"),
        .package(path: "../Common"),
        .package(path: "../Components"),
        .package(url: "https://github.com/BarredEwe/Prefire.git", branch: "main"),
        .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", from: "1.11.0")
    ],
    targets: [
        .target(
            name: "ModuleTypes",
            dependencies: [
                "Prefire",
                .product(name: "Assets", package: "Asset"),
                .product(name: "Common", package: "Common"),
                .product(name: "Components", package: "Components")
            ],
            path: "./",
            exclude: ["Tests"],
            plugins: [
                // For Snapshot Tests
                .plugin(name: "PrefireTestsPlugin", package: "Prefire")
            ]
        ),
        .testTarget(
            name: "SnapshotTests",
            dependencies: [
                "ModuleTypes",
                .product(name: "TestAssets", package: "Asset"),
                .product(name: "SnapshotTesting", package: "swift-snapshot-testing")
            ]
        )
    ]
)

Cannot find 'file' in scope

Seems that StaticString is conditional of argument.file but the assertSnapshot argument condition is not resolving correctly.

Provide means to delay snapshot

In our views we have UIImageView which fetches from an image url.

For testing purposes these test assets are loaded from load bundle:

public enum TestResource {
    public static func imageURL(named: String, ext: String) -> URL? {
        Bundle.module.url(
            forResource: named,
            withExtension: ext,
            subdirectory: nil

But for snapshots to work there needs to be a minor delay for completion closures to be called in which to display the image.

i.e:

let failure = verifySnapshot(
    matching: try value(),
    as: .wait(
        for: wait,
        on: .image(
            drawHierarchyInKeyWindow: false,
            precision: defaultPerceptualPrecision,
            size: size
        )
    ),

Globally define preview appearance

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Most of our previews look fine in preview without any additional attributes:

#Preview {
  ShowMetaStack(
    showModel: ShowModel.featureMockData,
    nowNextModel: .success(.init()),
    actionsRowModel: .withReminderMockData,
    playButtonAction: {
    },
    actions: .init(
      shareAction: nil,
      watchlistAction: nil,
      reminderAction: nil
    )
  )
  .preferredColorScheme(.dark)
}

What ๐ŸŒฑ

Our generated snapshots appear with white background and default device resolution:

test_ShowMetaStack_0_Preview ShowMetaStack_0

Proposal ๐ŸŽ‰

Without needing to apply preview layout and background colours too all our previews:

  .previewLayout(.sizeThatFits)
  .background(.red)

I wonder if can add to the config in order to apply global attributes to all our previews which generate snapshots

Xcode 15 NSCocoaError 513

When I try to run my tests on Xcode 15 with the PrefireTestsPlugin I get the following error:
Screenshot 2023-09-19 at 10 45 51

I am using a custom prefire config file where I write the tests in an internal folder of the project tests

Spaces in #Preview name break the PreviewTests.generated file

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

I'm integrating Prefire 2.2.1 in a SwiftUI Design System package.

What ๐ŸŒฑ

A space in the preview name isn't escaped or replaced with an underscore, causing compile errors in the generated code.
Compile error: Found an unexpected second identifier in function declaration; is there an accidental break?

Example:

#Preview("Redacted regular") {
    ...
}

Generates:

func test_Redacted regular_Preview() {
        let preview = {
            ...
        }
        
        if let failure = assertSnapshots(matching: AnyView(preview()), name: "Redacted regular", isScreen: true, device: deviceConfig) {
            XCTFail(failure)
        }
    }

No such module Prefire

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Attempting to generate snapshot tests.

  1. Installed Prefire according to the readme:
  • added it as dependency to my package
  • added it as plugin to my test target
  1. Using #Preview for SwiftUI previews.

  2. .prefire.yml:

test_configuration:
  - target: RedactedTests
  - simulator_device: "iPhone15,4"
  - required_os: 16
  - preview_default_enabled: true
  - imports:
    - Foundation
    - UIKit
  - testable_imports:
    - Prefire

What ๐ŸŒฑ

The generated code (PreviewTests.generated.swift) throws error No such module Prefire upon line import Prefire.

Invalid redeclaration of 'test_VStack_Preview()'

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

I'm integrating Prefire 2.2.1 in a SwiftUI Design System package.

What ๐ŸŒฑ

A common approach in our previews is the use of a VStack or HStack to display multiple instantiations of a view. This comes in handy for the (small) components of our design system, being able to see several variations at once.

Example:

#Preview {
    VStack {
        Redacted(.horizontal)
        Redacted(.vertical)
    }
}

This setup causes Prefire to use the same function name (test_VStack_Preview and test_HStack_Preview) for every generated preview test which results in invalid redeclaration compile errors.

func test_VStack_Preview() {
      let preview = {
          VStack {
              ...
          }
      }
      
      if let failure = assertSnapshots(matching: AnyView(preview()), name: "VStack", isScreen: true, device: deviceConfig) {
          XCTFail(failure)
      }
}

Setting a custom previewDisplayName or previewUserStory isn't picked up either by Prefire, which could have been a workaround although I'd rather not have to specify a custom name/story.

Xcode Cloud & Prefire

I've got Prefire up & running in a package on my own machine. I'm trying to get the tests running on Xcode Cloud but it seems like the snapshots tests aren't run. The plain XCTest included in the package tests is being run though.

I have added a ci_post_clone.sh script which resolved the "PrefireTestsPlugin" is disabled error I initially had. So again, it all seems set up correctly.

Before I dig deeper & post more info, can anyone confirm it has actually worked on Xcode Cloud?

Device/Height independent Tests

Would be nice to have the preview of the tests be device or height independent in some way.
What I mean is that it seems that there is no way to generate the previews so that they match exactly their fitting size.
This would be very useful to render scroll views for example, or very huge vertical stack layouts that do not fit a single iPhone screen.
Maybe the test code could only pick the device width (and not be completely device independent), and then have the height get rendered based on a size that fits it.
Or maybe in the configuration you could specify a specific device width (either from a device family like iPhone X or giving the px/pts value directly).

I am actually playing around myself with the .stencil code to see if I can achieve something like that but so far I did not find a solution that works generally.

Xcode 15.3 - Plug-in ended with uncaught signal: 5)

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Hi,

I updated to Xcode 15.3 and when I want to run my preview tests again I get Plug-in ended with uncaught signal: 5)
Screenshot 2024-03-07 at 12 00 12

If you need more information or logs, please let me know.
Thanks

.prefire.yml ignored by PrefirePlaybook plugin

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

Just updated from 1.5.0 to 2.3.0. I use playbook and tests plugins for my target.
Configuration file uses - preview_default_enabled: false to manually choose previews for snapshots and playbook view.

.prefire.yml content:

test_configuration:
  - preview_default_enabled: false
  - target: [Redacted]
  - simulator_device: "iPhone15,2"
  - required_os: 16
  - snapshot_devices:
    - iPhone 14 Pro

prefire_configuration:
  - preview_default_enabled: false

What ๐ŸŒฑ

Running Prefire Tests plugin:
PrefireTests

Running Prefire Playbook plugin:
PrefirePlaybook

Generated PreviewModels swift file has no access to preview files from Swift local packages

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

We have rather big project with some local SPM local packages. In those packages we have SwiftUI screens and components.
I added Prefire to the project and package and updated a SwiftUI preview in the local package to use PrefireProvider.
But then the project generated the PreviewModels file but it has no access to

Screenshot 2023-12-06 at 16 37 28

AppointmentDetailsScreen_Previews is part of Presentation package and that package isn't imported or cannot be accessed.. How can I do that?
Can I update the PreviewModels template file?

#Preview macro breaks the PreviewTests.generated file

Context ๐Ÿ•ต๏ธโ€โ™€๏ธ

I'm integrating Prefire 2.1.1 in a SwiftUI Design System package.

What ๐ŸŒฑ

The #Preview macro causes the PreviewTests.generated file to contain compile errors. It seems that in some cases the #Preview macro breaks the generated code.
Error: Expected '(' in argument list of function declaration.

When I remove the #Preview macro and create the SwiftUI preview with the old method, the compiler will fail on another one of these errors, but for a different preview. It seems like Prefires parsing of the #Preview macro is incorrectly adding a curly brace to the name in the generated code.

Example #Preview:

#Preview {
    VStack {
        Redacted("Hello, World!", .style1, .color1)
    }
}

The generated code in PreviewTests.generated, note the VStack{ reference in the name.

func test_VStack{_Preview() {
    let preview = {
        VStack {
            Redacted("Hello, World!", .style1, .color1)
        }
    }
    
    if let failure = assertSnapshots(matching: AnyView(preview()), name: "VStack{", isScreen: true, device: deviceConfig) {
        XCTFail(failure)
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.