Skip to content

Commit 916d5fe

Browse files
Write tests for web view positioning.
1 parent 05cfc99 commit 916d5fe

File tree

3 files changed

+144
-56
lines changed

3 files changed

+144
-56
lines changed

Tests/common/CommonMocks.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import Foundation
77
import UserNotifications
8+
import WebKit
89

910
@testable import IterableSDK
1011

@@ -407,3 +408,60 @@ struct MockAPNSTypeChecker: APNSTypeCheckerProtocol {
407408
self.apnsType = apnsType
408409
}
409410
}
411+
412+
struct MockViewCalculations: ViewCalculationsProtocol {
413+
let viewPosition: ViewPosition
414+
let safeAreaInsets: UIEdgeInsets
415+
416+
func width(for _: UIView) -> CGFloat {
417+
return viewPosition.width
418+
}
419+
420+
func height(for _: UIView) -> CGFloat {
421+
return viewPosition.height
422+
}
423+
424+
func center(for _: UIView) -> CGPoint {
425+
return viewPosition.center
426+
}
427+
428+
func safeAreaInsets(for _: UIView) -> UIEdgeInsets {
429+
return safeAreaInsets
430+
}
431+
}
432+
433+
class MockWebView: WebViewProtocol {
434+
let view: UIView = UIView()
435+
436+
func loadHTMLString(_: String, baseURL _: URL?) -> WKNavigation? {
437+
return nil
438+
}
439+
440+
func set(position: ViewPosition) {
441+
self.position = position
442+
view.frame.size.width = position.width
443+
view.frame.size.height = position.height
444+
view.center = position.center
445+
}
446+
447+
func set(navigationDelegate _: WKNavigationDelegate?) {}
448+
449+
func evaluateJavaScript(_: String, completionHandler: ((Any?, Error?) -> Void)?) {
450+
completionHandler?(height, nil)
451+
}
452+
453+
func layoutSubviews() {}
454+
455+
var position: ViewPosition?
456+
457+
private var height: CGFloat
458+
459+
init(height: CGFloat) {
460+
self.height = height
461+
}
462+
}
463+
464+
struct MockInjectedDependencyModule: InjectedDependencyModuleProtocol {
465+
let viewCalculations: ViewCalculationsProtocol
466+
let webView: WebViewProtocol
467+
}

Tests/swift-sdk-swift-tests/IterableHtmlMessageViewControllerTests.swift

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,63 +21,101 @@ class IterableHtmlMessageViewControllerTests: XCTestCase {
2121
super.tearDown()
2222
}
2323

