Skip to content

Commit

Permalink
Merge pull request #155 from hotwired/preserve-visit-options-response
Browse files Browse the repository at this point in the history
Persist visit options if a response is present
  • Loading branch information
jayohms authored Mar 22, 2024
2 parents 3bcea29 + 10e5c90 commit dabd33d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 3 deletions.
7 changes: 6 additions & 1 deletion Source/Session/Session.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ public class Session: NSObject {
private lazy var bridge = WebViewBridge(webView: webView)
private var initialized = false
private var refreshing = false

/// Options behave differently if a response is provided.
private let visitOptionsHandler = VisitOptionsHandler()

private var isShowingStaleContent = false
private var isSnapshotCacheStale = false

Expand Down Expand Up @@ -64,7 +68,8 @@ public class Session: NSObject {
initialized = false
}

let visit = makeVisit(for: visitable, options: options ?? VisitOptions())
let processedOptions = visitOptionsHandler.process(options)
let visit = makeVisit(for: visitable, options: processedOptions)
currentVisit?.cancel()
currentVisit = visit

Expand Down
24 changes: 24 additions & 0 deletions Source/Session/VisitOptionsHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation

class VisitOptionsHandler {

private var unhandledVisitOptions: VisitOptions?

/// If a form submission provides a response HTML, save the options and pass them to the next visit proposal.
func process(_ options: VisitOptions?) -> VisitOptions {

if let options, options.response?.responseHTML != nil {
/// A `responseHTML` is provided for the next visit.
unhandledVisitOptions = options
return options
} else if let unhandledVisitOptions {
/// Next visit is happening. Use the previous `responseHTML`.
self.unhandledVisitOptions = nil
return unhandledVisitOptions
} else {
/// No options are unhandled.
return options ?? VisitOptions()
}
}

}
40 changes: 38 additions & 2 deletions Tests/VisitOptionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,51 @@ class VisitOptionsTests: XCTestCase {
}

func test_Decodable_canBeInitializedWithResponse() throws {
_ = try validVisitVisitOptions(responseHTMLString: "<html></html>")
}

func test_visitOptionsArePreserved() throws {
let visitOptionsWithResponse = try validVisitVisitOptions(responseHTMLString: "<html></html>")
let handler = VisitOptionsHandler()

let processedOptions = handler.process(visitOptionsWithResponse)
XCTAssert(processedOptions == visitOptionsWithResponse)

let nextVisitOptions = try validVisitVisitOptions(responseHTMLString: nil)
let savedOptions = handler.process(nextVisitOptions)
XCTAssert(savedOptions == visitOptionsWithResponse)
}
}

extension VisitOptionsTests {
func validVisitVisitOptions(responseHTMLString: String?) throws -> VisitOptions {
var responseJSON = ""
if let responseHTMLString {
responseJSON = ", \"responseHTML\": \"\(responseHTMLString)\""
}

let json = """
{"response": {"statusCode": 200, "responseHTML": "<html></html>"}}
{"response": {"statusCode": 200\(responseJSON)}}
""".data(using: .utf8)!

let options = try JSONDecoder().decode(VisitOptions.self, from: json)
XCTAssertEqual(options.action, .advance)

let response = try XCTUnwrap(options.response)
XCTAssertEqual(response.statusCode, 200)
XCTAssertEqual(response.responseHTML, "<html></html>")
XCTAssertEqual(response.responseHTML, responseHTMLString)
return options
}
}

extension VisitOptions : Equatable {
public static func == (lhs: VisitOptions, rhs: VisitOptions) -> Bool {
lhs.action == rhs.action && lhs.response == rhs.response
}
}

extension VisitResponse : Equatable {
public static func == (lhs: VisitResponse, rhs: VisitResponse) -> Bool {
lhs.responseHTML == rhs.responseHTML && lhs.statusCode == rhs.statusCode
}
}

0 comments on commit dabd33d

Please sign in to comment.