robotframework-nl 3.1.0__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: robotframework-nl
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: robotnl is a proving ground to boost Robot framework closer to Natural Language.
5
5
  Author-email: Johan Foederer <github@famfoe.nl>
6
6
  License: BSD 3-Clause License
@@ -42,14 +42,15 @@ Requires-Python: >=3.8
42
42
  Description-Content-Type: text/markdown
43
43
  License-File: LICENSE
44
44
  Requires-Dist: robotframework>=7.0
45
+ Dynamic: license-file
45
46
 
46
- # robotframeworkNL - the oneliner
47
- robotframeworkNL is a proving ground to boost Robot framework closer to Natural Language.
47
+ # RobotNL - the oneliner
48
+ RobotNL is a proving ground to boost Robot framework closer to Natural Language.
48
49
 
49
50
  ## Introduction
50
51
  This project is an extension to [Robot framework](https://robotframework.org/) and although [Robot framework](https://robotframework.org/) made a very good step towards the goals of [keyword-driven testing ](https://en.wikipedia.org/wiki/Keyword-driven_testing) to make it readable for all stakeholders, there is still quite a lot of syntax involved that keeps test cases from really staying concise and to-the-point. In this project we will be introducing concepts to lift [Robot framework](https://robotframework.org/) to an even higher level.
51
52
 
52
- This second release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
53
+ This release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
53
54
 
54
55
  ## Installation
55
56
  The recommended installation method is using [pip](http://pip-installer.org)
@@ -100,17 +101,20 @@ Using *Check that* keywords offers a large reduction in the need for variables i
100
101
 
101
102
  ### Time constraints
102
103
 
103
- *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps robotnl optimise its polling algorithm.
104
+ *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps RobotNL optimise its polling algorithm.
104
105
 
105
106
  |**Example using time constaints**||||||
106
107
  |---|---|---|---|---|---|
107
108
  | Request elevator at floor | 3 |||||
108
109
  | Check that | elevator doors are closed | within | 20 seconds ||
109
110
  | Check that | current elevator floor | equals | 3 | within | 1 minute |
111
+ | Check that | elevator doors are opened | within | same timespan ||
112
+
113
+ The last line in the example uses the special argument `same timespan` to indicate that this check is linked to the same time constraint as the previous check. So, once the doors are closed, the elevator should not only reach the requested floor within 1 minute, but also the doors should be opened within that same 1-minute timespan. To use `within same timespan` you must have executed a check with a time constraint before. This is not necessarily the directly preceding line. The most recent time constraint set within scope is used as starting point. For test suites, that is the current test suite, for keywords that is the current keyword.
110
114
 
111
115
  ### Hybrid manual testing
112
116
 
113
- To manually interact with your automated test run during testing or test case development, robotnl offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
117
+ To manually interact with your automated test run during testing or test case development, RobotNL offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
114
118
 
115
119
  ***Check Manual*** allows asking the tester a question. The question typically requests manual verification of an expected outcome. The answer will PASS or FAIL the test case, which is also reflected in the test report.
116
120
 
@@ -1,10 +1,10 @@
1
- # robotframeworkNL - the oneliner
2
- robotframeworkNL is a proving ground to boost Robot framework closer to Natural Language.
1
+ # RobotNL - the oneliner
2
+ RobotNL is a proving ground to boost Robot framework closer to Natural Language.
3
3
 
4
4
  ## Introduction
5
5
  This project is an extension to [Robot framework](https://robotframework.org/) and although [Robot framework](https://robotframework.org/) made a very good step towards the goals of [keyword-driven testing ](https://en.wikipedia.org/wiki/Keyword-driven_testing) to make it readable for all stakeholders, there is still quite a lot of syntax involved that keeps test cases from really staying concise and to-the-point. In this project we will be introducing concepts to lift [Robot framework](https://robotframework.org/) to an even higher level.
6
6
 
7
- This second release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
7
+ This release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
8
8
 
9
9
  ## Installation
10
10
  The recommended installation method is using [pip](http://pip-installer.org)
@@ -55,17 +55,20 @@ Using *Check that* keywords offers a large reduction in the need for variables i
55
55
 
56
56
  ### Time constraints
57
57
 
58
- *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps robotnl optimise its polling algorithm.
58
+ *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps RobotNL optimise its polling algorithm.
59
59
 
60
60
  |**Example using time constaints**||||||
61
61
  |---|---|---|---|---|---|
62
62
  | Request elevator at floor | 3 |||||
63
63
  | Check that | elevator doors are closed | within | 20 seconds ||
64
64
  | Check that | current elevator floor | equals | 3 | within | 1 minute |
65
+ | Check that | elevator doors are opened | within | same timespan ||
66
+
67
+ The last line in the example uses the special argument `same timespan` to indicate that this check is linked to the same time constraint as the previous check. So, once the doors are closed, the elevator should not only reach the requested floor within 1 minute, but also the doors should be opened within that same 1-minute timespan. To use `within same timespan` you must have executed a check with a time constraint before. This is not necessarily the directly preceding line. The most recent time constraint set within scope is used as starting point. For test suites, that is the current test suite, for keywords that is the current keyword.
65
68
 
66
69
  ### Hybrid manual testing
67
70
 
68
- To manually interact with your automated test run during testing or test case development, robotnl offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
71
+ To manually interact with your automated test run during testing or test case development, RobotNL offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
69
72
 
70
73
  ***Check Manual*** allows asking the tester a question. The question typically requests manual verification of an expected outcome. The answer will PASS or FAIL the test case, which is also reflected in the test report.
71
74
 
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "robotframework-nl"
10
- version = "3.1.0"
10
+ version = "3.2.0"
11
11
  description = "robotnl is a proving ground to boost Robot framework closer to Natural Language."
12
12
  readme = "README.md"
13
13
  authors = [{ name = "Johan Foederer", email = "github@famfoe.nl" }]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: robotframework-nl
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: robotnl is a proving ground to boost Robot framework closer to Natural Language.
5
5
  Author-email: Johan Foederer <github@famfoe.nl>
6
6
  License: BSD 3-Clause License
@@ -42,14 +42,15 @@ Requires-Python: >=3.8
42
42
  Description-Content-Type: text/markdown
43
43
  License-File: LICENSE
44
44
  Requires-Dist: robotframework>=7.0
45
+ Dynamic: license-file
45
46
 
46
- # robotframeworkNL - the oneliner
47
- robotframeworkNL is a proving ground to boost Robot framework closer to Natural Language.
47
+ # RobotNL - the oneliner
48
+ RobotNL is a proving ground to boost Robot framework closer to Natural Language.
48
49
 
49
50
  ## Introduction
50
51
  This project is an extension to [Robot framework](https://robotframework.org/) and although [Robot framework](https://robotframework.org/) made a very good step towards the goals of [keyword-driven testing ](https://en.wikipedia.org/wiki/Keyword-driven_testing) to make it readable for all stakeholders, there is still quite a lot of syntax involved that keeps test cases from really staying concise and to-the-point. In this project we will be introducing concepts to lift [Robot framework](https://robotframework.org/) to an even higher level.
51
52
 
52
- This second release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
53
+ This release introduces ``inline keywords`` and a set of ``Check that`` keywords that help to vastly reduce the amount of ``${...}`` cluttering in your test cases. Combining these concepts helps to write a cleaner [Domain Specific Language](https://en.wikipedia.org/wiki/Domain-specific_language) around your [domain vocabulary](https://en.wikipedia.org/wiki/Jargon).
53
54
 
54
55
  ## Installation
55
56
  The recommended installation method is using [pip](http://pip-installer.org)
@@ -100,17 +101,20 @@ Using *Check that* keywords offers a large reduction in the need for variables i
100
101
 
101
102
  ### Time constraints
102
103
 
103
- *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps robotnl optimise its polling algorithm.
104
+ *Check that* offers support for executing checks that may take some time to complete. When using the optional `within` argument, followed by a time duration, *Check that* will apply *smart polling* to re-evaluate the expression and the keywords during the given period. Specifying the time limit is done using the standard [Robot Framework time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-176). It is advised to use a realistic time duration. This sets the correct expectation for the reader and helps RobotNL optimise its polling algorithm.
104
105
 
105
106
  |**Example using time constaints**||||||
106
107
  |---|---|---|---|---|---|
107
108
  | Request elevator at floor | 3 |||||
108
109
  | Check that | elevator doors are closed | within | 20 seconds ||
109
110
  | Check that | current elevator floor | equals | 3 | within | 1 minute |
111
+ | Check that | elevator doors are opened | within | same timespan ||
112
+
113
+ The last line in the example uses the special argument `same timespan` to indicate that this check is linked to the same time constraint as the previous check. So, once the doors are closed, the elevator should not only reach the requested floor within 1 minute, but also the doors should be opened within that same 1-minute timespan. To use `within same timespan` you must have executed a check with a time constraint before. This is not necessarily the directly preceding line. The most recent time constraint set within scope is used as starting point. For test suites, that is the current test suite, for keywords that is the current keyword.
110
114
 
111
115
  ### Hybrid manual testing
112
116
 
113
- To manually interact with your automated test run during testing or test case development, robotnl offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
117
+ To manually interact with your automated test run during testing or test case development, RobotNL offers the *Check manual* and *Check interactive* keywords. These keywords can be included at any point in the test case to suspend the test run at the current position for user input.
114
118
 
115
119
  ***Check Manual*** allows asking the tester a question. The question typically requests manual verification of an expected outcome. The answer will PASS or FAIL the test case, which is also reflected in the test report.
116
120
 
@@ -48,7 +48,25 @@ class CheckFailed(RuntimeError):
48
48
  class RobotChecks:
49
49
  ROBOT_LIBRARY_SCOPE = "GLOBAL"
50
50
  def __init__(self):
51
+ self.ROBOT_LIBRARY_LISTENER = self
51
52
  self.__gui = None
53
+ self.scope_depth = 0
54
+ self.nested_timespans = {}
55
+
56
+ def _start_suite(self, data, result):
57
+ self.scope_depth = 0
58
+ self.nested_timespans = {}
59
+ _end_suite = _start_suite
60
+
61
+ def _start_keyword(self, data, result):
62
+ self.scope_depth += 1
63
+
64
+ def _end_keyword(self, data, result):
65
+ if self.scope_depth + 1 in self.nested_timespans:
66
+ # use depth+1 because 'check that' itself is also a keyword. The +1
67
+ # keeps all check thats on the same level grouped.
68
+ self.nested_timespans.pop(self.scope_depth + 1)
69
+ self.scope_depth -= 1
52
70
 
53
71
  @property
54
72
  def _gui(self):
@@ -74,7 +92,7 @@ class RobotChecks:
74
92
  point where it was able to check the requirement it was testing for.
75
93
  """
76
94
  try:
77
- return RobotChecks.__execute_check("Precondition", *args)
95
+ return self.__execute_check("Precondition", *args)
78
96
  except CheckFailed as failure:
79
97
  failure.ROBOT_CONTINUE_ON_FAILURE = False
80
98
  raise failure
@@ -91,7 +109,7 @@ class RobotChecks:
91
109
  the cause of failure.
92
110
  """
93
111
  try:
94
- return RobotChecks.__execute_check("Postcondition", *args)
112
+ return self.__execute_check("Postcondition", *args)
95
113
  except CheckFailed as failure:
96
114
  failure.ROBOT_CONTINUE_ON_FAILURE = False
97
115
  raise failure
@@ -108,16 +126,19 @@ class RobotChecks:
108
126
  Check that has two basic forms.
109
127
  - A single keyword (with its arguments) can be evaluated to a truth value
110
128
  - Two values or keywords (with their arguments) can be evaluated using an operator. It will
111
- then have the form Check that ``<keyword or value>`` ``<operator>`` ``<keyword or value>``.
129
+ then have the form: Check that ``<keyword or value>`` ``<operator>`` ``<keyword or value>``.
112
130
 
113
- Operator can be any Robot keyword taking exactly two values (left and right operands) as
114
- input. A number of predefined operators on numeric, string and list types are included in
115
- this library.
131
+ Operator can be any Robot keyword taking at least one argument as input. The first argument is
132
+ placed on the left side of the operator, the left operand. Any following arguments are placed
133
+ to the right of the operator and form the right operands. A keyword with its argument values is
134
+ treated as a single operand. A number of predefined operators on numeric, string and list types
135
+ are included in this library.
116
136
 
117
137
  Examples:
118
138
  | `Check that` | 3 | `=` | 3 |
119
139
  | `Check that` | _Two times_ | 6 | `equals` | 12 |
120
140
  | `Check that` | _Two times_ | 5 | `≠` | _Two times_ | 7 |
141
+ | `Check that` | _the shoe box_ | _contains 2 items_ |
121
142
  | `Check that` | _Earth exists_ |
122
143
 
123
144
  'Two times' in these examples is assumed to be defined as a Robot keyword that takes one
@@ -129,16 +150,26 @@ class RobotChecks:
129
150
  This will cause the condition to be reevaluated until it becomes true, or until
130
151
  the specified time has passed. In the latter case the test case will fail.
131
152
 
153
+ Multiple checks can be linked to the same time constraint by using ``same timespan``
154
+ as the time constraint value. Suppose the previous time constraint was 5 seconds
155
+ and that check took 2 seconds to complete. If the next check uses
156
+ ``within same timespan``, then this check has the remaining 3 seconds to
157
+ complete.
158
+
132
159
  Example with time constraint:
133
160
  | `Check that` | _condition is true_ | within | 1 minute 30 seconds |
134
161
 
135
162
  Elevator example:
136
- | `Check that` | _elevator doors are closed_ |
137
163
  | _Request elevator at floor_ | 3 |
138
- | `Check that` | _elevator floor_ | `equals` | 3 | within | 20 seconds |
139
- | `Check that` | _offset to floor level in mm_ | `≤` | 5 | within | 3 seconds |
164
+ | `Check that` | _elevator doors are closed_ | within | 20 seconds |
165
+ | `Check that` | _elevator floor_ | `equals` | 3 | within | 1 minute |
166
+ | `Check that` | _elevator doors are opened_ | within | same timespan |
167
+
168
+ In the elevator example, the doors should be closed within 20 seconds after requesting a
169
+ floor. Then the elevator can take a maximum of 1 minute to reach the floor and open its
170
+ doors. `Check that` will continue as soon as the condition is detected.
140
171
  """
141
- return RobotChecks.__execute_check("Requirement", *args)
172
+ return self.__execute_check("Requirement", *args)
142
173
  RUN_KW_REGISTER.register_run_keyword('robotnl', check_that.__name__, args_to_process=0, deprecation_warning=False)
143
174
 
144
175
  def check_manual(self, checkRequestText=""):
@@ -210,8 +241,7 @@ class RobotChecks:
210
241
  except Exception as e:
211
242
  BuiltIn().log_to_console("Error in interactive keyword '%s'\n\n%s" % (newInput, e))
212
243
 
213
- @staticmethod
214
- def __execute_check(checkType, *args):
244
+ def __execute_check(self, checkType, *args):
215
245
  """
216
246
  Parse arguments for check keyword to determine its operands, evaluate them and execute the
217
247
  check.
@@ -223,14 +253,35 @@ class RobotChecks:
223
253
  TimeOutInSeconds = 0
224
254
  TimeRemaining = True
225
255
  s_TimeConstraint = ""
256
+ StartTime = time.perf_counter()
226
257
  if len(Arguments) >= 2 and str(Arguments[-2]).lower() == 'within':
227
- EvaluatedTimeArg = RobotChecks.__evaluateOperand([Arguments[-1]])[0]
228
- TimeOutInSeconds = timestr_to_secs(EvaluatedTimeArg)
229
- s_TimeConstraint = Arguments[-1]
258
+ timearg = Arguments[-1]
230
259
  Arguments = Arguments[:-2]
260
+ running_timespan_start, running_timespan, s_TimeConstraint =self.nested_timespans.get(
261
+ self.scope_depth, (None, None, ''))
262
+ if str(timearg).lower() == 'same timespan':
263
+ if running_timespan is None:
264
+ BuiltIn().fail("Joint timespan expected, but was not set before this check.")
265
+ TimeOutInSeconds = round(running_timespan_start + running_timespan - StartTime, ndigits=3)
266
+
267
+ remaining = self._human_time(0 if TimeOutInSeconds < 0 else TimeOutInSeconds)
268
+ BuiltIn().log(f"Reusing joint timespan: {s_TimeConstraint}\n"
269
+ f"Must complete within the remaining {remaining}")
270
+ else:
271
+ try:
272
+ EvaluatedTimeArg, s_TimeConstraint = RobotChecks.__evaluateOperand([timearg])
273
+ TimeOutInSeconds = timestr_to_secs(EvaluatedTimeArg)
274
+ except:
275
+ # End any running timespan on error
276
+ if self.scope_depth in self.nested_timespans:
277
+ self.nested_timespans.pop(self.scope_depth)
278
+ raise
279
+ if is_keyword(timearg):
280
+ s_TimeConstraint = f"{timearg} [{secs_to_timestr(TimeOutInSeconds)}]"
281
+ self.nested_timespans[self.scope_depth] = (StartTime, TimeOutInSeconds, s_TimeConstraint)
231
282
 
232
283
  if not len(Arguments):
233
- BuiltIn().fail("%s check failed. There was nothing to check." % checkType)
284
+ BuiltIn().fail(f"{checkType} check failed. There was nothing to check.")
234
285
 
235
286
  ############################################################################################
236
287
  # Build expression
@@ -263,8 +314,6 @@ class RobotChecks:
263
314
  # Evaluate expression
264
315
  EvaluatedResult = None
265
316
 
266
- StartTime = time.perf_counter()
267
- TimeLeft = TimeOutInSeconds
268
317
  PollMax = 20 # After 20s people start wondering: "Is it still going?" Time for an update.
269
318
  PollMin = min(PollMax/8, TimeOutInSeconds*3/100) # Shortest delay is 3% of the target time.
270
319
  PollDelay = PollMin # Initial poll delay will be 2x PollMin
@@ -312,8 +361,14 @@ class RobotChecks:
312
361
  ReportString = f"{checkType} check on '{s_LeftOperand} {OperatorKeyword} {s_RightOperand}'"
313
362
 
314
363
  if s_TimeConstraint:
315
- ReportString += " within %s" % secs_to_timestr(TimeOutInSeconds)
364
+ running_start, timespan, timestr = self.nested_timespans.get(self.scope_depth, (None, None, ''))
365
+ if TimeRemaining and running_start != StartTime:
366
+ elapsed = time.perf_counter() - running_start
367
+ BuiltIn().log(f"Check completed {self._human_time(elapsed)} into the alotted timespan ({timestr})")
368
+ ReportString += f" within {timestr}"
316
369
  if not TimeRemaining and EvaluatedResult == "passed":
370
+ overshoot = time.perf_counter() - (running_start + timespan)
371
+ BuiltIn().log(f"Check completed {self._human_time(overshoot)} too late")
317
372
  ReportString += " (too late)"
318
373
  raise CheckFailed(ReportString)
319
374
 
@@ -356,3 +411,10 @@ class RobotChecks:
356
411
  s_Operand += f" [{s_Value}]"
357
412
 
358
413
  return Value, s_Operand
414
+
415
+ @staticmethod
416
+ def _human_time(time_in_seconds: float):
417
+ """return a human readable string for a time in seconds"""
418
+ SKIP_MILLI = 10 # Do not report milliseconds for timespans above SKIP_MILLI seconds
419
+ rounded_time = int(time_in_seconds) if time_in_seconds > SKIP_MILLI else round(time_in_seconds, ndigits=3)
420
+ return secs_to_timestr(rounded_time)
@@ -0,0 +1 @@
1
+ VERSION = '3.2.0'
@@ -1 +0,0 @@
1
- VERSION = '3.1.0'