Skip to content

Commit

Permalink
Feature/ios 23 api improvments (#4)
Browse files Browse the repository at this point in the history
* Add filter discussion posts

* courseBannder, certificate from Get course outline by course_id

* dashboard pagination

* fix search courses

* minor fix
  • Loading branch information
IvanStepanok authored Apr 4, 2023
1 parent c3ce770 commit b3c3d09
Show file tree
Hide file tree
Showing 60 changed files with 1,078 additions and 788 deletions.
4 changes: 4 additions & 0 deletions Authorization/Authorization.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
022D04962976DA6500E0059B /* AuthorizationMock.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022D04952976DA6500E0059B /* AuthorizationMock.generated.swift */; };
025F40E029D1E2FC0064C183 /* ResetPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025F40DF29D1E2FC0064C183 /* ResetPasswordView.swift */; };
025F40E229D360E20064C183 /* ResetPasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025F40E129D360E20064C183 /* ResetPasswordViewModel.swift */; };
02E0618429DC2373006E9024 /* ResetPasswordViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E0618329DC2373006E9024 /* ResetPasswordViewModelTests.swift */; };
02F3BFE5292533720051930C /* AuthorizationRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F3BFE4292533720051930C /* AuthorizationRouter.swift */; };
071009C728D1DA4F00344290 /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 071009C628D1DA4F00344290 /* SignInViewModel.swift */; };
07169458296D913400E3DED6 /* Authorization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0770DE3B28D0A319006D8A5D /* Authorization.framework */; platformFilter = ios; };
Expand Down Expand Up @@ -45,6 +46,7 @@
022D04952976DA6500E0059B /* AuthorizationMock.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthorizationMock.generated.swift; sourceTree = "<group>"; };
025F40DF29D1E2FC0064C183 /* ResetPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordView.swift; sourceTree = "<group>"; };
025F40E129D360E20064C183 /* ResetPasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordViewModel.swift; sourceTree = "<group>"; };
02E0618329DC2373006E9024 /* ResetPasswordViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordViewModelTests.swift; sourceTree = "<group>"; };
02ED50CC29A64B90008341CD /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
02F3BFE4292533720051930C /* AuthorizationRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationRouter.swift; sourceTree = "<group>"; };
071009C628D1DA4F00344290 /* SignInViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -170,6 +172,7 @@
07169484296EC3D700E3DED6 /* Login */ = {
isa = PBXGroup;
children = (
02E0618329DC2373006E9024 /* ResetPasswordViewModelTests.swift */,
07169463296D96DD00E3DED6 /* SignInViewModelTests.swift */,
);
path = Login;
Expand Down Expand Up @@ -445,6 +448,7 @@
022D04962976DA6500E0059B /* AuthorizationMock.generated.swift in Sources */,
022D0482297442BA00E0059B /* SignUpViewModelTests.swift in Sources */,
07169464296D96DD00E3DED6 /* SignInViewModelTests.swift in Sources */,
02E0618429DC2373006E9024 /* ResetPasswordViewModelTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
50 changes: 40 additions & 10 deletions Authorization/AuthorizationTests/AuthorizationMock.generated.swift

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//
// ResetPasswordViewModelTests.swift
// AuthorizationTests
//
// Created by  Stepanok Ivan on 04.04.2023.
//

import SwiftyMocky
import XCTest
@testable import Core
@testable import Authorization
import Alamofire
import SwiftUI

final class ResetPasswordViewModelTests: XCTestCase {

func testResetPasswordValidationEmailError() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = ResetPasswordViewModel(interactor: interactor, router: router, validator: validator)

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "e", isRecovered: binding)

Verify(interactor, 0, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, AuthLocalization.Error.invalidEmailAddress)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordSuccess() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = ResetPasswordViewModel(interactor: interactor, router: router, validator: validator)

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

let data = ResetPassword(success: true, responseText: "Success")
Given(interactor, .resetPassword(email: .any, willReturn: data))

await viewModel.resetPassword(email: "[email protected]", isRecovered: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertFalse(isRecoveryPassword)
XCTAssertEqual(viewModel.errorMessage, nil)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, false)
}

func testResetPasswordErrorValidation() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = ResetPasswordViewModel(interactor: interactor, router: router, validator: validator)

let validationErrorMessage = "Some error"
let validationError = CustomValidationError(statusCode: 400, data: ["value": validationErrorMessage])
let error = AFError.responseValidationFailed(reason: AFError.ResponseValidationFailureReason.customValidationFailed(error: validationError))

Given(interactor, .resetPassword(email: .any, willThrow: error))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecovered: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, validationErrorMessage)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordErrorInvalidGrant() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = ResetPasswordViewModel(interactor: interactor, router: router, validator: validator)

Given(interactor, .resetPassword(email: .any, willThrow: APIError.invalidGrant))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecovered: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.invalidCredentials)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordErrorUnknown() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = ResetPasswordViewModel(interactor: interactor, router: router, validator: validator)

Given(interactor, .resetPassword(email: .any, willThrow: NSError()))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecovered: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.unknownError)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordNoInternetError() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = ResetPasswordViewModel(interactor: interactor, router: router, validator: validator)

let noInternetError = AFError.sessionInvalidated(error: URLError(.notConnectedToInternet))

Given(interactor, .resetPassword(email: .any, willThrow: noInternetError))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecovered: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.slowOrNoInternetConnection)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -143,155 +143,5 @@ final class SignInViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.slowOrNoInternetConnection)
XCTAssertEqual(viewModel.isShowProgress, false)
}

func testResetPasswordValidationEmailError() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = SignInViewModel(interactor: interactor, router: router, validator: validator)

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "e", isRecoveryPassord: binding)

Verify(interactor, 0, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, AuthLocalization.Error.invalidEmailAddress)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordSuccess() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = SignInViewModel(interactor: interactor, router: router, validator: validator)

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

let data = ResetPassword(success: true, responseText: "Success")
Given(interactor, .resetPassword(email: .any, willReturn: data))

await viewModel.resetPassword(email: "[email protected]", isRecoveryPassord: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.alertMessage, data.responseText)
XCTAssertEqual(viewModel.errorMessage, nil)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, false)
}

func testResetPasswordErrorValidation() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = SignInViewModel(interactor: interactor, router: router, validator: validator)

let validationErrorMessage = "Some error"
let validationError = CustomValidationError(statusCode: 400, data: ["value": validationErrorMessage])
let error = AFError.responseValidationFailed(reason: AFError.ResponseValidationFailureReason.customValidationFailed(error: validationError))

Given(interactor, .resetPassword(email: .any, willThrow: error))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecoveryPassord: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, validationErrorMessage)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordErrorInvalidGrant() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = SignInViewModel(interactor: interactor, router: router, validator: validator)

Given(interactor, .resetPassword(email: .any, willThrow: APIError.invalidGrant))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecoveryPassord: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.invalidCredentials)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordErrorUnknown() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = SignInViewModel(interactor: interactor, router: router, validator: validator)

Given(interactor, .resetPassword(email: .any, willThrow: NSError()))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecoveryPassord: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.unknownError)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

func testResetPasswordNoInternetError() async throws {
let interactor = AuthInteractorProtocolMock()
let router = AuthorizationRouterMock()
let validator = Validator()
let viewModel = SignInViewModel(interactor: interactor, router: router, validator: validator)

let noInternetError = AFError.sessionInvalidated(error: URLError(.notConnectedToInternet))

Given(interactor, .resetPassword(email: .any, willThrow: noInternetError))

var isRecoveryPassword = true
let binding = Binding(get: {
return isRecoveryPassword
}, set: { value in
isRecoveryPassword = value
})

await viewModel.resetPassword(email: "[email protected]", isRecoveryPassord: binding)

Verify(interactor, 1, .resetPassword(email: .any))

XCTAssertEqual(viewModel.errorMessage, CoreLocalization.Error.slowOrNoInternetConnection)
XCTAssertEqual(viewModel.isShowProgress, false)
XCTAssertEqual(isRecoveryPassword, true)
}

}
4 changes: 4 additions & 0 deletions Core/Core.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
02B2B594295C5C7A00914876 /* Thread.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B2B593295C5C7A00914876 /* Thread.swift */; };
02B3E3B32930198600A50475 /* AVPlayerViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B3E3B22930198600A50475 /* AVPlayerViewControllerExtension.swift */; };
02C2DC0829B63D6200F4445D /* WebViewHTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C2DC0729B63D6200F4445D /* WebViewHTML.swift */; };
02C917F029CDA99E00DBB8BD /* Data_Dashboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C917EF29CDA99E00DBB8BD /* Data_Dashboard.swift */; };
02CF46C829546AA200A698EE /* NoCachedDataError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CF46C729546AA200A698EE /* NoCachedDataError.swift */; };
02D800CC29348F460099CF16 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D800CB29348F460099CF16 /* ImagePicker.swift */; };
02E225B0291D29EB0067769A /* UrlExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E225AF291D29EB0067769A /* UrlExtension.swift */; };
Expand Down Expand Up @@ -187,6 +188,7 @@
02B2B593295C5C7A00914876 /* Thread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thread.swift; sourceTree = "<group>"; };
02B3E3B22930198600A50475 /* AVPlayerViewControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerViewControllerExtension.swift; sourceTree = "<group>"; };
02C2DC0729B63D6200F4445D /* WebViewHTML.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewHTML.swift; sourceTree = "<group>"; };
02C917EF29CDA99E00DBB8BD /* Data_Dashboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data_Dashboard.swift; sourceTree = "<group>"; };
02CF46C729546AA200A698EE /* NoCachedDataError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCachedDataError.swift; sourceTree = "<group>"; };
02D800CB29348F460099CF16 /* ImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePicker.swift; sourceTree = "<group>"; };
02E225AF291D29EB0067769A /* UrlExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlExtension.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -388,6 +390,7 @@
0727877628D23847002E9142 /* DataLayer.swift */,
0727878428D31657002E9142 /* Data_User.swift */,
0283347C28D4D3DE00C828FC /* Data_Discovery.swift */,
02C917EF29CDA99E00DBB8BD /* Data_Dashboard.swift */,
027DB33428D8C8FE002B6862 /* Data_MyCourse.swift */,
021D924728DC860C00ACC565 /* Data_UserProfile.swift */,
0259104929C4A5B6004B5A55 /* UserSettings.swift */,
Expand Down Expand Up @@ -773,6 +776,7 @@
027BD3BE2909478B00392132 /* UIResponder+CurrentResponder.swift in Sources */,
070019AE28F701B200D5FC78 /* Certificate.swift in Sources */,
0770DE5F28D0B22C006D8A5D /* Strings.swift in Sources */,
02C917F029CDA99E00DBB8BD /* Data_Dashboard.swift in Sources */,
024FCD0028EF1CD300232339 /* WebBrowser.swift in Sources */,
027BD3B52909475900392132 /* KeyboardStateObserver.swift in Sources */,
0283347D28D4D3DE00C828FC /* Data_Discovery.swift in Sources */,
Expand Down
Loading

0 comments on commit b3c3d09

Please sign in to comment.