cucu 1.0.0__py3-none-any.whl

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.

Potentially problematic release.


This version of cucu might be problematic. Click here for more details.

Files changed (83) hide show
  1. cucu/__init__.py +38 -0
  2. cucu/ansi_parser.py +58 -0
  3. cucu/behave_tweaks.py +196 -0
  4. cucu/browser/__init__.py +0 -0
  5. cucu/browser/core.py +80 -0
  6. cucu/browser/frames.py +106 -0
  7. cucu/browser/selenium.py +323 -0
  8. cucu/browser/selenium_tweaks.py +27 -0
  9. cucu/cli/__init__.py +3 -0
  10. cucu/cli/core.py +788 -0
  11. cucu/cli/run.py +207 -0
  12. cucu/cli/steps.py +137 -0
  13. cucu/cli/thread_dumper.py +55 -0
  14. cucu/config.py +440 -0
  15. cucu/edgedriver_autoinstaller/README.md +1 -0
  16. cucu/edgedriver_autoinstaller/__init__.py +37 -0
  17. cucu/edgedriver_autoinstaller/utils.py +231 -0
  18. cucu/environment.py +283 -0
  19. cucu/external/jquery/jquery-3.5.1.min.js +2 -0
  20. cucu/formatter/__init__.py +0 -0
  21. cucu/formatter/cucu.py +261 -0
  22. cucu/formatter/json.py +321 -0
  23. cucu/formatter/junit.py +289 -0
  24. cucu/fuzzy/__init__.py +3 -0
  25. cucu/fuzzy/core.py +107 -0
  26. cucu/fuzzy/fuzzy.js +253 -0
  27. cucu/helpers.py +875 -0
  28. cucu/hooks.py +205 -0
  29. cucu/language_server/__init__.py +3 -0
  30. cucu/language_server/core.py +114 -0
  31. cucu/lint/__init__.py +0 -0
  32. cucu/lint/linter.py +397 -0
  33. cucu/lint/rules/format.yaml +125 -0
  34. cucu/logger.py +113 -0
  35. cucu/matcher/__init__.py +0 -0
  36. cucu/matcher/core.py +30 -0
  37. cucu/page_checks.py +63 -0
  38. cucu/reporter/__init__.py +3 -0
  39. cucu/reporter/external/bootstrap.min.css +7 -0
  40. cucu/reporter/external/bootstrap.min.js +7 -0
  41. cucu/reporter/external/dataTables.bootstrap.min.css +1 -0
  42. cucu/reporter/external/dataTables.bootstrap.min.js +14 -0
  43. cucu/reporter/external/jquery-3.5.1.min.js +2 -0
  44. cucu/reporter/external/jquery.dataTables.min.js +192 -0
  45. cucu/reporter/external/popper.min.js +5 -0
  46. cucu/reporter/favicon.png +0 -0
  47. cucu/reporter/html.py +452 -0
  48. cucu/reporter/templates/feature.html +72 -0
  49. cucu/reporter/templates/flat.html +48 -0
  50. cucu/reporter/templates/index.html +49 -0
  51. cucu/reporter/templates/layout.html +109 -0
  52. cucu/reporter/templates/scenario.html +200 -0
  53. cucu/steps/__init__.py +27 -0
  54. cucu/steps/base_steps.py +88 -0
  55. cucu/steps/browser_steps.py +337 -0
  56. cucu/steps/button_steps.py +91 -0
  57. cucu/steps/checkbox_steps.py +111 -0
  58. cucu/steps/command_steps.py +181 -0
  59. cucu/steps/comment_steps.py +17 -0
  60. cucu/steps/draggable_steps.py +168 -0
  61. cucu/steps/dropdown_steps.py +467 -0
  62. cucu/steps/file_input_steps.py +80 -0
  63. cucu/steps/filesystem_steps.py +144 -0
  64. cucu/steps/flow_control_steps.py +198 -0
  65. cucu/steps/image_steps.py +37 -0
  66. cucu/steps/input_steps.py +301 -0
  67. cucu/steps/link_steps.py +63 -0
  68. cucu/steps/menuitem_steps.py +39 -0
  69. cucu/steps/platform_steps.py +29 -0
  70. cucu/steps/radio_steps.py +187 -0
  71. cucu/steps/step_utils.py +55 -0
  72. cucu/steps/tab_steps.py +68 -0
  73. cucu/steps/table_steps.py +437 -0
  74. cucu/steps/tables.js +28 -0
  75. cucu/steps/text_steps.py +78 -0
  76. cucu/steps/variable_steps.py +100 -0
  77. cucu/steps/webserver_steps.py +40 -0
  78. cucu/utils.py +269 -0
  79. cucu-1.0.0.dist-info/METADATA +424 -0
  80. cucu-1.0.0.dist-info/RECORD +83 -0
  81. cucu-1.0.0.dist-info/WHEEL +4 -0
  82. cucu-1.0.0.dist-info/entry_points.txt +2 -0
  83. cucu-1.0.0.dist-info/licenses/LICENSE +32 -0
