cucu 1.1.2__tar.gz → 1.2.1__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.

Potentially problematic release.


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

Files changed (95) hide show
  1. {cucu-1.1.2 → cucu-1.2.1}/CHANGELOG.md +9 -0
  2. {cucu-1.1.2 → cucu-1.2.1}/PKG-INFO +3 -11
  3. {cucu-1.1.2 → cucu-1.2.1}/pyproject.toml +4 -12
  4. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/behave_tweaks.py +6 -2
  5. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/browser/selenium.py +0 -2
  6. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/environment.py +17 -2
  7. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/lint/rules/format.yaml +9 -0
  8. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/html.py +6 -1
  9. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/templates/layout.html +35 -0
  10. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/__init__.py +1 -1
  11. cucu-1.2.1/src/cucu/steps/section_steps.py +25 -0
  12. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/utils.py +13 -0
  13. cucu-1.1.2/src/cucu/steps/comment_steps.py +0 -17
  14. {cucu-1.1.2 → cucu-1.2.1}/.gitignore +0 -0
  15. {cucu-1.1.2 → cucu-1.2.1}/LICENSE +0 -0
  16. {cucu-1.1.2 → cucu-1.2.1}/README.md +0 -0
  17. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/__init__.py +0 -0
  18. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/ansi_parser.py +0 -0
  19. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/browser/__init__.py +0 -0
  20. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/browser/core.py +0 -0
  21. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/browser/frames.py +0 -0
  22. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/browser/selenium_tweaks.py +0 -0
  23. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/cli/__init__.py +0 -0
  24. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/cli/core.py +0 -0
  25. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/cli/run.py +0 -0
  26. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/cli/steps.py +0 -0
  27. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/cli/thread_dumper.py +0 -0
  28. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/config.py +0 -0
  29. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/edgedriver_autoinstaller/README.md +0 -0
  30. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/edgedriver_autoinstaller/__init__.py +0 -0
  31. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/edgedriver_autoinstaller/utils.py +0 -0
  32. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/external/jquery/jquery-3.5.1.min.js +0 -0
  33. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/formatter/__init__.py +0 -0
  34. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/formatter/cucu.py +0 -0
  35. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/formatter/json.py +0 -0
  36. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/formatter/junit.py +0 -0
  37. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/fuzzy/__init__.py +0 -0
  38. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/fuzzy/core.py +0 -0
  39. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/fuzzy/fuzzy.js +0 -0
  40. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/helpers.py +0 -0
  41. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/hooks.py +0 -0
  42. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/.gitignore +0 -0
  43. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/README.md +0 -0
  44. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/cucurc.yml +0 -0
  45. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/data/www/example.html +0 -0
  46. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/features/cucurc.yml +0 -0
  47. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/features/environment.py +0 -0
  48. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/features/example.feature +0 -0
  49. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/features/lint_rules/sid.yaml +0 -0
  50. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/features/steps/__init__.py +0 -0
  51. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/init_data/features/steps/my_steps.py +0 -0
  52. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/language_server/__init__.py +0 -0
  53. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/language_server/core.py +0 -0
  54. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/lint/__init__.py +0 -0
  55. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/lint/linter.py +0 -0
  56. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/logger.py +0 -0
  57. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/matcher/__init__.py +0 -0
  58. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/matcher/core.py +0 -0
  59. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/page_checks.py +0 -0
  60. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/__init__.py +0 -0
  61. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/bootstrap.min.css +0 -0
  62. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/bootstrap.min.js +0 -0
  63. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/dataTables.bootstrap.min.css +0 -0
  64. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/dataTables.bootstrap.min.js +0 -0
  65. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/jquery-3.5.1.min.js +0 -0
  66. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/jquery.dataTables.min.js +0 -0
  67. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/external/popper.min.js +0 -0
  68. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/favicon.png +0 -0
  69. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/templates/feature.html +0 -0
  70. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/templates/flat.html +0 -0
  71. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/templates/index.html +0 -0
  72. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/reporter/templates/scenario.html +0 -0
  73. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/base_steps.py +0 -0
  74. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/browser_steps.py +0 -0
  75. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/button_steps.py +0 -0
  76. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/checkbox_steps.py +0 -0
  77. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/command_steps.py +0 -0
  78. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/draggable_steps.py +0 -0
  79. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/dropdown_steps.py +0 -0
  80. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/file_input_steps.py +0 -0
  81. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/filesystem_steps.py +0 -0
  82. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/flow_control_steps.py +0 -0
  83. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/image_steps.py +0 -0
  84. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/input_steps.py +0 -0
  85. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/link_steps.py +0 -0
  86. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/menuitem_steps.py +0 -0
  87. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/platform_steps.py +0 -0
  88. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/radio_steps.py +0 -0
  89. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/step_utils.py +0 -0
  90. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/tab_steps.py +0 -0
  91. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/table_steps.py +0 -0
  92. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/tables.js +0 -0
  93. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/text_steps.py +0 -0
  94. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/variable_steps.py +0 -0
  95. {cucu-1.1.2 → cucu-1.2.1}/src/cucu/steps/webserver_steps.py +0 -0
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project closely adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 1.2.1
9
+ - Add - add tab information to html report and cucu debug console log
10
+
11
+ ## 1.2.0
12
+ - Add - levels 2-4 to section step
13
+ - Change - rename comment step to section step
14
+ - Add - linting for section step
15
+ - Change - min python to 3.10
16
+
8
17
  ## 1.1.2
