diff --git a/Source/Session/Session.swift b/Source/Session/Session.swift index 45fcd45..3ed74cd 100644 --- a/Source/Session/Session.swift +++ b/Source/Session/Session.swift @@ -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 @@ -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 diff --git a/Source/Session/VisitOptionsHandler.swift b/Source/Session/VisitOptionsHandler.swift new file mode 100644 index 0000000..303337a --- /dev/null +++ b/Source/Session/VisitOptionsHandler.swift @@ -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() + } + } + +} diff --git a/Tests/VisitOptionsTests.swift b/Tests/VisitOptionsTests.swift index f98c1e3..ecd9a85 100644 --- a/Tests/VisitOptionsTests.swift +++ b/Tests/VisitOptionsTests.swift @@ -21,8 +21,31 @@ class VisitOptionsTests: XCTestCase { } func test_Decodable_canBeInitializedWithResponse() throws { + _ = try validVisitVisitOptions(responseHTMLString: "") + } + + func test_visitOptionsArePreserved() throws { + let visitOptionsWithResponse = try validVisitVisitOptions(responseHTMLString: "") + 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": ""}} + {"response": {"statusCode": 200\(responseJSON)}} """.data(using: .utf8)! let options = try JSONDecoder().decode(VisitOptions.self, from: json) @@ -30,6 +53,19 @@ class VisitOptionsTests: XCTestCase { let response = try XCTUnwrap(options.response) XCTAssertEqual(response.statusCode, 200) - XCTAssertEqual(response.responseHTML, "") + 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 } }