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.
- cucu/__init__.py +38 -0
- cucu/ansi_parser.py +58 -0
- cucu/behave_tweaks.py +196 -0
- cucu/browser/__init__.py +0 -0
- cucu/browser/core.py +80 -0
- cucu/browser/frames.py +106 -0
- cucu/browser/selenium.py +323 -0
- cucu/browser/selenium_tweaks.py +27 -0
- cucu/cli/__init__.py +3 -0
- cucu/cli/core.py +788 -0
- cucu/cli/run.py +207 -0
- cucu/cli/steps.py +137 -0
- cucu/cli/thread_dumper.py +55 -0
- cucu/config.py +440 -0
- cucu/edgedriver_autoinstaller/README.md +1 -0
- cucu/edgedriver_autoinstaller/__init__.py +37 -0
- cucu/edgedriver_autoinstaller/utils.py +231 -0
- cucu/environment.py +283 -0
- cucu/external/jquery/jquery-3.5.1.min.js +2 -0
- cucu/formatter/__init__.py +0 -0
- cucu/formatter/cucu.py +261 -0
- cucu/formatter/json.py +321 -0
- cucu/formatter/junit.py +289 -0
- cucu/fuzzy/__init__.py +3 -0
- cucu/fuzzy/core.py +107 -0
- cucu/fuzzy/fuzzy.js +253 -0
- cucu/helpers.py +875 -0
- cucu/hooks.py +205 -0
- cucu/language_server/__init__.py +3 -0
- cucu/language_server/core.py +114 -0
- cucu/lint/__init__.py +0 -0
- cucu/lint/linter.py +397 -0
- cucu/lint/rules/format.yaml +125 -0
- cucu/logger.py +113 -0
- cucu/matcher/__init__.py +0 -0
- cucu/matcher/core.py +30 -0
- cucu/page_checks.py +63 -0
- cucu/reporter/__init__.py +3 -0
- cucu/reporter/external/bootstrap.min.css +7 -0
- cucu/reporter/external/bootstrap.min.js +7 -0
- cucu/reporter/external/dataTables.bootstrap.min.css +1 -0
- cucu/reporter/external/dataTables.bootstrap.min.js +14 -0
- cucu/reporter/external/jquery-3.5.1.min.js +2 -0
- cucu/reporter/external/jquery.dataTables.min.js +192 -0
- cucu/reporter/external/popper.min.js +5 -0
- cucu/reporter/favicon.png +0 -0
- cucu/reporter/html.py +452 -0
- cucu/reporter/templates/feature.html +72 -0
- cucu/reporter/templates/flat.html +48 -0
- cucu/reporter/templates/index.html +49 -0
- cucu/reporter/templates/layout.html +109 -0
- cucu/reporter/templates/scenario.html +200 -0
- cucu/steps/__init__.py +27 -0
- cucu/steps/base_steps.py +88 -0
- cucu/steps/browser_steps.py +337 -0
- cucu/steps/button_steps.py +91 -0
- cucu/steps/checkbox_steps.py +111 -0
- cucu/steps/command_steps.py +181 -0
- cucu/steps/comment_steps.py +17 -0
- cucu/steps/draggable_steps.py +168 -0
- cucu/steps/dropdown_steps.py +467 -0
- cucu/steps/file_input_steps.py +80 -0
- cucu/steps/filesystem_steps.py +144 -0
- cucu/steps/flow_control_steps.py +198 -0
- cucu/steps/image_steps.py +37 -0
- cucu/steps/input_steps.py +301 -0
- cucu/steps/link_steps.py +63 -0
- cucu/steps/menuitem_steps.py +39 -0
- cucu/steps/platform_steps.py +29 -0
- cucu/steps/radio_steps.py +187 -0
- cucu/steps/step_utils.py +55 -0
- cucu/steps/tab_steps.py +68 -0
- cucu/steps/table_steps.py +437 -0
- cucu/steps/tables.js +28 -0
- cucu/steps/text_steps.py +78 -0
- cucu/steps/variable_steps.py +100 -0
- cucu/steps/webserver_steps.py +40 -0
- cucu/utils.py +269 -0
- cucu-1.0.0.dist-info/METADATA +424 -0
- cucu-1.0.0.dist-info/RECORD +83 -0
- cucu-1.0.0.dist-info/WHEEL +4 -0
- cucu-1.0.0.dist-info/entry_points.txt +2 -0
- 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,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
|