11import XCTest
22import Nimble
3+ import OHHTTPStubs
34@testable import WordPress
45
56class BlockEditorSettingsServiceTests : CoreDataTestCase {
@@ -10,30 +11,31 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
1011 private let blockSettingsThemeJSONResponseFilename = " wp-block-editor-v1-settings-success-ThemeJSON "
1112
1213 private var service : BlockEditorSettingsService !
13- var mockRemoteApi : MockWordPressComRestApi !
1414 var gssOriginalValue : Bool !
1515 private var blog : Blog !
1616
1717 override func setUp( ) {
18- mockRemoteApi = MockWordPressComRestApi ( )
1918 blog = BlogBuilder ( mainContext)
2019 . with ( wordPressVersion: " 5.8 " )
2120 . withAnAccount ( )
2221 . build ( )
2322 contextManager. saveContextAndWait ( mainContext)
24- service = BlockEditorSettingsService ( blog: blog, remoteAPI : mockRemoteApi , coreDataStack: contextManager)
23+ service = BlockEditorSettingsService ( blog: blog, coreDataStack: contextManager)
2524 }
2625
2726 // MARK: Editor `theme_supports` support
2827 func testThemeSupportsNewTheme( ) {
2928 blog = BlogBuilder ( mainContext)
3029 . with ( wordPressVersion: " 5.7 " )
3130 . with ( isHostedAtWPCom: true )
31+ . withAnAccount ( )
3232 . build ( )
3333 contextManager. saveContextAndWait ( mainContext)
3434
35- service = BlockEditorSettingsService ( blog: blog, remoteAPI: mockRemoteApi, coreDataStack: contextManager)
3635 let mockedResponse = mockedData ( withFilename: twentytwentyoneResponseFilename)
36+ stubThemeRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
37+
38+ service = BlockEditorSettingsService ( blog: blog, coreDataStack: contextManager)
3739 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
3840 service. fetchSettings { result in
3941 switch result {
@@ -46,8 +48,6 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
4648 waitExpectation. fulfill ( )
4749 }
4850
49- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
50-
5151 waitForExpectations ( timeout: expectationTimeout)
5252 validateThemeResponse ( )
5353 XCTAssertNotNil ( self . blog. blockEditorSettings? . checksum)
@@ -57,15 +57,18 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
5757 blog = BlogBuilder ( mainContext)
5858 . with ( wordPressVersion: " 5.7 " )
5959 . with ( isHostedAtWPCom: true )
60+ . withAnAccount ( )
6061 . build ( )
6162 contextManager. saveContextAndWait ( mainContext)
6263
63- service = BlockEditorSettingsService ( blog: blog, remoteAPI : mockRemoteApi , coreDataStack: contextManager)
64+ service = BlockEditorSettingsService ( blog: blog, coreDataStack: contextManager)
6465
6566 setData ( withFilename: twentytwentyResponseFilename)
6667 let originalChecksum = blog. blockEditorSettings? . checksum ?? " "
6768
6869 let mockedResponse = mockedData ( withFilename: twentytwentyoneResponseFilename)
70+ stubThemeRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
71+
6972 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
7073 service. fetchSettings { result in
7174 switch result {
@@ -78,8 +81,6 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
7881 waitExpectation. fulfill ( )
7982 }
8083
81- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
82-
8384 waitForExpectations ( timeout: expectationTimeout)
8485 validateThemeResponse ( )
8586 XCTAssertNotEqual ( self . blog. blockEditorSettings? . checksum, originalChecksum)
@@ -89,14 +90,17 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
8990 blog = BlogBuilder ( mainContext)
9091 . with ( wordPressVersion: " 5.7 " )
9192 . with ( isHostedAtWPCom: true )
93+ . withAnAccount ( )
9294 . build ( )
9395 contextManager. saveContextAndWait ( mainContext)
9496
95- service = BlockEditorSettingsService ( blog: blog, remoteAPI : mockRemoteApi , coreDataStack: contextManager)
97+ service = BlockEditorSettingsService ( blog: blog, coreDataStack: contextManager)
9698
9799 setData ( withFilename: twentytwentyoneResponseFilename)
98100 let originalChecksum = blog. blockEditorSettings? . checksum ?? " "
101+
99102 let mockedResponse = mockedData ( withFilename: twentytwentyoneResponseFilename)
103+ stubThemeRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
100104
101105 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
102106 service. fetchSettings { result in
@@ -109,25 +113,33 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
109113 }
110114 waitExpectation. fulfill ( )
111115 }
112- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
113116
114117 waitForExpectations ( timeout: expectationTimeout)
115118 validateThemeResponse ( )
116119 XCTAssertEqual ( self . blog. blockEditorSettings? . checksum, originalChecksum)
117120 }
118121
119122 private func validateThemeResponse( ) {
120- let siteID = blog. dotComID ?? 0
121- XCTAssertTrue ( self . mockRemoteApi. getMethodCalled)
122- XCTAssertEqual ( self . mockRemoteApi. URLStringPassedIn!, " /wp/v2/sites/ \( siteID) /themes " )
123- XCTAssertEqual ( ( self . mockRemoteApi. parametersPassedIn as! [ String : String ] ) [ " status " ] , " active " )
124123 XCTAssertGreaterThan ( self . blog. blockEditorSettings!. colors!. count, 0 )
125124 XCTAssertGreaterThan ( self . blog. blockEditorSettings!. gradients!. count, 0 )
126125 }
127126
127+ private func stubThemeRequest( response: HTTPStubsResponse ) {
128+ let siteID = blog. dotComID ?? 0
129+ stub (
130+ condition:
131+ isMethodGET ( )
132+ && { $0. url? . absoluteString. contains ( " /wp/v2/sites/ \( siteID) /themes " ) == true }
133+ && { $0. url? . absoluteString. contains ( " status=active " ) == true } ,
134+ response: { _ in response }
135+ )
136+ }
137+
128138 // MARK: Editor Global Styles support
129139 func testFetchBlockEditorSettingsNotThemeJSON( ) {
130140 let mockedResponse = mockedData ( withFilename: blockSettingsNOTThemeJSONResponseFilename)
141+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
142+
131143 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
132144 service. fetchSettings { result in
133145 switch result {
@@ -140,15 +152,15 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
140152 waitExpectation. fulfill ( )
141153 }
142154
143- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
144-
145155 waitForExpectations ( timeout: expectationTimeout)
146156 validateBlockEditorSettingsResponse ( isGlobalStyles: false )
147157 XCTAssertNotNil ( self . blog. blockEditorSettings? . checksum)
148158 }
149159
150160 func testFetchBlockEditorSettingsThemeJSON( ) {
151161 let mockedResponse = mockedData ( withFilename: blockSettingsThemeJSONResponseFilename)
162+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
163+
152164 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
153165 service. fetchSettings { result in
154166 switch result {
@@ -161,8 +173,6 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
161173 waitExpectation. fulfill ( )
162174 }
163175
164- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
165-
166176 waitForExpectations ( timeout: expectationTimeout)
167177 validateBlockEditorSettingsResponse ( )
168178 XCTAssertNotNil ( self . blog. blockEditorSettings? . checksum)
@@ -173,6 +183,8 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
173183 let originalChecksum = blog. blockEditorSettings? . checksum ?? " "
174184
175185 let mockedResponse = mockedData ( withFilename: blockSettingsThemeJSONResponseFilename)
186+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
187+
176188 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
177189 service. fetchSettings { result in
178190 switch result {
@@ -185,8 +197,6 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
185197 waitExpectation. fulfill ( )
186198 }
187199
188- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
189-
190200 waitForExpectations ( timeout: expectationTimeout)
191201 validateBlockEditorSettingsResponse ( )
192202 XCTAssertNotNil ( self . blog. blockEditorSettings? . checksum)
@@ -198,6 +208,8 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
198208 let originalChecksum = blog. blockEditorSettings? . checksum ?? " "
199209
200210 let mockedResponse = mockedData ( withFilename: blockSettingsThemeJSONResponseFilename)
211+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
212+
201213 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
202214 service. fetchSettings { result in
203215 switch result {
@@ -210,8 +222,6 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
210222 waitExpectation. fulfill ( )
211223 }
212224
213- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
214-
215225 waitForExpectations ( timeout: expectationTimeout)
216226 validateBlockEditorSettingsResponse ( )
217227 XCTAssertNotNil ( self . blog. blockEditorSettings? . checksum)
@@ -224,6 +234,8 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
224234 let originalChecksum = blog. blockEditorSettings? . checksum ?? " "
225235
226236 let mockedResponse = mockedData ( withFilename: blockSettingsThemeJSONResponseFilename)
237+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
238+
227239 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
228240 service. fetchSettings { result in
229241 switch result {
@@ -236,50 +248,51 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
236248 waitExpectation. fulfill ( )
237249 }
238250
239- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
240-
241251 waitForExpectations ( timeout: expectationTimeout)
242252 validateBlockEditorSettingsResponse ( )
243253 XCTAssertNotNil ( self . blog. blockEditorSettings? . checksum)
244254 XCTAssertEqual ( self . blog. blockEditorSettings? . checksum, originalChecksum)
245255 }
246256
247257 func testFetchBlockEditorSettings_OrgSite_NoPlugin( ) {
258+ let first = expectation ( description: " The app will call the none-experimental path first but fail because of compatibility reasons " )
259+ let second = expectation ( description: " The app will then retry the wp/v2/themes path " )
260+
248261 let mockedResponse = mockedData ( withFilename: blockSettingsNOTThemeJSONResponseFilename)
249- let mockOrgRemoteApi = MockWordPressOrgRestApi ( )
250- service = BlockEditorSettingsService ( blog: blog, remoteAPI: mockOrgRemoteApi, coreDataStack: contextManager)
262+ stub ( condition: isAbsoluteURLString ( " https://w.org/wp-json/wp-block-editor/v1/settings?context=mobile " ) ) { _ in
263+ first. fulfill ( )
264+ return HTTPStubsResponse ( error: URLError ( . networkConnectionLost) )
265+ }
266+ stub ( condition: isAbsoluteURLString ( " https://w.org/wp-json/wp/v2/themes?status=active " ) ) { _ in
267+ second. fulfill ( )
268+ return HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil )
269+ }
270+
271+ let remoteAPI = WordPressOrgRestApi ( selfHostedSiteWPJSONURL: URL ( string: " https://w.org/wp-json " ) !, credential: . init( loginURL: URL ( string: " https://not-used.org " ) !, username: " user " , password: " pass " , adminURL: URL ( string: " https://not-used.org " ) !) )
272+ service = BlockEditorSettingsService ( blog: blog, remoteAPI: remoteAPI, coreDataStack: contextManager)
251273
252274 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
253275 service. fetchSettings { _ in
254276 waitExpectation. fulfill ( )
255277 }
256278
257- // The app will call the none-experimental path first but fail because of compatibility reasons
258- mockOrgRemoteApi. completionPassedIn!( . failure( NSError ( domain: " test " , code: 404 , userInfo: nil ) ) , HTTPURLResponse ( ) )
259- // The app will then retry the wp/v2/themes path.
260- mockOrgRemoteApi. completionPassedIn!( . success( mockedResponse) , HTTPURLResponse ( ) )
261- waitForExpectations ( timeout: expectationTimeout)
262-
263- XCTAssertTrue ( mockOrgRemoteApi. getMethodCalled)
264- XCTAssertEqual ( mockOrgRemoteApi. URLStringPassedIn!, " /wp/v2/themes " )
265- XCTAssertEqual ( ( mockOrgRemoteApi. parametersPassedIn as! [ String : String ] ) [ " status " ] , " active " )
279+ wait ( for: [ first, second, waitExpectation] , timeout: 0.3 , enforceOrder: true )
266280 }
267281
268282 func testFetchBlockEditorSettings_OrgSite( ) {
269283 let mockedResponse = mockedData ( withFilename: blockSettingsNOTThemeJSONResponseFilename)
270- let mockOrgRemoteApi = MockWordPressOrgRestApi ( )
271- service = BlockEditorSettingsService ( blog: blog, remoteAPI: mockOrgRemoteApi, coreDataStack: contextManager)
284+ stub ( condition: isAbsoluteURLString ( " https://w.org/wp-json/wp-block-editor/v1/settings?context=mobile " ) ) { _ in
285+ HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil )
286+ }
287+
288+ let remoteAPI = WordPressOrgRestApi ( selfHostedSiteWPJSONURL: URL ( string: " https://w.org/wp-json " ) !, credential: . init( loginURL: URL ( string: " https://not-used.org " ) !, username: " user " , password: " pass " , adminURL: URL ( string: " https://not-used.org " ) !) )
289+ service = BlockEditorSettingsService ( blog: blog, remoteAPI: remoteAPI, coreDataStack: contextManager)
272290
273291 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
274292 service. fetchSettings { _ in
275293 waitExpectation. fulfill ( )
276294 }
277- mockOrgRemoteApi. completionPassedIn!( . success( mockedResponse) , HTTPURLResponse ( ) )
278295 waitForExpectations ( timeout: expectationTimeout)
279-
280- XCTAssertTrue ( mockOrgRemoteApi. getMethodCalled)
281- XCTAssertEqual ( mockOrgRemoteApi. URLStringPassedIn!, " /wp-block-editor/v1/settings " )
282- XCTAssertEqual ( ( mockOrgRemoteApi. parametersPassedIn as! [ String : String ] ) [ " context " ] , " mobile " )
283296 }
284297
285298 func testFetchBlockEditorSettings_Com5_8Site( ) {
@@ -289,19 +302,17 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
289302 . build ( )
290303 contextManager. saveContextAndWait ( mainContext)
291304
292- service = BlockEditorSettingsService ( blog: blog, remoteAPI : mockRemoteApi , coreDataStack: contextManager)
305+ service = BlockEditorSettingsService ( blog: blog, coreDataStack: contextManager)
293306
294307 let mockedResponse = mockedData ( withFilename: blockSettingsNOTThemeJSONResponseFilename)
308+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
309+
295310 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
296311 service. fetchSettings { _ in
297312 waitExpectation. fulfill ( )
298313 }
299- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
300- waitForExpectations ( timeout: expectationTimeout)
301314
302- XCTAssertTrue ( self . mockRemoteApi. getMethodCalled)
303- XCTAssertEqual ( self . mockRemoteApi. URLStringPassedIn!, " /wp-block-editor/v1/sites/ \( blog. dotComID!. intValue) /settings " )
304- XCTAssertEqual ( ( self . mockRemoteApi. parametersPassedIn as! [ String : String ] ) [ " context " ] , " mobile " )
315+ waitForExpectations ( timeout: expectationTimeout)
305316 }
306317
307318 func testFetchBlockEditorSettings_Com5_9Site( ) {
@@ -311,26 +322,19 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
311322 . build ( )
312323 contextManager. saveContextAndWait ( mainContext)
313324
314- service = BlockEditorSettingsService ( blog: blog, remoteAPI : mockRemoteApi , coreDataStack: contextManager)
325+ service = BlockEditorSettingsService ( blog: blog, coreDataStack: contextManager)
315326
316327 let mockedResponse = mockedData ( withFilename: blockSettingsNOTThemeJSONResponseFilename)
328+ stubBlockEditorSettingsRequest ( response: HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) )
317329 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
318330 service. fetchSettings { _ in
319331 waitExpectation. fulfill ( )
320332 }
321- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
322- waitForExpectations ( timeout: expectationTimeout)
323333
324- XCTAssertTrue ( self . mockRemoteApi. getMethodCalled)
325- XCTAssertEqual ( self . mockRemoteApi. URLStringPassedIn!, " /wp-block-editor/v1/sites/ \( blog. dotComID!. intValue) /settings " )
326- XCTAssertEqual ( ( self . mockRemoteApi. parametersPassedIn as! [ String : String ] ) [ " context " ] , " mobile " )
334+ waitForExpectations ( timeout: expectationTimeout)
327335 }
328336
329337 private func validateBlockEditorSettingsResponse( isGlobalStyles: Bool = true ) {
330- XCTAssertTrue ( self . mockRemoteApi. getMethodCalled)
331- XCTAssertEqual ( self . mockRemoteApi. URLStringPassedIn!, " /wp-block-editor/v1/sites/ \( blog. dotComID!. intValue) /settings " )
332- XCTAssertEqual ( ( self . mockRemoteApi. parametersPassedIn as! [ String : String ] ) [ " context " ] , " mobile " )
333-
334338 if isGlobalStyles {
335339 XCTAssertNotNil ( self . blog. blockEditorSettings? . rawStyles)
336340 XCTAssertNotNil ( self . blog. blockEditorSettings? . rawFeatures)
@@ -355,6 +359,17 @@ class BlockEditorSettingsServiceTests: CoreDataTestCase {
355359 }
356360 XCTAssertGreaterThan ( gradients. count, 0 )
357361 }
362+
363+ private func stubBlockEditorSettingsRequest( response: HTTPStubsResponse ) {
364+ let siteID = blog. dotComID ?? 0
365+ stub (
366+ condition:
367+ isMethodGET ( )
368+ && { $0. url? . absoluteString. contains ( " /wp-block-editor/v1/sites/ \( siteID) /settings " ) == true }
369+ && { $0. url? . absoluteString. contains ( " context=mobile " ) == true } ,
370+ response: { _ in response }
371+ )
372+ }
358373}
359374
360375extension BlockEditorSettingsServiceTests {
@@ -368,10 +383,11 @@ extension BlockEditorSettingsServiceTests {
368383 func setData( withFilename filename: String ) {
369384 let waitExpectation = expectation ( description: " Theme should be successfully fetched " )
370385 let mockedResponse = mockedData ( withFilename: filename)
386+ let descriptor = stub ( condition: { _ in true } , response: { _ in HTTPStubsResponse ( jsonObject: mockedResponse, statusCode: 200 , headers: nil ) } )
371387 service. fetchSettings { _ in
372388 waitExpectation. fulfill ( )
373389 }
374- mockRemoteApi. successBlockPassedIn!( mockedResponse, HTTPURLResponse ( ) )
375390 waitForExpectations ( timeout: expectationTimeout)
391+ HTTPStubs . removeStub ( descriptor)
376392 }
377393}
0 commit comments