cucu 1.3.11__py3-none-any.whl → 1.3.13__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/cli/core.py +78 -59
- cucu/cli/run.py +6 -7
- cucu/cli/steps.py +1 -1
- cucu/config.py +2 -1
- cucu/db.py +32 -17
- cucu/environment.py +1 -1
- cucu/fuzzy/core.py +2 -2
- cucu/reporter/html.py +29 -22
- cucu/reporter/templates/flat.html +4 -4
- cucu/reporter/templates/index.html +3 -3
- cucu/reporter/templates/scenario.html +28 -14
- cucu/steps/table_steps.py +4 -7
- {cucu-1.3.11.dist-info → cucu-1.3.13.dist-info}/METADATA +4 -4
- {cucu-1.3.11.dist-info → cucu-1.3.13.dist-info}/RECORD +16 -16
- {cucu-1.3.11.dist-info → cucu-1.3.13.dist-info}/WHEEL +1 -1
- {cucu-1.3.11.dist-info → cucu-1.3.13.dist-info}/entry_points.txt +0 -0
cucu/cli/core.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
import glob
|
|
3
2
|
import json
|
|
4
3
|
import os
|
|
5
4
|
import shutil
|
|
@@ -54,7 +53,9 @@ def main():
|
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
@main.command()
|
|
57
|
-
@click.argument(
|
|
56
|
+
@click.argument(
|
|
57
|
+
"filepath", default="features", type=click.Path(path_type=Path)
|
|
58
|
+
)
|
|
58
59
|
@click.option(
|
|
59
60
|
"-b",
|
|
60
61
|
"--browser",
|
|
@@ -110,6 +111,7 @@ def main():
|
|
|
110
111
|
default=None,
|
|
111
112
|
help="specify the output directory for JUnit XML files, default is "
|
|
112
113
|
"the same location as --results",
|
|
114
|
+
type=click.Path(path_type=Path),
|
|
113
115
|
)
|
|
114
116
|
@click.option(
|
|
115
117
|
"--junit-with-stacktrace",
|
|
@@ -150,6 +152,7 @@ def main():
|
|
|
150
152
|
"--report",
|
|
151
153
|
default="report",
|
|
152
154
|
help="the location to put the test report when --generate-report is used",
|
|
155
|
+
type=click.Path(path_type=Path),
|
|
153
156
|
)
|
|
154
157
|
@click.option(
|
|
155
158
|
"--report-only-failures",
|
|
@@ -162,6 +165,7 @@ def main():
|
|
|
162
165
|
"--results",
|
|
163
166
|
default="results",
|
|
164
167
|
help="the results directory used by cucu",
|
|
168
|
+
type=click.Path(path_type=Path),
|
|
165
169
|
)
|
|
166
170
|
@click.option(
|
|
167
171
|
"--runtime-timeout",
|
|
@@ -247,7 +251,7 @@ def run(
|
|
|
247
251
|
# when cucu is already running it means that we're running inside
|
|
248
252
|
# another cucu process and therefore we should make sure the results
|
|
249
253
|
# directory isn't the default one and throw an exception otherwise
|
|
250
|
-
if results == "results":
|
|
254
|
+
if results == Path("results"):
|
|
251
255
|
raise Exception(
|
|
252
256
|
"running within cucu but --results was not used, "
|
|
253
257
|
"this would lead to some very difficult to debug "
|
|
@@ -263,10 +267,10 @@ def run(
|
|
|
263
267
|
logger.init_logging(logging_level.upper())
|
|
264
268
|
|
|
265
269
|
if not preserve_results:
|
|
266
|
-
if
|
|
270
|
+
if results.exists():
|
|
267
271
|
shutil.rmtree(results)
|
|
268
272
|
|
|
269
|
-
|
|
273
|
+
results.mkdir(parents=True, exist_ok=True)
|
|
270
274
|
|
|
271
275
|
if selenium_remote_url is not None:
|
|
272
276
|
os.environ["CUCU_SELENIUM_REMOTE_URL"] = selenium_remote_url
|
|
@@ -302,12 +306,15 @@ def run(
|
|
|
302
306
|
generate_short_id(worker_id_seed)
|
|
303
307
|
)
|
|
304
308
|
|
|
305
|
-
os.environ["CUCU_FILEPATH"] = CONFIG["CUCU_FILEPATH"] = filepath
|
|
309
|
+
os.environ["CUCU_FILEPATH"] = CONFIG["CUCU_FILEPATH"] = str(filepath)
|
|
306
310
|
|
|
307
311
|
create_run(results, filepath)
|
|
308
312
|
|
|
309
313
|
try:
|
|
310
314
|
if workers is None or workers == 1:
|
|
315
|
+
logger.debug(
|
|
316
|
+
f"Starting cucu_run {CONFIG['CUCU_RUN_ID']} with single worker"
|
|
317
|
+
)
|
|
311
318
|
if runtime_timeout:
|
|
312
319
|
logger.debug("setting up runtime timeout timer")
|
|
313
320
|
|
|
@@ -347,9 +354,11 @@ def run(
|
|
|
347
354
|
raise ClickException("test run failed, see above for details")
|
|
348
355
|
|
|
349
356
|
else:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
357
|
+
logger.debug(
|
|
358
|
+
f"Starting cucu_run {CONFIG['CUCU_RUN_ID']} with multiple workers: {workers}"
|
|
359
|
+
)
|
|
360
|
+
if filepath.is_dir():
|
|
361
|
+
feature_filepaths = list(filepath.rglob("*.feature"))
|
|
353
362
|
else:
|
|
354
363
|
feature_filepaths = [filepath]
|
|
355
364
|
|
|
@@ -486,8 +495,10 @@ def run(
|
|
|
486
495
|
task_failed.update(async_results)
|
|
487
496
|
|
|
488
497
|
if task_failed:
|
|
489
|
-
failing_features =
|
|
490
|
-
logger.error(
|
|
498
|
+
failing_features = [str(x) for x in task_failed.keys()]
|
|
499
|
+
logger.error(
|
|
500
|
+
f"Failing Features:\n{'\n'.join(failing_features)}"
|
|
501
|
+
)
|
|
491
502
|
raise RuntimeError(
|
|
492
503
|
"there are failures, see above for details"
|
|
493
504
|
)
|
|
@@ -495,60 +506,58 @@ def run(
|
|
|
495
506
|
if dumper is not None:
|
|
496
507
|
dumper.stop()
|
|
497
508
|
|
|
498
|
-
if
|
|
509
|
+
if results.exists():
|
|
499
510
|
finish_worker_record(worker_run_id=CONFIG.get("WORKER_PARENT_ID"))
|
|
500
511
|
consolidate_database_files(results)
|
|
501
512
|
|
|
502
513
|
if generate_report:
|
|
503
514
|
_generate_report(
|
|
504
|
-
results,
|
|
505
|
-
report,
|
|
515
|
+
results_dir=results,
|
|
516
|
+
report_folder=report,
|
|
506
517
|
only_failures=report_only_failures,
|
|
507
|
-
|
|
518
|
+
junit_folder=junit,
|
|
508
519
|
)
|
|
509
520
|
|
|
510
521
|
|
|
511
522
|
def _generate_report(
|
|
512
|
-
results_dir:
|
|
513
|
-
|
|
523
|
+
results_dir: Path,
|
|
524
|
+
report_folder: Path,
|
|
514
525
|
only_failures: False,
|
|
515
|
-
|
|
526
|
+
junit_folder: Path | None = None,
|
|
516
527
|
):
|
|
517
|
-
if
|
|
518
|
-
shutil.rmtree(
|
|
528
|
+
if report_folder.exists():
|
|
529
|
+
shutil.rmtree(report_folder)
|
|
519
530
|
|
|
520
|
-
|
|
531
|
+
report_folder.mkdir(parents=True, exist_ok=True)
|
|
521
532
|
|
|
522
|
-
if
|
|
533
|
+
if results_dir.exists():
|
|
523
534
|
consolidate_database_files(results_dir)
|
|
524
535
|
|
|
525
536
|
report_location = reporter.generate(
|
|
526
|
-
results_dir,
|
|
537
|
+
results_dir, report_folder, only_failures=only_failures
|
|
527
538
|
)
|
|
528
539
|
print(f"HTML test report at {report_location}")
|
|
529
540
|
|
|
530
|
-
if
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
"index.html",
|
|
545
|
-
)
|
|
546
|
-
test_case.set("report_path", report_path)
|
|
547
|
-
junit.write(junit_file, encoding="utf-8", xml_declaration=False)
|
|
541
|
+
if junit_folder:
|
|
542
|
+
for junit_file in junit_folder.rglob("*.xml"):
|
|
543
|
+
junit = ET.parse(junit_file)
|
|
544
|
+
test_suite = junit.getroot()
|
|
545
|
+
ts_folder = test_suite.get("foldername")
|
|
546
|
+
for test_case in test_suite.iter("testcase"):
|
|
547
|
+
report_path = os.path.join(
|
|
548
|
+
report_folder,
|
|
549
|
+
ts_folder,
|
|
550
|
+
test_case.get("foldername"),
|
|
551
|
+
"index.html",
|
|
552
|
+
)
|
|
553
|
+
test_case.set("report_path", report_path)
|
|
554
|
+
junit.write(junit_file, encoding="utf-8", xml_declaration=False)
|
|
548
555
|
|
|
549
556
|
|
|
550
557
|
@main.command()
|
|
551
|
-
@click.argument(
|
|
558
|
+
@click.argument(
|
|
559
|
+
"results_dir", default="results", type=click.Path(path_type=Path)
|
|
560
|
+
)
|
|
552
561
|
@click.option(
|
|
553
562
|
"--only-failures",
|
|
554
563
|
default=False,
|
|
@@ -567,21 +576,27 @@ def _add_report_path_in_junit(junit_folder, report_folder):
|
|
|
567
576
|
is_flag=True,
|
|
568
577
|
help="when set skips are shown",
|
|
569
578
|
)
|
|
570
|
-
@click.option(
|
|
579
|
+
@click.option(
|
|
580
|
+
"-o",
|
|
581
|
+
"--output",
|
|
582
|
+
default="report",
|
|
583
|
+
type=click.Path(path_type=Path),
|
|
584
|
+
)
|
|
571
585
|
@click.option(
|
|
572
586
|
"-j",
|
|
573
587
|
"--junit",
|
|
574
588
|
default=None,
|
|
575
589
|
help="specify the output directory for JUnit XML files, default is "
|
|
576
590
|
"the same location as --results",
|
|
591
|
+
type=click.Path(path_type=Path),
|
|
577
592
|
)
|
|
578
593
|
def report(
|
|
579
|
-
results_dir,
|
|
594
|
+
results_dir: Path,
|
|
580
595
|
only_failures,
|
|
581
596
|
logging_level,
|
|
582
597
|
show_skips,
|
|
583
|
-
output,
|
|
584
|
-
junit,
|
|
598
|
+
output: Path,
|
|
599
|
+
junit: Path,
|
|
585
600
|
):
|
|
586
601
|
"""
|
|
587
602
|
generate a test report from a results directory
|
|
@@ -594,7 +609,7 @@ def report(
|
|
|
594
609
|
if show_skips:
|
|
595
610
|
os.environ["CUCU_SHOW_SKIPS"] = "true"
|
|
596
611
|
|
|
597
|
-
run_details_filepath =
|
|
612
|
+
run_details_filepath = results_dir / "run_details.json"
|
|
598
613
|
|
|
599
614
|
if os.path.exists(run_details_filepath):
|
|
600
615
|
# load the run details at the time of execution for the provided results
|
|
@@ -608,12 +623,17 @@ def report(
|
|
|
608
623
|
behave_init(run_details["filepath"])
|
|
609
624
|
|
|
610
625
|
_generate_report(
|
|
611
|
-
results_dir
|
|
626
|
+
results_dir=results_dir,
|
|
627
|
+
report_folder=output,
|
|
628
|
+
only_failures=only_failures,
|
|
629
|
+
junit_folder=junit,
|
|
612
630
|
)
|
|
613
631
|
|
|
614
632
|
|
|
615
633
|
@main.command()
|
|
616
|
-
@click.argument(
|
|
634
|
+
@click.argument(
|
|
635
|
+
"filepath", default="features", type=click.Path(path_type=Path)
|
|
636
|
+
)
|
|
617
637
|
@click.option(
|
|
618
638
|
"-f",
|
|
619
639
|
"--format",
|
|
@@ -639,7 +659,7 @@ def steps(filepath, format):
|
|
|
639
659
|
|
|
640
660
|
|
|
641
661
|
@main.command()
|
|
642
|
-
@click.argument("filepath", nargs=-1)
|
|
662
|
+
@click.argument("filepath", type=click.Path(path_type=Path), nargs=-1)
|
|
643
663
|
@click.option(
|
|
644
664
|
"--fix/--no-fix", default=False, help="fix lint violations, default: False"
|
|
645
665
|
)
|
|
@@ -741,7 +761,9 @@ def lsp(logging_level, port):
|
|
|
741
761
|
|
|
742
762
|
|
|
743
763
|
@main.command()
|
|
744
|
-
@click.argument(
|
|
764
|
+
@click.argument(
|
|
765
|
+
"filepath", default="features", type=click.Path(path_type=Path)
|
|
766
|
+
)
|
|
745
767
|
def vars(filepath):
|
|
746
768
|
"""
|
|
747
769
|
print built-in cucu variables
|
|
@@ -766,14 +788,14 @@ def vars(filepath):
|
|
|
766
788
|
|
|
767
789
|
|
|
768
790
|
@main.command()
|
|
769
|
-
@click.argument("
|
|
791
|
+
@click.argument("repo_dir", default="", type=click.Path(path_type=Path))
|
|
770
792
|
@click.option(
|
|
771
793
|
"-l",
|
|
772
794
|
"--logging-level",
|
|
773
795
|
default="INFO",
|
|
774
796
|
help="set logging level to one of debug, warn or info (default)",
|
|
775
797
|
)
|
|
776
|
-
def init(
|
|
798
|
+
def init(repo_dir, logging_level):
|
|
777
799
|
"""
|
|
778
800
|
initialize cucu in the current directory
|
|
779
801
|
|
|
@@ -785,10 +807,9 @@ def init(filepath, logging_level):
|
|
|
785
807
|
init_data_dir = Path(__file__).parent.parent / "init_data"
|
|
786
808
|
|
|
787
809
|
logger.debug(f"cucu init: copy example directory from {init_data_dir=}")
|
|
788
|
-
repo_dir = filepath if filepath.strip() else os.path.join(os.getcwd())
|
|
789
810
|
|
|
790
|
-
features_dir =
|
|
791
|
-
if
|
|
811
|
+
features_dir = repo_dir / "features"
|
|
812
|
+
if features_dir.exists():
|
|
792
813
|
answer = input("Overwrite existing files? [y/N]:")
|
|
793
814
|
if answer.lower() != "y":
|
|
794
815
|
print("Aborted!")
|
|
@@ -874,9 +895,7 @@ def tags(filepath, logging_level):
|
|
|
874
895
|
if not filepath.exists() or not feature_files:
|
|
875
896
|
raise ClickException("No feature files found.")
|
|
876
897
|
|
|
877
|
-
file_locations = [
|
|
878
|
-
FileLocation(os.path.abspath(str(f))) for f in feature_files
|
|
879
|
-
]
|
|
898
|
+
file_locations = [FileLocation(f.absolute()) for f in feature_files]
|
|
880
899
|
features = parse_features(file_locations)
|
|
881
900
|
tag_scenarios = Counter()
|
|
882
901
|
|
cucu/cli/run.py
CHANGED
|
@@ -85,8 +85,8 @@ def behave(
|
|
|
85
85
|
if debug_on_failure:
|
|
86
86
|
os.environ["CUCU_DEBUG_ON_FAILURE"] = "true"
|
|
87
87
|
|
|
88
|
-
os.environ["CUCU_RESULTS_DIR"] = results
|
|
89
|
-
os.environ["CUCU_JUNIT_DIR"] = junit
|
|
88
|
+
os.environ["CUCU_RESULTS_DIR"] = str(results)
|
|
89
|
+
os.environ["CUCU_JUNIT_DIR"] = str(junit)
|
|
90
90
|
|
|
91
91
|
if secrets:
|
|
92
92
|
os.environ["CUCU_SECRETS"] = secrets
|
|
@@ -123,7 +123,7 @@ def behave(
|
|
|
123
123
|
"--no-logcapture",
|
|
124
124
|
# generate a JSON file containing the exact details of the whole run
|
|
125
125
|
"--format=cucu.formatter.json:CucuJSONFormatter",
|
|
126
|
-
f"--outfile={
|
|
126
|
+
f"--outfile={results / run_json_filename}",
|
|
127
127
|
# console formatter
|
|
128
128
|
"--format=cucu.formatter.cucu:CucuFormatter",
|
|
129
129
|
f"--logging-level={os.environ['CUCU_LOGGING_LEVEL'].upper()}",
|
|
@@ -154,7 +154,7 @@ def behave(
|
|
|
154
154
|
if redirect_output:
|
|
155
155
|
feature_name = get_feature_name(filepath)
|
|
156
156
|
log_filename = f"{feature_name}.log"
|
|
157
|
-
log_filepath =
|
|
157
|
+
log_filepath = results / log_filename
|
|
158
158
|
|
|
159
159
|
CONFIG["__CUCU_PARENT_STDOUT"] = sys.stdout
|
|
160
160
|
|
|
@@ -185,8 +185,7 @@ def behave(
|
|
|
185
185
|
return result
|
|
186
186
|
|
|
187
187
|
|
|
188
|
-
def create_run(
|
|
189
|
-
results_path = Path(results)
|
|
188
|
+
def create_run(results_path: Path, filepath: Path):
|
|
190
189
|
run_json_filepath = results_path / "run_details.json"
|
|
191
190
|
|
|
192
191
|
if run_json_filepath.exists():
|
|
@@ -200,7 +199,7 @@ def create_run(results, filepath):
|
|
|
200
199
|
|
|
201
200
|
run_details = {
|
|
202
201
|
"cucu_run_id": CONFIG["CUCU_RUN_ID"],
|
|
203
|
-
"filepath": filepath,
|
|
202
|
+
"filepath": str(filepath),
|
|
204
203
|
"full_arguments": sys.argv,
|
|
205
204
|
"env": env_values,
|
|
206
205
|
"date": datetime.now().isoformat(),
|
cucu/cli/steps.py
CHANGED
|
@@ -131,7 +131,7 @@ def print_human_readable_steps(filepath=None):
|
|
|
131
131
|
|
|
132
132
|
for step_name in steps:
|
|
133
133
|
if steps[step_name] is not None:
|
|
134
|
-
if filepath in steps[step_name]["location"]["filepath"]:
|
|
134
|
+
if str(filepath) in steps[step_name]["location"]["filepath"]:
|
|
135
135
|
print(f"custom: {step_name}")
|
|
136
136
|
else:
|
|
137
137
|
print(f"cucu: {step_name}")
|
cucu/config.py
CHANGED
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
5
|
import socket
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import yaml
|
|
8
9
|
|
|
@@ -100,7 +101,7 @@ class Config(dict):
|
|
|
100
101
|
else:
|
|
101
102
|
self[key] = config[key]
|
|
102
103
|
|
|
103
|
-
def load_cucurc_files(self, filepath):
|
|
104
|
+
def load_cucurc_files(self, filepath: Path):
|
|
104
105
|
"""
|
|
105
106
|
load in order the ~/.cucurc.yml and then subsequent config files
|
|
106
107
|
starting from the current working directory to the filepath provided
|
cucu/db.py
CHANGED
|
@@ -38,16 +38,16 @@ class cucu_run(BaseModel):
|
|
|
38
38
|
cucu_run_id = TextField(primary_key=True)
|
|
39
39
|
full_arguments = JSONField()
|
|
40
40
|
filepath = TextField()
|
|
41
|
-
date = TextField()
|
|
42
41
|
start_at = DateTimeField()
|
|
43
42
|
end_at = DateTimeField(null=True)
|
|
43
|
+
db_path = TextField(null=True)
|
|
44
|
+
run_info = JSONField(null=True)
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
class worker(BaseModel):
|
|
47
48
|
worker_run_id = TextField(primary_key=True)
|
|
48
|
-
|
|
49
|
+
cucu_run = ForeignKeyField(
|
|
49
50
|
cucu_run,
|
|
50
|
-
field="cucu_run_id",
|
|
51
51
|
backref="workers",
|
|
52
52
|
column_name="cucu_run_id",
|
|
53
53
|
null=True,
|
|
@@ -56,7 +56,7 @@ class worker(BaseModel):
|
|
|
56
56
|
"self",
|
|
57
57
|
field="worker_run_id",
|
|
58
58
|
backref="child_workers",
|
|
59
|
-
column_name="
|
|
59
|
+
column_name="parent_run_id",
|
|
60
60
|
null=True,
|
|
61
61
|
)
|
|
62
62
|
start_at = DateTimeField()
|
|
@@ -66,9 +66,8 @@ class worker(BaseModel):
|
|
|
66
66
|
|
|
67
67
|
class feature(BaseModel):
|
|
68
68
|
feature_run_id = TextField(primary_key=True)
|
|
69
|
-
|
|
69
|
+
worker = ForeignKeyField(
|
|
70
70
|
worker,
|
|
71
|
-
field="worker_run_id",
|
|
72
71
|
backref="features",
|
|
73
72
|
column_name="worker_run_id",
|
|
74
73
|
)
|
|
@@ -84,9 +83,8 @@ class feature(BaseModel):
|
|
|
84
83
|
|
|
85
84
|
class scenario(BaseModel):
|
|
86
85
|
scenario_run_id = TextField(primary_key=True)
|
|
87
|
-
|
|
86
|
+
feature = ForeignKeyField(
|
|
88
87
|
feature,
|
|
89
|
-
field="feature_run_id",
|
|
90
88
|
backref="scenarios",
|
|
91
89
|
column_name="feature_run_id",
|
|
92
90
|
)
|
|
@@ -106,9 +104,8 @@ class scenario(BaseModel):
|
|
|
106
104
|
|
|
107
105
|
class step(BaseModel):
|
|
108
106
|
step_run_id = TextField(primary_key=True)
|
|
109
|
-
|
|
107
|
+
scenario = ForeignKeyField(
|
|
110
108
|
scenario,
|
|
111
|
-
field="scenario_run_id",
|
|
112
109
|
backref="steps",
|
|
113
110
|
column_name="scenario_run_id",
|
|
114
111
|
)
|
|
@@ -147,18 +144,21 @@ def record_cucu_run():
|
|
|
147
144
|
cucu_run_id=cucu_run_id_val,
|
|
148
145
|
full_arguments=sys.argv,
|
|
149
146
|
filepath=filepath,
|
|
150
|
-
date=start_at,
|
|
151
147
|
start_at=start_at,
|
|
152
148
|
)
|
|
153
149
|
|
|
150
|
+
parent_id = (
|
|
151
|
+
CONFIG.get("WORKER_PARENT_ID")
|
|
152
|
+
if CONFIG.get("WORKER_PARENT_ID") != worker_run_id
|
|
153
|
+
else None
|
|
154
|
+
)
|
|
154
155
|
worker.create(
|
|
155
156
|
worker_run_id=worker_run_id,
|
|
156
157
|
cucu_run_id=cucu_run_id_val,
|
|
157
|
-
parent_id=
|
|
158
|
-
if CONFIG.get("WORKER_PARENT_ID") != worker_run_id
|
|
159
|
-
else None,
|
|
158
|
+
parent_id=parent_id,
|
|
160
159
|
start_at=datetime.now().isoformat(),
|
|
161
160
|
)
|
|
161
|
+
|
|
162
162
|
return str(db_filepath)
|
|
163
163
|
|
|
164
164
|
|
|
@@ -166,7 +166,7 @@ def record_feature(feature_obj):
|
|
|
166
166
|
db.connect(reuse_if_open=True)
|
|
167
167
|
feature.create(
|
|
168
168
|
feature_run_id=feature_obj.feature_run_id,
|
|
169
|
-
|
|
169
|
+
worker=CONFIG["WORKER_RUN_ID"],
|
|
170
170
|
name=feature_obj.name,
|
|
171
171
|
filename=feature_obj.filename,
|
|
172
172
|
description="\n".join(feature_obj.description)
|
|
@@ -419,7 +419,7 @@ def consolidate_database_files(results_dir):
|
|
|
419
419
|
create_database_file(target_db_path)
|
|
420
420
|
|
|
421
421
|
db_files = [
|
|
422
|
-
db for db in results_path.glob("
|
|
422
|
+
db for db in results_path.glob("**/run*.db") if db.name != "run.db"
|
|
423
423
|
]
|
|
424
424
|
tables_to_copy = ["cucu_run", "worker", "feature", "scenario", "step"]
|
|
425
425
|
with sqlite3.connect(target_db_path) as target_conn:
|
|
@@ -432,13 +432,28 @@ def consolidate_database_files(results_dir):
|
|
|
432
432
|
rows = source_cursor.fetchall()
|
|
433
433
|
source_cursor.execute(f"PRAGMA table_info({table_name})")
|
|
434
434
|
columns = [col[1] for col in source_cursor.fetchall()]
|
|
435
|
+
|
|
436
|
+
# prep cucu_run for combining multiple runs
|
|
437
|
+
if table_name == "cucu_run":
|
|
438
|
+
db_path_index = columns.index("db_path")
|
|
439
|
+
rows = [
|
|
440
|
+
tuple(
|
|
441
|
+
item if idx != db_path_index else str(db_file)
|
|
442
|
+
for idx, item in enumerate(row)
|
|
443
|
+
)
|
|
444
|
+
for row in rows
|
|
445
|
+
]
|
|
446
|
+
|
|
435
447
|
placeholders = ",".join(["?" for _ in columns])
|
|
436
448
|
target_cursor.executemany(
|
|
437
449
|
f"INSERT OR REPLACE INTO {table_name} VALUES ({placeholders})",
|
|
438
450
|
rows,
|
|
439
451
|
)
|
|
440
452
|
target_conn.commit()
|
|
441
|
-
|
|
453
|
+
|
|
454
|
+
if db_file.name != "run.db":
|
|
455
|
+
# remove the worker db files
|
|
456
|
+
db_file.unlink()
|
|
442
457
|
|
|
443
458
|
|
|
444
459
|
def init_html_report_db(db_path):
|
cucu/environment.py
CHANGED
|
@@ -303,7 +303,7 @@ def after_step(ctx, step):
|
|
|
303
303
|
|
|
304
304
|
# Add tab info to step.stdout so it shows up in the HTML report
|
|
305
305
|
step.stdout.extend(
|
|
306
|
-
[f"tab({current_tab} of {total_tabs}): {title}", "url: {url}"]
|
|
306
|
+
[f"tab({current_tab} of {total_tabs}): {title}", f"url: {url}"]
|
|
307
307
|
)
|
|
308
308
|
|
|
309
309
|
# if the step has substeps from using `run_steps` then we already moved
|
cucu/fuzzy/core.py
CHANGED
|
@@ -107,9 +107,9 @@ def find(
|
|
|
107
107
|
|
|
108
108
|
fuzzy_return = search_in_all_frames(browser, execute_fuzzy_find)
|
|
109
109
|
if fuzzy_return is None:
|
|
110
|
-
logger.
|
|
110
|
+
logger.debug("Fuzzy found no element.")
|
|
111
111
|
return None
|
|
112
|
-
logger.
|
|
112
|
+
logger.debug(
|
|
113
113
|
"Fuzzy found element by search term {}".format(fuzzy_return[1])
|
|
114
114
|
)
|
|
115
115
|
return fuzzy_return[0]
|
cucu/reporter/html.py
CHANGED
|
@@ -10,13 +10,10 @@ from xml.sax.saxutils import escape as escape_
|
|
|
10
10
|
|
|
11
11
|
import jinja2
|
|
12
12
|
|
|
13
|
+
import cucu.db as db
|
|
13
14
|
from cucu import format_gherkin_table, logger
|
|
14
15
|
from cucu.ansi_parser import parse_log_to_html
|
|
15
16
|
from cucu.config import CONFIG
|
|
16
|
-
from cucu.db import close_html_report_db, init_html_report_db
|
|
17
|
-
from cucu.db import feature as FeatureModel
|
|
18
|
-
from cucu.db import scenario as ScenarioModel
|
|
19
|
-
from cucu.db import step as StepModel
|
|
20
17
|
from cucu.utils import ellipsize_filename, get_step_image_dir
|
|
21
18
|
|
|
22
19
|
|
|
@@ -68,15 +65,19 @@ def generate(results, basepath, only_failures=False):
|
|
|
68
65
|
|
|
69
66
|
db_path = os.path.join(results, "run.db")
|
|
70
67
|
try:
|
|
71
|
-
init_html_report_db(db_path)
|
|
68
|
+
db.init_html_report_db(db_path)
|
|
72
69
|
features = []
|
|
73
70
|
|
|
74
|
-
db_features =
|
|
71
|
+
db_features = db.feature.select().order_by(db.feature.start_at)
|
|
75
72
|
logger.info(
|
|
76
73
|
f"Starting to process {len(db_features)} features for report"
|
|
77
74
|
)
|
|
78
75
|
|
|
79
76
|
for db_feature in db_features:
|
|
77
|
+
feature_results_dir = results
|
|
78
|
+
if db_path := db_feature.worker.cucu_run.db_path:
|
|
79
|
+
feature_results_dir = os.path.dirname(db_path)
|
|
80
|
+
|
|
80
81
|
feature_dict = {
|
|
81
82
|
"name": db_feature.name,
|
|
82
83
|
"filename": db_feature.filename,
|
|
@@ -84,14 +85,13 @@ def generate(results, basepath, only_failures=False):
|
|
|
84
85
|
"tags": db_feature.tags if db_feature.tags else [],
|
|
85
86
|
"status": db_feature.status,
|
|
86
87
|
"elements": [],
|
|
88
|
+
"results_dir": feature_results_dir,
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
db_scenarios = (
|
|
90
|
-
|
|
91
|
-
.where(
|
|
92
|
-
|
|
93
|
-
)
|
|
94
|
-
.order_by(ScenarioModel.seq)
|
|
92
|
+
db.scenario.select()
|
|
93
|
+
.where(db.scenario.feature_run_id == db_feature.feature_run_id)
|
|
94
|
+
.order_by(db.scenario.seq)
|
|
95
95
|
)
|
|
96
96
|
|
|
97
97
|
feature_has_failures = False
|
|
@@ -113,12 +113,11 @@ def generate(results, basepath, only_failures=False):
|
|
|
113
113
|
feature_has_failures = True
|
|
114
114
|
|
|
115
115
|
db_steps = (
|
|
116
|
-
|
|
116
|
+
db.step.select()
|
|
117
117
|
.where(
|
|
118
|
-
|
|
119
|
-
== db_scenario.scenario_run_id
|
|
118
|
+
db.step.scenario_run_id == db_scenario.scenario_run_id
|
|
120
119
|
)
|
|
121
|
-
.order_by(
|
|
120
|
+
.order_by(db.step.seq)
|
|
122
121
|
)
|
|
123
122
|
|
|
124
123
|
for db_step in db_steps:
|
|
@@ -166,7 +165,7 @@ def generate(results, basepath, only_failures=False):
|
|
|
166
165
|
features.append(feature_dict)
|
|
167
166
|
|
|
168
167
|
finally:
|
|
169
|
-
close_html_report_db()
|
|
168
|
+
db.close_html_report_db()
|
|
170
169
|
|
|
171
170
|
cucu_dir = os.path.dirname(sys.modules["cucu"].__file__)
|
|
172
171
|
external_dir = os.path.join(cucu_dir, "reporter", "external")
|
|
@@ -208,14 +207,21 @@ def generate(results, basepath, only_failures=False):
|
|
|
208
207
|
if feature["status"] not in ["skipped", "untested"]:
|
|
209
208
|
# copy each feature directories contents over to the report directory
|
|
210
209
|
src_feature_filepath = os.path.join(
|
|
211
|
-
|
|
210
|
+
feature["results_dir"], feature["folder_name"]
|
|
212
211
|
)
|
|
213
212
|
dst_feature_filepath = os.path.join(
|
|
214
213
|
basepath, feature["folder_name"]
|
|
215
214
|
)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
215
|
+
if os.path.exists(src_feature_filepath):
|
|
216
|
+
shutil.copytree(
|
|
217
|
+
src_feature_filepath,
|
|
218
|
+
dst_feature_filepath,
|
|
219
|
+
dirs_exist_ok=True,
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
logger.warning(
|
|
223
|
+
f"Feature directory not found, skipping copy: {src_feature_filepath}"
|
|
224
|
+
)
|
|
219
225
|
|
|
220
226
|
for scenario in scenarios:
|
|
221
227
|
CONFIG.restore()
|
|
@@ -364,8 +370,8 @@ def generate(results, basepath, only_failures=False):
|
|
|
364
370
|
step_index += 1
|
|
365
371
|
logs_dir = os.path.join(scenario_filepath, "logs")
|
|
366
372
|
|
|
373
|
+
log_files = []
|
|
367
374
|
if os.path.exists(logs_dir):
|
|
368
|
-
log_files = []
|
|
369
375
|
for log_file in glob.iglob(os.path.join(logs_dir, "*.*")):
|
|
370
376
|
log_filepath = log_file.removeprefix(
|
|
371
377
|
f"{scenario_filepath}/"
|
|
@@ -434,9 +440,10 @@ def generate(results, basepath, only_failures=False):
|
|
|
434
440
|
"total_scenarios_failed",
|
|
435
441
|
"total_scenarios_skipped",
|
|
436
442
|
"total_scenarios_errored",
|
|
443
|
+
"total_steps",
|
|
437
444
|
"duration",
|
|
438
445
|
]
|
|
439
|
-
grand_totals = {}
|
|
446
|
+
grand_totals = {"total_features": len(reported_features)}
|
|
440
447
|
for k in keys:
|
|
441
448
|
grand_totals[k] = sum([float(x[k]) for x in reported_features])
|
|
442
449
|
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
<thead>
|
|
19
19
|
<tr class="align-text-top">
|
|
20
20
|
<th class="text-center">Started at</th>
|
|
21
|
-
<th>
|
|
22
|
-
<th>
|
|
23
|
-
<th class="text-center">
|
|
21
|
+
<th>Features<br/>{{ grand_totals['total_features'] | int }}</th>
|
|
22
|
+
<th>Scenarios<br/>{{ grand_totals['total_scenarios'] | int }}</th>
|
|
23
|
+
<th class="text-center">Steps<br/>{{ grand_totals['total_steps'] | int }}</th>
|
|
24
24
|
<th class="text-center">Status</th>
|
|
25
|
-
<th class="text-center">Duration
|
|
25
|
+
<th class="text-center">Duration<br/>{{ grand_totals['duration'] | int }}s</th>
|
|
26
26
|
</tr>
|
|
27
27
|
</thead>
|
|
28
28
|
{% for feature in features %}
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
<thead>
|
|
19
19
|
<tr class="align-text-top">
|
|
20
20
|
<th class="text-center">Started at</th>
|
|
21
|
-
<th>
|
|
22
|
-
<th class="text-center">
|
|
21
|
+
<th>Features<br/>{{ grand_totals['total_features'] | int }}</th>
|
|
22
|
+
<th class="text-center">Scenarios<br/>{{ grand_totals['total_scenarios'] | int }}</th>
|
|
23
23
|
<th class="text-center">Passed<br/>{{ grand_totals['total_scenarios_passed'] | int}}</th>
|
|
24
24
|
<th class="text-center">Failed<br/>{{ grand_totals['total_scenarios_failed'] | int }}</th>
|
|
25
25
|
<th class="text-center">Skipped<br/>{{ grand_totals['total_scenarios_skipped'] | int }}</th>
|
|
26
26
|
<th class="text-center">Errored<br/>{{ grand_totals['total_scenarios_errored'] | int }}</th>
|
|
27
27
|
<th class="text-center">Status<br/> </th>
|
|
28
|
-
<th class="text-center">Duration
|
|
28
|
+
<th class="text-center">Duration<br/>{{ grand_totals['duration'] | int }}s</th>
|
|
29
29
|
</tr>
|
|
30
30
|
</thead>
|
|
31
31
|
{% for feature in features %}
|
|
@@ -134,30 +134,44 @@
|
|
|
134
134
|
<tr class="row"><td style="min-width: 0;" class="col-12 collapse multi-collapse" id="collapsable-row-{{ loop.index }}" colspan="2">
|
|
135
135
|
|
|
136
136
|
{% if step['result']['stdout'] %}
|
|
137
|
-
|
|
138
|
-
<
|
|
137
|
+
<details open>
|
|
138
|
+
<summary style="color: dimgray;">stdout ({{ step['result']['stdout']|length }} lines)</summary>
|
|
139
|
+
<pre style="color: darkgray;">{{ escape("\n".join(step['result']['stdout'])) }}</pre>
|
|
140
|
+
</details>
|
|
139
141
|
{% endif %}
|
|
140
142
|
{% if step['result']['stderr'] %}
|
|
141
|
-
|
|
142
|
-
<
|
|
143
|
+
<details open>
|
|
144
|
+
<summary style="color: dimgray;">stderr ({{ step['result']['stderr']|length }} lines)</summary>
|
|
145
|
+
<pre style="color: darkgray;">{{ escape("\n".join(step['result']['stderr'])) }}</pre>
|
|
146
|
+
</details>
|
|
143
147
|
{% endif %}
|
|
144
148
|
{% if step['images'] %}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
<details open>
|
|
150
|
+
<summary style="color: dimgray;">images ({{ step['images']|length }} images)</summary>
|
|
151
|
+
<div style="margin: 10px 0 0 0;">
|
|
152
|
+
{% for image in step['images'] %}
|
|
153
|
+
<img class="mx-auto d-block img-fluid shadow bg-white rounded" style="margin-bottom:15px" alt='{{ image["label"] }}' title='{{ image["label"] }}' src='{{ image["src"] }}'></img>
|
|
154
|
+
{% endfor %}
|
|
155
|
+
</div>
|
|
156
|
+
</details>
|
|
149
157
|
{% endif %}
|
|
150
158
|
{% if step['result']['error_message'] %}
|
|
151
|
-
|
|
152
|
-
<
|
|
159
|
+
<details open>
|
|
160
|
+
<summary style="color: dimgray;">error message ({{ step['result']['error_message']|length }} lines)</summary>
|
|
161
|
+
<pre style="color: darkgray;">{{ escape("\n".join(step['result']['error_message'])) }}</pre>
|
|
162
|
+
</details>
|
|
153
163
|
{% endif %}
|
|
154
164
|
{% if step['result']['browser_logs'] %}
|
|
155
|
-
|
|
156
|
-
<
|
|
165
|
+
<details open>
|
|
166
|
+
<summary style="color: dimgray;">browser logs ({{ step['result']['browser_logs']|length }} lines)</summary>
|
|
167
|
+
<pre style="color: darkgray;">{{ escape("\n".join(step['result']['browser_logs'])) }}</pre>
|
|
168
|
+
</details>
|
|
157
169
|
{% endif %}
|
|
158
170
|
{% if step['result']['debug_output'] %}
|
|
159
|
-
|
|
160
|
-
<
|
|
171
|
+
<details open>
|
|
172
|
+
<summary style="color: dimgray;">debug output ({{ step['result']['debug_output']|length }} lines)</summary>
|
|
173
|
+
<pre style="color: darkgray;">{{ escape("\n".join(step['result']['debug_output'])) }}</pre>
|
|
174
|
+
</details>
|
|
161
175
|
{% endif %}
|
|
162
176
|
|
|
163
177
|
</td></tr>
|
cucu/steps/table_steps.py
CHANGED
|
@@ -70,18 +70,15 @@ def check_table_matches_table(table, expected_table):
|
|
|
70
70
|
check if table matches the regex patterns in expected table
|
|
71
71
|
"""
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
table_matched = bool(len(table) == len(expected_table))
|
|
74
|
+
if table_matched:
|
|
76
75
|
for expected_row, row in zip(expected_table, table):
|
|
77
76
|
for expected_value, value in zip(expected_row, row):
|
|
78
77
|
if not re.match(expected_value, value):
|
|
79
78
|
table_matched = False
|
|
79
|
+
break
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
return True
|
|
83
|
-
|
|
84
|
-
return False
|
|
81
|
+
return table_matched
|
|
85
82
|
|
|
86
83
|
|
|
87
84
|
def check_table_contains_table(table, expected_table):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: cucu
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.13
|
|
4
4
|
Summary: Easy BDD web testing
|
|
5
5
|
Keywords: cucumber,selenium,behave
|
|
6
6
|
Author: Domino Data Lab, Rodney Gomes, Cedric Young, Xin Dong, Kavya Yakkati, Kevin Garton, Joy Liao
|
|
@@ -13,13 +13,13 @@ Classifier: License :: OSI Approved :: BSD License
|
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Natural Language :: English
|
|
15
15
|
Classifier: Topic :: Software Development :: Testing :: BDD
|
|
16
|
-
Requires-Dist: beautifulsoup4~=4.
|
|
16
|
+
Requires-Dist: beautifulsoup4~=4.14.2
|
|
17
17
|
Requires-Dist: behave==1.2.6
|
|
18
18
|
Requires-Dist: chromedriver-autoinstaller~=0.6.2
|
|
19
|
-
Requires-Dist: click~=8.
|
|
19
|
+
Requires-Dist: click~=8.3.0
|
|
20
20
|
Requires-Dist: coverage[toml]~=7.8
|
|
21
21
|
Requires-Dist: geckodriver-autoinstaller~=0.1.0
|
|
22
|
-
Requires-Dist: humanize~=4.
|
|
22
|
+
Requires-Dist: humanize~=4.13.0
|
|
23
23
|
Requires-Dist: importlib-metadata~=8.7.0
|
|
24
24
|
Requires-Dist: jellyfish>=1.1
|
|
25
25
|
Requires-Dist: jinja2~=3.1.3
|
|
@@ -7,16 +7,16 @@ cucu/browser/frames.py,sha256=IW7kzRJn5PkbMaovIelAeCWO-T-2sOTwqaYBw-0-LKU,3545
|
|
|
7
7
|
cucu/browser/selenium.py,sha256=eUC2DZkhUIZi70sVTaNE_0AhanGTceyx_pCLIT7PN6o,13299
|
|
8
8
|
cucu/browser/selenium_tweaks.py,sha256=oUIhWVhBZbc9qsmQUJMpIr9uUWKxtgZBcnySWU6Yttk,879
|
|
9
9
|
cucu/cli/__init__.py,sha256=uXX5yVG1konJ_INdlrcfMg-Tt_5_cSx29Ed8R8v908A,62
|
|
10
|
-
cucu/cli/core.py,sha256=
|
|
11
|
-
cucu/cli/run.py,sha256=
|
|
12
|
-
cucu/cli/steps.py,sha256=
|
|
10
|
+
cucu/cli/core.py,sha256=rdnMNvTletzjFeA1JFzc2wF_Hd_YI0KFMe1M0eAvA00,27298
|
|
11
|
+
cucu/cli/run.py,sha256=6w7lkgf3iWsg9lqrmCJEWmOHGRXJFbVyZItVGGk_9gM,6105
|
|
12
|
+
cucu/cli/steps.py,sha256=5-aOGf3fmcnge4pcFM__4shcA3PZwjKe6oZN6XKY1pM,4215
|
|
13
13
|
cucu/cli/thread_dumper.py,sha256=Z3XnYSxidx6pqjlQ7zu-TKMIYZWk4z9c5YLdPkcemiU,1593
|
|
14
|
-
cucu/config.py,sha256=
|
|
15
|
-
cucu/db.py,sha256=
|
|
14
|
+
cucu/config.py,sha256=Pi59JiRcCdzugDwraM4R1hXRkP52123z0hSP8X6lyzI,14970
|
|
15
|
+
cucu/db.py,sha256=ofJZQjGw_dBp-WpgG-CjEXOzotagi1n_T_AGL2QRSVY,15082
|
|
16
16
|
cucu/edgedriver_autoinstaller/README.md,sha256=tDkAWIqgRdCjt-oX1nYqikIC_FfiOEM2-pc5S5VbRLo,84
|
|
17
17
|
cucu/edgedriver_autoinstaller/__init__.py,sha256=fo6xJJPvcc5Xvni8epXfxDoPxJH5_b6Vk2jD9JTwfRs,969
|
|
18
18
|
cucu/edgedriver_autoinstaller/utils.py,sha256=iRKTww77CGaTAntt_QDvxlKPxpMU4otx95OeD97khcM,6802
|
|
19
|
-
cucu/environment.py,sha256=
|
|
19
|
+
cucu/environment.py,sha256=wjj-CA3i3sDi9G_sVzkIUgOv1CgBlwaePdUWIZQMBsw,11729
|
|
20
20
|
cucu/external/jquery/jquery-3.5.1.min.js,sha256=9_aliU8dGd2tb6OSsuzixeV4y_faTqgFtohetphbbj0,89476
|
|
21
21
|
cucu/formatter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
cucu/formatter/cucu.py,sha256=NRLFsd6xl3uwUk45ihKN2OEioOeAqeTURrcQgscDGnU,9351
|
|
@@ -24,7 +24,7 @@ cucu/formatter/json.py,sha256=fJ1dZBGwYD4OkhQFDE49MRKGNzsrhDzQYq-dUfsYh94,10589
|
|
|
24
24
|
cucu/formatter/junit.py,sha256=dCyS47iHOqn5AZjsRpWCsDRkxxJ67IZy3wIlE5jjhoM,10249
|
|
25
25
|
cucu/formatter/rundb.py,sha256=dKNlD-LXmrJ1Gm4OHI7Cs49eMuBGlBfwLz7NLISF5sg,7857
|
|
26
26
|
cucu/fuzzy/__init__.py,sha256=ce4JRmaBF6oab6U99Qbpt7DrD3elhH32__-ND6fw5xc,104
|
|
27
|
-
cucu/fuzzy/core.py,sha256=
|
|
27
|
+
cucu/fuzzy/core.py,sha256=TnUFaBgtJ4QeXXxW5E8Eviwy3zYpQuBPefAdNZzzjkM,3397
|
|
28
28
|
cucu/fuzzy/fuzzy.js,sha256=7ppPmR8szoEQ2rfIsyTmtYDgTrNwXrP_g11y-qEITGk,13882
|
|
29
29
|
cucu/helpers.py,sha256=l_YMmbuXjtBRo-MER-qe6soUIyjt0ey2BoSgWs4zYwA,36285
|
|
30
30
|
cucu/hooks.py,sha256=3Z1mavU42XMQ0DZ7lVWwTB-BJYHRyYUOzzOtmkdIsow,7117
|
|
@@ -56,12 +56,12 @@ cucu/reporter/external/jquery-3.5.1.min.js,sha256=9_aliU8dGd2tb6OSsuzixeV4y_faTq
|
|
|
56
56
|
cucu/reporter/external/jquery.dataTables.min.js,sha256=XNhaB1tBOSFMHu96BSAJpZOJzfZ4SZI1nwAbnwry2UY,90265
|
|
57
57
|
cucu/reporter/external/popper.min.js,sha256=pS96pU17yq-gVu4KBQJi38VpSuKN7otMrDQprzf_DWY,19188
|
|
58
58
|
cucu/reporter/favicon.png,sha256=9ikXLAmzfQzy2NQps_8CGaZog2FvQrOX8nnSZ0e1UmM,2161
|
|
59
|
-
cucu/reporter/html.py,sha256=
|
|
59
|
+
cucu/reporter/html.py,sha256=MpTwYmd-_GycFh3zqQrmSp6Wp-FBJ1CvfatV5bBxpbs,19925
|
|
60
60
|
cucu/reporter/templates/feature.html,sha256=IBkwGiul-sRO5lT8q8VFXMUJx1owsAd1YbdDzziSjKw,3645
|
|
61
|
-
cucu/reporter/templates/flat.html,sha256=
|
|
62
|
-
cucu/reporter/templates/index.html,sha256=
|
|
61
|
+
cucu/reporter/templates/flat.html,sha256=inx9wBo23SKsETA5BqU3GAxM7WaLTsDgCyL_D7TPpdA,2531
|
|
62
|
+
cucu/reporter/templates/index.html,sha256=pJ1eojL19EIUuIiqtALPm3atTabKJb7M1FwGzWpGkdg,2818
|
|
63
63
|
cucu/reporter/templates/layout.html,sha256=2iDRbm8atO8mgHWgijIvDCrBMKvcP6YHrmr95WtJiE4,4561
|
|
64
|
-
cucu/reporter/templates/scenario.html,sha256=
|
|
64
|
+
cucu/reporter/templates/scenario.html,sha256=yOAVb3cHMDvf1xzHatbXdpJnhClVMwMMyZrTSU9Nz9o,11735
|
|
65
65
|
cucu/steps/__init__.py,sha256=seSmASBlWu6-6wbFbvEbPwigBcRXiYP18C4X_2cW8Ng,753
|
|
66
66
|
cucu/steps/base_steps.py,sha256=0fPvdaKoan8lMAKrDnK0-zrALpxm11P1zVAY5CN7iXA,1893
|
|
67
67
|
cucu/steps/browser_steps.py,sha256=iTRl5ffpf2YrFk5qh655WFHAeSOwoE3HFhmXhjsZtao,12687
|
|
@@ -82,13 +82,13 @@ cucu/steps/radio_steps.py,sha256=FygUNPCEBXzmzGMHL8DYNtLe9q4qjeyITiRLH-5Nbag,593
|
|
|
82
82
|
cucu/steps/section_steps.py,sha256=BBsRtJTub_L1grKngRCj7t-f8S4ihOQht68TCzPHZxw,1283
|
|
83
83
|
cucu/steps/step_utils.py,sha256=Chd0NQbMnfAEJmQkoVQRMbVRbCnJIBvVeH7CmXrCMm0,1417
|
|
84
84
|
cucu/steps/tab_steps.py,sha256=TVVytkihvJ2GYQ9bwAs1CVzb-twzUq11QONlEbd6uO0,1818
|
|
85
|
-
cucu/steps/table_steps.py,sha256=
|
|
85
|
+
cucu/steps/table_steps.py,sha256=Xf_9sMZXJRaO64Sd12vCnBm9Olxq1qyyfHHpy_hveWI,13737
|
|
86
86
|
cucu/steps/tables.js,sha256=Os2a7Fo-cg03XVli7USvcnBVad4N7idXr-HBuzdLvVQ,945
|
|
87
87
|
cucu/steps/text_steps.py,sha256=Jj_GHoHeemNwVdUOdqcehArNp7WM-WMjljA4w0pLXuw,2576
|
|
88
88
|
cucu/steps/variable_steps.py,sha256=WSctH3_xcxjijGPYZlxp-foC_SIAAKtF__saNtgZJbk,2966
|
|
89
89
|
cucu/steps/webserver_steps.py,sha256=wWkpSvcSMdiskPkh4cqlepWx1nkvEpTU2tRXQmPDbyo,1410
|
|
90
90
|
cucu/utils.py,sha256=LCcs8sMzvdvH05N8P5QYO4lO6j-_PQC530mEAD96go8,10957
|
|
91
|
-
cucu-1.3.
|
|
92
|
-
cucu-1.3.
|
|
93
|
-
cucu-1.3.
|
|
94
|
-
cucu-1.3.
|
|
91
|
+
cucu-1.3.13.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
92
|
+
cucu-1.3.13.dist-info/entry_points.txt,sha256=11WRIhQM7LuUnQg1lAoZQoNvvBvYNN1maDgQS4djwJo,40
|
|
93
|
+
cucu-1.3.13.dist-info/METADATA,sha256=-BJsZqK7AOpXZK6eQ6Qlh5psQCo3CmtM3l3R_3zHYvU,16722
|
|
94
|
+
cucu-1.3.13.dist-info/RECORD,,
|
|
File without changes
|