Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions platforms/swift/Sources/ShopifyCheckoutKit/CheckoutBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ enum BridgeError: Swift.Error {

protocol CheckoutBridgeProtocol {
static func instrument(_ webView: WKWebView, _ instrumentation: InstrumentationPayload)
static func sendMessage(_ webView: WKWebView, messageName: String, messageBody: String?)
@discardableResult static func sendMessage(_ webView: WKWebView, messageName: String, messageBody: String?) async -> Bool
static func sendResponse(_ webView: WKWebView, messageBody: String)
}

Expand All @@ -27,19 +27,27 @@ enum CheckoutBridge: CheckoutBridgeProtocol {

static func instrument(_ webView: WKWebView, _ instrumentation: InstrumentationPayload) {
if let payload = instrumentation.toBridgeEvent() {
sendMessage(webView, messageName: "instrumentation", messageBody: payload)
Task {
await sendMessage(webView, messageName: "instrumentation", messageBody: payload)
}
}
}

static func sendMessage(_ webView: WKWebView, messageName: String, messageBody: String?) {
@discardableResult static func sendMessage(_ webView: WKWebView, messageName: String, messageBody: String?) async -> Bool {
let dispatchMessageBody: String
if let body = messageBody {
dispatchMessageBody = "'\(messageName)', \(body)"
} else {
dispatchMessageBody = "'\(messageName)'"
}
let script = dispatchMessageTemplate(body: dispatchMessageBody)
webView.evaluateJavaScript(script)
do {
try await webView.evaluateJavaScript(script)
return true
} catch {
OSLogger.shared.error("Failed to dispatch bridge message: \(error.localizedDescription)")
return false
}
}

static func sendResponse(_ webView: WKWebView, messageBody: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class CheckoutWebView: WKWebView {

weak var viewDelegate: CheckoutWebViewDelegate?
var presentedEventDidDispatch = false
private var presentedEventDispatchInFlight = false
var checkoutDidPresent: Bool = false {
didSet {
dispatchPresentedMessage(checkoutDidLoad, checkoutDidPresent)
Expand Down Expand Up @@ -151,10 +152,17 @@ class CheckoutWebView: WKWebView {
}

private func dispatchPresentedMessage(_ checkoutDidLoad: Bool, _ checkoutDidPresent: Bool) {
if checkoutDidLoad, checkoutDidPresent, isBridgeAttached {
OSLogger.shared.info("Emitting presented event to checkout")
CheckoutBridge.sendMessage(self, messageName: "presented", messageBody: nil)
presentedEventDidDispatch = true
guard checkoutDidLoad, checkoutDidPresent, isBridgeAttached, !presentedEventDidDispatch, !presentedEventDispatchInFlight else {
return
}

OSLogger.shared.info("Emitting presented event to checkout")
presentedEventDispatchInFlight = true
Task { @MainActor [weak self] in
guard let self else { return }
let didDispatch = await CheckoutBridge.sendMessage(self, messageName: "presented", messageBody: nil)
presentedEventDispatchInFlight = false
presentedEventDidDispatch = didDispatch
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,30 +54,24 @@ class CheckoutBridgeTests: XCTestCase {
}
}

func testSendMessageShouldCallEvaluateJavaScriptPresented() {
@MainActor
func testSendMessageShouldCallEvaluateJavaScriptPresented() async {
let webView = MockWebView()
webView.expectedScript = expectedPresentedScript()
let evaluateJavaScriptExpectation = expectation(
description: "evaluateJavaScript was called"
)
webView.evaluateJavaScriptExpectation = evaluateJavaScriptExpectation

CheckoutBridge.sendMessage(webView, messageName: "presented", messageBody: nil)
let didDispatch = await CheckoutBridge.sendMessage(webView, messageName: "presented", messageBody: nil)

wait(for: [evaluateJavaScriptExpectation], timeout: 2)
XCTAssertTrue(didDispatch)
XCTAssertEqual(webView.evaluatedScript, expectedPresentedScript())
}

func testSendMessageWithPayloadEvaulatesJavaScript() {
@MainActor
func testSendMessageWithPayloadEvaulatesJavaScript() async {
let webView = MockWebView()
webView.expectedScript = expectedPayloadScript()
let evaluateJavaScriptExpectation = expectation(
description: "evaluateJavaScript was called"
)
webView.evaluateJavaScriptExpectation = evaluateJavaScriptExpectation

CheckoutBridge.sendMessage(webView, messageName: "payload", messageBody: "{\"one\": true}")
let didDispatch = await CheckoutBridge.sendMessage(webView, messageName: "payload", messageBody: "{\"one\": true}")

wait(for: [evaluateJavaScriptExpectation], timeout: 2)
XCTAssertTrue(didDispatch)
XCTAssertEqual(webView.evaluatedScript, expectedPayloadScript())
}

private func expectedPresentedScript() -> String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,9 @@ class MockCheckoutBridge: CheckoutBridgeProtocol {
instrumentCalled = true
}

static func sendMessage(_: WKWebView, messageName _: String, messageBody _: String?) {
static func sendMessage(_: WKWebView, messageName _: String, messageBody _: String?) async -> Bool {
sendMessageCalled = true
return true
}

static func sendResponse(_: WKWebView, messageBody: String) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
@testable import ShopifyCheckoutKit
import WebKit
import XCTest

class MockWebView: CheckoutWebView {
var expectedScript = ""

var evaluateJavaScriptExpectation: XCTestExpectation?
var evaluatedScript: String?

override func evaluateJavaScript(_ javaScriptString: String) async throws -> Any {
if javaScriptString == expectedScript {
evaluateJavaScriptExpectation?.fulfill()
}
evaluatedScript = javaScriptString
return true
}
}
Loading