Skip to content

Commit 4a438c6

Browse files
committed
Make OrderItemProductImage src optional to avoid decoding issues
1 parent a802238 commit 4a438c6

File tree

3 files changed

+181
-2
lines changed

3 files changed

+181
-2
lines changed

Modules/Sources/NetworkingCore/Model/OrderItem.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,5 +240,19 @@ private struct OrderItemProductAddOnContainer: Decodable {
240240
// MARK: - Order Item Product Image
241241
//
242242
public struct OrderItemProductImage: Codable, Equatable, Hashable, Sendable {
243-
public let src: String
243+
public let src: String?
244+
245+
public init(from decoder: Decoder) throws {
246+
let container = try decoder.container(keyedBy: CodingKeys.self)
247+
self.src = try? container.decodeIfPresent(String.self, forKey: .src)
248+
}
249+
250+
public func encode(to encoder: Encoder) throws {
251+
var container = encoder.container(keyedBy: CodingKeys.self)
252+
try container.encodeIfPresent(src, forKey: .src)
253+
}
254+
255+
private enum CodingKeys: String, CodingKey {
256+
case src
257+
}
244258
}

Modules/Tests/NetworkingTests/Mapper/OrderListMapperTests.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,35 @@ class OrderListMapperTests: XCTestCase {
163163
}
164164
}
165165
}
166-
}
167166

167+
/// Verifies that OrderItem decoding is robust for various image field scenarios from WooCommerce API
168+
///
169+
func test_order_item_image_decoding_robustness() {
170+
let orders = mapOrders(from: "order-item-image")
171+
XCTAssertEqual(orders.count, 1)
172+
173+
let order = orders[0]
174+
XCTAssertEqual(order.items.count, 4)
175+
176+
// Item 1: Product with valid image src
177+
let item1 = order.items[0]
178+
XCTAssertNotNil(item1.image)
179+
XCTAssertEqual(item1.image?.src, "https://example.com/image.jpg")
180+
181+
// Item 2: Product with no image field
182+
let item2 = order.items[1]
183+
XCTAssertNil(item2.image)
184+
185+
// Item 3: Product with image but no src field
186+
let item3 = order.items[2]
187+
XCTAssertNotNil(item3.image)
188+
XCTAssertNil(item3.image?.src)
189+
190+
// Item 4: Product with wrong src type
191+
let item4 = order.items[3]
192+
XCTAssertNil(item4.image?.src)
193+
}
194+
}
168195

169196
/// Private Methods.
170197
///
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
{
2+
"data": [
3+
{
4+
"id": 963,
5+
"parent_id": 0,
6+
"is_editable": true,
7+
"needs_payment": true,
8+
"needs_processing": true,
9+
"number": "963",
10+
"status": "processing",
11+
"order_key": "abc123",
12+
"currency": "USD",
13+
"currency_symbol": "$",
14+
"date_created_gmt": "2018-04-03T23:05:12",
15+
"date_modified_gmt": "2018-04-03T23:05:14",
16+
"discount_total": "30.00",
17+
"discount_tax": "1.20",
18+
"shipping_total": "0.00",
19+
"shipping_tax": "0.00",
20+
"cart_tax": "1.20",
21+
"total": "31.20",
22+
"total_tax": "1.20",
23+
"customer_id": 11,
24+
"customer_note": "",
25+
"billing": {
26+
"first_name": "Johnny",
27+
"last_name": "Appleseed",
28+
"company": "",
29+
"address_1": "234 70th Street",
30+
"address_2": "",
31+
"city": "Niagara Falls",
32+
"state": "NY",
33+
"postcode": "14304",
34+
"country": "US",
35+
"email": "[email protected]",
36+
"phone": "333-333-3333"
37+
},
38+
"shipping": {
39+
"first_name": "Johnny",
40+
"last_name": "Appleseed",
41+
"company": "",
42+
"address_1": "234 70th Street",
43+
"address_2": "",
44+
"city": "Niagara Falls",
45+
"state": "NY",
46+
"postcode": "14304",
47+
"country": "US",
48+
"email": "[email protected]",
49+
"phone": "333-333-3333"
50+
},
51+
"shipping_lines": [],
52+
"fee_lines": [],
53+
"tax_lines": [],
54+
"payment_method": "stripe",
55+
"payment_method_title": "Credit Card (Stripe)",
56+
"payment_url": "http://www.automattic.com",
57+
"date_paid_gmt": "2018-04-03T23:05:14",
58+
"date_completed_gmt": null,
59+
"line_items": [
60+
{
61+
"id": 1,
62+
"name": "Product with valid image src",
63+
"product_id": 123,
64+
"variation_id": 0,
65+
"quantity": 1,
66+
"price": 10.0,
67+
"sku": "",
68+
"subtotal": "10.00",
69+
"subtotal_tax": "0.00",
70+
"tax_class": "",
71+
"taxes": [],
72+
"total": "10.00",
73+
"total_tax": "0.00",
74+
"meta_data": [],
75+
"image": {
76+
"src": "https://example.com/image.jpg"
77+
}
78+
},
79+
{
80+
"id": 2,
81+
"name": "Product with no image field",
82+
"product_id": 124,
83+
"variation_id": 0,
84+
"quantity": 1,
85+
"price": 10.0,
86+
"sku": "",
87+
"subtotal": "10.00",
88+
"subtotal_tax": "0.00",
89+
"tax_class": "",
90+
"taxes": [],
91+
"total": "10.00",
92+
"total_tax": "0.00",
93+
"meta_data": []
94+
},
95+
{
96+
"id": 3,
97+
"name": "Product with image but no src",
98+
"product_id": 125,
99+
"variation_id": 0,
100+
"quantity": 1,
101+
"price": 10.0,
102+
"sku": "",
103+
"subtotal": "10.00",
104+
"subtotal_tax": "0.00",
105+
"tax_class": "",
106+
"taxes": [],
107+
"total": "10.00",
108+
"total_tax": "0.00",
109+
"meta_data": [],
110+
"image": {
111+
"alt": "Product image alt text"
112+
}
113+
},
114+
{
115+
"id": 4,
116+
"name": "Product with wrong src type",
117+
"product_id": 126,
118+
"variation_id": 0,
119+
"quantity": 1,
120+
"price": 10.0,
121+
"sku": "",
122+
"subtotal": "10.00",
123+
"subtotal_tax": "0.00",
124+
"tax_class": "",
125+
"taxes": [],
126+
"total": "10.00",
127+
"total_tax": "0.00",
128+
"meta_data": [],
129+
"image": {
130+
"src": 12345
131+
}
132+
}
133+
],
134+
"coupon_lines": [],
135+
"refunds": []
136+
}
137+
]
138+
}

0 commit comments

Comments
 (0)