{"id":22191180,"url":"https://github.com/filimo/testableapp","last_synced_at":"2026-04-16T15:32:41.518Z","repository":{"id":83254429,"uuid":"441532700","full_name":"filimo/TestableApp","owner":"filimo","description":"The demo project to show how to organize code to make SwiftUI apps easy to be test.","archived":false,"fork":false,"pushed_at":"2021-12-24T18:48:53.000Z","size":3862,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-15T01:36:54.054Z","etag":null,"topics":["swift","swiftui","testautomation"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/filimo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2021-12-24T18:32:01.000Z","updated_at":"2025-02-28T17:02:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"7976b78c-8cd4-4f7e-8f97-085c5fa3a149","html_url":"https://github.com/filimo/TestableApp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/filimo/TestableApp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filimo%2FTestableApp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filimo%2FTestableApp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filimo%2FTestableApp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filimo%2FTestableApp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/filimo","download_url":"https://codeload.github.com/filimo/TestableApp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filimo%2FTestableApp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31892225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T11:36:10.202Z","status":"ssl_error","status_checked_at":"2026-04-16T11:36:09.652Z","response_time":69,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["swift","swiftui","testautomation"],"created_at":"2024-12-02T12:14:50.058Z","updated_at":"2026-04-16T15:32:41.490Z","avatar_url":"https://github.com/filimo.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"#  TestableApp\n\nI combined [the idea to use functional programming](https://www.swiftbysundell.com/articles/dependency-injection-and-unit-testing-using-async-await/#adding-a-bit-of-functional-programming) instead of an loader instance in ModelView(I prefer to think of it as a service) and [Resolver](https://github.com/hmlongco/Resolver.git).\n\n![video](Assets/CanvasPreview.gif)\n\n## Functional signatures for loads or actions \n```swift\ntypealias AsyncAction\u003cT\u003e = (T) async throws -\u003e Void\ntypealias Loading\u003cT\u003e = () async throws -\u003e T\n```\n\n## How to use it in the app\n```swift\n@main\nstruct TestableApp: App {\n    init() {\n        Resolver.register {\n            NewsService.initLoader()\n        }\n    }\n    \n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n```\n\n## How to use it in a view for running\n```swift\nstruct ContentView_Previews: PreviewProvider {\n    static var previews: some View {\n        Resolver.register {\n            NewsService.mockLoader() //the app isn't running in canvas preview\n//            NewsService.initLoader() //the app is running in canvas preview\n        }\n        \n        return ContentView()\n    }\n}\n```\n\n## How to use it in tests \n```swift\nclass TestableAppTests: XCTestCase {\n    private var service: NewsService!\n    \n    override func setUpWithError() throws {\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n        Resolver.register {\n            NewsService.mockLoader()\n            \n        }\n        service = NewsService()\n    }\n\n    func testLoadingNews() async throws {\n        XCTAssertEqual(service.news.count, 0)\n        try await service.fetchAllNews()\n        XCTAssertGreaterThan(service.news.count, 0)\n    }\n}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilimo%2Ftestableapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffilimo%2Ftestableapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilimo%2Ftestableapp/lists"}