@@ -10,27 +10,25 @@ import XCTest
1010
1111@testable import Client
1212
13+ @MainActor
1314class HistoryPanelViewModelTests : XCTestCase {
14- var subject : HistoryPanelViewModel !
1515 var profile : MockProfile !
1616
17- override func setUp( ) {
18- super. setUp ( )
17+ override func setUp( ) async throws {
18+ try await super. setUp ( )
1919
2020 DependencyHelperMock ( ) . bootstrapDependencies ( )
2121 profile = MockProfile ( databasePrefix: " HistoryPanelViewModelTest " )
2222 LegacyFeatureFlagsManager . shared. initializeDeveloperFeatures ( with: profile)
2323 profile. reopen ( )
24- subject = HistoryPanelViewModel ( profile: profile)
2524 }
2625
27- override func tearDown( ) {
26+ override func tearDown( ) async throws {
2827 DependencyHelperMock ( ) . reset ( )
2928 clear ( profile: profile)
3029 profile. shutdown ( )
3130 profile = nil
32- subject = nil
33- super. tearDown ( )
31+ try await super. tearDown ( )
3432 }
3533
3634 func testHistorySectionTitle( ) {
@@ -53,131 +51,150 @@ class HistoryPanelViewModelTests: XCTestCase {
5351 }
5452
5553 func testFetchHistory_WithResults( ) {
54+ let subject = createSubject ( )
5655 setupSiteVisits ( )
5756
58- fetchHistory { success in
57+ fetchHistory ( from : subject ) { success in
5958 XCTAssertTrue ( success)
60- XCTAssertFalse ( self . subject. dateGroupedSites. isEmpty)
61- XCTAssertFalse ( self . subject. visibleSections. isEmpty)
59+ XCTAssertFalse ( subject. dateGroupedSites. isEmpty)
60+ XCTAssertFalse ( subject. visibleSections. isEmpty)
6261 }
6362 }
6463
6564 func testFetchHistoryFail_WithFetchInProgress( ) {
65+ let subject = createSubject ( )
6666 subject. isFetchInProgress = true
6767
68- fetchHistory { success in
68+ fetchHistory ( from : subject ) { success in
6969 XCTAssertFalse ( success)
7070 }
7171 }
7272
7373 func testPerformSearch_ForNoResults( ) {
74- fetchSearchHistory ( searchTerm: " moz " ) { hasResults in
74+ let subject = createSubject ( )
75+ fetchSearchHistory ( from: subject, searchTerm: " moz " ) { hasResults in
7576 XCTAssertFalse ( hasResults)
76- XCTAssertEqual ( self . subject. searchResultSites. count, 0 )
77+ XCTAssertEqual ( subject. searchResultSites. count, 0 )
7778 }
7879 }
7980
8081 func testPerformSearch_WithResults( ) {
82+ let subject = createSubject ( )
8183 setupSiteVisits ( )
8284
83- fetchSearchHistory ( searchTerm: " moz " ) { hasResults in
85+ fetchSearchHistory ( from : subject , searchTerm: " moz " ) { hasResults in
8486 XCTAssertTrue ( hasResults)
85- XCTAssertEqual ( self . subject. searchResultSites. count, 2 )
87+ XCTAssertEqual ( subject. searchResultSites. count, 2 )
8688 }
8789 }
8890
8991 func testEmptyStateText_ForSearch( ) {
92+ let subject = createSubject ( )
9093 subject. isSearchInProgress = true
9194 XCTAssertEqual ( subject. emptyStateText, . LibraryPanel. History. NoHistoryResult)
9295 }
9396
9497 func testEmptyStateText_ForHistoryResults( ) {
98+ let subject = createSubject ( )
9599 subject. isSearchInProgress = false
96100 XCTAssertEqual ( subject. emptyStateText, . HistoryPanelEmptyStateTitle)
97101 }
98102
99103 func testShouldShowEmptyState_ForEmptySearch( ) {
104+ let subject = createSubject ( )
100105 setupSiteVisits ( )
101106 subject. isSearchInProgress = true
102107
103- fetchSearchHistory ( searchTerm: " " ) { hasResults in
104- XCTAssertFalse ( self . subject. shouldShowEmptyState ( searchText: " " ) )
108+ fetchSearchHistory ( from : subject , searchTerm: " " ) { hasResults in
109+ XCTAssertFalse ( subject. shouldShowEmptyState ( searchText: " " ) )
105110 }
106111 }
107112
108113 func testShouldShowEmptyState_ForNoResultSearch( ) {
114+ let subject = createSubject ( )
109115 setupSiteVisits ( )
110116 subject. isSearchInProgress = true
111117
112- fetchSearchHistory ( searchTerm: " ui " ) { hasResults in
113- XCTAssertTrue ( self . subject. shouldShowEmptyState ( searchText: " ui " ) )
118+ fetchSearchHistory ( from : subject , searchTerm: " ui " ) { hasResults in
119+ XCTAssertTrue ( subject. shouldShowEmptyState ( searchText: " ui " ) )
114120 }
115121 }
116122
117123 func testShouldShowEmptyState_ForNoHistory( ) {
124+ let subject = createSubject ( )
118125 subject. isSearchInProgress = false
119126
120- fetchHistory { _ in
121- XCTAssertTrue ( self . subject. shouldShowEmptyState ( ) )
127+ fetchHistory ( from : subject ) { _ in
128+ XCTAssertTrue ( subject. shouldShowEmptyState ( ) )
122129 }
123130 }
124131
125132 func testCollapseSection( ) {
133+ let subject = createSubject ( )
126134 setupSiteVisits ( )
127135 XCTAssertTrue ( subject. hiddenSections. isEmpty)
128136
129- fetchHistory { _ in
130- self . subject. collapseSection ( sectionIndex: 1 )
131- XCTAssertEqual ( self . subject. hiddenSections. count, 1 )
137+ fetchHistory ( from : subject ) { _ in
138+ subject. collapseSection ( sectionIndex: 1 )
139+ XCTAssertEqual ( subject. hiddenSections. count, 1 )
132140 // Starts at 0, removing the Additional section
133- XCTAssertTrue ( self . subject. isSectionCollapsed ( sectionIndex: 0 ) )
134- XCTAssertTrue ( self . subject. hiddenSections. contains ( where: { $0 == . lastHour } ) )
141+ XCTAssertTrue ( subject. isSectionCollapsed ( sectionIndex: 0 ) )
142+ XCTAssertTrue ( subject. hiddenSections. contains ( where: { $0 == . lastHour } ) )
135143 }
136144 }
137145
138146 func testExpandSection( ) {
147+ let subject = createSubject ( )
139148 setupSiteVisits ( )
140149 XCTAssertTrue ( subject. hiddenSections. isEmpty)
141150
142- fetchHistory { _ in
143- self . subject. collapseSection ( sectionIndex: 1 )
144- XCTAssertEqual ( self . subject. hiddenSections. count, 1 )
151+ fetchHistory ( from : subject ) { _ in
152+ subject. collapseSection ( sectionIndex: 1 )
153+ XCTAssertEqual ( subject. hiddenSections. count, 1 )
145154 // Starts at 0, removing the Additional section
146- XCTAssertTrue ( self . subject. isSectionCollapsed ( sectionIndex: 0 ) )
147- XCTAssertTrue ( self . subject. hiddenSections. contains ( where: { $0 == . lastHour } ) )
155+ XCTAssertTrue ( subject. isSectionCollapsed ( sectionIndex: 0 ) )
156+ XCTAssertTrue ( subject. hiddenSections. contains ( where: { $0 == . lastHour } ) )
148157
149- self . subject. collapseSection ( sectionIndex: 1 )
150- XCTAssertTrue ( self . subject. hiddenSections. isEmpty)
151- XCTAssertFalse ( self . subject. isSectionCollapsed ( sectionIndex: 1 ) )
158+ subject. collapseSection ( sectionIndex: 1 )
159+ XCTAssertTrue ( subject. hiddenSections. isEmpty)
160+ XCTAssertFalse ( subject. isSectionCollapsed ( sectionIndex: 1 ) )
152161 }
153162 }
154163
155164 func testRemoveAllData( ) {
165+ let subject = createSubject ( )
156166 setupSiteVisits ( )
157167 XCTAssertTrue ( subject. hiddenSections. isEmpty)
158168
159- fetchHistory { _ in
160- self . subject. removeAllData ( )
169+ fetchHistory ( from : subject ) { _ in
170+ subject. removeAllData ( )
161171
162- XCTAssertEqual ( self . subject. currentFetchOffset, 0 )
163- XCTAssertTrue ( self . subject. dateGroupedSites. isEmpty)
164- XCTAssertTrue ( self . subject. visibleSections. isEmpty)
172+ XCTAssertEqual ( subject. currentFetchOffset, 0 )
173+ XCTAssertTrue ( subject. dateGroupedSites. isEmpty)
174+ XCTAssertTrue ( subject. visibleSections. isEmpty)
165175 }
166176 }
167177
168178 // MARK: - Deletion
169179
170180 func testDeleteGroup_ForLastHour( ) {
181+ let subject = createSubject ( )
171182 setupSiteVisits ( )
172183
173- fetchHistory { _ in
174- XCTAssertEqual ( self . subject. visibleSections [ 0 ] , . lastHour)
175- self . subject. deleteGroupsFor ( dateOption: . lastHour)
176- XCTAssertEqual ( self . subject. visibleSections. count, 0 )
184+ fetchHistory ( from : subject ) { _ in
185+ XCTAssertEqual ( subject. visibleSections [ 0 ] , . lastHour)
186+ subject. deleteGroupsFor ( dateOption: . lastHour)
187+ XCTAssertEqual ( subject. visibleSections. count, 0 )
177188 }
178189 }
179190
180191 // MARK: - Setup
192+ private func createSubject( ) -> HistoryPanelViewModel {
193+ let subject = HistoryPanelViewModel ( profile: profile)
194+ trackForMemoryLeaks ( subject)
195+ return subject
196+ }
197+
181198 private func setupSiteVisits( ) {
182199 addSiteVisit ( profile, url: " http://mozilla.org/ " , title: " Mozilla internet " )
183200 addSiteVisit ( profile, url: " http://mozilla.dev.org/ " , title: " Internet dev " )
@@ -202,9 +219,10 @@ class HistoryPanelViewModelTests: XCTestCase {
202219 XCTAssertTrue ( result. value. isSuccess, " History cleared. " , file: file, line: line)
203220 }
204221
205- private func fetchHistory( file: StaticString = #filePath,
222+ private func fetchHistory( from subject: HistoryPanelViewModel ,
223+ file: StaticString = #filePath,
206224 line: UInt = #line,
207- completion: @escaping ( Bool ) -> Void ) {
225+ completion: @escaping @ Sendable ( Bool ) -> Void ) {
208226 let expectation = self . expectation ( description: " Wait for history " )
209227
210228 subject. reloadData { success in
@@ -216,10 +234,11 @@ class HistoryPanelViewModelTests: XCTestCase {
216234 waitForExpectations ( timeout: 5 )
217235 }
218236
219- private func fetchSearchHistory( searchTerm: String ,
237+ private func fetchSearchHistory( from subject: HistoryPanelViewModel ,
238+ searchTerm: String ,
220239 file: StaticString = #filePath,
221240 line: UInt = #line,
222- completion: @escaping ( Bool ) -> Void ) {
241+ completion: @escaping @ Sendable ( Bool ) -> Void ) {
223242 let expectation = self . expectation ( description: " Wait for history search " )
224243
225244 subject. performSearch ( term: searchTerm) { hasResults in
0 commit comments