Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public struct ShopifyCheckout: UIViewControllerRepresentable, CheckoutConfigurab
var onFailAction: ((CheckoutError) -> Void)?

public init(checkout url: URL) {
checkoutURL = CheckoutProtocol.url(for: url, colorScheme: ShopifyCheckoutKit.configuration.colorScheme.rawValue)
Comment thread
toneymathews marked this conversation as resolved.
checkoutURL = CheckoutProtocol.url(for: url)

ShopifyCheckoutKit.invalidateOnConfigurationChange = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public func preload(checkout url: URL) {
return
}

let url = CheckoutProtocol.url(for: url, colorScheme: configuration.colorScheme.rawValue)
let url = CheckoutProtocol.url(for: url)
CheckoutWebView.preloadingActivatedByClient = true
CheckoutWebView.for(checkout: url).load(checkout: url, isPreload: true)
}
Expand All @@ -64,15 +64,15 @@ public func invalidate() {

@discardableResult
public func present(checkout url: URL, from: UIViewController, client: (any CheckoutCommunicationProtocol)? = nil) -> CheckoutViewController {
let decorated = CheckoutProtocol.url(for: url, colorScheme: configuration.colorScheme.rawValue)
let decorated = CheckoutProtocol.url(for: url)
let viewController = CheckoutViewController(checkout: decorated, client: client)
from.present(viewController, animated: true)
return viewController
}

@discardableResult
package func present(checkout url: URL, from: UIViewController, entryPoint: MetaData.EntryPoint, client: (any CheckoutCommunicationProtocol)? = nil) -> CheckoutViewController {
let decorated = CheckoutProtocol.url(for: url, colorScheme: configuration.colorScheme.rawValue)
let decorated = CheckoutProtocol.url(for: url)
let viewController = CheckoutViewController(checkout: decorated, client: client, entryPoint: entryPoint)
from.present(viewController, animated: true)
return viewController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,16 @@ import Foundation
extension CheckoutProtocol {
/// Returns the given checkout URL with the query parameters required to
/// initiate the Embedded Checkout Protocol handshake (`ec_version`,
/// `ec_color_scheme`, `ec_delegate`).
/// `ec_delegate`).
public static func url(
for url: URL,
colorScheme: String,
delegations: [String] = defaultDelegations
) -> URL {
guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return url
}
var queryItems = components.queryItems ?? []
queryItems.append(URLQueryItem(name: "ec_version", value: specVersion))
queryItems.append(URLQueryItem(name: "ec_color_scheme", value: colorScheme))
if !delegations.isEmpty {
queryItems.append(URLQueryItem(name: "ec_delegate", value: delegations.joined(separator: ",")))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,53 +27,41 @@ import Testing

@Suite("CheckoutProtocol URL Tests")
struct CheckoutProtocolURLTests {
@Test func appendsVersionAndColorScheme() throws {
let input = try #require(URL(string: "https://shop.example.com/checkout"))
let result = CheckoutProtocol.url(for: input, colorScheme: "automatic")
private let baseURL = URL(string: "https://shop.com/cart/c/abc")!

let components = try #require(URLComponents(url: result, resolvingAgainstBaseURL: false))
let items = try #require(components.queryItems)
#expect(items.contains(URLQueryItem(name: "ec_version", value: CheckoutProtocol.specVersion)))
#expect(items.contains(URLQueryItem(name: "ec_color_scheme", value: "automatic")))
private func queryItems(_ url: URL) -> [URLQueryItem] {
URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems ?? []
}

@Test func appendsDefaultDelegate() throws {
let input = try #require(URL(string: "https://shop.example.com/checkout"))
let result = CheckoutProtocol.url(for: input, colorScheme: "light")
@Test func appendsEcVersion() {
let items = queryItems(CheckoutProtocol.url(for: baseURL))
#expect(items.contains(URLQueryItem(name: "ec_version", value: CheckoutProtocol.specVersion)))
}

let components = try #require(URLComponents(url: result, resolvingAgainstBaseURL: false))
let items = try #require(components.queryItems)
@Test func appendsDefaultDelegate() {
let items = queryItems(CheckoutProtocol.url(for: baseURL))
#expect(items.contains(URLQueryItem(name: "ec_delegate", value: "window.open")))
}

@Test func joinsMultipleDelegationsWithComma() throws {
let input = try #require(URL(string: "https://shop.example.com/checkout"))
@Test func joinsMultipleDelegationsWithComma() {
let result = CheckoutProtocol.url(
for: input,
colorScheme: "light",
for: baseURL,
delegations: ["window.open", "payment.credential"]
)

let components = try #require(URLComponents(url: result, resolvingAgainstBaseURL: false))
let items = try #require(components.queryItems)
let items = queryItems(result)
#expect(items.contains(URLQueryItem(name: "ec_delegate", value: "window.open,payment.credential")))
}

@Test func omitsDelegateWhenEmpty() throws {
let input = try #require(URL(string: "https://shop.example.com/checkout"))
let result = CheckoutProtocol.url(for: input, colorScheme: "light", delegations: [])

let components = try #require(URLComponents(url: result, resolvingAgainstBaseURL: false))
let items = try #require(components.queryItems)
@Test func omitsDelegateWhenEmpty() {
let items = queryItems(CheckoutProtocol.url(for: baseURL, delegations: []))
#expect(!items.contains(where: { $0.name == "ec_delegate" }))
}

@Test func preservesExistingQueryItems() throws {
let input = try #require(URL(string: "https://shop.example.com/checkout?cart=abc"))
let result = CheckoutProtocol.url(for: input, colorScheme: "light")

let components = try #require(URLComponents(url: result, resolvingAgainstBaseURL: false))
let items = try #require(components.queryItems)
#expect(items.contains(URLQueryItem(name: "cart", value: "abc")))
let url = try #require(URL(string: "https://shop.com/cart/c/abc?key=cart_token&utm_source=email"))
let items = queryItems(CheckoutProtocol.url(for: url))
#expect(items.contains(URLQueryItem(name: "key", value: "cart_token")))
#expect(items.contains(URLQueryItem(name: "utm_source", value: "email")))
#expect(items.contains(URLQueryItem(name: "ec_version", value: CheckoutProtocol.specVersion)))
}
}
Loading