From be62ee25560125c674e763d68c4358a4bcceb8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20B=C3=BCnz?= Date: Sat, 14 Sep 2024 21:03:01 +0200 Subject: [PATCH] Update tests.yml (#510) * Update tests.yml * update tests.yaml * update packages * update test * update snapshot tests * make sendable * update package * update fastfile * add config --- .editorconfig | 10 + .github/workflows/tests.yml | 12 +- CriticalMaps.xcodeproj/project.pbxproj | 4 + .../xcshareddata/swiftpm/Package.resolved | 10 +- CriticalMapsKit/Package.swift | 219 ++++++++++-------- .../Sources/ApiClient/Endpoint.swift | 2 +- .../ApiClient/Requests/HTTPMethod.swift | 2 +- .../Sources/ApiClient/Requests/Request.swift | 2 +- .../AppFeatureTests/AppFeatureCoreTests.swift | 14 +- .../UserTrackingButtonSnapshotTests.swift | 8 +- .../test_userTracking_follow.1.png | Bin 3026 -> 2730 bytes .../test_userTracking_followWithHeading.1.png | Bin 3077 -> 2560 bytes .../test_userTracking_none.1.png | Bin 4115 -> 3798 bytes fastlane/Fastfile | 2 +- 14 files changed, 152 insertions(+), 133 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..355b1fc0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*.swift] +indent_style = space +indent_size = 2 +tab_width = 2 +end_of_line = crlf +max_line_length = 180 +trim_trailing_whitespace = true +insert_final_newline = true \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6d3b775c..d88ef448 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ on: jobs: unit_tests: name: Unit Tests - runs-on: macos-13 + runs-on: macos-14 strategy: matrix: platform: @@ -26,16 +26,10 @@ jobs: - name: Setup Xcode version uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: latest-stable - - - name: Setup ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.7 - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + xcode-version: 15.4 - name: Run UnitTests - run: bundle exec fastlane test + run: fastlane test - name: Archive test artifacts uses: actions/upload-artifact@v4 diff --git a/CriticalMaps.xcodeproj/project.pbxproj b/CriticalMaps.xcodeproj/project.pbxproj index 55c09ffd..b0c8ce4f 100644 --- a/CriticalMaps.xcodeproj/project.pbxproj +++ b/CriticalMaps.xcodeproj/project.pbxproj @@ -606,6 +606,7 @@ SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_STRICT_CONCURRENCY = complete; }; name = Debug; }; @@ -661,6 +662,7 @@ SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_STRICT_CONCURRENCY = complete; VALIDATE_PRODUCT = YES; }; name = Release; @@ -689,6 +691,7 @@ PROVISIONING_PROFILE_SPECIFIER = "Critical Maps Prov Profile"; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Criticalmaps dist"; RUN_DOCUMENTATION_COMPILER = NO; + SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -719,6 +722,7 @@ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Criticalmaps dist"; RUN_DOCUMENTATION_COMPILER = NO; SKIP_INSTALL = NO; + SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e2fb766d..cdf186b6 100644 --- a/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,6 +32,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mltbnz/composable-core-location.git", "state" : { + "branch" : "main", "revision" : "1f9070ce561e4ef164cc8e124e37c77eaf2f4b4f" } }, @@ -161,15 +162,6 @@ "version" : "600.0.0" } }, - { - "identity" : "swiftformatplugin", - "kind" : "remoteSourceControl", - "location" : "https://github.com/MarcoEidinger/SwiftFormatPlugin", - "state" : { - "revision" : "cc9614586ab73e7137959396885a13773d89f66e", - "version" : "0.50.3" - } - }, { "identity" : "xctest-dynamic-overlay", "kind" : "remoteSourceControl", diff --git a/CriticalMapsKit/Package.swift b/CriticalMapsKit/Package.swift index 27ca552a..b282d7fb 100644 --- a/CriticalMapsKit/Package.swift +++ b/CriticalMapsKit/Package.swift @@ -20,10 +20,6 @@ let package = Package( .library(name: "Styleguide", targets: ["Styleguide"]), ], dependencies: [ - .package( - url: "https://github.com/MarcoEidinger/SwiftFormatPlugin", - from: "0.49.18" - ), .package( url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMajor(from: "1.0.0") @@ -34,7 +30,7 @@ let package = Package( ), .package( url: "https://github.com/mltbnz/composable-core-location.git", - .revisionItem("1f9070ce561e4ef164cc8e124e37c77eaf2f4b4f") + branch: "main" ), .package( url: "https://github.com/pointfreeco/swift-snapshot-testing.git", @@ -57,29 +53,29 @@ let package = Package( .target( name: "ApiClient", dependencies: [ - "Helpers", - "SharedModels" + .helpers, + .sharedModels ] ), .target( name: "AppFeature", dependencies: [ - "ApiClient", - "Helpers", - "FileClient", + .apiClient, + .helpers, + .fileClient, "GuideFeature", - "Logger", - "L10n", - "IDProvider", + .logger, + .l10n, + .idProvider, "MapFeature", "NextRideFeature", - "PathMonitorClient", + .pathMonitorClient, "SettingsFeature", - "SharedDependencies", + .sharedDependencies, "SocialFeature", - "Styleguide", - "UserDefaultsClient", - "UIApplicationClient", + .styleguide, + .userDefaultsClient, + .uiApplicationClient, .tca, .product(name: "BottomSheet", package: "BottomSheet") ] @@ -87,49 +83,49 @@ let package = Package( .target( name: "ChatFeature", dependencies: [ - "ApiClient", - "Helpers", - "IDProvider", - "L10n", - "Logger", - "SharedDependencies", - "SharedModels", - "Styleguide", - "SwiftUIHelpers", - "UserDefaultsClient" + .apiClient, + .helpers, + .idProvider, + .l10n, + .logger, + .sharedDependencies, + .sharedModels, + .styleguide, + .swiftUIHelpers, + .userDefaultsClient ] ), .target( name: "FileClient", dependencies: [ - "Helpers", - "SharedModels", + .helpers, + .sharedModels, .tca ] ), .target( name: "GuideFeature", dependencies: [ - "Helpers", - "L10n", - "Logger", - "Styleguide", - "SwiftUIHelpers" + .helpers, + .l10n, + .logger, + .styleguide, + .swiftUIHelpers ] ), .target( name: "Helpers", dependencies: [ - "Styleguide", + .styleguide, .tca ] ), .target( name: "IDProvider", dependencies: [ - "Helpers", + .helpers, .tca, - "UserDefaultsClient" + .userDefaultsClient ] ), .target( @@ -146,15 +142,15 @@ let package = Package( .target( name: "MapFeature", dependencies: [ - "ApiClient", - "Helpers", - "L10n", - "Logger", + .apiClient, + .helpers, + .l10n, + .logger, "NextRideFeature", - "SharedDependencies", - "SharedModels", - "Styleguide", - "SwiftUIHelpers", + .sharedDependencies, + .sharedModels, + .styleguide, + .swiftUIHelpers, .composableCoreLocation, .tca ] @@ -162,14 +158,14 @@ let package = Package( .target( name: "NextRideFeature", dependencies: [ - "ApiClient", - "Helpers", - "L10n", - "Logger", - "SharedDependencies", - "SharedModels", - "Styleguide", - "UserDefaultsClient", + .apiClient, + .helpers, + .l10n, + .logger, + .sharedDependencies, + .sharedModels, + .styleguide, + .userDefaultsClient, .composableCoreLocation, .tca ] @@ -183,15 +179,15 @@ let package = Package( .target( name: "SettingsFeature", dependencies: [ - "FileClient", - "L10n", - "Logger", - "Helpers", - "SharedDependencies", - "SharedModels", - "Styleguide", - "SwiftUIHelpers", - "UIApplicationClient", + .fileClient, + .l10n, + .logger, + .helpers, + .sharedDependencies, + .sharedModels, + .styleguide, + .swiftUIHelpers, + .uiApplicationClient, .tca, .product(name: "AcknowList", package: "AcknowList") ], @@ -200,19 +196,19 @@ let package = Package( .target( name: "SharedDependencies", dependencies: [ - "ApiClient", - "FileClient", - "IDProvider", - "PathMonitorClient", - "UIApplicationClient", - "UserDefaultsClient", + .apiClient, + .fileClient, + .idProvider, + .pathMonitorClient, + .uiApplicationClient, + .userDefaultsClient, .tca ] ), .target( name: "SharedModels", dependencies: [ - "Helpers", + .helpers, .tca ] ), @@ -220,17 +216,17 @@ let package = Package( name: "SocialFeature", dependencies: [ "ChatFeature", - "L10n", + .l10n, "MastodonFeedFeature", - "UserDefaultsClient", + .userDefaultsClient, .tca ] ), .target( name: "Styleguide", dependencies: [ - "L10n", - "SwiftUIHelpers" + .l10n, + .swiftUIHelpers ], exclude: ["README.md"], resources: [.process("Resources")] @@ -248,12 +244,12 @@ let package = Package( .target( name: "MastodonFeedFeature", dependencies: [ - "ApiClient", - "Logger", - "SharedDependencies", - "SharedModels", - "Styleguide", - "UIApplicationClient", + .apiClient, + .logger, + .sharedDependencies, + .sharedModels, + .styleguide, + .uiApplicationClient, .tca, .product(name: "MastodonKit", package: "MastodonKit") ] @@ -267,8 +263,8 @@ let package = Package( .target( name: "UserDefaultsClient", dependencies: [ - "Helpers", - "SharedModels", + .helpers, + .sharedModels, .tca ] ) @@ -282,8 +278,8 @@ package.targets.append(contentsOf: [ name: "AppFeatureTests", dependencies: [ "AppFeature", - "PathMonitorClient", - "TestHelper", + .pathMonitorClient, + .testHelper, .tca, ], exclude: [ @@ -294,9 +290,9 @@ package.targets.append(contentsOf: [ name: "ChatFeatureTests", dependencies: [ "ChatFeature", - "TestHelper", - "SharedModels", - "UserDefaultsClient", + .testHelper, + .sharedModels, + .userDefaultsClient, .tca ], exclude: [ @@ -306,19 +302,19 @@ package.targets.append(contentsOf: [ .testTarget( name: "HelperTests", dependencies: [ - "Helpers", - "UserDefaultsClient" + .helpers, + .userDefaultsClient ] ), .testTarget( name: "IDProviderTests", - dependencies: ["IDProvider"] + dependencies: [.idProvider] ), .testTarget( name: "MapFeatureTests", dependencies: [ "MapFeature", - "TestHelper", + .testHelper, .tca ], exclude: [ @@ -328,8 +324,8 @@ package.targets.append(contentsOf: [ .testTarget( name: "NextRideFeatureTests", dependencies: [ - "Helpers", - "UserDefaultsClient", + .helpers, + .userDefaultsClient, "NextRideFeature", .tca ] @@ -338,15 +334,15 @@ package.targets.append(contentsOf: [ name: "SocialFeatureTests", dependencies: [ "SocialFeature", - "TestHelper", + .testHelper, .tca ] ), .testTarget( name: "StyleguideTests", dependencies: [ - "Styleguide", - "TestHelper", + .styleguide, + .testHelper, .tca ], exclude: ["__Snapshots__"] @@ -354,11 +350,11 @@ package.targets.append(contentsOf: [ .testTarget( name: "SettingsFeatureTests", dependencies: [ - "Helpers", - "L10n", + .helpers, + .l10n, "SettingsFeature", - "TestHelper", - "UserDefaultsClient", + .testHelper, + .userDefaultsClient, .tca ], exclude: ["__Snapshots__"] @@ -366,10 +362,10 @@ package.targets.append(contentsOf: [ .testTarget( name: "MastodonFeedFeatureTests", dependencies: [ - "Helpers", - "SharedDependencies", + .helpers, + .sharedDependencies, "MastodonFeedFeature", - "TestHelper", + .testHelper, .tca, .product(name: "MastodonKit", package: "MastodonKit") ], @@ -380,6 +376,23 @@ package.targets.append(contentsOf: [ ]) extension Target.Dependency { + // MARK: - Internal + static let apiClient = byName(name: "ApiClient") + static let fileClient = byName(name: "FileClient") + static let helpers = byName(name: "Helpers") + static let idProvider = byName(name: "IDProvider") + static let l10n = byName(name: "L10n") + static let logger = byName(name: "Logger") + static let pathMonitorClient = byName(name: "PathMonitorClient") + static let sharedDependencies = byName(name: "SharedDependencies") + static let sharedModels = byName(name: "SharedModels") + static let styleguide = byName(name: "Styleguide") + static let swiftUIHelpers = byName(name: "SwiftUIHelpers") + static let testHelper = byName(name: "TestHelper") + static let uiApplicationClient = byName(name: "UIApplicationClient") + static let userDefaultsClient = byName(name: "UserDefaultsClient") + + // MARK: - External static let tca = product( name: "ComposableArchitecture", package: "swift-composable-architecture" diff --git a/CriticalMapsKit/Sources/ApiClient/Endpoint.swift b/CriticalMapsKit/Sources/ApiClient/Endpoint.swift index 28c5e78e..7ad6dd29 100644 --- a/CriticalMapsKit/Sources/ApiClient/Endpoint.swift +++ b/CriticalMapsKit/Sources/ApiClient/Endpoint.swift @@ -1,7 +1,7 @@ import Foundation /// A structure to define an endpoint on the Critical Maps API -public struct Endpoint { +public struct Endpoint: Sendable { public let baseUrl: String public let pathComponents: [String] diff --git a/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift b/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift index c9f5a279..89eae2d9 100644 --- a/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift +++ b/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift @@ -1,6 +1,6 @@ import Foundation -public enum HTTPMethod: String { +public enum HTTPMethod: String, Sendable { case get = "GET" case post = "POST" case put = "PUT" diff --git a/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift b/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift index 2c79249a..5a36d131 100644 --- a/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift +++ b/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift @@ -1,7 +1,7 @@ import Foundation import Helpers -public struct Request { +public struct Request: Sendable { let endpoint: Endpoint let httpMethod: HTTPMethod var headers: [String: String] = defaultHeaders diff --git a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift index 335fd183..00dbbb94 100644 --- a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift @@ -275,17 +275,22 @@ final class AppFeatureTests: XCTestCase { } } + @MainActor func test_mapAction_focusEvent() async throws { - throw XCTSkip("Seems to have issues comparing $bottomSheetPosition") - var state = AppFeature.State() state.bottomSheetPosition = .absolute(1) + let testClock = TestClock() + let store = TestStore( initialState: state, - reducer: { AppFeature() } + reducer: { AppFeature() }, + withDependencies: { + $0.continuousClock = testClock + $0.mainQueue = .immediate + } ) - store.dependencies.mainQueue = .immediate + store.exhaustivity = .off(showSkippedAssertions: false) let coordinate = Coordinate.make() @@ -293,6 +298,7 @@ final class AppFeatureTests: XCTestCase { $0.mapFeatureState.eventCenter = CoordinateRegion(center: coordinate.asCLLocationCoordinate) } await store.receive(.binding(.set(\.$bottomSheetPosition, .relative(0.4)))) + await testClock.advance(by: .seconds(1)) await store.receive(.map(.resetRideEventCenter)) { $0.mapFeatureState.eventCenter = nil } diff --git a/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift b/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift index a3a5bc3b..786cdfc9 100644 --- a/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift +++ b/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift @@ -1,4 +1,5 @@ import MapFeature +import SnapshotTesting import TestHelper import XCTest @@ -12,7 +13,7 @@ final class UserTrackingButtonSnapshotTests: XCTestCase { ) ) - assertViewSnapshot(sut, height: 60, width: 60, sloppy: true) + assertSnapshot(of: sut, as: .image) } @MainActor @@ -24,7 +25,7 @@ final class UserTrackingButtonSnapshotTests: XCTestCase { ) ) - assertViewSnapshot(sut, height: 60, width: 60, sloppy: true) + assertSnapshot(of: sut, as: .image) } @MainActor @@ -35,7 +36,6 @@ final class UserTrackingButtonSnapshotTests: XCTestCase { reducer: { UserTrackingFeature() } ) ) - - assertViewSnapshot(sut, height: 60, width: 60, sloppy: true) + assertSnapshot(of: sut, as: .image) } } diff --git a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_follow.1.png b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_follow.1.png index 6562ad64e9ce4806e1bfac6de1e2d38b286d3df4..906dcdeb1386817f1be7301359615161b1ec3512 100644 GIT binary patch literal 2730 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 Mmi88p%?aec0J;diU;qFB literal 3026 zcmd^BjXRV38-GTV*Nj45hS~8Nx-iv}mo1tN5ps+qrG6+;M2OLuoG2tF6^*EfNoFcd zIgz(R^AeetMJJZLgvaJ!`8_*V=bZoH_xnEA{e154_xju~*K=Rr`+lx^93&{nYRCcr zpg?qX^n{Qp7HKKyZQCVf2>~q1lYj>p-CAFu4fUii@syhzU;^pV034rSC?JTS7dTB=5U4a&NHy#R}J$%J!g%+ZmXc6N5X98UHpY>hVG zeSUCo@Q#gzT&5I96*F4tbu=*0D>inw6M@jc)YEJl?C-y2ZQYqE$)VMaEpNSd_pV1& zRPCpSDhG1sUXJ$kjIWlSS#(Zj5fK!t>xG5L3I@Z#-rnBJCm5ZyaJ_U!lCJL@85dWO zo{?dD*>^uuO^px{5uqIYY0X#y6pCtQ?(692U~Ft$uvn~iYGumY*RQpeK34AXoKrD< z)DyP$_I-T5k-ni}0{kg})X*T+*Vh~TKDN3aU@oigIi>5cED+?Zz|&Y^@n2b0Rb2)F zkrWMJHc4@G?{9zpiLGO?_WBSbU<3CIb#;@QwVuf*vy9qBqQr{FkI^ua;_t&k?7F3s z4$9$c!+7eNrlzL1kIyON<07Z1$jFbW73^5qWC6bVRbyjFP*BR^;^G-eGM(}0(Kr0^ zm@V8P;R&z0x*CJU62E-;!n#~p#hG{vuZMB8ox$<(6sgUdjZvs3S~i@&zJ5v3`>Y5B z<2K7P7!0ijydD}IE=Tq+#IE07bMJwH_g*Z%5h9VuLnlt4p}G!fKLrYJ+`vu5*|x$s zXG>qO*=~mqAI=oTaXSp(%z_|O^YHLmF))j_b8&I;_VqPt2|M%hb@N-_EgLfJHCpo16QSbui3t=8V#C-5$l{ zn4Gz;E`?g2C-=We1emDt+FGly&`^uSgqv47D*P8FEGP6n+X1UQs!$+! z#A4CbMWUg~w$%*6kx~=+&$wy^!;?sqacR~Fso8v^uQM?*HpoO~b!qA5(BsOTHsej=YxWRI&cH#AL{C?lWAG}@l2U6*( zm)r@Fl9H0?cc1jfKbQ9JV3MnkL^z_Bh6@V|8GgqW_LSoumX!si4%mK1+=*@xs+cI2 z<1*B+xpCIk33Cbx3MT$B{pQvoH5%u*hbFc}F60NbbQ(XhOM>Rg#>SZXg+!=PtBM=- zY$4XgG#qhYem;^XRDnw>Nh)D1wl+7ny>9b%!&qC!@M3XIZLSFUYu*Tq6#{J$$>U{d zub6nweEH(pFexv;ZLH?O^uDQGy|tjd+QM*8&yB}bRTqqnjfsi#b90#&bH=Z2?7X|{ z)$nJ5V8G4Q^;viK!9fn^BXns34j;~YTv-{dqN2ih`En#LFYkG8Z|?_oX=$^Hnp#6i ziQdn?zI<6(*&|6wjh&sHQO}=0H#amijCt4H9YZFQ&8@8ZP6h`*1HtHg8g0_k%WGqV zQuOA{8=k^=*1iUrV#=M*t*vPZ6iO`AC+3!y-$N~+Atfb6=Vl|DEvi>qFPI{Plo=f$ z5Gbzv(b0f1vyws8;yg>}>aHmjLq*Tq_3J5rs!zx4L+aSbh&NaFcDRzCaXr*Vm(kGy z0Rc1fF=Z-xLy*n!rS2CY_egh(ihOR{y%4i(!i(8`*@}vaq&`Bu8Ggsf-B@gSJXKp= z{m|`wTruNSdAYH5FVi4$%pwrlwQ_aC$n7uAZ}ykMJ{IenMrGm!I3Yb0^7*dm0Kz#Q+1bS1ZSUXb{e1vc zSw_^}!{b$B3TDMAM(E)ac-_%SNsJ!{^Uxgoh>mu5&+7FSh@HG0%Ru3HiiwvlRbui) zVw-aw#Ws8Q<{FSP#k(ag*N=_{$Ht0!9ozr)W!nw$_*`FfUvHK`>M& zX}b=Lnwgb9PvG%*HuD;0N!?BffirDpS`yO8Ev@bi7w2174)O;Ee8ygH7_*PrJMxc> zToMg*bzMIl7PjgcHlH4lpP%0tzo1Lmgy8Bte4Vve3Qe$#0E4-W`*pGE&x?yuV=r}X zO%J~Ml@nMivmB_cqchsxe$~dtCL>_gtbY=-RYKa#$jB7o5F%&%^cM(lxS$jO@9%sA zNd@q7va)iJXMFmM?k0qvhlj6jGDp=jcrz-QbNTXb5-=(&ThB%sMpfOmO;uW#nYwKV z2LYY_!~rNaD{b3?2a4hFRJeq6ILavo@jn`B1Lky)z*`X#MbK|8Ky*6j$iN@F{9hgd BKzslI diff --git a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_followWithHeading.1.png b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_followWithHeading.1.png index 8927498ba76cb438f4b359297fd6ef160dc0e040..7248509e42202e29da861a0f89d69269d8163fcf 100644 GIT binary patch literal 2560 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 Mb#NhbNdfHt0I1pwWB>pF diff --git a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_none.1.png b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_none.1.png index fd8ab312bfcccd1703cbc920d74c85b93bab1b29..d8c276881048bd5e9454debeac71c66bb587f6f9 100644 GIT binary patch literal 3798 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 PV*t!e(8jL~u{Zw@HXX{5 literal 4115 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 yNS+;73