Skip to content

Commit 763f61c

Browse files
committed
test: add unit tests
1 parent 949ed1f commit 763f61c

File tree

9 files changed

+442
-10
lines changed

9 files changed

+442
-10
lines changed

OSInAppBrowserLib.xcodeproj/project.pbxproj

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
4040
75EF1AFB2C13069E005D7164 /* OSIABViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EF1AFA2C13069E005D7164 /* OSIABViewModelTests.swift */; };
4141
75EF1AFD2C1306B1005D7164 /* OSIABCacheManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EF1AFC2C1306B1005D7164 /* OSIABCacheManagerTests.swift */; };
4242
75EF1B012C134878005D7164 /* OSIABWebViewStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EF1B002C134878005D7164 /* OSIABWebViewStub.swift */; };
43+
887287832E717E8F00D9E41B /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 887287822E717E8F00D9E41B /* ViewInspector */; };
44+
8872878B2E71806200D9E41B /* OSIABWebViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8872878A2E71806200D9E41B /* OSIABWebViewTests.swift */; };
45+
8872878F2E7192C200D9E41B /* OSIABWebViewRepresentableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8872878E2E7192C200D9E41B /* OSIABWebViewRepresentableTests.swift */; };
46+
887287912E7194D800D9E41B /* OSIABApplicationRouterAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887287902E7194D800D9E41B /* OSIABApplicationRouterAdapterTests.swift */; };
47+
887287932E7196C800D9E41B /* OSIABErrorViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887287922E7196C800D9E41B /* OSIABErrorViewTests.swift */; };
4348
/* End PBXBuildFile section */
4449

4550
/* Begin PBXContainerItemProxy section */
@@ -87,6 +92,10 @@
8792
75EF1AFA2C13069E005D7164 /* OSIABViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABViewModelTests.swift; sourceTree = "<group>"; };
8893
75EF1AFC2C1306B1005D7164 /* OSIABCacheManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABCacheManagerTests.swift; sourceTree = "<group>"; };
8994
75EF1B002C134878005D7164 /* OSIABWebViewStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABWebViewStub.swift; sourceTree = "<group>"; };
95+
8872878A2E71806200D9E41B /* OSIABWebViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABWebViewTests.swift; sourceTree = "<group>"; };
96+
8872878E2E7192C200D9E41B /* OSIABWebViewRepresentableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABWebViewRepresentableTests.swift; sourceTree = "<group>"; };
97+
887287902E7194D800D9E41B /* OSIABApplicationRouterAdapterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABApplicationRouterAdapterTests.swift; sourceTree = "<group>"; };
98+
887287922E7196C800D9E41B /* OSIABErrorViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIABErrorViewTests.swift; sourceTree = "<group>"; };
9099
/* End PBXFileReference section */
91100

