{"id":15055309,"url":"https://github.com/nalexn/viewinspector","last_synced_at":"2025-05-13T22:06:38.515Z","repository":{"id":37602161,"uuid":"222102253","full_name":"nalexn/ViewInspector","owner":"nalexn","description":"Runtime introspection and unit testing of SwiftUI views","archived":false,"fork":false,"pushed_at":"2025-04-13T06:40:13.000Z","size":2084,"stargazers_count":2333,"open_issues_count":47,"forks_count":167,"subscribers_count":27,"default_branch":"0.10.2","last_synced_at":"2025-04-29T17:47:20.747Z","etag":null,"topics":["best-practices","runtime-typechecking","swift","swift5","swiftui","swiftui-views","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nalexn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["nalexn"],"custom":["https://venmo.com/nallexn"]}},"created_at":"2019-11-16T13:19:44.000Z","updated_at":"2025-04-28T22:35:23.000Z","dependencies_parsed_at":"2023-11-25T09:38:20.038Z","dependency_job_id":"88d27b12-ed8d-400d-9f13-34bece347df6","html_url":"https://github.com/nalexn/ViewInspector","commit_stats":{"total_commits":1075,"total_committers":49,"mean_commits":21.93877551020408,"dds":"0.40930232558139534","last_synced_commit":"95ef7e922bc3b30535cb55e9aec636876c5fa1e0"},"previous_names":[],"tags_count":77,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2FViewInspector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2FViewInspector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2FViewInspector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nalexn%2FViewInspector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nalexn","download_url":"https://codeload.github.com/nalexn/ViewInspector/tar.gz/refs/heads/0.10.2","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251584105,"owners_count":21612960,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["best-practices","runtime-typechecking","swift","swift5","swiftui","swiftui-views","unit-testing"],"created_at":"2024-09-24T21:40:43.708Z","updated_at":"2025-04-29T21:23:40.791Z","avatar_url":"https://github.com/nalexn.png","language":"Swift","funding_links":["https://github.com/sponsors/nalexn","https://venmo.com/nallexn"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eViewInspector 🕵️‍♂️ for SwiftUI\u003c/h1\u003e\n\n\u003cspan align=\"center\"\u003e\n  \n![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20visionOS-lightgrey) [![codecov](https://codecov.io/gh/nalexn/ViewInspector/branch/master/graph/badge.svg)](https://codecov.io/gh/nalexn/ViewInspector)\n\n\u003c/span\u003e\n\n**ViewInspector** is a library for unit testing SwiftUI views.\nIt allows for traversing a view hierarchy at runtime providing direct access to the underlying `View` structs.\n\n## Why?\n\nSwiftUI view is a function of state. We could provide it with the input but could not verify the output... Until now!\n\n## Helpful links\n\n* **[Inspection guide](guide.md)**\n* **[SwiftUI API coverage](readiness.md)**\n\n## Use cases\n\n### 1. Search the view of a specific type or condition\n\nUse one of the `find` functions to quickly locate a specific view or assert there are none of such:\n\n```swift\ntry sut.inspect().find(button: \"Back\")\n\ntry sut.inspect().findAll(ViewType.Text.self,\n                          where: { try $0.attributes().isBold() })\n```\n\nCheck out [this section](guide.md#dynamic-query-with-find) in the guide for the reference.\n\n### 2. Read the inner state of the standard views\n\nStandard SwiftUI views are no longer a black box:\n\n```swift\nlet sut = Text(\"Completed by \\(72.51, specifier: \"%.1f\")%\").font(.caption)\n\nlet string = try sut.inspect().text().string(locale: Locale(identifier: \"es\"))\nXCTAssertEqual(string, \"Completado por 72,5%\")\n\nXCTAssertEqual(try sut.inspect().text().attributes().font(), .caption)\n```\n\nEach view has its own set of inspectable parameters, you can refer to the [API coverage](readiness.md) document to see what's available for a particular SwiftUI view.\n\n### 3. Verify your custom view's state\n\nObtain a copy of your custom view with actual state and references from the hierarchy of any depth:\n\n```swift\nlet sut = try view.inspect().find(CustomView.self).actualView()\nXCTAssertTrue(sut.viewModel.isUserLoggedIn)\n```\n\nThe library can operate with various types of the view's state, such as `@Binding`, `@State`, `@ObservedObject` and `@EnvironmentObject`.\n\n### 4. Trigger side effects\n\nYou can simulate user interaction by programmatically triggering system-control callbacks:\n\n```swift\ntry sut.inspect().find(button: \"Close\").tap()\n\nlet list = try view.inspect().list()\ntry list[5].view(RowItemView.self).callOnAppear()\n```\n\nThe library provides helpers for writing asynchronous tests for views with callbacks.\n\n## FAQs\n\n### Which views and modifiers are supported?\n\nCheck out the [API coverage](readiness.md).\n\n### Is it using private APIs?\n\n**ViewInspector** is using the official Swift reflection API to dissect the view structures. So it'll be production-friendly even if you could somehow ship the test target to the production.\n\n### How do I add it to my Xcode project?\n\nAssure you're adding the framework to your unit-test target. **Do NOT** add it to the main build target.\n\n#### Swift Package Manager\n\n`https://github.com/nalexn/ViewInspector`\n\n#### Carthage\n\n`github \"nalexn/ViewInspector\"`\n\n#### CocoaPods\n\n`pod 'ViewInspector'`\n\n### How do I use it in my project?\n\nPlease refer to the [Inspection guide](guide.md). You can also check out my other [project](https://github.com/nalexn/clean-architecture-swiftui) that harnesses the **ViewInspector** for testing the entire UI.\n\n### Contributions\n\nContributions are welcomed! If you see an unsupported view or modifier, you can either open an issue (so I could prioritize such SwiftUI APIs over the rest), or try to crack it yourself: use the `print(\"\\(Inspector.print(\u003c#view#\u003e) as AnyObject)\")` as the starting point of the investigation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnalexn%2Fviewinspector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnalexn%2Fviewinspector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnalexn%2Fviewinspector/lists"}