@@ -76,6 +76,9 @@ class ActionObject
7676 const ACTION_ATTRIBUTE_USERINPUT = 'userInput ' ;
7777 const ACTION_TYPE_COMMENT = 'comment ' ;
7878 const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField ' , 'getSecret ' ];
79+ const REGEX_SINGLE_GROUP = '[\w]+ ' ;
80+ const REGEX_WITH_INDEX = '[\w]+\.[\w\[\]]+ ' ;
81+ const REGEX_WITH_PARAM = '[\w]+\.[\w]+\((?(?!}}).)+\) ' ;
7982
8083 /**
8184 * The unique identifier for the action
@@ -415,6 +418,14 @@ private function resolveUrlReference()
415418 $ url = $ this ->actionAttributes [ActionObject::ACTION_ATTRIBUTE_URL ];
416419
417420 $ replacement = $ this ->findAndReplaceReferences (PageObjectHandler::getInstance (), $ url );
421+
422+ $ missingReferences = $ this ->getMissingReferences ($ replacement );
423+ if (!empty ($ missingReferences )) {
424+ throw new TestReferenceException (
425+ sprintf ('Can not resolve replacements: "%s" ' , implode ('", " ' , $ missingReferences ))
426+ );
427+ }
428+
418429 if ($ replacement ) {
419430 $ this ->resolvedCustomAttributes [ActionObject::ACTION_ATTRIBUTE_URL ] = $ replacement ;
420431 $ allPages = PageObjectHandler::getInstance ()->getAllObjects ();
@@ -428,6 +439,27 @@ private function resolveUrlReference()
428439 }
429440 }
430441
442+ /**
443+ * Returns array of missing references
444+ *
445+ * @param string $replacement
446+ * @return array
447+ */
448+ private function getMissingReferences ($ replacement ): array
449+ {
450+ $ matchPatterns = [
451+ self ::REGEX_SINGLE_GROUP ,
452+ self ::REGEX_WITH_INDEX ,
453+ self ::REGEX_WITH_PARAM
454+ ];
455+
456+ preg_match_all ($ this ->getMustachePattern ($ matchPatterns ), $ replacement , $ matches );
457+
458+ return array_filter ($ matches [1 ], function ($ match ) {
459+ return !empty ($ match ) && false === strpos ($ match , '_ENV. ' );
460+ });
461+ }
462+
431463 /**
432464 * Look up the value for EntityDataObjectName.Key and set it as the corresponding attribute in the resolved custom
433465 * attributes.
@@ -521,10 +553,12 @@ private function stripAndReturnParameters($reference)
521553 */
522554 private function findAndReplaceReferences ($ objectHandler , $ inputString )
523555 {
524- //look for parameter area, if so use different regex
525- $ regex = ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN ;
556+ $ matchPatterns = [
557+ self ::REGEX_WITH_INDEX ,
558+ self ::REGEX_WITH_PARAM
559+ ];
526560
527- preg_match_all ($ regex , $ inputString , $ matches );
561+ preg_match_all ($ this -> getMustachePattern ( $ matchPatterns ) , $ inputString , $ matches );
528562
529563 $ outputString = $ inputString ;
530564
@@ -722,7 +756,11 @@ private function resolveParameterization($isParameterized, $replacement, $match,
722756 */
723757 private function matchParameterReferences ($ reference , $ parameters )
724758 {
725- preg_match_all ('/{{[\w.]+}}/ ' , $ reference , $ varMatches );
759+ $ matchPatterns = [
760+ self ::REGEX_SINGLE_GROUP
761+ ];
762+
763+ preg_match_all ($ this ->getMustachePattern ($ matchPatterns ), $ reference , $ varMatches );
726764 $ varMatches [0 ] = array_unique ($ varMatches [0 ]);
727765 $ this ->checkParameterCount ($ varMatches [0 ], $ parameters , $ reference );
728766
@@ -793,6 +831,17 @@ private function checkParameterCount($matches, $parameters, $reference)
793831 }
794832 }
795833
834+ /**
835+ * Returns Mustache regex pattern
836+ *
837+ * @param array|null $patterns
838+ * @return string
839+ */
840+ private function getMustachePattern (array $ patterns = []): string
841+ {
842+ return '/({{ ' .implode ('}})|({{ ' , $ patterns ).'}})/ ' ;
843+ }
844+
796845 /**
797846 * Returns array of deprecated usages in Action.
798847 *
0 commit comments