92101
/* Begin PBXFrameworksBuildPhase section */
@@ -102,6 +111,7 @@
102111
buildActionMask = 2147483647;
103112
files = (
104113
7575CF6A2BFCEE6F008F3FD0 /* OSInAppBrowserLib.framework in Frameworks */,
114+
887287832E717E8F00D9E41B /* ViewInspector in Frameworks */,
105115
);
106116
runOnlyForDeploymentPostprocessing = 0;
107117
};
@@ -209,6 +219,8 @@
209219
7575CF6D2BFCEE6F008F3FD0 /* OSInAppBrowserLibTests */ = {
210220
isa = PBXGroup;
211221
children = (
222+
887287902E7194D800D9E41B /* OSIABApplicationRouterAdapterTests.swift */,
223+
8872877F2E717C4600D9E41B /* WebView */,
212224
7575CF7E2BFCEEEA008F3FD0 /* Helper Files */,
213225
75EF1AFC2C1306B1005D7164 /* OSIABCacheManagerTests.swift */,
214226
7575CF7D2BFCEEEA008F3FD0 /* OSIABEngineTests.swift */,
@@ -230,6 +242,24 @@
230242
path = "Helper Files";
231243
sourceTree = "<group>";
232244
};
245+
8872877E2E717C4600D9E41B /* Views */ = {
246+
isa = PBXGroup;
247+
children = (
248+
887287922E7196C800D9E41B /* OSIABErrorViewTests.swift */,
249+
8872878A2E71806200D9E41B /* OSIABWebViewTests.swift */,
250+
8872878E2E7192C200D9E41B /* OSIABWebViewRepresentableTests.swift */,
251+
);
252+
path = Views;
253+
sourceTree = "<group>";
254+
};
255+
8872877F2E717C4600D9E41B /* WebView */ = {
256+
isa = PBXGroup;
257+
children = (
258+
8872877E2E717C4600D9E41B /* Views */,
259+
);
260+
path = WebView;
261+
sourceTree = "<group>";
262+
};
233263
/* End PBXGroup section */
234264

235265
/* Begin PBXHeadersBuildPhase section */
@@ -309,6 +339,9 @@
309339
Base,
310340
);
311341
mainGroup = 7575CF572BFCEE6F008F3FD0;
342+
packageReferences = (
343+
887287812E717E8F00D9E41B /* XCRemoteSwiftPackageReference "ViewInspector" */,
344+
);
312345
productRefGroup = 7575CF622BFCEE6F008F3FD0 /* Products */;
313346
projectDirPath = "";
314347
projectRoot = "";
@@ -394,12 +427,16 @@
394427
buildActionMask = 2147483647;
395428
files = (
396429
756346482C00DD4700685AA3 /* OSIABSafariViewControllerRouterAdapterTests.swift in Sources */,
430+
8872878F2E7192C200D9E41B /* OSIABWebViewRepresentableTests.swift in Sources */,
431+
8872878B2E71806200D9E41B /* OSIABWebViewTests.swift in Sources */,
397432
75EF1AFB2C13069E005D7164 /* OSIABViewModelTests.swift in Sources */,
398433
7575CF812BFCEEEA008F3FD0 /* OSIABRouterSpy.swift in Sources */,
399434
75094A072C121BD9006843E1 /* OSIABCacheManagerStub.swift in Sources */,
435+
887287932E7196C800D9E41B /* OSIABErrorViewTests.swift in Sources */,
400436
75EF1AFD2C1306B1005D7164 /* OSIABCacheManagerTests.swift in Sources */,
401437
7575CF802BFCEEEA008F3FD0 /* OSIABEngineTests.swift in Sources */,
402438
75EF1B012C134878005D7164 /* OSIABWebViewStub.swift in Sources */,
439+
887287912E7194D800D9E41B /* OSIABApplicationRouterAdapterTests.swift in Sources */,
403440
75094A052C1213A3006843E1 /* OSIABWebViewRouterAdapterTests.swift in Sources */,
404441
);
405442
runOnlyForDeploymentPostprocessing = 0;
@@ -619,7 +656,7 @@
619656
CODE_SIGN_STYLE = Automatic;
620657
CURRENT_PROJECT_VERSION = 5;
621658
GENERATE_INFOPLIST_FILE = YES;
622-
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
659+
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
623660
MARKETING_VERSION = 2.2.0;
624661
PRODUCT_BUNDLE_IDENTIFIER = com.outsystems.rd.inappbrowser.OSInAppBrowserLibTests;
625662
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -641,7 +678,7 @@
641678
CODE_SIGN_STYLE = Automatic;
642679
CURRENT_PROJECT_VERSION = 5;
643680
GENERATE_INFOPLIST_FILE = YES;
644-
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
681+
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
645682
MARKETING_VERSION = 2.2.0;
646683
PRODUCT_BUNDLE_IDENTIFIER = com.outsystems.rd.inappbrowser.OSInAppBrowserLibTests;
647684
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -685,6 +722,25 @@
685722
defaultConfigurationName = Release;
686723
};
687724
/* End XCConfigurationList section */
725+
726+
/* Begin XCRemoteSwiftPackageReference section */
727+
887287812E717E8F00D9E41B /* XCRemoteSwiftPackageReference "ViewInspector" */ = {
728+
isa = XCRemoteSwiftPackageReference;
729+
repositoryURL = "https://github.com/nalexn/ViewInspector";
730+
requirement = {
731+
kind = upToNextMajorVersion;
732+
minimumVersion = 0.10.2;
733+
};
734+
};
735+
/* End XCRemoteSwiftPackageReference section */
736+
737+
/* Begin XCSwiftPackageProductDependency section */
738+
887287822E717E8F00D9E41B /* ViewInspector */ = {
739+
isa = XCSwiftPackageProductDependency;
740+
package = 887287812E717E8F00D9E41B /* XCRemoteSwiftPackageReference "ViewInspector" */;
741+
productName = ViewInspector;
742+
};
743+
/* End XCSwiftPackageProductDependency section */
688744
};
689745
rootObject = 7575CF582BFCEE6F008F3FD0 /* Project object */;
690746
}

