@@ -287,13 +287,44 @@ public function testCreateTwoProductsWithAllCustomOptionsAndRetrieveOrderItems()
287287
288288 $ customOptions = $ item ['product_option ' ]['extension_attributes ' ]['custom_options ' ];
289289 self ::assertIsArray ($ customOptions );
290- self ::assertGreaterThanOrEqual (9 , count ($ customOptions ));
291-
292- foreach ($ customOptions as $ option ) {
293- self ::assertArrayHasKey ('option_id ' , $ option );
294- self ::assertArrayHasKey ('option_value ' , $ option );
295- self ::assertNotEmpty ($ option ['option_id ' ]);
296- self ::assertNotEmpty ($ option ['option_value ' ]);
290+ self ::assertCount (9 , $ customOptions , sprintf (
291+ 'Expected exactly 9 custom options for item "%s", but found %d ' ,
292+ $ item ['sku ' ],
293+ count ($ customOptions )
294+ ));
295+
296+ foreach ($ customOptions as $ index => $ option ) {
297+ self ::assertArrayHasKey (
298+ 'option_id ' ,
299+ $ option ,
300+ sprintf ('Custom option at index %d for item "%s" is missing option_id ' , $ index , $ item ['sku ' ])
301+ );
302+ self ::assertArrayHasKey (
303+ 'option_value ' ,
304+ $ option ,
305+ sprintf ('Custom option at index %d for item "%s" is missing option_value ' , $ index , $ item ['sku ' ])
306+ );
307+ self ::assertNotEmpty (
308+ $ option ['option_id ' ],
309+ sprintf ('Custom option at index %d for item "%s" has empty option_id ' , $ index , $ item ['sku ' ])
310+ );
311+ $ optionValue = $ option ['option_value ' ];
312+ if (is_array ($ optionValue )) {
313+ self ::assertNotEmpty (
314+ $ optionValue ,
315+ sprintf ('Custom option at index %d for item "%s" has empty option_value ' , $ index , $ item ['sku ' ])
316+ );
317+ } else {
318+ self ::assertNotEmpty (
319+ $ optionValue ,
320+ sprintf ('Custom option at index %d for item "%s" has empty option_value ' , $ index , $ item ['sku ' ])
321+ );
322+ }
323+ $ this ->validateCustomOptionValue (
324+ $ optionValue ,
325+ $ index ,
326+ $ item ['sku ' ]
327+ );
297328 }
298329 }
299330 }
@@ -329,14 +360,14 @@ private function prepareCustomOptionsForProductBySku(string $sku): array
329360 $ objectManager = Bootstrap::getObjectManager ();
330361 $ productId = $ this ->productResource ->getIdBySku ($ sku );
331362 $ product = $ objectManager ->create (Product::class)->load ($ productId );
332-
363+
333364 $ customOptionCollection = $ objectManager ->get (Option::class)
334365 ->getProductOptionCollection ($ product );
335-
366+
336367 $ customOptions = [];
337368 foreach ($ customOptionCollection as $ option ) {
338369 $ optionType = $ option ->getType ();
339-
370+
340371 $ optionData = match ($ optionType ) {
341372 'field ' => 'Test field value ' ,
342373 'area ' => 'Test textarea value ' ,
@@ -517,6 +548,63 @@ private function getOrder(int $orderId): array
517548 return $ this ->_webApiCall ($ serviceInfo );
518549 }
519550
551+ /**
552+ * Validate custom option value format
553+ *
554+ * This method validates that the option value matches one of the expected patterns:
555+ * - Text string (field/area options)
556+ * - Numeric ID (drop_down/radio options)
557+ * - Comma-separated numeric IDs (checkbox/multiple options)
558+ * - Date/datetime/time format (YYYY-MM-DD HH:MM:SS or array structure)
559+ *
560+ * @param string|array $optionValue The option value to validate
561+ * @param int $index The index of the option in the array
562+ * @param string $sku The product SKU for error messages
563+ * @return void
564+ */
565+ private function validateCustomOptionValue (string |array $ optionValue , int $ index , string $ sku ): void
566+ {
567+ // Handle array option values (date/time options)
568+ if (is_array ($ optionValue )) {
569+ self ::assertNotEmpty (
570+ $ optionValue ,
571+ sprintf (
572+ 'Custom option at index %d for item "%s" has empty array option_value ' ,
573+ $ index ,
574+ $ sku
575+ )
576+ );
577+ return ;
578+ }
579+
580+ // Define expected patterns for string option types
581+ $ patterns = [
582+ '/^Test (field|textarea) value$/ ' , // Text field or textarea
583+ '/^\d+$/ ' , // Single numeric ID (drop_down, radio)
584+ '/^\d+(,\d+)*$/ ' , // Comma-separated numeric IDs (checkbox, multiple)
585+ '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/ ' , // Date/datetime/time format
586+ ];
587+
588+ $ isValid = false ;
589+ foreach ($ patterns as $ pattern ) {
590+ if (preg_match ($ pattern , $ optionValue )) {
591+ $ isValid = true ;
592+ break ;
593+ }
594+ }
595+
596+ self ::assertTrue (
597+ $ isValid ,
598+ sprintf (
599+ 'Custom option at index %d for item "%s" has invalid option_value format: "%s". ' .
600+ 'Expected one of: text string, numeric ID, comma-separated IDs, or date format (YYYY-MM-DD HH:MM:SS) ' ,
601+ $ index ,
602+ $ sku ,
603+ $ optionValue
604+ )
605+ );
606+ }
607+
520608 /**
521609 * Get order items by order ID via REST API
522610 *
0 commit comments