diff --git a/SDWebImageSwiftUI.xcodeproj/project.pbxproj b/SDWebImageSwiftUI.xcodeproj/project.pbxproj index d747697..48e3759 100644 --- a/SDWebImageSwiftUI.xcodeproj/project.pbxproj +++ b/SDWebImageSwiftUI.xcodeproj/project.pbxproj @@ -48,6 +48,9 @@ 32B933E623659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; }; 32B933E723659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; }; 32B933E823659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; }; + 32BD9C4723E03B08008D5F6A /* IndicatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BD9C4623E03B08008D5F6A /* IndicatorTests.swift */; }; + 32BD9C4823E03B08008D5F6A /* IndicatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BD9C4623E03B08008D5F6A /* IndicatorTests.swift */; }; + 32BD9C4923E03B08008D5F6A /* IndicatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BD9C4623E03B08008D5F6A /* IndicatorTests.swift */; }; 32C43DE622FD54CD00BE87F5 /* SDWebImageSwiftUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 32C43DE422FD54CD00BE87F5 /* SDWebImageSwiftUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32C43DEA22FD577300BE87F5 /* SDWebImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32C43DE922FD577300BE87F5 /* SDWebImage.framework */; }; 32C43DEB22FD577300BE87F5 /* SDWebImage.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 32C43DE922FD577300BE87F5 /* SDWebImage.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -162,6 +165,7 @@ 326B848B236335400011BDFB /* ProgressIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressIndicator.swift; sourceTree = ""; }; 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewWrapper.swift; sourceTree = ""; }; 32B933E423659A1900BB7CAD /* Transition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transition.swift; sourceTree = ""; }; + 32BD9C4623E03B08008D5F6A /* IndicatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndicatorTests.swift; sourceTree = ""; }; 32C43DCC22FD540D00BE87F5 /* SDWebImageSwiftUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageSwiftUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32C43DDC22FD54C600BE87F5 /* ImageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageManager.swift; sourceTree = ""; }; 32C43DDE22FD54C600BE87F5 /* WebImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebImage.swift; sourceTree = ""; }; @@ -254,6 +258,7 @@ 3211F84823DE984D00FC757F /* Info.plist */, 3211F84623DE984D00FC757F /* AnimatedImageTests.swift */, 3211F84F23DE98E300FC757F /* WebImageTests.swift */, + 32BD9C4623E03B08008D5F6A /* IndicatorTests.swift */, ); path = Tests; sourceTree = ""; @@ -704,6 +709,7 @@ buildActionMask = 2147483647; files = ( 3211F85023DE98E300FC757F /* WebImageTests.swift in Sources */, + 32BD9C4723E03B08008D5F6A /* IndicatorTests.swift in Sources */, 3211F84723DE984D00FC757F /* AnimatedImageTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -713,6 +719,7 @@ buildActionMask = 2147483647; files = ( 321C1D6B23DEDB98009CF62A /* WebImageTests.swift in Sources */, + 32BD9C4823E03B08008D5F6A /* IndicatorTests.swift in Sources */, 321C1D6A23DEDB98009CF62A /* AnimatedImageTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -722,6 +729,7 @@ buildActionMask = 2147483647; files = ( 321C1D6D23DEDB98009CF62A /* WebImageTests.swift in Sources */, + 32BD9C4923E03B08008D5F6A /* IndicatorTests.swift in Sources */, 321C1D6C23DEDB98009CF62A /* AnimatedImageTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/AnimatedImageTests.swift b/Tests/AnimatedImageTests.swift index 02c28a7..60136ea 100644 --- a/Tests/AnimatedImageTests.swift +++ b/Tests/AnimatedImageTests.swift @@ -124,6 +124,41 @@ class AnimatedImageTests: XCTestCase { self.waitForExpectations(timeout: 5, handler: nil) } + func testAnimatedImageModifier() throws { + let expectation = self.expectation(description: "WebImage modifier") + let imageUrl = URL(string: "https://assets.sbnation.com/assets/2512203/dogflops.gif") + let imageView = AnimatedImage(url: imageUrl, options: [.progressiveLoad], context: [.imageScaleFactor: 1]) + let introspectView = imageView + .onSuccess { _, _ in + expectation.fulfill() + } + .onFailure { _ in + XCTFail() + } + .onProgress { _, _ in + + } + .placeholder(WebImage.emptyImage) + .indicator(SDWebImageActivityIndicator.medium) + // Image + .resizable() + .renderingMode(.original) + .interpolation(.high) + .antialiased(true) + // Animation + .runLoopMode(.common) + .customLoopCount(1) + .maxBufferSize(0) + .pausable(true) + .purgeable(true) + .playbackRate(1) + .transition(.fade) + .animation(.easeInOut) + _ = try introspectView.inspect(AnimatedImage.self) + ViewHosting.host(view: introspectView) + self.waitForExpectations(timeout: 5, handler: nil) + } + // MARK: Helper func testBundle() -> Bundle { Bundle(for: type(of: self)) diff --git a/Tests/IndicatorTests.swift b/Tests/IndicatorTests.swift new file mode 100644 index 0000000..2c7345c --- /dev/null +++ b/Tests/IndicatorTests.swift @@ -0,0 +1,113 @@ +import XCTest +import SwiftUI +import ViewInspector +import Introspect +@testable import SDWebImageSwiftUI + +extension ActivityIndicator : Inspectable {} +extension ProgressIndicator : Inspectable {} + +#if os(iOS) || os(tvOS) +typealias ActivityIndicatorViewType = UIActivityIndicatorView +typealias ProgressIndicatorViewType = UIProgressView +#else +typealias ActivityIndicatorViewType = NSProgressIndicator +typealias ProgressIndicatorViewType = NSProgressIndicator +#endif + +extension View { + func introspectActivityIndicator(customize: @escaping (ActivityIndicatorViewType) -> ()) -> some View { + return inject(IntrospectionView( + selector: { introspectionView in + guard let viewHost = Introspect.findViewHost(from: introspectionView) else { + return nil + } + return Introspect.previousSibling(containing: ActivityIndicatorViewType.self, from: viewHost) + }, + customize: customize + )) + } + + func introspectProgressIndicator(customize: @escaping (ProgressIndicatorViewType) -> ()) -> some View { + return inject(IntrospectionView( + selector: { introspectionView in + guard let viewHost = Introspect.findViewHost(from: introspectionView) else { + return nil + } + return Introspect.previousSibling(containing: ProgressIndicatorViewType.self, from: viewHost) + }, + customize: customize + )) + } +} + +class IndicatorTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + SDImageCache.shared.clear(with: .all) + } + + func testActivityIndicator() throws { + let expectation = self.expectation(description: "Activity indicator") + let binding = Binding(wrappedValue: true) + let indicator = ActivityIndicator(binding, style: .medium) + let introspectView = indicator.introspectActivityIndicator { indicatorView in + #if os(iOS) || os(tvOS) + XCTAssertTrue(indicatorView.isAnimating) + #endif + binding.wrappedValue = false + XCTAssertFalse(binding.wrappedValue) + XCTAssertFalse(indicator.isAnimating) + #if os(iOS) || os(tvOS) + indicatorView.stopAnimating() + #else + indicatorView.stopAnimation(nil) + #endif + #if os(iOS) || os(tvOS) + XCTAssertFalse(indicatorView.isAnimating) + #endif + expectation.fulfill() + } + _ = try introspectView.inspect(ActivityIndicator.self) + ViewHosting.host(view: introspectView) + self.waitForExpectations(timeout: 5, handler: nil) + } + + func testProgressIndicator() throws { + let expectation = self.expectation(description: "Progress indicator") + let binding = Binding(wrappedValue: true) + let progress = Binding(wrappedValue: 0) + let indicator = ProgressIndicator(binding, progress: progress) + let introspectView = indicator.introspectProgressIndicator { indicatorView in + #if os(iOS) || os(tvOS) + XCTAssertEqual(indicatorView.progress, 0.0) + #else + XCTAssertEqual(indicatorView.doubleValue, 0.0) + #endif + progress.wrappedValue = 1.0 + XCTAssertEqual(indicator.progress, 1.0) + #if os(iOS) || os(tvOS) + indicatorView.setProgress(1.0, animated: true) + #else + indicatorView.increment(by: 1.0) + #endif + #if os(iOS) || os(tvOS) + XCTAssertEqual(indicatorView.progress, 1.0) + #else + XCTAssertEqual(indicatorView.doubleValue, 1.0) + #endif + expectation.fulfill() + } + _ = try introspectView.inspect(ProgressIndicator.self) + ViewHosting.host(view: introspectView) + self.waitForExpectations(timeout: 5, handler: nil) + } + +} diff --git a/Tests/WebImageTests.swift b/Tests/WebImageTests.swift index f1c2cac..8f497b6 100644 --- a/Tests/WebImageTests.swift +++ b/Tests/WebImageTests.swift @@ -15,6 +15,7 @@ class WebImageTests: XCTestCase { override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() + SDImageCache.shared.clear(with: .all) } func testWebImageWithStaticURL() throws { @@ -66,4 +67,44 @@ class WebImageTests: XCTestCase { self.waitForExpectations(timeout: 5, handler: nil) } + func testWebImageModifier() throws { + let expectation = self.expectation(description: "WebImage modifier") + let imageUrl = URL(string: "https://raw.githubusercontent.com/ibireme/YYImage/master/Demo/YYImageDemo/mew_baseline.jpg") + let imageView = WebImage(url: imageUrl, options: [.progressiveLoad], context: [.imageScaleFactor: 1]) + let introspectView = imageView + .onSuccess { _, _ in + expectation.fulfill() + } + .onFailure { _ in + XCTFail() + } + .onProgress { _, _ in + + } + .placeholder { + Circle() + } + // Image + .resizable() + .renderingMode(.original) + .interpolation(.high) + .antialiased(true) + // Animation + .runLoopMode(.common) + .customLoopCount(1) + .maxBufferSize(0) + .pausable(true) + .purgeable(true) + .playbackRate(1) + // WebImage + .retryOnAppear(true) + .cancelOnDisappear(true) + .indicator(.activity) + .transition(.fade) + .animation(.easeInOut) + _ = try introspectView.inspect(WebImage.self) + ViewHosting.host(view: introspectView) + self.waitForExpectations(timeout: 5, handler: nil) + } + }