Skip to content

Commit a1d5102

Browse files
committed
Add unit tests for InboxViewModel.
1 parent 441fa01 commit a1d5102

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@
210210
0262DA5B23A244830029AF30 /* Product+ShippingSettingsViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0262DA5A23A244830029AF30 /* Product+ShippingSettingsViewModels.swift */; };
211211
02645D7D27BA027B0065DC68 /* Inbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02645D7927BA027B0065DC68 /* Inbox.swift */; };
212212
02645D7E27BA027B0065DC68 /* InboxViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02645D7A27BA027B0065DC68 /* InboxViewModel.swift */; };
213+
02645D8227BA20A30065DC68 /* InboxViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02645D8127BA20A30065DC68 /* InboxViewModelTests.swift */; };
213214
02691780232600A6002AFC20 /* ProductsTabProductViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0269177F232600A6002AFC20 /* ProductsTabProductViewModelTests.swift */; };
214215
02691782232605B9002AFC20 /* PaginatedListViewControllerStateCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02691781232605B9002AFC20 /* PaginatedListViewControllerStateCoordinatorTests.swift */; };
215216
0269576A23726304001BA0BF /* KeyboardFrameObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0269576923726304001BA0BF /* KeyboardFrameObserver.swift */; };
@@ -1835,6 +1836,7 @@
18351836
0262DA5A23A244830029AF30 /* Product+ShippingSettingsViewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Product+ShippingSettingsViewModels.swift"; sourceTree = "<group>"; };
18361837
02645D7927BA027B0065DC68 /* Inbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Inbox.swift; sourceTree = "<group>"; };
18371838
02645D7A27BA027B0065DC68 /* InboxViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InboxViewModel.swift; sourceTree = "<group>"; };
1839+
02645D8127BA20A30065DC68 /* InboxViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxViewModelTests.swift; sourceTree = "<group>"; };
18381840
0269177F232600A6002AFC20 /* ProductsTabProductViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsTabProductViewModelTests.swift; sourceTree = "<group>"; };
18391841
02691781232605B9002AFC20 /* PaginatedListViewControllerStateCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginatedListViewControllerStateCoordinatorTests.swift; sourceTree = "<group>"; };
18401842
0269576923726304001BA0BF /* KeyboardFrameObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardFrameObserver.swift; sourceTree = "<group>"; };
@@ -3758,6 +3760,14 @@
37583760
path = Inbox;
37593761
sourceTree = "<group>";
37603762
};
3763+
02645D8027BA20950065DC68 /* Inbox */ = {
3764+
isa = PBXGroup;
3765+
children = (
3766+
02645D8127BA20A30065DC68 /* InboxViewModelTests.swift */,
3767+
);
3768+
path = Inbox;
3769+
sourceTree = "<group>";
3770+
};
37613771
0269177E23260090002AFC20 /* Products */ = {
37623772
isa = PBXGroup;
37633773
children = (
@@ -7089,6 +7099,7 @@
70897099
D816DDBA22265D8000903E59 /* ViewRelated */ = {
70907100
isa = PBXGroup;
70917101
children = (
7102+
02645D8027BA20950065DC68 /* Inbox */,
70927103
BAA34C1E2787494300846F3C /* Reviews */,
70937104
03FBDAF7263EE49300ACE257 /* Coupons */,
70947105
BA143222273662DE00E4B3AB /* Settings */,
@@ -9170,6 +9181,7 @@
91709181
B55BC1F321A8790F0011A0C0 /* StringHTMLTests.swift in Sources */,
91719182
455800CC24C6F83F00A8D117 /* ProductSettingsSectionsTests.swift in Sources */,
91729183
D85B833F2230F268002168F3 /* SummaryTableViewCellTests.swift in Sources */,
9184+
02645D8227BA20A30065DC68 /* InboxViewModelTests.swift in Sources */,
91739185
57ABE36824EB048A00A64F49 /* MockSwitchStoreUseCase.swift in Sources */,
91749186
311F827626CD8AB100DF5BAD /* MockCardReaderSettingsAlerts.swift in Sources */,
91759187
02ADC7CE23978EAA008D4BED /* PaginatedProductShippingClassListSelectorDataSourceTests.swift in Sources */,
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import Combine
2+
import XCTest
3+
import Yosemite
4+
@testable import WooCommerce
5+
6+
final class InboxViewModelTests: XCTestCase {
7+
private let sampleSiteID: Int64 = 322
8+
private var subscriptions: [AnyCancellable] = []
9+
10+
override func setUp() {
11+
super.setUp()
12+
subscriptions = []
13+
}
14+
15+
func test_state_is_empty_without_any_actions() {
16+
// Given
17+
let stores = MockStoresManager(sessionManager: .testingInstance)
18+
var invocationCountOfLoadInboxNotes = 0
19+
stores.whenReceivingAction(ofType: InboxNotesAction.self) { action in
20+
guard case .loadAllInboxNotes = action else {
21+
return
22+
}
23+
invocationCountOfLoadInboxNotes += 1
24+
}
25+
let viewModel = InboxViewModel(siteID: sampleSiteID, stores: stores)
26+
27+
// Then
28+
XCTAssertEqual(viewModel.syncState, .empty)
29+
XCTAssertEqual(invocationCountOfLoadInboxNotes, 0)
30+
}
31+
32+
func test_state_is_syncingFirstPage_and_loadAllInboxNotes_is_dispatched_after_the_first_onLoadTrigger() {
33+
// Given
34+
let stores = MockStoresManager(sessionManager: .testingInstance)
35+
var invocationCountOfLoadInboxNotes = 0
36+
stores.whenReceivingAction(ofType: InboxNotesAction.self) { action in
37+
guard case .loadAllInboxNotes = action else {
38+
return
39+
}
40+
invocationCountOfLoadInboxNotes += 1
41+
}
42+
let viewModel = InboxViewModel(siteID: sampleSiteID, stores: stores)
43+
44+
// When
45+
viewModel.onLoadTrigger.send()
46+
let stateAfterTheFirstOnLoadTrigger = viewModel.syncState
47+
48+
viewModel.onLoadTrigger.send()
49+
let stateAfterTheSecondOnLoadTrigger = viewModel.syncState
50+
51+
// Then
52+
XCTAssertEqual(stateAfterTheFirstOnLoadTrigger, .syncingFirstPage)
53+
XCTAssertEqual(stateAfterTheSecondOnLoadTrigger, .syncingFirstPage)
54+
XCTAssertEqual(invocationCountOfLoadInboxNotes, 1)
55+
}
56+
57+
func test_state_is_results_after_onLoadTrigger_with_nonempty_results() {
58+
// Given
59+
let stores = MockStoresManager(sessionManager: .testingInstance)
60+
var invocationCountOfLoadInboxNotes = 0
61+
var syncPageNumber: Int?
62+
let note = InboxNote.fake()
63+
stores.whenReceivingAction(ofType: InboxNotesAction.self) { action in
64+
guard case let .loadAllInboxNotes(_, pageNumber, _, _, _, _, completion) = action else {
65+
return
66+
}
67+
invocationCountOfLoadInboxNotes += 1
68+
syncPageNumber = pageNumber
69+
completion(.success([note]))
70+
}
71+
let viewModel = InboxViewModel(siteID: sampleSiteID, stores: stores)
72+
73+
var states = [InboxViewModel.SyncState]()
74+
viewModel.$syncState.sink { state in
75+
states.append(state)
76+
}.store(in: &subscriptions)
77+
78+
// When
79+
viewModel.onLoadTrigger.send()
80+
81+
// Then
82+
XCTAssertEqual(invocationCountOfLoadInboxNotes, 1)
83+
XCTAssertEqual(syncPageNumber, 1)
84+
XCTAssertEqual(states, [.empty, .syncingFirstPage, .results])
85+
}
86+
87+
func test_state_is_back_to_empty_after_onLoadTrigger_with_empty_results() {
88+
// Given
89+
let stores = MockStoresManager(sessionManager: .testingInstance)
90+
var invocationCountOfLoadInboxNotes = 0
91+
var syncPageNumber: Int?
92+
stores.whenReceivingAction(ofType: InboxNotesAction.self) { action in
93+
guard case let .loadAllInboxNotes(_, pageNumber, _, _, _, _, completion) = action else {
94+
return
95+
}
96+
invocationCountOfLoadInboxNotes += 1
97+
syncPageNumber = pageNumber
98+
completion(.success([]))
99+
}
100+
let viewModel = InboxViewModel(siteID: sampleSiteID, stores: stores)
101+
102+
var states = [InboxViewModel.SyncState]()
103+
viewModel.$syncState.sink { state in
104+
states.append(state)
105+
}.store(in: &subscriptions)
106+
107+
// When
108+
viewModel.onLoadTrigger.send()
109+
110+
// Then
111+
XCTAssertEqual(invocationCountOfLoadInboxNotes, 1)
112+
XCTAssertEqual(syncPageNumber, 1)
113+
XCTAssertEqual(states, [.empty, .syncingFirstPage, .empty])
114+
}
115+
116+
func test_it_loads_next_page_after_onLoadTrigger_and_onLoadNextPageAction_until_the_data_size_is_smaller_than_page_size() {
117+
// Given
118+
let pageSize: Int = 2
119+
120+
let stores = MockStoresManager(sessionManager: .testingInstance)
121+
var invocationCountOfLoadInboxNotes = 0
122+
var syncPageNumber: Int?
123+
let firstPageNotes = [InboxNote](repeating: .fake(), count: pageSize)
124+
let secondPageNotes = [InboxNote](repeating: .fake(), count: pageSize - 1)
125+
stores.whenReceivingAction(ofType: InboxNotesAction.self) { action in
126+
guard case let .loadAllInboxNotes(_, pageNumber, _, _, _, _, completion) = action else {
127+
return
128+
}
129+
invocationCountOfLoadInboxNotes += 1
130+
syncPageNumber = pageNumber
131+
completion(.success(pageNumber == 1 ? firstPageNotes: secondPageNotes))
132+
}
133+
134+
let viewModel = InboxViewModel(siteID: sampleSiteID, pageSize: pageSize, stores: stores)
135+
136+
var states = [InboxViewModel.SyncState]()
137+
viewModel.$syncState.sink { state in
138+
states.append(state)
139+
}.store(in: &subscriptions)
140+
141+
// When
142+
viewModel.onLoadTrigger.send() // Syncs `firstPageNotes` with size as page size.
143+
viewModel.onLoadNextPageAction() // Syncs `secondPageNotes` with size smaller than page size.
144+
viewModel.onLoadNextPageAction() // No more data to be synced.
145+
146+
// Then
147+
XCTAssertEqual(states, [.empty, .syncingFirstPage, .results, .results])
148+
XCTAssertEqual(invocationCountOfLoadInboxNotes, 2)
149+
XCTAssertEqual(syncPageNumber, 2)
150+
}
151+
}

0 commit comments

Comments
 (0)