Skip to content

Commit 8583fde

Browse files
committed
✨[feat]: 상세 뷰 작업 구현 및 상세 api 테스트코드 작성 #22
1 parent 548a114 commit 8583fde

File tree

10 files changed

+115
-70
lines changed

10 files changed

+115
-70
lines changed

MarketApp/MarketApp/Network/Main/MainShoesService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ enum MainShoesService {
1414

1515
extension MainShoesService: TargetType {
1616
var baseURL: URL {
17-
return URL(string: "https://run.mocky.io")!
17+
return URL(string: "https://640de3d61a18a5db83827295.mockapi.io")!
1818
}
1919

2020
var path: String {

MarketApp/MarketApp/Network/MarketAPI/AffinityAPI-Main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99

1010
enum AffinityAPI {
1111

12-
static let MainShoes = String("/v3/a238cfb6-d2fa-4884-b42c-a796abe580a1")
12+
static let MainShoes = String("/shoes/")
1313
static let MainDetailShoes = String("/shoes/")
1414

1515

MarketApp/MarketApp/View/Home/HomeView.swift

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct HomeView: View {
1818
@State private var showNikeView: Bool = false
1919

2020
@State private var selectBrandType: BrandType = .all
21-
@State private var filterBrand: [ShoeData] = []
21+
@State private var filterBrand: [ShoesDetailData] = []
2222

2323
@State var path = NavigationPath()
2424

@@ -50,7 +50,7 @@ struct HomeView: View {
5050
viewModel.mainShoesRequest()
5151
}
5252
.onChange(of: selectBrandType) { newValue in
53-
filterBrand = viewModel.shoesData?.filter({ shoes in
53+
filterBrand = viewModel.shoesDetailData?.filter({ shoes in
5454
shoes.brandName == selectBrandType.brandDescription
5555
}) ?? []
5656
}
@@ -168,53 +168,58 @@ struct HomeView: View {
168168
}
169169
}
170170

171-
//MARK: - 리스트 뷰
171+
//MARK: - 리스트 뷰
172172
@ViewBuilder
173173
private func ProductView() -> some View {
174174
LazyVStack {
175-
if let shoesData = viewModel.shoesData {
175+
if let shoesData = viewModel.shoesDetailData {
176176
ProdductListView(shoesData: shoesData)
177+
} else {
178+
ProgressView()
179+
.onAppear {
180+
viewModel.mainShoesRequest()
181+
}
177182
}
178183
}
179184
}
180-
181-
@ViewBuilder
182-
private func SelectBrandProductView() -> some View {
183-
LazyVStack {
184-
if let shoesData = filterBrand {
185-
ProdductListView(shoesData: shoesData)
185+
186+
@ViewBuilder
187+
private func SelectBrandProductView() -> some View {
188+
LazyVStack {
189+
if let shoesData = filterBrand {
190+
ProdductListView(shoesData: shoesData)
191+
}
186192
}
187193
}
188-
}
189-
190-
@ViewBuilder
191-
private func SelectBrandProductVIew() -> some View {
192-
if selectBrandType == .all {
193-
ProductView()
194-
} else if selectBrandType.brandDescription == BrandType.nike.brandDescription {
195-
SelectBrandProductView()
196-
} else if selectBrandType.brandDescription == BrandType.adidas.brandDescription {
197-
SelectBrandProductView()
198-
} else if selectBrandType.brandDescription == BrandType.converse.brandDescription {
199-
SelectBrandProductView()
200-
} else if selectBrandType.brandDescription == BrandType.jordan.brandDescription{
201-
SelectBrandProductView()
202-
} else if selectBrandType.brandDescription == BrandType.miharaYasuhiro.brandDescription {
203-
SelectBrandProductView()
204-
} else if selectBrandType.brandDescription == BrandType.newBalance.brandDescription {
205-
SelectBrandProductView()
206-
} else {
207-
ProductView()
194+
195+
@ViewBuilder
196+
private func SelectBrandProductVIew() -> some View {
197+
if selectBrandType == .all {
198+
ProductView()
199+
} else if selectBrandType.brandDescription == BrandType.nike.brandDescription {
200+
SelectBrandProductView()
201+
} else if selectBrandType.brandDescription == BrandType.adidas.brandDescription {
202+
SelectBrandProductView()
203+
} else if selectBrandType.brandDescription == BrandType.converse.brandDescription {
204+
SelectBrandProductView()
205+
} else if selectBrandType.brandDescription == BrandType.jordan.brandDescription{
206+
SelectBrandProductView()
207+
} else if selectBrandType.brandDescription == BrandType.miharaYasuhiro.brandDescription {
208+
SelectBrandProductView()
209+
} else if selectBrandType.brandDescription == BrandType.newBalance.brandDescription {
210+
SelectBrandProductView()
211+
} else {
212+
ProductView()
213+
}
208214
}
209215
}
210-
}
211-
212-
struct HomeView_Previews: PreviewProvider {
213-
static var previews: some View {
214-
NavigationStack {
215-
HomeView(viewModel: MainShoesViewModel())
216+
217+
struct HomeView_Previews: PreviewProvider {
218+
static var previews: some View {
219+
NavigationStack {
220+
HomeView(viewModel: MainShoesViewModel())
221+
}
216222
}
217223
}
218-
}
219-
220-
224+
225+

MarketApp/MarketApp/View/ProductList/ProdductListView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct ProdductListView: View {
1515

1616
@State private var btnTaped = false
1717
@State private var btnCount = 1
18-
var shoesData: [ShoeData]
18+
var shoesData: [ShoesDetailData]
1919

2020
let columns = [
2121
GridItem(.flexible()),
@@ -26,7 +26,7 @@ struct ProdductListView: View {
2626
ScrollView {
2727
LazyVGrid(columns: columns, spacing: 20) {
2828
ForEach(shoesData) { item in
29-
gridList(image: item.image ?? "", transName: item.transName ?? "", price: item.price ?? "", productName: item.productName ?? "")
29+
gridList(image: item.productImg.first ?? "", transName: item.transName ?? "", price: item.price ?? "", productName: item.productName ?? "")
3030
}
3131
}
3232

@@ -81,6 +81,6 @@ struct ProdductListView: View {
8181

8282
struct ProdductListView_Previews: PreviewProvider {
8383
static var previews: some View {
84-
ProdductListView(shoesData: dev.shoesData)
84+
ProdductListView(shoesData: dev.shoesDetailData)
8585
}
8686
}

MarketApp/MarketApp/View/Profile/ProfileView.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ struct ProfileView: View {
2424
@State private var deniedAlbum = false
2525
@State private var notDeterminedAlbum = false
2626
@State private var editProfileName: Bool = false
27+
@State private var showTermsPolicesView: Bool = false
2728
@State private var selectedImage: UIImage?
2829
@State private var profileImage: Image?
2930

31+
3032
var body: some View {
3133
NavigationStack {
3234
VStack {
@@ -52,6 +54,9 @@ struct ProfileView: View {
5254
.navigationDestination(isPresented: $editProfileName) {
5355
ProfileNickNameView()
5456
}
57+
.navigationDestination(isPresented: $showTermsPolicesView, destination: {
58+
WebViews(url: "https://velog.io/@suhwj/개인정보-처리-방침")
59+
})
5560
//MARK: - 팝업 관련
5661
.popup(isPresented: $showLogoutPOPUPView, type: .default, position: .bottom, animation: .spring(), autohideIn: 2, closeOnTap: true, closeOnTapOutside: true) {
5762
SignOutPOPUPView()
@@ -138,9 +143,7 @@ struct ProfileView: View {
138143

139144
Spacer()
140145
}
141-
142-
143-
146+
144147
Spacer()
145148

146149
}
@@ -227,6 +230,9 @@ struct ProfileView: View {
227230
switch item {
228231
case .termsPolices:
229232
ListArrowView(listTitle: item.description, showView: $showTermsView)
233+
.onTapGesture {
234+
showTermsPolicesView.toggle()
235+
}
230236
case .connatAS:
231237
ListArrowView(listTitle: item.description, showView: $showConnatView)
232238
case .developer:

MarketApp/MarketApp/View/Search/NaviagationSearchView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct NaviagationSearchView: View {
1717
@State private var removeSearch = false
1818
@State var recentSearchList : [String] = []
1919

20-
@State var searchShoesResults : ShoesModel = []
20+
@State var searchShoesResults : ShoesDetailModel = []
2121
private let searchBarPlaceholder: String = "신발을 검색해주세요"
2222

2323
private let minCharacters = 3
@@ -50,9 +50,9 @@ struct NaviagationSearchView: View {
5050
}
5151
.onChange(of: searchText) { searchText in
5252
if searchText.isEmpty {
53-
searchShoesResults = viewModel.shoesData ?? []
53+
searchShoesResults = viewModel.shoesDetailData ?? []
5454
} else {
55-
searchShoesResults = viewModel.shoesData?.filter({ shoes in
55+
searchShoesResults = viewModel.shoesDetailData?.filter({ shoes in
5656
shoes.transName?.contains(searchText) ?? true
5757
}) ?? []
5858
}

MarketApp/MarketApp/View/Search/SearchRowListView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Kingfisher
1010

1111
struct SearchRowListView: View {
1212
@StateObject var viewModel = MainShoesViewModel()
13-
let shoesData: [ShoeData]
13+
let shoesData: [ShoesDetailData]
1414

1515
let columns = [
1616
GridItem(.flexible()),
@@ -21,7 +21,7 @@ struct SearchRowListView: View {
2121
ScrollView {
2222
LazyVGrid(columns: columns, spacing: 30) {
2323
ForEach(shoesData) { item in
24-
gridList(image: item.image ?? "", brandName: item.brandName ?? "", price: item.price ?? "", productName: item.transName ?? "")
24+
gridList(image: item.productImg.first ?? "", brandName: item.brandName ?? "", price: item.price ?? "", productName: item.transName ?? "")
2525
.onAppear {
2626
viewModel.shoesName = item.transName
2727
viewModel.mainDetailShoesRequest()
@@ -74,7 +74,7 @@ struct SearchRowListView: View {
7474
struct SearchRowListView_Previews: PreviewProvider {
7575
static var previews: some View {
7676
NavigationStack {
77-
SearchRowListView(shoesData: dev.shoesData)
77+
SearchRowListView(shoesData: dev.shoesDetailData)
7878
}
7979
}
8080
}

MarketApp/MarketApp/View/Search/SearchView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct SearchView: View {
1313

1414
@State var searchText = ""
1515
@State var removeSearch = false
16-
@State var searchShoesResults : ShoesModel = []
16+
@State var searchShoesResults : ShoesDetailModel = []
1717
@State var recentSearchList : [String] = []
1818

1919
private let searchBarPlaceholder: String = "신발을 검색해주세요"
@@ -36,9 +36,9 @@ struct SearchView: View {
3636
}
3737
.onChange(of: searchText) { searchText in
3838
if searchText.isEmpty {
39-
searchShoesResults = viewModel.shoesData ?? []
39+
searchShoesResults = viewModel.shoesDetailData ?? []
4040
} else {
41-
searchShoesResults = viewModel.shoesData?.filter({ shoes in
41+
searchShoesResults = viewModel.shoesDetailData?.filter({ shoes in
4242
shoes.transName?.contains(searchText) ?? true
4343
}) ?? []
4444
}

MarketApp/MarketApp/ViewModel/MainShoesViewModel/MainShoesViewModel.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class MainShoesViewModel: ObservableObject {
2323
// mainShoesRequest()
2424
}
2525

26-
func toViewModel(_ list: ShoesModel) {
27-
self.shoesData = list
26+
func toViewModel(_ list: ShoesDetailModel) {
27+
self.shoesDetailData = list
2828
}
2929

3030
func toDetailViewModel(_ list: ShoesDetailModel) {
@@ -48,7 +48,7 @@ class MainShoesViewModel: ObservableObject {
4848
print("신발 데이터")
4949
}
5050
}, receiveValue: { model in
51-
let data = try? model.map(ShoesModel.self)
51+
let data = try? model.map(ShoesDetailModel.self)
5252
guard let shoesData = data else { return }
5353
print("신발 데이터 \(shoesData)")
5454
self.toViewModel(shoesData)

MarketApp/MarketAppTests/MainViewModel/MainVIewModelTests.swift

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,37 @@ final class MainVIewModelTests: XCTestCase {
2727

2828

2929
func testToViewModel() {
30-
let mockData = [ShoeData(shoesId: 1, brandName: "Nike", productName: "Nike Air Force 1 '07 Low White", transName: "나이키 에어포스 1 '07 로우 화이트", image: "https://kream-phinf.pstatic.net/MjAyMjA2MTVfMjYw/MDAxNjU1MjgzNjk2Mzk3.gh8n5rs7p-pWVqzIhNh7yj_KdyjLFBeJr9QbsDumoFEg.KdvPfvgBYmjm7MKKhcbIEQIP6FGeuof_GnmcDUgrvyAg.PNG/a_baa1ccea3726495badba419dfede63f9.png?type=m", price: "128,000")]
30+
let mockData = [ShoesDetailData(shoesId: 1, brandName: "Nike", productName: "Nike Air Force 1 '07 Low White", transName: "나이키 에어포스 1 '07 로우 화이트", price: "128,000", productImg: ["https://kream-phinf.pstatic.net/MjAyMjA2MTVfMjYw/MDAxNjU1MjgzNjk2Mzk3.gh8n5rs7p-pWVqzIhNh7yj_KdyjLFBeJr9QbsDumoFEg.KdvPfvgBYmjm7MKKhcbIEQIP6FGeuof_GnmcDUgrvyAg.PNG/a_baa1ccea3726495badba419dfede63f9.png?type=m"])]
3131

3232
viewModel.toViewModel(mockData)
3333

34-
XCTAssertEqual(viewModel.shoesData?.count, mockData.count)
35-
XCTAssertEqual(viewModel.shoesData?.count, mockData.count)
36-
XCTAssertEqual(viewModel.shoesData?.first?.shoesId, mockData.first?.shoesId)
37-
XCTAssertEqual(viewModel.shoesData?.first?.brandName , mockData.first?.brandName)
38-
XCTAssertEqual(viewModel.shoesData?.first?.productName, mockData.first?.productName)
39-
XCTAssertEqual(viewModel.shoesData?.first?.transName, mockData.first?.transName)
40-
XCTAssertEqual(viewModel.shoesData?.first?.image, mockData.first?.image)
41-
XCTAssertEqual(viewModel.shoesData?.first?.price, mockData.first?.price)
34+
XCTAssertEqual(viewModel.shoesDetailData?.count, mockData.count)
35+
XCTAssertEqual(viewModel.shoesDetailData?.count, mockData.count)
36+
XCTAssertEqual(viewModel.shoesDetailData?.first?.shoesId, mockData.first?.shoesId)
37+
XCTAssertEqual(viewModel.shoesDetailData?.first?.brandName , mockData.first?.brandName)
38+
XCTAssertEqual(viewModel.shoesDetailData?.first?.productName, mockData.first?.productName)
39+
XCTAssertEqual(viewModel.shoesDetailData?.first?.transName, mockData.first?.transName)
40+
XCTAssertEqual(viewModel.shoesDetailData?.first?.productImg, mockData.first?.productImg)
41+
XCTAssertEqual(viewModel.shoesDetailData?.first?.price, mockData.first?.price)
4242

4343
}
4444

4545

46+
func testToDetailViewModel() {
47+
let mockData = [ShoesDetailData(shoesId: 1, brandName: "Nike", productName: "Nike Air Force 1 '07 Low White", transName: "나이키 에어포스 1 '07 로우 화이트", price: "128,000", productImg: ["https://kream-phinf.pstatic.net/MjAyMTA5MDlfMTM2/MDAxNjMxMTY4NDgxNjYy.zbjY9wciksaYT7sUz-OdfVfMijT4zlN3ZrP1_FKTIkAg.q1tp-NTfS052i0hTqbYKf1mhtxZZBWEcEm9LUCfevhkg.PNG/a_bd87be02eddb460798690f5d082217c5.png?type=l", "https://kream-phinf.pstatic.net/MjAyMTA5MDlfMTE5/MDAxNjMxMTY4NDg0Mzk1.h6CHbDt3cSsoyGumXlzNmhTa8iNJvWcIzhzimNzNF2Ig.Gh0liKYzQEZ-r3l3gFAX0DBPT9bt2FuywdbiPK1-LJ0g.PNG/a_32465a09d3214e2e8cba85d1bc62ee04.png?type=l", "https://kream-phinf.pstatic.net/MjAyMTA5MDlfMTU5/MDAxNjMxMTY4NDg2Nzg3.Kf0RTLiVjQ2dxE8Z-ZgFPWDQGhJiQKt-LjVvrCo5NS4g.VPstVD7BiTciaEAwad02Z2i85fJvls4-zKUkaQHyElUg.PNG/a_dca56f9e768f4b028640d578f4703575.png?type=l"])]
48+
49+
viewModel.toViewModel(mockData)
50+
51+
XCTAssertEqual(viewModel.shoesDetailData?.count, mockData.count)
52+
XCTAssertEqual(viewModel.shoesDetailData?.count, mockData.count)
53+
XCTAssertEqual(viewModel.shoesDetailData?.first?.shoesId, mockData.first?.shoesId)
54+
XCTAssertEqual(viewModel.shoesDetailData?.first?.brandName , mockData.first?.brandName)
55+
XCTAssertEqual(viewModel.shoesDetailData?.first?.productName, mockData.first?.productName)
56+
XCTAssertEqual(viewModel.shoesDetailData?.first?.transName, mockData.first?.transName)
57+
XCTAssertEqual(viewModel.shoesDetailData?.first?.productImg, mockData.first?.productImg)
58+
XCTAssertEqual(viewModel.shoesDetailData?.first?.price, mockData.first?.price)
59+
}
60+
4661

4762
func test_신발APIRequestTest() {
4863
let expectation = XCTestExpectation(description: "api 통신 테스트")
@@ -56,9 +71,28 @@ final class MainVIewModelTests: XCTestCase {
5671
break
5772
}
5873
}, receiveValue: { model in
59-
let data = try? model.map(ShoesModel.self)
74+
let data = try? model.map(ShoesDetailData.self)
75+
XCTAssertNotNil(data, "shoesModel maping error")
76+
self.viewModel.toViewModel([data!])
77+
expectation.fulfill()
78+
})
79+
}
80+
81+
func test_신발상세APIRequestTest() {
82+
let expectation = XCTestExpectation(description: "api 통신 테스트")
83+
viewModel.shoesCancellable = MoyaProvider<MainDetailService>().requestPublisher(.mainShoesDetail(trans_name: "나이키 에어포스 1 '07 로우 화이트"))
84+
.compactMap { $0 }
85+
.sink(receiveCompletion: { result in
86+
switch result {
87+
case .failure(let error):
88+
XCTFail("api 통신 에러 : \(error.localizedDescription)")
89+
case .finished:
90+
break
91+
}
92+
}, receiveValue: { model in
93+
let data = try? model.map(ShoesDetailData.self)
6094
XCTAssertNotNil(data, "shoesModel maping error")
61-
self.viewModel.toViewModel(data!)
95+
self.viewModel.toDetailViewModel([data!])
6296
expectation.fulfill()
6397
})
6498
}

0 commit comments

Comments
 (0)