cucu/hooks.py ADDED
@@ -0,0 +1,205 @@
1
+ import re
2
+ from collections import OrderedDict
3
+
4
+ from cucu.config import CONFIG
5
+
6
+ CONFIG.define(
7
+ "CUCU_BROKEN_IMAGES_PAGE_CHECK",
8
+ "enable/disable the broken image page checker",
9
+ default="enabled",
10
+ )
11
+ CONFIG.define(
12
+ "CUCU_READY_STATE_PAGE_CHECK",
13
+ "enable/disable the ready state page checker",
14
+ default="enabled",
15
+ )
16
+
17
+
18
+ def init_global_hook_variables():
19
+ CONFIG["__CUCU_BEFORE_ALL_HOOKS"] = []
20
+ CONFIG["__CUCU_AFTER_ALL_HOOKS"] = []
21
+
22
+ CONFIG["__CUCU_BEFORE_SCENARIO_HOOKS"] = []
23
+ CONFIG["__CUCU_AFTER_SCENARIO_HOOKS"] = []
24
+
25
+ CONFIG["__CUCU_BEFORE_STEP_HOOKS"] = []
26
+ CONFIG["__CUCU_AFTER_STEP_HOOKS"] = []
27
+
28
+ CONFIG["__CUCU_PAGE_CHECK_HOOKS"] = OrderedDict()
29
+ CONFIG["__CUCU_HTML_REPORT_TAG_HANDLERS"] = {}
30
+ CONFIG["__CUCU_HTML_REPORT_SCENARIO_SUBHEADER_HANDLER"] = []
31
+
32
+ CONFIG["__CUCU_CUSTOM_FAILURE_HANDLERS"] = []
33
+ CONFIG["__CUCU_BEFORE_RETRY_HOOKS"] = []
34
+ CONFIG["__CUCU_CTX"] = None
35
+
36
+
37
+ def init_scenario_hook_variables():
38
+ CONFIG["__CUCU_BEFORE_THIS_SCENARIO_HOOKS"] = []
39
+ CONFIG["__CUCU_AFTER_THIS_SCENARIO_HOOKS"] = []
40
+
41
+
42
+ def register_before_all_hook(hook_func):
43
+ """
44
+ register a before all hook that will execute once before anything is
45
+ executed and we will pass the current behave context object as the only
46
+ argument to the hook_func provided.
47
+ """
48
+ CONFIG["__CUCU_BEFORE_ALL_HOOKS"].append(hook_func)
49
+
50
+
51
+ def register_after_all_hook(hook_func):
52
+ """
53
+ register an after all hook that will execute once after everything is
54
+ executed and we will pass the current behave context object as the only
55
+ argument to the hook_func provided.
56
+ """
57
+ CONFIG["__CUCU_AFTER_ALL_HOOKS"].append(hook_func)
58
+
59
+
60
+ def register_before_scenario_hook(hook_func):
61
+ """
62
+ register a before scenario hook that will execute before every scenario has
63
+ executed and we will pass the current behave context object as the only
64
+ argument to the hook_func provided.
65
+ """
66
+ CONFIG["__CUCU_BEFORE_SCENARIO_HOOKS"].append(hook_func)
67
+
68
+
69
+ def register_after_scenario_hook(hook_func):
70
+ """
71
+ register an after scenario hook that will execute after every scenario has
72
+ executed and we will pass the current behave context object as the only
73
+ argument to the hook_func provided.
74
+ """
75
+ CONFIG["__CUCU_AFTER_SCENARIO_HOOKS"].append(hook_func)
76
+
77
+
78
+ def register_after_this_scenario_hook(hook_func):
79
+ """
80
+ register an after scenario hook that will only once after the next scenario
81
+ has executed and we will pass the current behave context object as the only
82
+ argument to the hook_func provided.
83
+ """
84
+ CONFIG["__CUCU_AFTER_THIS_SCENARIO_HOOKS"].append(hook_func)
85
+
86
+
87
+ def register_before_step_hook(hook_func):
88
+ """
89
+ register a before step hook that will execute before every step is executed
90
+ and we will pass the current behave context object as the only argument to
91
+ the hook_func provided.
92
+ """
93
+ CONFIG["__CUCU_BEFORE_STEP_HOOKS"].append(hook_func)
94
+
95
+
96
+ def register_after_step_hook(hook_func):
97
+ """
98
+ register an after step hook that will execute after every step executes and
99
+ we will pass the current behave context object as the only argument to the
100
+ hook_func provided.
101
+ """
102
+ CONFIG["__CUCU_AFTER_STEP_HOOKS"].append(hook_func)
103
+
104
+
105
+ def register_page_check_hook(name, hook_func):
106
+ """
107
+ register a hook to run after every "page load", a "page load" event isn't
108
+ accurate but we try to simply check the page after every interaction such as
109
+ clicking or navigating.
110
+
111
+ parameters:
112
+ name(string): name used when logging for the page check
113
+ hook_func(function): function called with the current
114
+ `cucu.browser.Browser` instance
115
+ """
116
+ CONFIG["__CUCU_PAGE_CHECK_HOOKS"][name] = hook_func
117
+
118
+
119
+ def register_custom_variable_handling(regex, lookup):
120
+ """
121
+ register a regex to match variable names on and allow the lookup
122
+ function provided to do the handling of the resolution of the variable
123
+ name.
124
+
125
+ parameters:
126
+ regex(string): regular expression to match on any config variable
127
+ name when doing lookups
128
+ lookup(func): a function that accepts a variable name to return its
129
+ value at runtime.
130
+
131
+ def lookup(name):
132
+ return [value of the variable at runtime]
133
+ """
134
+ CONFIG.register_custom_variable_handling(regex, lookup)
135
+
136
+
137
+ def register_custom_tags_in_report_handling(regex, handler):
138
+ """
139
+ register a regex to match tag names when generating the HTML test report
140
+ and the function provided will process the exact tag found and return
141
+ the HTML/text to place in the report when a tag that matches the provided
142
+ regex is found.
143
+
144
+ parameters:
145
+ regex(string): regular expression to match on any tag name in the HTML
146
+ test report.
147
+ handler(func): a function that accepts the complete tag name (ie @foo)
148
+ and returns the exact value to put in the HTMl test
149
+ report (HTML/text).
150
+
151
+ def handle(tag):
152
+ return "<a href="...">{tag}</a>"
153
+ """
154
+ CONFIG["__CUCU_HTML_REPORT_TAG_HANDLERS"][re.compile(regex)] = handler
155
+
156
+
157
+ def register_custom_scenario_subheader_in_report_handling(handler):
158
+ """
159
+ register a handler to add HTML content under the scenario header.
160
+
161
+ parameters:
162
+ handler(func): a function that accepts the scenario and returns a HTML to
163
+ go below the scenario header
164
+
165
+ def handle(scenario):
166
+ return f"<div>this is below the {scenario['name']}'s header</div>"
167
+ """
168
+ CONFIG["__CUCU_HTML_REPORT_SCENARIO_SUBHEADER_HANDLER"].append(handler)
169
+
170
+
171
+ def register_custom_junit_failure_handler(handler):
172
+ """
173
+ register a callback function to call when there is a test failure and
174
+ we want to augment the failure output message in the junit results
175
+ files.
176
+
177
+ parameters:
178
+ handler(feature, scenario):
179
+ where feature and scenario are the following behave model
180
+ objects:
181
+
182
+ * https://behave.readthedocs.io/en/stable/api.html#behave.model.Feature
183
+ * https://behave.readthedocs.io/en/stable/api.html#behave.model.Scenario
184
+
185
+ You must return a string that will be appended to the top of the
186
+ failure message in the JUnit XML results files.
187
+ """
188
+ CONFIG["__CUCU_CUSTOM_FAILURE_HANDLERS"].append(handler)
189
+
190
+
191
+ def register_before_retry_hook(hook_func):
192
+ """
193
+ register an before retry hook that will execute before retrying
194
+ cucu.utils.retry function call. The arguments passed to the provided hook
195
+ are only the current behave context object.
196
+
197
+ parameters:
198
+ handler(ctx): a method that accepts the current behave context and
199
+ executes whatever it needs to before a retryable call is
200
+ about to be retried.
201
+
202
+ def handle(ctx):
203
+ ctx.do_something()
204
+ """
205
+ CONFIG["__CUCU_BEFORE_RETRY_HOOKS"].append(hook_func)
@@ -0,0 +1,3 @@
1
+ # flake8: noqa
2
+ # nopycln: file
3
+ from cucu.language_server.core import start
@@ -0,0 +1,114 @@
1
+ import logging
2
+ import re
3
+ from importlib import metadata
4
+
5
+ import jellyfish
6
+ from lsprotocol.types import (
7
+ TEXT_DOCUMENT_COMPLETION,
8
+ CompletionItem,
9
+ CompletionList,
10
+ CompletionOptions,
11
+ CompletionParams,
12
+ )
13
+ from pygls.server import LanguageServer
14
+
15
+ from cucu import init_global_hook_variables
16
+ from cucu.cli.steps import load_cucu_steps
17
+
18
+ init_global_hook_variables()
19
+
20
+
21
+ def find_completions(step_fragment, steps_cache=None):
22
+ """
23
+ given a step name fragment return all of the possible step name completions
24
+ for that fragment.
25
+
26
+ Params:
27
+ step_fragment(string): prefix of the step name to look for such as
28
+ "I click"
29
+
30
+ Returns:
31
+ an Array tuples of step name and locations.
32
+ """
33
+ items = []
34
+
35
+ if steps_cache is None:
36
+ steps_cache, _ = load_cucu_steps()
37
+
38
+ # first pass try to find steps that start with fragment provided
39
+ for step in steps_cache.keys():
40
+ if step.startswith(step_fragment):
41
+ step_details = steps_cache[step]
42
+ location = step_details["location"]
43
+ location = f"{location['filepath']}:{location['line']}"
44
+ items.append((step, location))
45
+
46
+ # if there were 0 steps found then lets at least find some that are close
47
+ # based on some string distance heuristic
48
+ if len(items) == 0:
49
+ for step in steps_cache.keys():
50
+ if jellyfish.jaro_similarity(step_fragment, step) > 0.6:
51
+ step_details = steps_cache[step]
52
+ location = step_details["location"]
53
+ location = f"{location['filepath']}:{location['line']}"
54
+ items.append((step, location))
55
+
56
+ def compare_completion_item(completion_item):
57
+ return jellyfish.jaro_similarity(completion_item[0], step_fragment)
58
+
59
+ items.sort(key=compare_completion_item, reverse=True)
60
+
61
+ return items
62
+
63
+
64
+ def start(port=None):
65
+ version = metadata.version(__package__.split(".")[0])
66
+ server = LanguageServer(name="cucu", version=version)
67
+ steps_cache, _ = load_cucu_steps()
68
+ logging.basicConfig(
69
+ filename="pygls.log", filemode="w", level=logging.DEBUG
70
+ )
71
+
72
+ @server.feature(
73
+ TEXT_DOCUMENT_COMPLETION, CompletionOptions(trigger_characters=[","])
74
+ )
75
+ def completions(ls: LanguageServer, params: CompletionParams):
76
+ logging.warn(f"{TEXT_DOCUMENT_COMPLETION}: {params}")
77
+
78
+ document_uri = params.text_document.uri
79
+ document = document_lines = ls.workspace.get_document(document_uri)
80
+ document_lines = document.source.split("\n")
81
+
82
+ completion_line = document_lines[params.position.line]
83
+ logging.debug(f'completions for "{completion_line}"')
84
+
85
+ completion_line = completion_line.lstrip()
86
+ step_line = re.match(
87
+ "(Given|When|Then|And) (.*)", completion_line
88
+ ).groups()[1]
89
+
90
+ items = []
91
+ step_completions = find_completions(
92
+ completion_line, steps_cache=steps_cache
93
+ )
94
+
95
+ for step_name, step_location in step_completions:
96
+ insert_text = step_name.replace(step_line, "")
97
+ items.append(
98
+ CompletionItem(
99
+ label=step_name,
100
+ detail=f"defined in {step_location}",
101
+ insert_text=insert_text,
102
+ )
103
+ )
104
+
105
+ return CompletionList(
106
+ is_incomplete=False,
107
+ items=items,
108
+ )
109
+
110
+ if port:
111
+ server.start_tcp("0.0.0.0", int(port))
112
+
113
+ else:
114
+ server.start_io()
cucu/lint/__init__.py ADDED
File without changes