9
18
  - Add - `cucu init` command to setup new projects
10
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cucu
3
- Version: 1.1.2
3
+ Version: 1.2.1
4
4
  Summary: Easy BDD web testing
5
5
  Project-URL: Homepage, https://github.com/dominodatalab/cucu/wiki
6
6
  Project-URL: Download, https://pypi.org/project/cucu/
@@ -16,20 +16,12 @@ Classifier: Intended Audience :: Developers
16
16
  Classifier: License :: OSI Approved :: BSD License
17
17
  Classifier: Natural Language :: English
18
18
  Classifier: Operating System :: OS Independent
19
- Classifier: Programming Language :: Python
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3 :: Only
22
- Classifier: Programming Language :: Python :: 3.9
23
- Classifier: Programming Language :: Python :: 3.10
24
- Classifier: Programming Language :: Python :: 3.11
25
- Classifier: Programming Language :: Python :: 3.12
26
- Classifier: Programming Language :: Python :: 3.13
27
19
  Classifier: Topic :: Software Development :: Testing :: BDD
28
- Requires-Python: >=3.9
20
+ Requires-Python: >=3.10
29
21
  Requires-Dist: beautifulsoup4~=4.13.3
30
22
  Requires-Dist: behave==1.2.6
31
23
  Requires-Dist: chromedriver-autoinstaller~=0.6.2
32
- Requires-Dist: click~=8.1.7
24
+ Requires-Dist: click~=8.2.0
33
25
  Requires-Dist: coverage[toml]~=7.8
34
26
  Requires-Dist: geckodriver-autoinstaller~=0.1.0
35
27
  Requires-Dist: humanize~=4.12.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cucu"
3
- version = "1.1.2"
3
+ version = "1.2.1"
4
4
  description = "Easy BDD web testing"
5
5
  readme = "README.md"
6
6
  license = { text = "The Clear BSD License" }
@@ -27,26 +27,18 @@ classifiers = [
27
27
  "License :: OSI Approved :: BSD License",
28
28
  "Operating System :: OS Independent",
29
29
  "Natural Language :: English",
30
- "Programming Language :: Python",
31
- "Programming Language :: Python :: 3",
32
- "Programming Language :: Python :: 3.9",
33
- "Programming Language :: Python :: 3.10",
34
- "Programming Language :: Python :: 3.11",
35
- "Programming Language :: Python :: 3.12",
36
- "Programming Language :: Python :: 3.13",
37
- "Programming Language :: Python :: 3 :: Only",
38
30
  "Topic :: Software Development :: Testing :: BDD",
39
31
  ]
40
32
  include = [
41
33
  { path = "CHANGELOG.md", format = "sdist" },
42
34
  { path = "LICENSE", format = "sdist" },
43
35
  ]