OSInAppBrowserLib.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1640"
4+
version = "1.7">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES"
8+
buildArchitectures = "Automatic">
9+
</BuildAction>
10+
<TestAction
11+
buildConfiguration = "Debug"
12+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
13+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
14+
shouldUseLaunchSchemeArgsEnv = "YES"
15+
shouldAutocreateTestPlan = "YES">
16+
<Testables>
17+
<TestableReference
18+
skipped = "NO"
19+
parallelizable = "YES">
20+
<BuildableReference
21+
BuildableIdentifier = "primary"
22+
BlueprintIdentifier = "7575CF682BFCEE6F008F3FD0"
23+
BuildableName = "OSInAppBrowserLibTests.xctest"
24+
BlueprintName = "OSInAppBrowserLibTests"
25+
ReferencedContainer = "container:OSInAppBrowserLib.xcodeproj">
26+
</BuildableReference>
27+
</TestableReference>
28+
</Testables>
29+
</TestAction>
30+
<LaunchAction
31+
buildConfiguration = "Debug"
32+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
33+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
34+
launchStyle = "0"
35+
useCustomWorkingDirectory = "NO"
36+
ignoresPersistentStateOnLaunch = "NO"
37+
debugDocumentVersioning = "YES"
38+
debugServiceExtension = "internal"
39+
allowLocationSimulation = "YES">
40+
</LaunchAction>
41+
<ProfileAction
42+
buildConfiguration = "Release"
43+
shouldUseLaunchSchemeArgsEnv = "YES"
44+
savedToolIdentifier = ""
45+
useCustomWorkingDirectory = "NO"
46+
debugDocumentVersioning = "YES">
47+
</ProfileAction>
48+
<AnalyzeAction
49+
buildConfiguration = "Debug">
50+
</AnalyzeAction>
51+
<ArchiveAction
52+
buildConfiguration = "Release"
53+
revealArchiveInOrganizer = "YES">
54+
</ArchiveAction>
55+
</Scheme>
Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
11
import UIKit
22

