Skip to content
Draft
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 @@ -143,6 +143,38 @@ class QRLoginVerifyCoordinatorTests: CoreDataTestCase {
XCTAssertEqual(parentCoordinator.trackStack, expectedTrackStack)
}

func testConfirmFromWaitingForUserVerificationAndAuthenticationRejected() {
let view = QRLoginVerifyViewMock()
let parentCoordinator = ParentCoorinatorMock()
let service = QRLoginServiceMock(coreDataStack: contextManager)
let connectionChecker = QRConnectionCheckerMock(mockConnectionAvailable: true)

let coordinator = QRLoginVerifyCoordinator(token: testToken,
view: view,
parentCoordinator: parentCoordinator,
connectionChecker: connectionChecker,
service: service,
coreDataStack: contextManager)

// Configure the mocks — server responds but rejects authentication
coordinator.state = .waitingForUserVerification
service.responseExpectation = .authenticationRejected

// Trigger the action
coordinator.confirm()

// Verify the coordinator is in the error state, not done
XCTAssertEqual(coordinator.state, .error)

// Check the view stack
let expectedStack: [QRLoginVerifyViewMock.LoginState] = [.showAuthenticating, .showAuthenticationFailedError]
XCTAssertEqual(view.stateStack, expectedStack)

// Verify tracks are being recorded correctly
let expectedTrackStack: [WPAnalyticsEvent] = [.qrLoginVerifyCodeApproved, .qrLoginVerifyCodeFailed]
XCTAssertEqual(parentCoordinator.trackStack, expectedTrackStack)
}

func testConfirmFromWaitingForUserVerificationAndFails() {
let view = QRLoginVerifyViewMock()
let parentCoordinator = ParentCoorinatorMock()
Expand Down Expand Up @@ -375,14 +407,15 @@ private class QRLoginVerifyViewMock: QRLoginVerifyView {
private class QRLoginServiceMock: QRLoginService {
enum ResponseExpectation {
case success
case authenticationRejected
case failure
}

var responseExpectation: ResponseExpectation = .success

override func validate(token: QRLoginToken, success: @escaping(QRLoginValidationResponse) -> Void, failure: @escaping(Error?, QRLoginError?) -> Void) {
switch responseExpectation {
case .success:
case .success, .authenticationRejected:
let json = "{\"browser\": \"browser\",\"location\": \"location\"}"
let data = json.data(using: .utf8) ?? Data()
let jsonDecoder = JSONDecoder()
Expand All @@ -403,6 +436,9 @@ private class QRLoginServiceMock: QRLoginService {
case .success:
success(true)

case .authenticationRejected:
success(false)

case .failure:
failure(NSError.testInstance())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ extension QRLoginVerifyCoordinator {
view.showAuthenticating()
state = .authenticating

service.authenticate(token: token) { _ in
service.authenticate(token: token) { authenticated in
guard authenticated else {
self.state = .error
self.view.showAuthenticationFailedError()
self.parentCoordinator.track(.qrLoginVerifyCodeFailed, properties: ["error": "authentication_failed"])
return
}
self.parentCoordinator.track(.qrLoginAuthenticated)
self.state = .done
self.view.renderCompletion()
Expand Down