From a27d7dd466bec1a9123684f537cb0a1db3b27bdd Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 18 Jan 2023 14:26:14 +0700 Subject: [PATCH 1/4] Update SitePluginsMapper to parse contents without the data envelope --- Networking/Networking/Mapper/SitePluginsMapper.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Networking/Networking/Mapper/SitePluginsMapper.swift b/Networking/Networking/Mapper/SitePluginsMapper.swift index 5fcbe59a437..2aebbebe75c 100644 --- a/Networking/Networking/Mapper/SitePluginsMapper.swift +++ b/Networking/Networking/Mapper/SitePluginsMapper.swift @@ -17,7 +17,11 @@ struct SitePluginsMapper: Mapper { .siteID: siteID ] - return try decoder.decode(SitePluginsEnvelope.self, from: response).plugins + do { + return try decoder.decode(SitePluginsEnvelope.self, from: response).plugins + } catch { + return try decoder.decode([SitePlugin].self, from: response) + } } } From 632d59786c4e72a24907fc06fa8a2c12fb5650da Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 18 Jan 2023 14:26:31 +0700 Subject: [PATCH 2/4] Update test for SitePluginsMapper --- .../Networking.xcodeproj/project.pbxproj | 4 + .../Mapper/SitePluginsMapperTests.swift | 37 ++++++++++ .../Responses/plugins-without-data.json | 74 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 Networking/NetworkingTests/Responses/plugins-without-data.json diff --git a/Networking/Networking.xcodeproj/project.pbxproj b/Networking/Networking.xcodeproj/project.pbxproj index 2d7cd8bb5e5..ef203e1e228 100644 --- a/Networking/Networking.xcodeproj/project.pbxproj +++ b/Networking/Networking.xcodeproj/project.pbxproj @@ -728,6 +728,7 @@ DE66C5632977CBC700DAA978 /* shipping-label-eligibility-failure-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = DE66C5622977CBC700DAA978 /* shipping-label-eligibility-failure-without-data.json */; }; DE66C5652977CC4300DAA978 /* shipping-label-purchase-success-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = DE66C5642977CC4300DAA978 /* shipping-label-purchase-success-without-data.json */; }; DE66C5672977CEB800DAA978 /* shipping-label-status-success-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = DE66C5662977CEB800DAA978 /* shipping-label-status-success-without-data.json */; }; + DE66C5692977D62700DAA978 /* plugins-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = DE66C5682977D62700DAA978 /* plugins-without-data.json */; }; DE6F308727966FEF004E1C9A /* CouponReportListMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6F308627966FEF004E1C9A /* CouponReportListMapperTests.swift */; }; DE74F29A27E08F5A0002FE59 /* SiteSettingMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE74F29927E08F5A0002FE59 /* SiteSettingMapper.swift */; }; DE74F29C27E0A1D00002FE59 /* setting-coupon.json in Resources */ = {isa = PBXBuildFile; fileRef = DE74F29B27E0A1D00002FE59 /* setting-coupon.json */; }; @@ -1569,6 +1570,7 @@ DE66C5622977CBC700DAA978 /* shipping-label-eligibility-failure-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "shipping-label-eligibility-failure-without-data.json"; sourceTree = ""; }; DE66C5642977CC4300DAA978 /* shipping-label-purchase-success-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "shipping-label-purchase-success-without-data.json"; sourceTree = ""; }; DE66C5662977CEB800DAA978 /* shipping-label-status-success-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "shipping-label-status-success-without-data.json"; sourceTree = ""; }; + DE66C5682977D62700DAA978 /* plugins-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "plugins-without-data.json"; sourceTree = ""; }; DE6F308627966FEF004E1C9A /* CouponReportListMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponReportListMapperTests.swift; sourceTree = ""; }; DE74F29927E08F5A0002FE59 /* SiteSettingMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteSettingMapper.swift; sourceTree = ""; }; DE74F29B27E0A1D00002FE59 /* setting-coupon.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "setting-coupon.json"; sourceTree = ""; }; @@ -2188,6 +2190,7 @@ B559EBA820A0B5B100836CD4 /* Responses */ = { isa = PBXGroup; children = ( + DE66C5682977D62700DAA978 /* plugins-without-data.json */, DE66C5662977CEB800DAA978 /* shipping-label-status-success-without-data.json */, DE66C5642977CC4300DAA978 /* shipping-label-purchase-success-without-data.json */, DE66C5622977CBC700DAA978 /* shipping-label-eligibility-failure-without-data.json */, @@ -3171,6 +3174,7 @@ 03E8FEC427B40E3F00F5FC7D /* wcpay-charge-card-present-minimal.json in Resources */, EE6FDCFC2966A70400E1CECF /* product-without-data.json in Resources */, 31054724262E2FC600C5C02B /* wcpay-payment-intent-requires-capture.json in Resources */, + DE66C5692977D62700DAA978 /* plugins-without-data.json in Resources */, 7492FAE3217FBDBC00ED2C69 /* settings-general-alt.json in Resources */, 93D8BBFF226BC1DA00AD2EB3 /* me-settings.json in Resources */, 74C947842193A6C70024CB60 /* comment-moderate-approved.json in Resources */, diff --git a/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift b/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift index d9a01ab68e2..0c52fcee08c 100644 --- a/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift +++ b/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift @@ -39,6 +39,37 @@ class SitePluginsMapperTests: XCTestCase { XCTAssertEqual(wooCommerceSubscriptionsPlugin.version, "3.0.13") XCTAssertEqual(wooCommerceSubscriptionsPlugin.textDomain, "woocommerce-subscriptions") } + + /// Verifies the SitePlugin fields are parsed correctly. + /// + func test_SitePlugin_fields_are_properly_parsed_when_response_has_no_data_envelope() { + let plugins = mapLoadSitePluginsResponseWithoutDataEnvelope() + XCTAssertEqual(plugins.count, 3) + + let helloDollyPlugin = plugins[0] + XCTAssertNotNil(helloDollyPlugin) + XCTAssertEqual(helloDollyPlugin.siteID, dummySiteID) + XCTAssertEqual(helloDollyPlugin.status, .inactive) + XCTAssertEqual(helloDollyPlugin.name, "Hello Dolly") + XCTAssertEqual(helloDollyPlugin.pluginUri, "http://wordpress.org/plugins/hello-dolly/") + XCTAssertEqual(helloDollyPlugin.authorUri, "http://ma.tt/") + XCTAssertEqual(helloDollyPlugin.descriptionRaw, "This is not just a plugin, it...") + XCTAssertEqual(helloDollyPlugin.descriptionRendered, "This is not just a plugin, it symbolizes...") + XCTAssertEqual(helloDollyPlugin.version, "1.7.2") + XCTAssertEqual(helloDollyPlugin.textDomain, "") + + let wooCommerceSubscriptionsPlugin = plugins[4] + XCTAssertNotNil(wooCommerceSubscriptionsPlugin) + XCTAssertEqual(wooCommerceSubscriptionsPlugin.siteID, dummySiteID) + XCTAssertEqual(wooCommerceSubscriptionsPlugin.status, .active) + XCTAssertEqual(wooCommerceSubscriptionsPlugin.name, "WooCommerce Subscriptions") + XCTAssertEqual(wooCommerceSubscriptionsPlugin.pluginUri, "https://www.woocommerce.com/products/woocommerce-subscriptions/") + XCTAssertEqual(wooCommerceSubscriptionsPlugin.authorUri, "https://woocommerce.com/") + XCTAssertEqual(wooCommerceSubscriptionsPlugin.descriptionRaw, "Sell products and services...") + XCTAssertEqual(wooCommerceSubscriptionsPlugin.descriptionRendered, "Sell products and services with recurring payments...") + XCTAssertEqual(wooCommerceSubscriptionsPlugin.version, "3.0.13") + XCTAssertEqual(wooCommerceSubscriptionsPlugin.textDomain, "woocommerce-subscriptions") + } } @@ -61,4 +92,10 @@ private extension SitePluginsMapperTests { func mapLoadSitePluginsResponse() -> [SitePlugin] { return mapPlugins(from: "plugins") } + + /// Returns the SitePluginsMapper output upon receiving `plugins-without-data` + /// + func mapLoadSitePluginsResponseWithoutDataEnvelope() -> [SitePlugin] { + return mapPlugins(from: "plugins-without-data") + } } diff --git a/Networking/NetworkingTests/Responses/plugins-without-data.json b/Networking/NetworkingTests/Responses/plugins-without-data.json new file mode 100644 index 00000000000..60ef0f46867 --- /dev/null +++ b/Networking/NetworkingTests/Responses/plugins-without-data.json @@ -0,0 +1,74 @@ +[ + { + "plugin": "hello", + "status": "inactive", + "name": "Hello Dolly", + "plugin_uri": "http://wordpress.org/plugins/hello-dolly/", + "author": "Matt Mullenweg", + "author_uri": "http://ma.tt/", + "description": { + "raw": "This is not just a plugin, it...", + "rendered": "This is not just a plugin, it symbolizes..." + }, + "version": "1.7.2", + "network_only": false, + "requires_wp": "", + "requires_php": "", + "textdomain": "", + "_links": { + "self": [ + { + "href": "https://example.com/wp-json/wp/v2/plugins/hello" + } + ] + } + }, + { + "plugin": "jetpack/jetpack", + "status": "active", + "name": "Jetpack by WordPress.com", + "plugin_uri": "https://jetpack.com", + "author": "Automattic", + "author_uri": "https://jetpack.com", + "description": { + "raw": "Bring the power of the WordPress.com cloud to your self-hosted WordPress. Jetpack enables you to connect your blog to a WordPress.com account to use the powerful features normally only available to WordPress.com users.", + "rendered": "Bring the power of the WordPress.com cloud to your self-hosted WordPress. Jetpack enables you to connect your blog to a WordPress.com account to use the powerful features normally only available to WordPress.com users. By Automattic." + }, + "version": "9.5", + "network_only": false, + "requires_wp": "5.6", + "requires_php": "5.6", + "textdomain": "jetpack", + "_links": { + "self": [ + { + "href": "https://example.com/wp-json/wp/v2/plugins/jetpack/jetpack" + } + ] + } + }, + { + "plugin": "woocommerce/woocommerce", + "status": "active", + "name": "WooCommerce", + "plugin_uri": "https://woocommerce.com/", + "author": "Automattic", + "author_uri": "https://woocommerce.com", + "description": { + "raw": "An eCommerce toolkit that helps you sell anything. Beautifully.", + "rendered": "An eCommerce toolkit that helps you sell anything. Beautifully. By Automattic." + }, + "version": "5.1.0", + "network_only": false, + "requires_wp": "5.4", + "requires_php": "7.0", + "textdomain": "woocommerce", + "_links": { + "self": [ + { + "href": "https://example.com//wp-json/wp/v2/plugins/woocommerce/woocommerce" + } + ] + } + } +] From 0ab98b62737342e2f3ea69f2ced90f6727a01049 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 18 Jan 2023 14:26:43 +0700 Subject: [PATCH 3/4] Enable REST API for the fetch site plugin endpoint --- Networking/Networking/Remote/SitePluginsRemote.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Networking/Networking/Remote/SitePluginsRemote.swift b/Networking/Networking/Remote/SitePluginsRemote.swift index 9fea1c2b7e2..0ff871dcd09 100644 --- a/Networking/Networking/Remote/SitePluginsRemote.swift +++ b/Networking/Networking/Remote/SitePluginsRemote.swift @@ -13,7 +13,12 @@ public class SitePluginsRemote: Remote { public func loadPlugins(for siteID: Int64, completion: @escaping (Result<[SitePlugin], Error>) -> Void) { let path = Constants.sitePluginsPath - let request = JetpackRequest(wooApiVersion: .none, method: .get, siteID: siteID, path: path, parameters: nil) + let request = JetpackRequest(wooApiVersion: .none, + method: .get, + siteID: siteID, + path: path, + parameters: nil, + availableAsRESTRequest: true) let mapper = SitePluginsMapper(siteID: siteID) enqueue(request, mapper: mapper, completion: completion) From b57abd9ecb992f642b3740d5638acf24c7e7f56d Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 18 Jan 2023 14:27:14 +0700 Subject: [PATCH 4/4] Update test for SitePluginsMapperTests --- .../Mapper/SitePluginsMapperTests.swift | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift b/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift index 0c52fcee08c..a7906de48aa 100644 --- a/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift +++ b/Networking/NetworkingTests/Mapper/SitePluginsMapperTests.swift @@ -57,18 +57,6 @@ class SitePluginsMapperTests: XCTestCase { XCTAssertEqual(helloDollyPlugin.descriptionRendered, "This is not just a plugin, it symbolizes...") XCTAssertEqual(helloDollyPlugin.version, "1.7.2") XCTAssertEqual(helloDollyPlugin.textDomain, "") - - let wooCommerceSubscriptionsPlugin = plugins[4] - XCTAssertNotNil(wooCommerceSubscriptionsPlugin) - XCTAssertEqual(wooCommerceSubscriptionsPlugin.siteID, dummySiteID) - XCTAssertEqual(wooCommerceSubscriptionsPlugin.status, .active) - XCTAssertEqual(wooCommerceSubscriptionsPlugin.name, "WooCommerce Subscriptions") - XCTAssertEqual(wooCommerceSubscriptionsPlugin.pluginUri, "https://www.woocommerce.com/products/woocommerce-subscriptions/") - XCTAssertEqual(wooCommerceSubscriptionsPlugin.authorUri, "https://woocommerce.com/") - XCTAssertEqual(wooCommerceSubscriptionsPlugin.descriptionRaw, "Sell products and services...") - XCTAssertEqual(wooCommerceSubscriptionsPlugin.descriptionRendered, "Sell products and services with recurring payments...") - XCTAssertEqual(wooCommerceSubscriptionsPlugin.version, "3.0.13") - XCTAssertEqual(wooCommerceSubscriptionsPlugin.textDomain, "woocommerce-subscriptions") } }