3-
/// Adapter that makes the required calls so that can perform the External Browser routing.
4-
public class OSIABApplicationRouterAdapter: OSIABRouter {
5-
public typealias ReturnType = Bool
6-
7-
/// Constructor method.
3+
public protocol URLOpener {
4+
func canOpenURL(_ url: URL) -> Bool
5+
func open(_ url: URL, completionHandler: ((Bool) -> Void)?)
6+
}
7+
8+
public class DefaultURLOpener: URLOpener {
89
public init() {}
910

11+
public func canOpenURL(_ url: URL) -> Bool {
12+
UIApplication.shared.canOpenURL(url)
13+
}
14+
15+
public func open(_ url: URL, completionHandler: ((Bool) -> Void)?) {
16+
UIApplication.shared.open(url, completionHandler: completionHandler ?? { _ in })
17+
}
18+
}
19+
20+
public class OSIABApplicationRouterAdapter: OSIABRouter {
21+
public typealias ReturnType = Bool
22+
23+
private let urlOpener: URLOpener
24+
25+
public init(urlOpener: URLOpener = DefaultURLOpener()) {
26+
self.urlOpener = urlOpener
27+
}
28+
1029
public func handleOpen(_ url: URL, _ completionHandler: @escaping (ReturnType) -> Void) {
11-
guard UIApplication.shared.canOpenURL(url) else { return completionHandler(false) }
12-
UIApplication.shared.open(url, completionHandler: completionHandler)
30+
guard urlOpener.canOpenURL(url) else {
31+
return completionHandler(false)
32+
}
33+
urlOpener.open(url, completionHandler: completionHandler)
1334
}
1435
}

Sources/OSInAppBrowserLib/WebView/OSIABWebViewModel.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ class OSIABWebViewModel: NSObject, ObservableObject {
3838
@Published private(set) var addressLabel: String = ""
3939

4040
private var cancellables = Set<AnyCancellable>()
41-
41+
42+
#if DEBUG
43+
/// Test-only method to set error for unit tests
44+
func setErrorForTesting(_ error: Error?) {
45+
self.error = error
46+
}
47+
#endif
48+
4249
/// Constructor method.
4350
/// - Parameters:
4451
/// - url: The current URL being displayed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import XCTest
2+
@testable import OSInAppBrowserLib
3+
4+
class MockURLOpener: URLOpener {
5+
var canOpenURLCalled = false
6+
var openCalled = false
7+
8+
var canOpenURLResult = true
9+
var lastOpenedURL: URL?
10+
var completionResult = true
11+
12+
func canOpenURL(_ url: URL) -> Bool {
13+
canOpenURLCalled = true
14+
return canOpenURLResult
15+
}
16+
17+
func open(_ url: URL, completionHandler: ((Bool) -> Void)?) {
18+
openCalled = true
19+
lastOpenedURL = url
20+
completionHandler?(completionResult)
21+
}
22+
}
23+
24+
final class OSIABApplicationRouterAdapterTests: XCTestCase {
25+
26+
func test_handleOpen_whenCanOpenURLIsFalse_shouldCallCompletionWithFalse() {
27+
let mock = MockURLOpener()
28+
mock.canOpenURLResult = false
29+
let sut = OSIABApplicationRouterAdapter(urlOpener: mock)
30+
31+
let expectation = XCTestExpectation(description: "Completion called")
32+
33+
sut.handleOpen(URL(string: "https://example.com")!) { success in
34+
XCTAssertFalse(success)
35+
XCTAssertTrue(mock.canOpenURLCalled)
36+
XCTAssertFalse(mock.openCalled)
37+
expectation.fulfill()
38+
}
39+
40+
wait(for: [expectation], timeout: 1)
41+
}
42+
43+
func test_handleOpen_whenCanOpenURLIsTrue_shouldOpenURL() {
44+
let mock = MockURLOpener()
45+
mock.canOpenURLResult = true
46+
mock.completionResult = true
47+
let sut = OSIABApplicationRouterAdapter(urlOpener: mock)
48+
49+
let url = URL(string: "https://example.com")!
50+
let expectation = XCTestExpectation(description: "Completion called")
51+
52+
sut.handleOpen(url) { success in
53+
XCTAssertTrue(success)
54+
XCTAssertTrue(mock.canOpenURLCalled)
55+
XCTAssertTrue(mock.openCalled)
56+
XCTAssertEqual(mock.lastOpenedURL, url)
57+
expectation.fulfill()
58+
}
59+
60+
wait(for: [expectation], timeout: 1)
61+
}
62+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import XCTest
2+
import SwiftUI
3+
import ViewInspector
4+
@testable import OSInAppBrowserLib
5+
6+
extension OSIABErrorView: Inspectable {}
7+
8+
final class OSIABErrorViewTests: XCTestCase {
9+
func testShowsErrorMessage() throws {
10+
let view = OSIABErrorView(
11+
NSError(domain: "Test", code: 1, userInfo: nil),
12+
reload: {},
13+
reloadViewLayoutDirection: .fixed(value: .leftToRight)
14+
)
15+
let vStack = try view.inspect().vStack()
16+
let text = try vStack.text(0).string()
17+
XCTAssertEqual(text, "Couldn't load the page content.")
18+
}
19+
20+
func testReloadButtonAction() throws {
21+
var reloaded = false
22+
let view = OSIABErrorView(
23+
NSError(domain: "Test", code: 1, userInfo: nil),
24+
reload: { reloaded = true },
25+
reloadViewLayoutDirection: .fixed(value: .leftToRight)
26+
)
27+
let vStack = try view.inspect().vStack()
28+
let hStack = try vStack.hStack(1)
29+
let button = try hStack.button(0)
30+
try button.tap()
31+
XCTAssertTrue(reloaded)
32+
}
33+
34+
func testReloadButtonLabel() throws {
35+
let view = OSIABErrorView(
36+
NSError(domain: "Test", code: 1, userInfo: nil),
37+
reload: {},
38+
reloadViewLayoutDirection: .fixed(value: .leftToRight)
39+
)
40+
let vStack = try view.inspect().vStack()
41+
let hStack = try vStack.hStack(1)
42+
let button = try hStack.button(0)
43+
let labelHStack = try button.labelView().hStack()
44+
let imageName = try labelHStack.image(0).actualImage().name()
45+
let text = try labelHStack.text(1).string()
46+
XCTAssertEqual(imageName, "arrow.clockwise")
47+
XCTAssertEqual(text, "Reload page")
48+
}
49+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import XCTest
2+
import WebKit
3+
@testable import OSInAppBrowserLib
4+
5+
final class OSIABWebViewRepresentableTests: XCTestCase {
6+
7+
func testInitializerStoresInjectedWebView() {
8+
let webView = WKWebView()
9+
let representable = OSIABWebViewRepresentable(webView)
10+
XCTAssertNotNil(representable)
11+
}
12+
}

0 commit comments

Comments
 (0)