diff --git a/atest/robot/keywords/optional_given_when_then.robot b/atest/robot/keywords/optional_given_when_then.robot index 9f8dd9f884f..86325f3ec15 100644 --- a/atest/robot/keywords/optional_given_when_then.robot +++ b/atest/robot/keywords/optional_given_when_then.robot @@ -46,6 +46,22 @@ Keyword can be used with and without prefix Should Be Equal ${tc.kws[5].full_name} Then we are in Berlin city Should Be Equal ${tc.kws[6].full_name} we are in Berlin city +Only single prefixes are a processed + ${tc} = Check Test Case ${TEST NAME} + Should Be Equal ${tc.kws[0].full_name} Given we are in Berlin city + Should Be Equal ${tc.kws[1].full_name} but then we are in Berlin city + +First word of a keyword can be a prefix + ${tc} = Check Test Case ${TEST NAME} + Should Be Equal ${tc.kws[0].full_name} Given the prefix is part of the keyword + +First word in a keyword can be an argument + ${tc} = Check Test Case ${TEST NAME} + Should Be Equal ${tc.kws[0].full_name} Given we don't drink too many beers + Should Be Equal ${tc.kws[1].full_name} Then Pekka drinks lonkero instead + Should Be Equal ${tc.kws[2].full_name} and Miikka drinks water instead + Should Be Equal ${tc.kws[3].full_name} Étant donné Miikka drinks water instead + Localized prefixes ${tc} = Check Test Case ${TEST NAME} Should Be Equal ${tc.kws[0].full_name} Oletetaan we don't drink too many beers diff --git a/atest/testdata/keywords/optional_given_when_then.robot b/atest/testdata/keywords/optional_given_when_then.robot index 5cd8d82ff04..1acf9eab4c0 100644 --- a/atest/testdata/keywords/optional_given_when_then.robot +++ b/atest/testdata/keywords/optional_given_when_then.robot @@ -48,6 +48,20 @@ Keyword can be used with and without prefix Then we are in Berlin city we are in Berlin city +Only single prefixes are a processed + [Documentation] FAIL No keyword with name 'but then we are in Berlin city' found. + Given we are in Berlin city + but then we are in Berlin city + +First word of a keyword can be a prefix + Given the prefix is part of the keyword + +First word in a keyword can be an argument + Given we don't drink too many beers + Then Pekka drinks lonkero instead + and Miikka drinks water instead + Étant donné Miikka drinks water instead + Localized prefixes Oletetaan we don't drink too many beers Kun we are in museum cafe @@ -66,7 +80,7 @@ Prefix consisting of multiple words Fie ca multipart prefixes didn't work with RF 6.0 Prefix must be followed by space - [Documentation] FAIL + [Documentation] FAIL ... No keyword with name 'Givenwe don't drink too many beers' found. Did you mean: ... ${SPACE*4}We don't drink too many beers Givenwe don't drink too many beers @@ -76,27 +90,36 @@ We don't drink too many beers No Operation We are in - [Arguments] ${a1} ${a2} - Should Be Equal ${a1}-${a2} museum-cafe + [Arguments] ${a1} ${a2} + Should Be Equal ${a1}-${a2} museum-cafe Time - [Arguments] @{args} - Length Should Be ${args} 4 + [Arguments] @{args} + Length Should Be ${args} 4 we get this feature ready today Given we don't drink too many beers We Are In ${name} city - Should be equal ${name} Berlin + Should be equal ${name} Berlin It Does Not ${x} - Should Be Equal ${x} rain + Should Be Equal ${x} rain We ${x} This ${thing} Implemented - Should Be Equal ${x}-${thing} get-feature + Should Be Equal ${x}-${thing} get-feature We Go To ${somewhere} - Should Be Equal ${somewhere} walking tour + Should Be Equal ${somewhere} walking tour + +${person} drinks lonkero instead + Should be equal ${person} Pekka + +${person} drinks water instead + Should be equal ${person} Miikka Multipart prefixes didn't work with RF 6.0 No Operation + +Given the prefix is part of the keyword + No operation diff --git a/doc/userguide/src/CreatingTestData/CreatingTestCases.rst b/doc/userguide/src/CreatingTestData/CreatingTestCases.rst index 5216ff640a3..2a3ebc24ee9 100644 --- a/doc/userguide/src/CreatingTestData/CreatingTestCases.rst +++ b/doc/userguide/src/CreatingTestData/CreatingTestCases.rst @@ -1142,17 +1142,23 @@ Ignoring :name:`Given/When/Then/And/But` prefixes ''''''''''''''''''''''''''''''''''''''''''''''''' Prefixes :name:`Given`, :name:`When`, :name:`Then`, :name:`And` and :name:`But` -are dropped when matching keywords are searched, if no match with the full name -is found. This works for both user keywords and library keywords. For example, -:name:`Given login page is open` in the above example can be implemented as -user keyword either with or without the word :name:`Given`. Ignoring prefixes -also allows using the same keyword with different prefixes. For example -:name:`Welcome page should be open` could also used as :name:`And welcome page -should be open`. +are dropped when searching for matching keywords. This works for both user +keywords and library keywords. For example, :name:`Given login page is open` in +the above example is typically implemented as a keyword without the word +:name:`Given`, i.e. :name:`Login page is open`. Ignoring prefixes allows using +the same keyword with different prefixes. For example :name:`Welcome page +should be open` could be used as :name:`Then welcome page should be open` or +:name:`and welcome page should be open`. It is valid to include the prefix +directly as part of the keyword's name. If this causes a naming conflict, then +the one without prefix will get precedence. .. note:: These prefixes can be localized_. See the Translations_ appendix for supported translations. +.. note:: Prior to Robot Framework 7.1, arguments had precedence over prefixes. + If a keyword started with an argument, then any prefix would be + included in the argument value. + Embedding data to keywords '''''''''''''''''''''''''' diff --git a/src/robot/running/namespace.py b/src/robot/running/namespace.py index 99b46b09060..fe5d04ddeda 100644 --- a/src/robot/running/namespace.py +++ b/src/robot/running/namespace.py @@ -287,26 +287,26 @@ def _raise_no_keyword_found(self, name, recommend=True): else: raise KeywordError(message) - def _get_runner(self, name): + def _get_runner(self, name, strip_bdd_prefix=True): if not name: raise DataError('Keyword name cannot be empty.') if not is_string(name): raise DataError('Keyword name must be a string.') - runner = self._get_runner_from_suite_file(name) + runner = self._get_bdd_style_runner(name) if strip_bdd_prefix else None + if not runner: + runner = self._get_runner_from_suite_file(name) if not runner and '.' in name: runner = self._get_explicit_runner(name) if not runner: runner = self._get_implicit_runner(name) - if not runner: - runner = self._get_bdd_style_runner(name, self.languages.bdd_prefixes) return runner - def _get_bdd_style_runner(self, name, prefixes): + def _get_bdd_style_runner(self, name): parts = name.split() for index in range(1, len(parts)): prefix = ' '.join(parts[:index]).title() - if prefix in prefixes: - runner = self._get_runner(' '.join(parts[index:])) + if prefix in self.languages.bdd_prefixes: + runner = self._get_runner(' '.join(parts[index:]), strip_bdd_prefix=False) if runner: runner = copy.copy(runner) runner.name = name