diff --git a/AutoCat/Screens/FiltersScreen/FiltersScreen.swift b/AutoCat/Screens/FiltersScreen/FiltersScreen.swift index 2d71b06..be5d1d0 100644 --- a/AutoCat/Screens/FiltersScreen/FiltersScreen.swift +++ b/AutoCat/Screens/FiltersScreen/FiltersScreen.swift @@ -19,6 +19,8 @@ enum DetailScreen: Hashable { struct FiltersScreen: View { + @Environment(\.dismiss) var dismiss + @State var viewModel: FiltersViewModel var body: some View { @@ -107,6 +109,7 @@ struct FiltersScreen: View { ToolbarItem(placement: .topBarTrailing) { Button("Done") { viewModel.applyFilters() + dismiss() } } } diff --git a/AutoCatCore/Models/VehicleRegion.swift b/AutoCatCore/Models/VehicleRegion.swift index 0153f62..28cd847 100644 --- a/AutoCatCore/Models/VehicleRegion.swift +++ b/AutoCatCore/Models/VehicleRegion.swift @@ -4,6 +4,11 @@ public struct VehicleRegion: Codable, Hashable, Sendable { public var name: String public var codes: [Int] + public init(name: String, codes: [Int]) { + self.name = name + self.codes = codes + } + public static func == (lhs: VehicleRegion, rhs: VehicleRegion) -> Bool { return lhs.name == rhs.name } diff --git a/AutoCatCore/Services/SettingsService/SettingsServiceProtocol.swift b/AutoCatCore/Services/SettingsService/SettingsServiceProtocol.swift index 722ec0f..c4b4ec1 100644 --- a/AutoCatCore/Services/SettingsService/SettingsServiceProtocol.swift +++ b/AutoCatCore/Services/SettingsService/SettingsServiceProtocol.swift @@ -6,8 +6,9 @@ // Copyright © 2024 Selim Mustafaev. All rights reserved. // -import Foundation +import Mockable +@Mockable public protocol SettingsServiceProtocol { var user: User { get set } diff --git a/AutoCatTests/Extensions/TestError.swift b/AutoCatTests/Extensions/TestError.swift new file mode 100644 index 0000000..d186183 --- /dev/null +++ b/AutoCatTests/Extensions/TestError.swift @@ -0,0 +1,20 @@ +// +// TestError.swift +// AutoCatTests +// +// Created by Selim Mustafaev on 12.11.2024. +// Copyright © 2024 Selim Mustafaev. All rights reserved. +// + +import Foundation + +enum TestError: LocalizedError { + + case generic + + var errorDescription: String? { + switch self { + case .generic: return "Generic test error" + } + } +} diff --git a/AutoCatTests/FiltersTests.swift b/AutoCatTests/FiltersTests.swift new file mode 100644 index 0000000..4ed7fd0 --- /dev/null +++ b/AutoCatTests/FiltersTests.swift @@ -0,0 +1,117 @@ +// +// FiltersTests.swift +// AutoCatTests +// +// Created by Selim Mustafaev on 12.11.2024. +// Copyright © 2024 Selim Mustafaev. All rights reserved. +// + +import Testing +import AutoCatCore +import Mockable +@testable import AutoCat + +@MainActor +struct FiltersTests { + + var settingsServiceMock = MockSettingsServiceProtocol() + var apiServiceMock = MockApiServiceProtocol() + var viewModel: FiltersViewModel + + let testBrand = "testBrand" + let testColor = "testColor" + let testModel = "testModel" + let testRegion = VehicleRegion(name: "testRegion", codes: [111]) + let testYear = 2222 + + init() { + ServiceContainer.shared.register(SettingsServiceProtocol.self, instance: settingsServiceMock) + ServiceContainer.shared.register(ApiServiceProtocol.self, instance: apiServiceMock) + viewModel = FiltersViewModel(filter: Filter()) + } + + @Test("Main filters data loaded") + func mainDataLoaded() async { + + given(apiServiceMock) + .getBrands().willReturn([testBrand]) + .getColors().willReturn([testColor]) + .getRegions().willReturn([testRegion]) + .getYears().willReturn([testYear]) + .getModels(of: .value(testBrand)).willReturn([testModel]) + + await viewModel.loadData() + await viewModel.loadModels(brand: testBrand) + + verify(apiServiceMock) + .getBrands().called(.once) + .getColors().called(.once) + .getYears().called(.once) + .getModels(of: .value(testBrand)).called(.once) + .getRegions().called(.never) + + #expect(viewModel.brands == [.any, .value(testBrand)]) + #expect(viewModel.colors == [.any, .value(testColor)]) + #expect(viewModel.years == [.any, .value(String(testYear))]) + #expect(viewModel.models == [.any, .value(testModel)]) + } + + @Test("Try second load") + func trySecondLoad() async throws { + + viewModel.brands.append(.value(testBrand)) + viewModel.colors.append(.value(testColor)) + viewModel.years.append(.value(String(testYear))) + viewModel.models.append(.value(testModel)) + + await viewModel.loadData() + + verify(apiServiceMock) + .getBrands().called(.never) + .getColors().called(.never) + .getYears().called(.never) + .getModels(of: .any).called(.never) + .getRegions().called(.never) + + #expect(viewModel.brands == [.any, .value(testBrand)]) + #expect(viewModel.colors == [.any, .value(testColor)]) + #expect(viewModel.years == [.any, .value(String(testYear))]) + #expect(viewModel.models == [.any, .value(testModel)]) + } + + @Test("Load data error") + func loadDataError() async throws { + + given(apiServiceMock) + .getBrands().willThrow(TestError.generic) + .getColors().willThrow(TestError.generic) + .getRegions().willThrow(TestError.generic) + .getYears().willThrow(TestError.generic) + .getModels(of: .any).willThrow(TestError.generic) + + await viewModel.loadData() + await viewModel.loadModels(brand: testBrand) + + #expect(viewModel.brands == [.any]) + #expect(viewModel.colors == [.any]) + #expect(viewModel.years == [.any]) + #expect(viewModel.models == [.any]) + } + + @Test("Clear all filters") + func clearAllFilters() async throws { + + viewModel.currentBrand = .value(testBrand) + viewModel.filter.brand = .value(testBrand) + viewModel.filter.color = .value(testColor) + viewModel.filter.year = .value(String(testYear)) + viewModel.filter.model = .value(testModel) + + viewModel.clearAllFilters() + + #expect(viewModel.filter.brand == .any) + #expect(viewModel.filter.color == .any) + #expect(viewModel.filter.year == .any) + #expect(viewModel.filter.model == .any) + } +} diff --git a/AutoCatTests/Mocks/ApiServiceMock.swift b/AutoCatTests/Mocks/ApiServiceMock.swift deleted file mode 100644 index 4202822..0000000 --- a/AutoCatTests/Mocks/ApiServiceMock.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// ApiServiceMock.swift -// AutoCatTests -// -// Created by Selim Mustafaev on 13.07.2024. -// Copyright © 2024 Selim Mustafaev. All rights reserved. -// - -import AutoCatCore - -actor ApiServiceMock { - - var vehicle = VehicleDto() - - func setVehicle(_ vehicle: VehicleDto) async { - self.vehicle = vehicle - } - - func addNote(text: String) async { - vehicle.notes.append(VehicleNoteDto(text: text)) - } -} - -extension ApiServiceMock: ApiServiceProtocol { - - func add(notes: [VehicleNoteDto], to number: String) async throws -> VehicleDto { - vehicle - } - - func edit(note: VehicleNoteDto) async throws -> VehicleDto { - vehicle - } - - func remove(note id: String) async throws -> VehicleDto { - vehicle - } -}