24-
func testWebViewPositioning() {
24+
func testWebViewTopPositioning() {
2525
IterableAPI.initializeForTesting()
26-
struct MockViewCalculations: ViewCalculationsProtocol {
27-
func width(for _: UIView) -> CGFloat {
28-
return 1234.0
29-
}
30-
}
31-
class MockWebView: WebViewProtocol {
32-
let view: UIView = UIView()
33-
34-
func loadHTMLString(_: String, baseURL _: URL?) -> WKNavigation? {
35-
return nil
36-
}
37-
38-
func set(position: ViewPosition) {
39-
self.position = position
40-
view.frame.size.width = position.width
41-
view.frame.size.height = position.height
42-
view.center = position.center
43-
}
44-
45-
func set(navigationDelegate _: WKNavigationDelegate?) {}
46-
47-
func evaluateJavaScript(_: String, completionHandler: ((Any?, Error?) -> Void)?) {
48-
completionHandler?(CGFloat(200.0), nil)
49-
}
50-
51-
func layoutSubviews() {}
52-
53-
var position: ViewPosition?
54-
}
55-
struct MockInjectedDependencyModule: InjectedDependencyModuleProtocol {
56-
static let shared = MockInjectedDependencyModule()
57-
58-
let viewCalculations: ViewCalculationsProtocol = MockViewCalculations()
59-
60-
let webView: WebViewProtocol = MockWebView()
61-
62-
init() {}
63-
}
26+
checkPositioning(viewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)),
27+
safeAreaInsets: .zero,
28+
inAppHeight: 200,
29+
messageLocation: .top,
30+
expectedWebViewPosition: ViewPosition(width: 1234, height: 200, center: CGPoint(x: 617.0, y: 100.0)))
31+
}
32+
33+
func testWebViewBottomPositioning() {
34+
IterableAPI.initializeForTesting()
35+
checkPositioning(viewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)),
36+
safeAreaInsets: .zero,
37+
inAppHeight: 200,
38+
messageLocation: .bottom,
39+
expectedWebViewPosition: ViewPosition(width: 1234, height: 200, center: CGPoint(x: 617.0, y: 300.0)))
40+
}
41+
42+
func testWebViewCenterPositioning() {
43+
IterableAPI.initializeForTesting()
44+
checkPositioning(viewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)),
45+
safeAreaInsets: .zero,
46+
inAppHeight: 200,
47+
messageLocation: .center,
48+
expectedWebViewPosition: ViewPosition(width: 1234, height: 200, center: CGPoint(x: 617.0, y: 200.0)))
49+
}
50+
51+
func testWebViewFullPositioning() {
52+
IterableAPI.initializeForTesting()
53+
checkPositioning(viewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)),
54+
safeAreaInsets: .zero,
55+
inAppHeight: 200,
56+
messageLocation: .full,
57+
expectedWebViewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)))
58+
}
59+
60+
func testWebViewTopPositioningWithSafeAreaInsets() {
61+
IterableAPI.initializeForTesting()
62+
checkPositioning(viewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)),
63+
safeAreaInsets: UIEdgeInsets(top: 25, left: 0, bottom: 30, right: 0),
64+
inAppHeight: 200,
65+
messageLocation: .top,
66+
expectedWebViewPosition: ViewPosition(width: 1234, height: 200, center: CGPoint(x: 617.0, y: 125.0)))
67+
}
68+
69+
func testWebViewBottomPositioningWithSafeAreaInsets() {
70+
IterableAPI.initializeForTesting()
71+
checkPositioning(viewPosition: ViewPosition(width: 1234, height: 400, center: CGPoint(x: 617.0, y: 200.0)),
72+
safeAreaInsets: UIEdgeInsets(top: 25, left: 0, bottom: 30, right: 0),
73+
inAppHeight: 200,
74+
messageLocation: .bottom,
75+
expectedWebViewPosition: ViewPosition(width: 1234, height: 200, center: CGPoint(x: 617.0, y: 270.0)))
76+
}
77+
78+
private func checkPositioning(viewPosition: ViewPosition,
79+
safeAreaInsets: UIEdgeInsets,
80+
inAppHeight: CGFloat,
81+
messageLocation: IterableMessageLocation,
82+
expectedWebViewPosition: ViewPosition) {
83+
let viewCalculations = MockViewCalculations(viewPosition: viewPosition, safeAreaInsets: safeAreaInsets)
84+
let webView = MockWebView(height: inAppHeight)
85+
let dependencyModule = MockInjectedDependencyModule(viewCalculations: viewCalculations, webView: webView)
6486

6587
InjectedDependencies.shared.set {
66-
MockInjectedDependencyModule.shared as InjectedDependencyModuleProtocol
88+
dependencyModule as InjectedDependencyModuleProtocol
6789
}
6890

6991
let viewController = IterableHtmlMessageViewController.create(parameters: IterableHtmlMessageViewController.Parameters(html: "",
70-
padding: UIEdgeInsets(top: 0, left: 0, bottom: -1, right: 0),
92+
padding: padding(from: messageLocation),
7193
messageMetadata: nil,
7294
isModal: true,
7395
inboxSessionId: nil)).viewController
7496
viewController.loadView()
7597
viewController.viewDidLayoutSubviews()
7698

77-
let mockWebView = MockInjectedDependencyModule.shared.webView as! MockWebView
78-
XCTAssertEqual(mockWebView.view.frame.width, 1234.0)
79-
XCTAssertEqual(mockWebView.view.frame.height, 200.0)
80-
XCTAssertEqual(mockWebView.view.center.x, 617.0)
81-
XCTAssertEqual(mockWebView.view.center.y, 100.0)
99+
checkPosition(for: webView.view, expectedPosition: expectedWebViewPosition)
100+
}
101+
102+
private func checkPosition(for view: UIView, expectedPosition: ViewPosition) {
103+
XCTAssertEqual(view.frame.width, expectedPosition.width)
104+
XCTAssertEqual(view.frame.height, expectedPosition.height)
105+
XCTAssertEqual(view.center.x, expectedPosition.center.x)
106+
XCTAssertEqual(view.center.y, expectedPosition.center.y)
107+
}
108+
109+
private func padding(from messageLocation: IterableMessageLocation) -> UIEdgeInsets {
110+
switch messageLocation {
111+
case .top:
112+
return UIEdgeInsets(top: 0, left: 0, bottom: -1, right: 0)
113+
case .bottom:
114+
return UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
115+
case .center:
116+
return UIEdgeInsets(top: -1, left: 0, bottom: -1, right: 0)
117+
case .full:
118+
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
119+
}
82120
}
83121
}

swift-sdk/Internal/IterableHtmlMessageViewController.swift

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -190,17 +190,9 @@ class IterableHtmlMessageViewController: UIViewController {
190190
let halfWebViewHeight = height / 2
191191
switch location {
192192
case .top:
193-
if #available(iOS 11, *) {
194-
position.center.y = halfWebViewHeight + view.safeAreaInsets.top
195-
} else {
196-
position.center.y = halfWebViewHeight
197-
}
193+
position.center.y = halfWebViewHeight + viewCalculations.safeAreaInsets(for: view).top
198194
case .bottom:
199-
if #available(iOS 11, *) {
200-
position.center.y = view.frame.height - halfWebViewHeight - view.safeAreaInsets.bottom
201-
} else {
202-
position.center.y = view.frame.height - halfWebViewHeight
203-
}
195+
position.center.y = viewCalculations.height(for: view) - halfWebViewHeight - viewCalculations.safeAreaInsets(for: view).bottom
204196
default: break
205197
}
206198

0 commit comments

Comments
 (0)