44
- requires-python = ">=3.9"
36
+ requires-python = ">=3.10"
45
37
  dependencies = [
46
38
  "beautifulsoup4~=4.13.3",
47
39
  "behave==1.2.6",
48
40
  "chromedriver-autoinstaller~=0.6.2",
49
- "click~=8.1.7",
41
+ "click~=8.2.0",
50
42
  "coverage[toml]~=7.8",
51
43
  "geckodriver-autoinstaller~=0.1.0",
52
44
  "humanize~=4.12.1",
@@ -90,7 +82,7 @@ exclude = [
90
82
  [tool.uv]
91
83
  dev-dependencies = [
92
84
  "pre-commit>=3.8.0",
93
- "pytest~=8.3.5",
85
+ "pytest~=8.4.0",
94
86
  "ruff>=0.6.4",
95
87
  ]
96
88
 
@@ -66,7 +66,9 @@ def init_step_hooks(stdout, stderr):
66
66
  # resolve variables in the table values
67
67
  if ctx.table is not None:
68
68
  ctx.table.original = Table(
69
- ctx.table.headings, rows=ctx.table.rows, line=ctx.table.line
69
+ ctx.table.headings,
70
+ rows=ctx.table.rows,
71
+ line=ctx.table.line,
70
72
  )
71
73
  new_rows = []
72
74
  for row in ctx.table.rows:
@@ -123,7 +125,9 @@ def init_step_hooks(stdout, stderr):
123
125
 
124
126
  return wrapper
125
127
 
126
- behave.__dict__[decorator_name.title()] = behave.__dict__[decorator_name] = new_decorator
128
+ behave.__dict__[decorator_name.title()] = behave.__dict__[
129
+ decorator_name
130
+ ] = new_decorator
127
131
 
128
132
 
129
133
  _stdout = sys.stdout
@@ -215,7 +215,6 @@ class Selenium(Browser):
215
215
 
216
216
  if window_handle_index == len(window_handles) - 1:
217
217
  raise RuntimeError("no next browser tab available")
218
-
219
218
  self.driver.switch_to.window(window_handles[window_handle_index + 1])
220
219
 
221
220
  def switch_to_previous_tab(self):
@@ -225,7 +224,6 @@ class Selenium(Browser):
225
224
 
226
225
  if window_handle_index == 0:
227
226
  raise RuntimeError("no previous browser tab available")
228
-
229
227
  self.driver.switch_to.window(window_handles[window_handle_index - 1])
230
228
 
231
229
  def back(self):
@@ -10,7 +10,7 @@ from functools import partial
10
10
  from cucu import config, init_scenario_hook_variables, logger
11
11
  from cucu.config import CONFIG
12
12
  from cucu.page_checks import init_page_checks
13
- from cucu.utils import ellipsize_filename, take_screenshot
13
+ from cucu.utils import ellipsize_filename, get_tab_information, take_screenshot
14
14
 
15
15
  CONFIG.define(
16
16
  "FEATURE_RESULTS_DIR",
@@ -24,7 +24,7 @@ CONFIG.define(
24
24
  )
25
25
  CONFIG.define(
26
26
  "SCENARIO_DOWNLOADS_DIR",
27
- "the browser downloads directory for the currently " "executing scenario",
27
+ "the browser downloads directory for the currently executing scenario",
28
28
  default=None,
29
29
  )
30
30
 
@@ -264,6 +264,21 @@ def after_step(ctx, step):
264
264
  if ctx.browser is not None and ctx.current_step.has_substeps is False:
265
265
  take_screenshot(ctx, step.name, label=f"After {step.name}")
266
266
 
267
+ tab_info = get_tab_information(ctx)
268
+ total_tabs = tab_info["window_count"]
269
+ current_tab = tab_info["current_index"] + 1
270
+ title = tab_info["current_title"]
271
+ url = tab_info["current_url"]
272
+ log_message = (
273
+ f"\ntab({current_tab} of {total_tabs}): {title}\nurl: {url}\n"
274
+ )
275
+ logger.debug(log_message)
276
+
277
+ # Add tab info to step.stdout so it shows up in the HTML report
278
+ step.stdout += (
279
+ f"\ntab({current_tab} of {total_tabs}): {title}\nurl: {url}\n"
280
+ )
281
+
267
282
  # if the step has substeps from using `run_steps` then we already moved
268
283
  # the step index in the run_steps method and shouldn't do it here
269
284
  if not step.has_substeps:
@@ -105,6 +105,15 @@ and_keyword_indented_correctly:
105
105
  match: '^\s*'
106
106
  replace: ' '
107
107
 
108
+ section_step_indented_correctly:
109
+ message: "section step (* #...) should be indented with 8 spaces"
110
+ type: warning
111
+ current_line:
112
+ match: '^(\s{0,7}|\s{9,})\* .*'
113
+ fix:
114
+ match: '^\s*'
115
+ replace: ' '
116
+
108
117
  line_with_extraneous_whitespace:
109
118
  message: line has extraneous whitespace at the end
110
119
  type: warning
@@ -199,8 +199,13 @@ def generate(results, basepath, only_failures=False):
199
199
  image_dir = get_step_image_dir(step_index, step["name"])
200
200
  image_dirpath = os.path.join(scenario_filepath, image_dir)
201
201
 
202
+ # Handle section headings with different levels (# to ####)
202
203
  if step["name"].startswith("#"):
203
- step["heading_level"] = "h4"
204
+ # Map the count to the appropriate HTML heading (h2-h5)
205
+ # We use h2-h5 instead of h1-h4 so h1 can be reserved for scenario/feature titles
206
+ step["heading_level"] = (
207
+ f"h{step["name"][:4].count("#") + 1}"
208
+ )
204
209
 
205
210
  if os.path.exists(image_dirpath):
206
211
  _, _, image_names = next(os.walk(image_dirpath))
@@ -51,6 +51,41 @@
51
51
  display: inline;
52
52
  color: gray;
53
53
  }
54
+
55
+ /* Section heading styles */
56
+ h2[style*="display: contents;"] {
57
+ font-size: 1.5em;
58
+ font-weight: bold;
59
+ color: #333;
60
+ border-bottom: 1px solid #ccc;
61
+ margin-top: 10px;
62
+ margin-bottom: 10px;
63
+ }
64
+
65
+ h3[style*="display: contents;"] {
66
+ font-size: 1.3em;
67
+ font-weight: bold;
68
+ color: #444;
69
+ margin-top: 8px;
70
+ margin-bottom: 8px;
71
+ }
72
+
73
+ h4[style*="display: contents;"] {
74
+ font-size: 1.1em;
75
+ font-weight: bold;
76
+ color: #555;
77
+ margin-top: 6px;
78
+ margin-bottom: 6px;
79
+ }
80
+
81
+ h5[style*="display: contents;"] {
82
+ font-size: 1em;
83
+ font-style: italic;
84
+ font-weight: bold;
85
+ color: #666;
86
+ margin-top: 4px;
87
+ margin-bottom: 4px;
88
+ }
54
89
  </style>
55
90
  <script>
56
91
  function setupReportTables(defaultOrder, columns) {
@@ -2,7 +2,7 @@
2
2
  # nopycln: file
3
3
  import cucu.hooks
4
4
 
5
- import cucu.steps.comment_steps
5
+ import cucu.steps.section_steps
6
6
  import cucu.steps.base_steps
7
7
 
8
8
  import cucu.steps.browser_steps
@@ -0,0 +1,25 @@
1
+ from behave import use_step_matcher
2
+
3
+ from cucu import step
4
+
5
+ use_step_matcher("re") # use regex to match section heading patterns
6
+
7
+
8
+ @step("(#{1,4})\\s*(.*)")
9
+ def section_step(ctx, heading_level, section_text):
10
+ """
11
+ A section heading step that organizes scenarios into logical sections.
12
+
13
+ Usage:
14
+ * # Main section
15
+ * ## Subsection
16
+ * ### Sub-subsection
17
+ * #### Deep subsection
18
+
19
+ The number of # characters determines the heading level (1-4).
20
+ This step is a no-op but provides structure in the HTML report.
21
+ """
22
+ pass
23
+
24
+
25
+ use_step_matcher("parse") # set this back to cucu's default matcher parser
@@ -271,3 +271,16 @@ def take_screenshot(ctx, step_name, label="", element=None):
271
271
  shutil.copyfile(filepath, CONFIG["CUCU_MONITOR_PNG"])
272
272
 
273
273
  CONFIG["__STEP_SCREENSHOT_COUNT"] += 1
274
+
275
+
276
+ def get_tab_information(ctx):
277
+ driver = ctx.browser.driver
278
+ window_handles = driver.window_handles
279
+ current_window = driver.current_window_handle
280
+ window_handle_index = window_handles.index(current_window)
281
+ return {
282
+ "window_count": len(window_handles),
283
+ "current_index": window_handle_index,
284
+ "current_title": driver.title,
285
+ "current_url": driver.current_url,
286
+ }
@@ -1,17 +0,0 @@
1
- from behave import use_step_matcher
2
-
3
- from cucu import step
4
-
5
- use_step_matcher("re") # use regex to match comments
6
-
7
-
8
- @step("#.*")
9
- def comment_step(ctx):
10
- """
11
- A no-op step so that we can see "comments" in results and report.
12
- Usage: add `* #` to the line you want to show up.
13
- """
14
- pass
15
-
16
-
17
- use_step_matcher("parse") # set this back to cucu's default matcher parser
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes