cucu 1.0.2__tar.gz → 1.0.7__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 (255) hide show
  1. {cucu-1.0.2 → cucu-1.0.7}/.circleci/config.yml +11 -4
  2. {cucu-1.0.2 → cucu-1.0.7}/.github/workflows/build.yml +1 -1
  3. {cucu-1.0.2 → cucu-1.0.7}/CHANGELOG.md +51 -31
  4. {cucu-1.0.2 → cucu-1.0.7}/PKG-INFO +4 -4
  5. cucu-1.0.7/data/www/drag_drop.html +89 -0
  6. {cucu-1.0.2 → cucu-1.0.7}/features/browser/file_upload.feature +6 -0
  7. {cucu-1.0.2 → cucu-1.0.7}/features/cli/report_basics.feature +1 -1
  8. {cucu-1.0.2 → cucu-1.0.7}/pyproject.toml +3 -3
  9. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/cli/core.py +42 -11
  10. cucu-1.0.7/src/cucu/steps/file_input_steps.py +184 -0
  11. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/webserver_steps.py +5 -1
  12. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/utils.py +4 -0
  13. {cucu-1.0.2 → cucu-1.0.7}/uv.lock +73 -66
  14. cucu-1.0.2/src/cucu/steps/file_input_steps.py +0 -80
  15. {cucu-1.0.2 → cucu-1.0.7}/.env +0 -0
  16. {cucu-1.0.2 → cucu-1.0.7}/.github/CODEOWNERS +0 -0
  17. {cucu-1.0.2 → cucu-1.0.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  18. {cucu-1.0.2 → cucu-1.0.7}/.github/workflows/create_a_new_release.yml +0 -0
  19. {cucu-1.0.2 → cucu-1.0.7}/.github/workflows/publish-production.yml +0 -0
  20. {cucu-1.0.2 → cucu-1.0.7}/.github/workflows/publish-test.yml +0 -0
  21. {cucu-1.0.2 → cucu-1.0.7}/.gitignore +0 -0
  22. {cucu-1.0.2 → cucu-1.0.7}/.pre-commit-config.yaml +0 -0
  23. {cucu-1.0.2 → cucu-1.0.7}/.python-version +0 -0
  24. {cucu-1.0.2 → cucu-1.0.7}/CODE_OF_CONDUCT.md +0 -0
  25. {cucu-1.0.2 → cucu-1.0.7}/CONTRIBUTING.md +0 -0
  26. {cucu-1.0.2 → cucu-1.0.7}/CONTRIBUTORS.md +0 -0
  27. {cucu-1.0.2 → cucu-1.0.7}/LICENSE +0 -0
  28. {cucu-1.0.2 → cucu-1.0.7}/Makefile +0 -0
  29. {cucu-1.0.2 → cucu-1.0.7}/README.md +0 -0
  30. {cucu-1.0.2 → cucu-1.0.7}/bin/cucu +0 -0
  31. {cucu-1.0.2 → cucu-1.0.7}/bin/start_seleniarm_hub.sh +0 -0
  32. {cucu-1.0.2 → cucu-1.0.7}/bin/start_selenium_hub.sh +0 -0
  33. {cucu-1.0.2 → cucu-1.0.7}/cortex.yaml +0 -0
  34. {cucu-1.0.2 → cucu-1.0.7}/data/features/custom_step_test/custom_step.feature +0 -0
  35. {cucu-1.0.2 → cucu-1.0.7}/data/features/custom_step_test/steps/__init__.py +0 -0
  36. {cucu-1.0.2 → cucu-1.0.7}/data/features/custom_step_test/steps/cucu_steps.py +0 -0
  37. {cucu-1.0.2 → cucu-1.0.7}/data/features/echo.feature +0 -0
  38. {cucu-1.0.2 → cucu-1.0.7}/data/features/environment.py +0 -0
  39. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_skipping_scenarios_by_file_presence.feature +0 -0
  40. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_background.feature +0 -0
  41. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_background_using_substeps.feature +0 -0
  42. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_failing_scenario.feature +0 -0
  43. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_failing_scenario_with_table.feature +0 -0
  44. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_failing_scenario_with_web.feature +0 -0
  45. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_logging.feature +0 -0
  46. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_long_names.feature +0 -0
  47. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_mixed_results.feature +0 -0
  48. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_multilines_and_tables.feature +0 -0
  49. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_passing_scenario.feature +0 -0
  50. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_passing_scenario_with_web.feature +0 -0
  51. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_platform_specific_scenarios.feature +0 -0
  52. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_scenario_outline.feature +0 -0
  53. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_scenario_using_nth_type.feature +0 -0
  54. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_tagging.feature +0 -0
  55. {cucu-1.0.2 → cucu-1.0.7}/data/features/feature_with_xml_tags.feature +0 -0
  56. {cucu-1.0.2 → cucu-1.0.7}/data/features/multiple_scenarios_with_browser_steps.feature +0 -0
  57. {cucu-1.0.2 → cucu-1.0.7}/data/features/scenario_stop_retry_early.feature +0 -0
  58. {cucu-1.0.2 → cucu-1.0.7}/data/features/scenario_that_fails_with_after_scenario_steps.feature +0 -0
  59. {cucu-1.0.2 → cucu-1.0.7}/data/features/scenario_that_passes_with_after_scenario_steps.feature +0 -0
  60. {cucu-1.0.2 → cucu-1.0.7}/data/features/scenario_with_console_logs.feature +0 -0
  61. {cucu-1.0.2 → cucu-1.0.7}/data/features/scenario_with_substeps.feature +0 -0
  62. {cucu-1.0.2 → cucu-1.0.7}/data/features/scenario_with_substeps_and_logging.feature +0 -0
  63. {cucu-1.0.2 → cucu-1.0.7}/data/features/slow_features/slow_feature1.feature +0 -0
  64. {cucu-1.0.2 → cucu-1.0.7}/data/features/slow_features/slow_feature2.feature +0 -0
  65. {cucu-1.0.2 → cucu-1.0.7}/data/features/slow_features/slow_feature3.feature +0 -0
  66. {cucu-1.0.2 → cucu-1.0.7}/data/features/slow_features/slow_feature4.feature +0 -0
  67. {cucu-1.0.2 → cucu-1.0.7}/data/features/slow_features/slow_feature5.feature +0 -0
  68. {cucu-1.0.2 → cucu-1.0.7}/data/features/steps/__init__.py +0 -0
  69. {cucu-1.0.2 → cucu-1.0.7}/data/features/steps/cucu_steps.py +0 -0
  70. {cucu-1.0.2 → cucu-1.0.7}/data/features/tagged_features/tagged_feature1.feature +0 -0
  71. {cucu-1.0.2 → cucu-1.0.7}/data/features/tagged_features/tagged_feature2.feature +0 -0
  72. {cucu-1.0.2 → cucu-1.0.7}/data/features/tagged_features/tagged_feature3.feature +0 -0
  73. {cucu-1.0.2 → cucu-1.0.7}/data/features/with_secret/cucurc.yml +0 -0
  74. {cucu-1.0.2 → cucu-1.0.7}/data/features/with_secret/scenario_with_comments.feature +0 -0
  75. {cucu-1.0.2 → cucu-1.0.7}/data/unit/ansi.log +0 -0
  76. {cucu-1.0.2 → cucu-1.0.7}/data/unit/ansi.log.html +0 -0
  77. {cucu-1.0.2 → cucu-1.0.7}/data/www/broken_images.html +0 -0
  78. {cucu-1.0.2 → cucu-1.0.7}/data/www/buttons.html +0 -0
  79. {cucu-1.0.2 → cucu-1.0.7}/data/www/checkboxes.html +0 -0
  80. {cucu-1.0.2 → cucu-1.0.7}/data/www/clipboard.html +0 -0
  81. {cucu-1.0.2 → cucu-1.0.7}/data/www/comboboxes.html +0 -0
  82. {cucu-1.0.2 → cucu-1.0.7}/data/www/console_logging.html +0 -0
  83. {cucu-1.0.2 → cucu-1.0.7}/data/www/cookies.html +0 -0
  84. {cucu-1.0.2 → cucu-1.0.7}/data/www/counter.html +0 -0
  85. {cucu-1.0.2 → cucu-1.0.7}/data/www/draggables.html +0 -0
  86. {cucu-1.0.2 → cucu-1.0.7}/data/www/dropdowns.html +0 -0
  87. {cucu-1.0.2 → cucu-1.0.7}/data/www/duplicate_buttons.html +0 -0
  88. {cucu-1.0.2 → cucu-1.0.7}/data/www/duplicate_inputs.html +0 -0
  89. {cucu-1.0.2 → cucu-1.0.7}/data/www/dynamic_dropdown.html +0 -0
  90. {cucu-1.0.2 → cucu-1.0.7}/data/www/file.txt +0 -0
  91. {cucu-1.0.2 → cucu-1.0.7}/data/www/files.html +0 -0
  92. {cucu-1.0.2 → cucu-1.0.7}/data/www/frames.html +0 -0
  93. {cucu-1.0.2 → cucu-1.0.7}/data/www/fuzzy_rules.html +0 -0
  94. {cucu-1.0.2 → cucu-1.0.7}/data/www/images.html +0 -0
  95. {cucu-1.0.2 → cucu-1.0.7}/data/www/inputs.html +0 -0
  96. {cucu-1.0.2 → cucu-1.0.7}/data/www/js/util.js +0 -0
  97. {cucu-1.0.2 → cucu-1.0.7}/data/www/links.html +0 -0
  98. {cucu-1.0.2 → cucu-1.0.7}/data/www/nothing_to_see_here.html +0 -0
  99. {cucu-1.0.2 → cucu-1.0.7}/data/www/page_that_loads_forever.html +0 -0
  100. {cucu-1.0.2 → cucu-1.0.7}/data/www/radio_buttons.html +0 -0
  101. {cucu-1.0.2 → cucu-1.0.7}/data/www/stars.png +0 -0
  102. {cucu-1.0.2 → cucu-1.0.7}/data/www/tables.html +0 -0
  103. {cucu-1.0.2 → cucu-1.0.7}/data/www/tabs.html +0 -0
  104. {cucu-1.0.2 → cucu-1.0.7}/data/www/text.html +0 -0
  105. {cucu-1.0.2 → cucu-1.0.7}/features/browser/browser_tab_managemenet.feature +0 -0
  106. {cucu-1.0.2 → cucu-1.0.7}/features/browser/browser_window_managemenet.feature +0 -0
  107. {cucu-1.0.2 → cucu-1.0.7}/features/browser/buttons.feature +0 -0
  108. {cucu-1.0.2 → cucu-1.0.7}/features/browser/checkboxes.feature +0 -0
  109. {cucu-1.0.2 → cucu-1.0.7}/features/browser/clipboard.feature +0 -0
  110. {cucu-1.0.2 → cucu-1.0.7}/features/browser/comboboxes.feature +0 -0
  111. {cucu-1.0.2 → cucu-1.0.7}/features/browser/console_logs.feature +0 -0
  112. {cucu-1.0.2 → cucu-1.0.7}/features/browser/cookies.feature +0 -0
  113. {cucu-1.0.2 → cucu-1.0.7}/features/browser/draggables.feature +0 -0
  114. {cucu-1.0.2 → cucu-1.0.7}/features/browser/dropdowns.feature +0 -0
  115. {cucu-1.0.2 → cucu-1.0.7}/features/browser/duplicate_buttons.feature +0 -0
  116. {cucu-1.0.2 → cucu-1.0.7}/features/browser/duplicate_draggables.feature +0 -0
  117. {cucu-1.0.2 → cucu-1.0.7}/features/browser/duplicate_inputs.feature +0 -0
  118. {cucu-1.0.2 → cucu-1.0.7}/features/browser/file_downloads.feature +0 -0
  119. {cucu-1.0.2 → cucu-1.0.7}/features/browser/frames.feature +0 -0
  120. {cucu-1.0.2 → cucu-1.0.7}/features/browser/fuzzy_rules.feature +0 -0
  121. {cucu-1.0.2 → cucu-1.0.7}/features/browser/helpers.feature +0 -0
  122. {cucu-1.0.2 → cucu-1.0.7}/features/browser/images.feature +0 -0
  123. {cucu-1.0.2 → cucu-1.0.7}/features/browser/inputs.feature +0 -0
  124. {cucu-1.0.2 → cucu-1.0.7}/features/browser/inputs_limits.feature +0 -0
  125. {cucu-1.0.2 → cucu-1.0.7}/features/browser/links.feature +0 -0
  126. {cucu-1.0.2 → cucu-1.0.7}/features/browser/mht.feature +0 -0
  127. {cucu-1.0.2 → cucu-1.0.7}/features/browser/page_checks.feature +0 -0
  128. {cucu-1.0.2 → cucu-1.0.7}/features/browser/radio_buttons.feature +0 -0
  129. {cucu-1.0.2 → cucu-1.0.7}/features/browser/tables.feature +0 -0
  130. {cucu-1.0.2 → cucu-1.0.7}/features/browser/tabs.feature +0 -0
  131. {cucu-1.0.2 → cucu-1.0.7}/features/browser/text.feature +0 -0
  132. {cucu-1.0.2 → cucu-1.0.7}/features/cli/config.feature +0 -0
  133. {cucu-1.0.2 → cucu-1.0.7}/features/cli/help.feature +0 -0
  134. {cucu-1.0.2 → cucu-1.0.7}/features/cli/internals.feature +0 -0
  135. {cucu-1.0.2 → cucu-1.0.7}/features/cli/ipdb.feature +0 -0
  136. {cucu-1.0.2 → cucu-1.0.7}/features/cli/lint.feature +0 -0
  137. {cucu-1.0.2 → cucu-1.0.7}/features/cli/lsp.feature +0 -0
  138. {cucu-1.0.2 → cucu-1.0.7}/features/cli/report_search_and_sorting.feature +0 -0
  139. {cucu-1.0.2 → cucu-1.0.7}/features/cli/report_with_custom_failure_handler.feature +0 -0
  140. {cucu-1.0.2 → cucu-1.0.7}/features/cli/report_with_custom_subheader.feature +0 -0
  141. {cucu-1.0.2 → cucu-1.0.7}/features/cli/report_with_custom_tags.feature +0 -0
  142. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run.feature +0 -0
  143. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_outputs.feature +0 -0
  144. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_hooks.feature +0 -0
  145. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_junit.feature +0 -0
  146. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_logging.feature +0 -0
  147. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_report.feature +0 -0
  148. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_tags.feature +0 -0
  149. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_thread_dumper.feature +0 -0
  150. {cucu-1.0.2 → cucu-1.0.7}/features/cli/run_with_workers.feature +0 -0
  151. {cucu-1.0.2 → cucu-1.0.7}/features/cli/secrets.feature +0 -0
  152. {cucu-1.0.2 → cucu-1.0.7}/features/cli/steps.feature +0 -0
  153. {cucu-1.0.2 → cucu-1.0.7}/features/cli/vars.feature +0 -0
  154. {cucu-1.0.2 → cucu-1.0.7}/features/environment.py +0 -0
  155. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/before_retry_handlers.feature +0 -0
  156. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/repeating_steps.feature +0 -0
  157. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/run_after_scenario_steps.feature +0 -0
  158. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/run_and_measure.feature +0 -0
  159. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/run_other_features.feature +0 -0
  160. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/run_scenarios_conditionally.feature +0 -0
  161. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/run_steps_conditionally.feature +0 -0
  162. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/run_steps_on_element_visibilty.feature +0 -0
  163. {cucu-1.0.2 → cucu-1.0.7}/features/flow_control/wait_for_steps.feature +0 -0
  164. {cucu-1.0.2 → cucu-1.0.7}/features/os/command_steps.feature +0 -0
  165. {cucu-1.0.2 → cucu-1.0.7}/features/os/file_steps.feature +0 -0
  166. {cucu-1.0.2 → cucu-1.0.7}/features/os/platform_steps.feature +0 -0
  167. {cucu-1.0.2 → cucu-1.0.7}/features/os/screenshot.feature +0 -0
  168. {cucu-1.0.2 → cucu-1.0.7}/features/os/variables.feature +0 -0
  169. {cucu-1.0.2 → cucu-1.0.7}/features/steps/__init__.py +0 -0
  170. {cucu-1.0.2 → cucu-1.0.7}/features/steps/cucu_steps.py +0 -0
  171. {cucu-1.0.2 → cucu-1.0.7}/logo.png +0 -0
  172. {cucu-1.0.2 → cucu-1.0.7}/renovate.json +0 -0
  173. {cucu-1.0.2 → cucu-1.0.7}/sonar-project.properties +0 -0
  174. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/__init__.py +0 -0
  175. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/ansi_parser.py +0 -0
  176. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/behave_tweaks.py +0 -0
  177. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/browser/__init__.py +0 -0
  178. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/browser/core.py +0 -0
  179. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/browser/frames.py +0 -0
  180. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/browser/selenium.py +0 -0
  181. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/browser/selenium_tweaks.py +0 -0
  182. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/cli/__init__.py +0 -0
  183. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/cli/run.py +0 -0
  184. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/cli/steps.py +0 -0
  185. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/cli/thread_dumper.py +0 -0
  186. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/config.py +0 -0
  187. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/edgedriver_autoinstaller/README.md +0 -0
  188. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/edgedriver_autoinstaller/__init__.py +0 -0
  189. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/edgedriver_autoinstaller/utils.py +0 -0
  190. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/environment.py +0 -0
  191. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/external/jquery/jquery-3.5.1.min.js +0 -0
  192. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/formatter/__init__.py +0 -0
  193. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/formatter/cucu.py +0 -0
  194. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/formatter/json.py +0 -0
  195. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/formatter/junit.py +0 -0
  196. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/fuzzy/__init__.py +0 -0
  197. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/fuzzy/core.py +0 -0
  198. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/fuzzy/fuzzy.js +0 -0
  199. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/helpers.py +0 -0
  200. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/hooks.py +0 -0
  201. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/language_server/__init__.py +0 -0
  202. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/language_server/core.py +0 -0
  203. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/lint/__init__.py +0 -0
  204. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/lint/linter.py +0 -0
  205. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/lint/rules/format.yaml +0 -0
  206. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/logger.py +0 -0
  207. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/matcher/__init__.py +0 -0
  208. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/matcher/core.py +0 -0
  209. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/page_checks.py +0 -0
  210. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/__init__.py +0 -0
  211. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/bootstrap.min.css +0 -0
  212. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/bootstrap.min.js +0 -0
  213. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/dataTables.bootstrap.min.css +0 -0
  214. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/dataTables.bootstrap.min.js +0 -0
  215. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/jquery-3.5.1.min.js +0 -0
  216. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/jquery.dataTables.min.js +0 -0
  217. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/external/popper.min.js +0 -0
  218. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/favicon.png +0 -0
  219. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/html.py +0 -0
  220. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/templates/feature.html +0 -0
  221. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/templates/flat.html +0 -0
  222. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/templates/index.html +0 -0
  223. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/templates/layout.html +0 -0
  224. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/reporter/templates/scenario.html +0 -0
  225. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/__init__.py +0 -0
  226. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/base_steps.py +0 -0
  227. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/browser_steps.py +0 -0
  228. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/button_steps.py +0 -0
  229. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/checkbox_steps.py +0 -0
  230. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/command_steps.py +0 -0
  231. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/comment_steps.py +0 -0
  232. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/draggable_steps.py +0 -0
  233. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/dropdown_steps.py +0 -0
  234. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/filesystem_steps.py +0 -0
  235. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/flow_control_steps.py +0 -0
  236. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/image_steps.py +0 -0
  237. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/input_steps.py +0 -0
  238. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/link_steps.py +0 -0
  239. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/menuitem_steps.py +0 -0
  240. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/platform_steps.py +0 -0
  241. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/radio_steps.py +0 -0
  242. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/step_utils.py +0 -0
  243. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/tab_steps.py +0 -0
  244. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/table_steps.py +0 -0
  245. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/tables.js +0 -0
  246. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/text_steps.py +0 -0
  247. {cucu-1.0.2 → cucu-1.0.7}/src/cucu/steps/variable_steps.py +0 -0
  248. {cucu-1.0.2 → cucu-1.0.7}/tests/__init__.py +0 -0
  249. {cucu-1.0.2 → cucu-1.0.7}/tests/test_behave_tweaks.py +0 -0
  250. {cucu-1.0.2 → cucu-1.0.7}/tests/test_browser.py +0 -0
  251. {cucu-1.0.2 → cucu-1.0.7}/tests/test_config.py +0 -0
  252. {cucu-1.0.2 → cucu-1.0.7}/tests/test_core.py +0 -0
  253. {cucu-1.0.2 → cucu-1.0.7}/tests/test_language_server.py +0 -0
  254. {cucu-1.0.2 → cucu-1.0.7}/tests/test_reporter_parser.py +0 -0
  255. {cucu-1.0.2 → cucu-1.0.7}/tests/test_table_steps.py +0 -0
@@ -51,9 +51,14 @@ jobs:
51
51
  default: "chrome"
52
52
  docker:
53
53
  - image: cimg/python:3.12
54
- - image: selenium/standalone-<<parameters.browser>>:124.0
55
54
  environment:
55
+ # Starting with python 3.12 coverage could be 2x slower so use experimental COVERAGE_CORE=sysmon
56
+ COVERAGE_CORE: sysmon
57
+ - image: selenium/standalone-<<parameters.browser>>:125.0
58
+ environment:
59
+ SE_ENABLE_TRACING: false
56
60
  SE_NODE_MAX_SESSIONS: 12
61
+ SE_NODE_OVERRIDE_MAX_SESSIONS: true
57
62
  SE_NODE_SESSION_TIMEOUT: 300
58
63
  SCREEN_WIDTH: 1366
59
64
  SCREEN_HEIGHT: 768
@@ -77,7 +82,7 @@ jobs:
77
82
  command: curl --retry 60 --retry-delay 5 --retry-connrefused http://localhost:4444
78
83
  - run:
79
84
  name: run_functional_tests
80
- command: uv run cucu run features --workers 6 --selenium-remote-url http://localhost:4444 --generate-report --junit junit_results --browser "<<parameters.browser>>"
85
+ command: uv run cucu run features --workers 8 --selenium-remote-url http://localhost:4444 --generate-report --junit junit_results --browser "<<parameters.browser>>"
81
86
  environment:
82
87
  COVERAGE_PROCESS_START: pyproject.toml # set to config file
83
88
  - run:
@@ -125,12 +130,14 @@ orbs:
125
130
  - run:
126
131
  name: Install uv
127
132
  command: |
133
+ echo 'export UV_INSTALL_DIR=$HOME/.uv' >> $BASH_ENV
134
+ source $BASH_ENV
128
135
  curl -LsSf https://astral.sh/uv/install.sh | sh
129
- echo 'source $HOME/.cargo/env' >> $BASH_ENV
136
+ echo 'source $UV_INSTALL_DIR/env' >> $BASH_ENV
130
137
  source $BASH_ENV
131
138
  - save_cache:
132
139
  paths:
133
- - $HOME/.cargo/env
140
+ - $UV_INSTALL_DIR/env
134
141
  key: v1-uv-cache-{{ checksum "uv.lock" }}
135
142
  - run:
136
143
  name: Verify uv installation
@@ -70,7 +70,7 @@ jobs:
70
70
  pull-requests: write
71
71
  services:
72
72
  webserver:
73
- image: selenium/standalone-${{ matrix.browser }}:124.0
73
+ image: selenium/standalone-${{ matrix.browser }}:125.0
74
74
  ports:
75
75
  - 4444:4444
76
76
  options: --shm-size=4gb
@@ -5,62 +5,82 @@ 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.0.7
9
+ - Fix - stablize CI runs (increase workers, add envvar tweaks)
10
+ - Fix - parse --workers correctly
11
+ - Fix - Ctrl-C to terminate for multi-workers
12
+ - Fix - ensure testing webserver is online
13
+ - Change - use fork when not MacOS for multi-worker
14
+ - Chore - bump jellyfish to 1.1.3
15
+
16
+ ## 1.0.6
17
+ - Chore - relax required versions for requests library
18
+
19
+ ## 1.0.5
20
+ - Fix - Resolved issues with the drag-and-drop feature to ensure compatibility with all input options.
21
+
22
+ ## 1.0.4
23
+ - Change - for retry steps, also log before and after call messages
24
+
25
+ ## 1.0.3
26
+ - Add - functional test for drag and drop file functionality
27
+
8
28
  ## 1.0.2
9
- - chore - fix logo for pypi
29
+ - Chore - fix logo for pypi
10
30
 
11
31
  ## 1.0.1
12
- - chore - fix pyproject.toml authors and urls
13
- - change - add pre-commit to makefile
32
+ - Chore - fix pyproject.toml authors and urls
33
+ - Change - add pre-commit to makefile
14
34
 
15
35
  ## 1.0.0
16
- - change to 1.0.0!
17
- - chore - fix GH workflow for test publish
36
+ - Change to 1.0.0!
37
+ - Chore - fix GH workflow for test publish
18
38
 
19
39
  ## 0.207.0
20
- - chore - prep for publish - p2
21
- - replace poetry with uv
22
- - set default local python to 3.12
23
- - run pre-commit with uv
24
- - fix isort with ruff
40
+ - Chore - prep for publish - p2
41
+ - Replace poetry with uv
42
+ - Set default local python to 3.12
43
+ - Run pre-commit with uv
44
+ - Fix isort with ruff
25
45
 
26
46
  ## 0.206.0
27
- - chore - prep for publish
28
- - replace black with ruff
29
- - remove detect-secrets to be replaced by GH repo security
30
- - remove bandit to be replaced by GH CodeQL
31
- - cleanup makefile
47
+ - Chore - prep for publish
48
+ - Replace black with ruff
49
+ - Remove detect-secrets to be replaced by GH repo security
50
+ - Remove bandit to be replaced by GH CodeQL
51
+ - Cleanup makefile
32
52
 
33
53
  ## 0.205.0
34
- - change - increase information logged for failing before_scenario_hooks
54
+ - Change - increase information logged for failing before_scenario_hooks
35
55
 
36
56
  ## 0.204.0
37
- - chore - add gh workflows for publishing
38
- - chore - fix project metadata
57
+ - Chore - add gh workflows for publishing
58
+ - Chore - fix project metadata
39
59
 
40
60
  ## 0.203.0
41
- - chore - move repo GH org locations
42
- - chore - remove sonarqube
61
+ - Chore - move repo GH org locations
62
+ - Chore - remove sonarqube
43
63
 
44
64
  ## 0.202.0
45
- - add - wait step to saving values from any table cells to a variable
65
+ - Add - wait step to saving values from any table cells to a variable
46
66
 
47
67
  ## 0.201.0
48
- - change - add report path to the JUnit files when available
68
+ - Change - add report path to the JUnit files when available
49
69
 
50
70
  ## 0.200.0
51
- - change - increase the log level of scheduling a feature file
71
+ - Change - increase the log level of scheduling a feature file
52
72
 
53
73
  ## 0.199.0
54
- - chore - remove deprecated CI
55
- - chore - add PR template
74
+ - Chore - remove deprecated CI
75
+ - Chore - add PR template
56
76
 
57
77
  ## 0.198.0
58
- - chore - add sonarqube
59
- - chore - refactor circle config (config-drive executor, embed commands, move workflows up)
60
- - chore - configure renovate
61
- - chore - remove dependabot config (duplicates renovate)
62
- - chore - remove safety (duplicates sonarqube)
63
- - change - swap pebble for mpire, kill procs on run timeout
78
+ - Chore - add sonarqube
79
+ - Chore - refactor circle config (config-drive executor, embed commands, move workflows up)
80
+ - Chore - configure renovate
81
+ - Chore - remove dependabot config (duplicates renovate)
82
+ - Chore - remove safety (duplicates sonarqube)
83
+ - Change - swap pebble for mpire, kill procs on run timeout
64
84
 
65
85
  ## 0.197.0
66
86
  - Fix - before all hooks are now executed
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: cucu
3
- Version: 1.0.2
3
+ Version: 1.0.7
4
4
  Summary: Easy BDD web testing
5
5
  Project-URL: Homepage, https://github.com/dominodatalab/cucu
6
6
  Project-URL: Download, https://pypi.org/project/cucu/
@@ -34,14 +34,14 @@ Requires-Dist: geckodriver-autoinstaller~=0.1.0
34
34
  Requires-Dist: humanize~=4.8.0
35
35
  Requires-Dist: importlib-metadata~=8.0.0
36
36
  Requires-Dist: ipdb~=0.13.13
37
- Requires-Dist: jellyfish~=1.0.1
37
+ Requires-Dist: jellyfish~=1.1.3
38
38
  Requires-Dist: jinja2~=3.1.3
39
39
  Requires-Dist: lsprotocol~=2023.0.1
40
40
  Requires-Dist: mpire~=2.10.2
41
41
  Requires-Dist: psutil~=6.0.0
42
42
  Requires-Dist: pygls~=1.3.1
43
43
  Requires-Dist: pyyaml~=6.0.1
44
- Requires-Dist: requests~=2.31.0
44
+ Requires-Dist: requests<3.0.0,>=2.31.0
45
45
  Requires-Dist: selenium~=4.15
46
46
  Requires-Dist: tabulate~=0.9.0
47
47
  Requires-Dist: tenacity~=9.0.0
@@ -0,0 +1,89 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Drag and Drop File Upload Test with Validation</title>
7
+ <style>
8
+ #drop-zone {
9
+ width: 500px;
10
+ height: 100px;
11
+ border: 2px dashed #0088cc;
12
+ display: flex;
13
+ justify-content: center;
14
+ align-items: center;
15
+ margin: 20px auto;
16
+ font-family: Arial, sans-serif;
17
+ color: #0088cc;
18
+ background-color: #f9f9f9;
19
+ }
20
+ #drop-zone.hover {
21
+ background-color: #f0f0f0;
22
+ }
23
+ #message {
24
+ text-align: center;
25
+ margin-top: 20px;
26
+ font-family: Arial, sans-serif;
27
+ color: #ff0000;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body>
32
+
33
+ <h2>Drag and Drop File Upload Test</h2>
34
+
35
+ <!-- Drag and Drop Zone -->
36
+ <div id="drop-zone">
37
+ Click or drag file to this area to upload
38
+ </div>
39
+
40
+ <input type="file" id="myFile" style="display: none;">
41
+
42
+ <!-- Validation Message Area -->
43
+ <div id="message"></div>
44
+
45
+ <script>
46
+ const dropZone = document.getElementById('drop-zone');
47
+ const fileInput = document.getElementById('myFile');
48
+ const messageDiv = document.getElementById('message');
49
+
50
+ // Function to display validation messages
51
+ function showMessage(message, isError = false) {
52
+ messageDiv.textContent = message;
53
+ messageDiv.style.color = isError ? '#ff0000' : '#008000'; // Red for errors, green for success
54
+ }
55
+
56
+ // Trigger file input click when the drop zone is clicked
57
+ dropZone.addEventListener('click', function() {
58
+ fileInput.click();
59
+ });
60
+
61
+ // Handle drag over
62
+ dropZone.addEventListener('dragover', function(e) {
63
+ e.preventDefault();
64
+ dropZone.classList.add('hover');
65
+ });
66
+
67
+ // Handle drag leave
68
+ dropZone.addEventListener('dragleave', function() {
69
+ dropZone.classList.remove('hover');
70
+ });
71
+
72
+ // Handle file drop
73
+ dropZone.addEventListener('drop', function(e) {
74
+ e.preventDefault();
75
+ dropZone.classList.remove('hover');
76
+ const files = e.dataTransfer.files;
77
+
78
+ if (files.length > 0) {
79
+ showMessage(`File dropped: ${files[0].name}`, false);
80
+ fileInput.files = files;
81
+ }
82
+ else {
83
+ showMessage('No file was dropped.', true);
84
+ }
85
+ });
86
+ </script>
87
+
88
+ </body>
89
+ </html>
@@ -9,3 +9,9 @@ Feature: File upload
9
9
  And I click the button "upload!"
10
10
  And I save the current url to the variable "URL"
11
11
  Then I should see "{URL}" matches ".*\?filename=file_upload.feature"
12
+
13
+ Scenario: User can drag and drop to upload a file
14
+ Given I start a webserver at directory "data/www" and save the port to the variable "PORT"
15
+ And I open a browser at the url "http://{HOST_ADDRESS}:{PORT}/drag_drop.html"
16
+ When I wait to drag and drop the file "features/browser/file_upload.feature" to "Click or drag file to this area to upload"
17
+ Then I wait to see the text "File dropped: file_upload.feature"
@@ -204,7 +204,7 @@ Feature: Report basics
204
204
  @runtime-timeout
205
205
  Scenario: User can run with a runtime timeout and still produce a valid report
206
206
  Given I run the command "cucu run data/features/slow_features --runtime-timeout 9 --results {CUCU_RESULTS_DIR}/runtime_timeout_reporting_results" and expect exit code "1"
207
- Then I should see the previous step took less than "13" seconds
207
+ Then I should see the previous step took less than "14" seconds
208
208
  When I run the command "cucu report {CUCU_RESULTS_DIR}/runtime_timeout_reporting_results --output {CUCU_RESULTS_DIR}/runtime_timeout_reporting_report" and expect exit code "0"
209
209
  And I start a webserver at directory "{CUCU_RESULTS_DIR}/runtime_timeout_reporting_report/" and save the port to the variable "PORT"
210
210
  And I open a browser at the url "http://{HOST_ADDRESS}:{PORT}/index.html"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cucu"
3
- version = "1.0.2"
3
+ version = "1.0.7"
4
4
  description = "Easy BDD web testing"
5
5
  readme = "README.md"
6
6
  license = { text = "The Clear BSD License" }
@@ -51,14 +51,14 @@ dependencies = [
51
51
  "humanize~=4.8.0",
52
52
  "importlib-metadata~=8.0.0",
53
53
  "ipdb~=0.13.13",
54
- "jellyfish~=1.0.1",
54
+ "jellyfish~=1.1.3",
55
55
  "jinja2~=3.1.3",
56
56
  "lsprotocol~=2023.0.1",
57
57
  "mpire~=2.10.2",
58
58
  "psutil~=6.0.0",
59
59
  "pygls~=1.3.1",
60
60
  "pyyaml~=6.0.1",
61
- "requests~=2.31.0",
61
+ "requests>=2.31.0,<3.0.0",
62
62
  "selenium~=4.15",
63
63
  "tabulate~=0.9.0",
64
64
  "tenacity~=9.0.0",
@@ -4,6 +4,7 @@ import json
4
4
  import os
5
5
  import shutil
6
6
  import signal
7
+ import sys
7
8
  import time
8
9
  import xml.etree.ElementTree as ET
9
10
  from importlib.metadata import version
@@ -189,6 +190,7 @@ def main():
189
190
  "--workers",
190
191
  default=None,
191
192
  help="Specifies the number of workers to use to run tests in parallel",
193
+ type=int,
192
194
  )
193
195
  @click.option(
194
196
  "--verbose/--no-verbose",
@@ -338,11 +340,20 @@ def run(
338
340
  if os.path.isdir(filepath):
339
341
  basepath = os.path.join(filepath, "**/*.feature")
340
342
  feature_filepaths = list(glob.iglob(basepath, recursive=True))
341
-
342
343
  else:
343
344
  feature_filepaths = [filepath]
344
345
 
345
- with WorkerPool(n_jobs=int(workers), start_method="spawn") as pool:
346
+ if sys.platform == "darwin":
347
+ logger.info(
348
+ "MAC OS detected, using 'forkserver' start method since 'fork' is unstable"
349
+ )
350
+ start_method = "forkserver"
351
+ else:
352
+ start_method = "fork"
353
+
354
+ with WorkerPool(
355
+ n_jobs=int(workers), start_method=start_method
356
+ ) as pool:
346
357
  # Each feature file is applied to the pool as an async task.
347
358
  # It then polls the async result of each task. It the result
348
359
  # is ready, it removes the result from the list of results that
@@ -364,6 +375,34 @@ def run(
364
375
  timer = Timer(runtime_timeout, runtime_exit)
365
376
  timer.start()
366
377
 
378
+ def kill_workers():
379
+ for worker in pool._workers:
380
+ try:
381
+ worker_proc = psutil.Process(worker.pid)
382
+ for child in worker_proc.children():
383
+ child.kill()
384
+
385
+ worker_proc.kill()
386
+ except psutil.NoSuchProcess:
387
+ pass
388
+
389
+ def handle_kill_signal(signum, frame):
390
+ signal.signal(
391
+ signum, signal.SIG_IGN
392
+ ) # ignore additional signals
393
+ logger.warn(
394
+ f"received signal {signum}, sending kill signal to workers"
395
+ )
396
+ kill_workers()
397
+ if timer:
398
+ timer.cancel()
399
+
400
+ os.kill(os.getpid(), signal.SIGINT)
401
+
402
+ # This is for local runs where you want to cancel the run with a ctrl+c or SIGTERM
403
+ signal.signal(signal.SIGINT, handle_kill_signal)
404
+ signal.signal(signal.SIGTERM, handle_kill_signal)
405
+
367
406
  async_results = {}
368
407
  for feature_filepath in feature_filepaths:
369
408
  async_results[feature_filepath] = pool.apply_async(
@@ -430,15 +469,7 @@ def run(
430
469
 
431
470
  if timeout_reached:
432
471
  logger.warn("Timeout reached, send kill signal to workers")
433
- for worker in pool._workers:
434
- try:
435
- worker_proc = psutil.Process(worker.pid)
436
- for child in worker_proc.children():
437
- child.kill()
438
-
439
- worker_proc.kill()
440
- except psutil.NoSuchProcess:
441
- pass
472
+ kill_workers()
442
473
 
443
474
  task_failed.update(async_results)
444
475
 
@@ -0,0 +1,184 @@
1
+ import os
2
+
3
+ import humanize
4
+
5
+ from cucu import fuzzy, logger, retry, step
6
+ from cucu.utils import take_saw_element_screenshot
7
+
8
+
9
+ def find_file_input(ctx, name, index=0):
10
+ """
11
+
12
+ * <input type="file">
13
+
14
+ parameters:
15
+ ctx(object): behave context object used to share data between steps
16
+ name(str): name that identifies the desired button on screen
17
+ index(str): the index of the button if there are duplicates
18
+
19
+ returns:
20
+ the WebElement that matches the provided arguments.
21
+ """
22
+ ctx.check_browser_initialized()
23
+ element = fuzzy.find(
24
+ ctx.browser, name, ['input[type="file"]'], index=index
25
+ )
26
+
27
+ prefix = "" if index == 0 else f"{humanize.ordinal(index)} "
28
+
29
+ take_saw_element_screenshot(ctx, "file input", name, index, element)
30
+
31
+ if element is None:
32
+ raise RuntimeError(f'unable to find the {prefix}file input "{name}"')
33
+
34
+ return element
35
+
36
+
37
+ @step('I upload the file "{filepath}" to the file input "{name}"')
38
+ def upload_file_to_input(ctx, filepath, name):
39
+ _input = find_file_input(ctx, name)
40
+ _input.send_keys(os.path.abspath(filepath))
41
+
42
+
43
+ JS_DROP_FILE = """
44
+ var args = arguments,
45
+ element = args[0],
46
+ offsetX = args[1],
47
+ offsetY = args[2],
48
+ doc = element.ownerDocument || document;
49
+
50
+ var box = element.getBoundingClientRect(),
51
+ clientX = box.left + (offsetX || box.width / 2),
52
+ clientY = box.top + (offsetY || box.height / 2),
53
+ target = doc.elementFromPoint(clientX, clientY);
54
+ if (!(target && element.contains(target))) {
55
+ element.scrollIntoView({
56
+ behavior: "instant",
57
+ block: "center",
58
+ inline: "center",
59
+ });
60
+ var box = element.getBoundingClientRect(),
61
+ clientX = box.left + (offsetX || box.width / 2),
62
+ clientY = box.top + (offsetY || box.height / 2),
63
+ target = doc.elementFromPoint(clientX, clientY);
64
+
65
+ if (!(target && element.contains(target))) {
66
+ // Scrolling didn't do the trick, so give up
67
+ var ex = new Error("Element not interactable");
68
+ ex.code = 15;
69
+ throw ex;
70
+ }
71
+ }
72
+
73
+ var input = doc.createElement("INPUT");
74
+ input.setAttribute("type", "file");
75
+ input.setAttribute("multiple", "");
76
+ input.setAttribute("style", "position:fixed;z-index:2147483647;left:0;top:0;");
77
+ input.onchange = function (ev) {
78
+ input.parentElement.removeChild(input);
79
+ ev.stopPropagation();
80
+
81
+ var dataTransfer = {
82
+ constructor: DataTransfer,
83
+ effectAllowed: "all",
84
+ dropEffect: "none",
85
+ types: ["Files"],
86
+ files: input.files,
87
+ setData: function setData() {},
88
+ getData: function getData() {},
89
+ clearData: function clearData() {},
90
+ setDragImage: function setDragImage() {},
91
+ };
92
+
93
+ if (window.DataTransferItemList) {
94
+ dataTransfer.items = Object.setPrototypeOf(
95
+ Array.prototype.map.call(input.files, function (f) {
96
+ return {
97
+ constructor: DataTransferItem,
98
+ kind: "file",
99
+ type: f.type,
100
+ getAsFile: function getAsFile() {
101
+ return f;
102
+ },
103
+ getAsString: function getAsString(callback) {
104
+ var reader = new FileReader();
105
+ reader.onload = function (ev) {
106
+ callback(ev.target.result);
107
+ };
108
+ reader.readAsText(f);
109
+ },
110
+ webkitGetAsEntry: function webkitGetAsEntry() {
111
+ return {
112
+ constructor: window.FileSystemEntry || window.Entry,
113
+ name: f.name,
114
+ fullPath: "/" + f.name,
115
+ isFile: true,
116
+ isDirectory: false,
117
+ file: function file(callback) {
118
+ callback(f);
119
+ },
120
+ };
121
+ },
122
+ };
123
+ }),
124
+ {
125
+ constructor: DataTransferItemList,
126
+ add: function add() {},
127
+ clear: function clear() {},
128
+ remove: function remove() {},
129
+ }
130
+ );
131
+ }
132
+
133
+ ["dragenter", "dragover", "drop"].forEach(function (type) {
134
+ var event = doc.createEvent("DragEvent");
135
+ event.initMouseEvent(
136
+ type,
137
+ true,
138
+ true,
139
+ doc.defaultView,
140
+ 0,
141
+ 0,
142
+ 0,
143
+ clientX,
144
+ clientY,
145
+ false,
146
+ false,
147
+ false,
148
+ false,
149
+ 0,
150
+ null
151
+ );
152
+
153
+ Object.setPrototypeOf(event, null);
154
+ event.dataTransfer = dataTransfer;
155
+ Object.setPrototypeOf(event, DragEvent.prototype);
156
+
157
+ target.dispatchEvent(event);
158
+ });
159
+ };
160
+
161
+ doc.documentElement.appendChild(input);
162
+ input.getBoundingClientRect(); /* force reflow for Firefox */
163
+ return input;
164
+ """
165
+
166
+
167
+ def drag_and_drop_file(ctx, name, filepath):
168
+ drop_target = fuzzy.find(ctx.browser, name, ["*"])
169
+ drop_target_html = drop_target.get_attribute("outerHTML")
170
+ logger.debug(
171
+ f'looked for drag & drop target "{name}" and found "{drop_target_html}"'
172
+ )
173
+ file_input = ctx.browser.execute(JS_DROP_FILE, drop_target, 0, 0)
174
+ file_input.send_keys(os.path.abspath(filepath))
175
+
176
+
177
+ @step('I drag and drop the file "{filepath}" to "{name}"')
178
+ def should_drag_and_drop_file(ctx, filepath, name):
179
+ drag_and_drop_file(ctx, name, filepath)
180
+
181
+
182
+ @step('I wait to drag and drop the file "{filepath}" to "{name}"')
183
+ def wait_to_drag_and_drop_file(ctx, filepath, name):
184
+ retry(drag_and_drop_file)(ctx, name, filepath)
@@ -1,10 +1,11 @@
1
+ import socket
1
2
  from functools import partial
2
3
  from http.server import HTTPServer, SimpleHTTPRequestHandler
3
4
  from threading import Thread
4
5
 
5
6
  from behave import step
6
7
 
7
- from cucu import register_after_this_scenario_hook
8
+ from cucu import logger, register_after_this_scenario_hook
8
9
  from cucu.config import CONFIG
9
10
 
10
11
 
@@ -33,6 +34,9 @@ def run_webserver_for_scenario(ctx, directory, variable):
33
34
  _, port = httpd.server_address
34
35
  CONFIG[variable] = str(port)
35
36
 
37
+ with socket.create_connection(("localhost", port), timeout=5):
38
+ logger.debug(f"Webserver is running at {port=}port")
39
+
36
40
  def shutdown_webserver(_):
37
41
  httpd.shutdown()
38
42
  thread.join()
@@ -11,6 +11,8 @@ import shutil
11
11
  import humanize
12
12
  from tabulate import DataRow, TableFormat, tabulate
13
13
  from tenacity import (
14
+ after_log,
15
+ before_log,
14
16
  before_sleep_log,
15
17
  retry_if_not_exception_type,
16
18
  stop_after_delay,
@@ -119,6 +121,8 @@ def retry(func, wait_up_to_s=None, retry_after_s=None):
119
121
  stop=stop_after_delay(wait_up_to_s),
120
122
  wait=wait_fixed(retry_after_s),
121
123
  retry=retry_if_not_exception_type(StopRetryException),
124
+ before=before_log(logger, logging.DEBUG),
125
+ after=after_log(logger, logging.DEBUG),
122
126
  before_sleep=before_sleep_log(logger, logging.DEBUG),
123
127
  )
124
128
  def new_decorator(*args, **kwargs):