pingera-cli 0.1.13__tar.gz → 0.1.14__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.
- {pingera_cli-0.1.13/pingera_cli.egg-info → pingera_cli-0.1.14}/PKG-INFO +1 -1
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/__init__.py +1 -1
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/on_demand_checks.py +120 -23
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/main.py +3 -2
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/utils/config.py +26 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14/pingera_cli.egg-info}/PKG-INFO +1 -1
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli.egg-info/SOURCES.txt +1 -0
- pingera_cli-0.1.14/pwscript.js +14 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/.gitignore +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/.replit +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/LICENSE +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/README.md +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/assert +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/docs/cli-commands.md +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/docs/example-check.yaml +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/docs/example-synthetic-screenshot.json +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/docs/example-web-check.json +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/__main__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/auth.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/base.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/check_groups.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/check_secrets.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/checks.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/execution_groups.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/commands/secrets.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/base_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/dns_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/generic_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/icmp_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/multistep_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/registry.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/ssl_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/synthetic_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/formatters/web_formatter.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/utils/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/utils/console.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli/utils/file_utils.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli.egg-info/dependency_links.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli.egg-info/entry_points.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli.egg-info/requires.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pingera_cli.egg-info/top_level.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/pyproject.toml +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/replit.md +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/run_tests.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/setup.cfg +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/setup.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/__init__.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/conftest.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/requirements.txt +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/test_auth.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/test_checks.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/test_config.py +0 -0
- {pingera_cli-0.1.13 → pingera_cli-0.1.14}/tests/test_on_demand_checks.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Pingera CLI - A beautiful CLI tool for Pingera Platform
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.1.
|
|
5
|
+
__version__ = "0.1.14"
|
|
6
6
|
__author__ = "Pingera Team"
|
|
7
7
|
__description__ = "A beautiful Python CLI tool built with typer and rich, distributed via pip and based on Pingera SDK"
|
|
8
8
|
|
|
@@ -19,8 +19,9 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
19
19
|
Commands for managing on-demand monitoring checks
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
def __init__(self, output_format: Optional[str] = None):
|
|
22
|
+
def __init__(self, output_format: Optional[str] = None, verbose: bool = False):
|
|
23
23
|
super().__init__(output_format)
|
|
24
|
+
self.verbose = verbose
|
|
24
25
|
|
|
25
26
|
def _parse_check_file(self, file_path: str) -> dict:
|
|
26
27
|
"""Parse check configuration from JSON or YAML file (local or URL)"""
|
|
@@ -446,15 +447,17 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
446
447
|
}
|
|
447
448
|
self.output_data(job_data)
|
|
448
449
|
else:
|
|
449
|
-
# Rich formatted detailed view
|
|
450
|
-
self.
|
|
450
|
+
# Rich formatted detailed view - fetch and display with results
|
|
451
|
+
self._fetch_and_display_job_result(job_id, job_status, verbose=self.verbose)
|
|
451
452
|
|
|
452
453
|
except Exception as e:
|
|
453
454
|
self.display_error(f"Failed to get job status: {str(e)}")
|
|
454
455
|
raise typer.Exit(1)
|
|
455
456
|
|
|
456
|
-
def _fetch_and_display_job_result(self, job_id: str, job_status):
|
|
457
|
+
def _fetch_and_display_job_result(self, job_id: str, job_status, verbose: bool = False):
|
|
457
458
|
"""Fetch detailed results from the new results endpoint and display them"""
|
|
459
|
+
import time
|
|
460
|
+
|
|
458
461
|
try:
|
|
459
462
|
# Extract result_id(s) from job response
|
|
460
463
|
result_ids = []
|
|
@@ -463,14 +466,56 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
463
466
|
if hasattr(job_status, 'result') and job_status.result:
|
|
464
467
|
result = job_status.result
|
|
465
468
|
|
|
469
|
+
# Debug: Print the raw result to see what we're getting (only in verbose mode)
|
|
470
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
471
|
+
import json
|
|
472
|
+
self.console.print(f"[dim]DEBUG: Raw result from job status:[/dim]")
|
|
473
|
+
self.console.print(f"[dim]{json.dumps(result, indent=2, default=str)}[/dim]")
|
|
474
|
+
|
|
466
475
|
# Check if this is a multi-region result
|
|
467
476
|
if isinstance(result, dict):
|
|
468
477
|
if 'regional_summary' in result and result['regional_summary']:
|
|
469
478
|
# Multi-region execution
|
|
470
479
|
is_multi_region = True
|
|
471
|
-
|
|
480
|
+
regional_summary = result['regional_summary']
|
|
481
|
+
|
|
482
|
+
# Debug: Show what we found (only in verbose mode)
|
|
483
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
484
|
+
self.console.print(f"[dim]DEBUG: Found {len(regional_summary)} regions in regional_summary[/dim]")
|
|
485
|
+
|
|
486
|
+
for regional_result in regional_summary:
|
|
472
487
|
if 'result_id' in regional_result:
|
|
473
488
|
result_ids.append(regional_result['result_id'])
|
|
489
|
+
|
|
490
|
+
# Check if we might be missing results (race condition detection)
|
|
491
|
+
total_regions = result.get('total_regions', len(regional_summary))
|
|
492
|
+
completed_regions = result.get('completed_regions', len(regional_summary))
|
|
493
|
+
|
|
494
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
495
|
+
self.console.print(f"[dim]DEBUG: total_regions={total_regions}, completed_regions={completed_regions}, found result_ids={len(result_ids)}[/dim]")
|
|
496
|
+
|
|
497
|
+
# If we're missing results, wait a bit and refetch
|
|
498
|
+
if len(result_ids) < total_regions:
|
|
499
|
+
if self.output_format not in ['json', 'yaml']:
|
|
500
|
+
self.console.print(f"[yellow]⚠ Race condition detected: {len(result_ids)}/{total_regions} results ready. Waiting 2s and retrying...[/yellow]")
|
|
501
|
+
time.sleep(2)
|
|
502
|
+
|
|
503
|
+
# Refetch job status
|
|
504
|
+
checks_api = self.get_client()
|
|
505
|
+
job_status = checks_api.v1_checks_jobs_job_id_get(job_id=job_id)
|
|
506
|
+
|
|
507
|
+
# Re-extract result_ids
|
|
508
|
+
result_ids = []
|
|
509
|
+
if hasattr(job_status, 'result') and job_status.result:
|
|
510
|
+
result = job_status.result
|
|
511
|
+
if isinstance(result, dict) and 'regional_summary' in result:
|
|
512
|
+
for regional_result in result['regional_summary']:
|
|
513
|
+
if 'result_id' in regional_result:
|
|
514
|
+
result_ids.append(regional_result['result_id'])
|
|
515
|
+
|
|
516
|
+
if verbose and self.output_format not in ['json', 'yaml']:
|
|
517
|
+
self.console.print(f"[dim]DEBUG: After retry, found {len(result_ids)} result_ids[/dim]")
|
|
518
|
+
|
|
474
519
|
elif 'result_id' in result:
|
|
475
520
|
# Single-region execution
|
|
476
521
|
result_ids.append(result['result_id'])
|
|
@@ -487,14 +532,14 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
487
532
|
raise typer.Exit(1)
|
|
488
533
|
|
|
489
534
|
from pingera import ApiClient, Configuration
|
|
490
|
-
from pingera.api import
|
|
535
|
+
from pingera.api import ChecksUnifiedResultsApi
|
|
491
536
|
from ..utils.config import get_config
|
|
492
537
|
|
|
493
538
|
configuration = Configuration()
|
|
494
539
|
configuration.host = get_config().get('base_url', 'https://api.pingera.ru')
|
|
495
540
|
configuration.api_key['apiKeyAuth'] = api_key
|
|
496
541
|
api_client = ApiClient(configuration)
|
|
497
|
-
checks_api =
|
|
542
|
+
checks_api = ChecksUnifiedResultsApi(api_client)
|
|
498
543
|
|
|
499
544
|
# Fetch detailed results for each result_id
|
|
500
545
|
if is_multi_region:
|
|
@@ -547,13 +592,15 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
547
592
|
self.console.print(f"\n[bold cyan]Multi-Region Execution Result[/bold cyan]")
|
|
548
593
|
self.console.print(f"• Job ID: [white]{job_id}[/white]")
|
|
549
594
|
self.console.print(f"• Status: [{status_color}]{status_emoji} {job_status.status}[/{status_color}]")
|
|
550
|
-
self.console.print(f"• Regions: [white]{len(result_ids)}[/white]")
|
|
551
595
|
|
|
552
596
|
# Extract and display aggregated statistics
|
|
553
597
|
if hasattr(job_status, 'result') and isinstance(job_status.result, dict):
|
|
554
598
|
result = job_status.result
|
|
555
599
|
regional_summary = result.get('regional_summary', [])
|
|
556
600
|
|
|
601
|
+
# Display region count from actual regional_summary
|
|
602
|
+
self.console.print(f"• Regions: [white]{len(regional_summary)}[/white]")
|
|
603
|
+
|
|
557
604
|
if regional_summary:
|
|
558
605
|
# Calculate aggregated statistics
|
|
559
606
|
response_times = []
|
|
@@ -616,19 +663,63 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
616
663
|
|
|
617
664
|
def _display_detailed_result_with_job_info(self, job_status, job_id: str, detailed_result):
|
|
618
665
|
"""Display detailed result information combined with job info"""
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
666
|
+
from rich.panel import Panel
|
|
667
|
+
from ..formatters.registry import FormatterRegistry
|
|
668
|
+
|
|
669
|
+
# Determine status color and emoji
|
|
670
|
+
status_emoji = "✅" if hasattr(detailed_result, 'status') and detailed_result.status == 'ok' else "❌"
|
|
671
|
+
status_color = "green" if hasattr(detailed_result, 'status') and detailed_result.status == 'ok' else "red"
|
|
672
|
+
|
|
673
|
+
# Basic information
|
|
674
|
+
basic_info = f"""[bold cyan]Basic Information:[/bold cyan]
|
|
675
|
+
• Result ID: [white]{detailed_result.id if hasattr(detailed_result, 'id') else 'Unknown'}[/white]
|
|
676
|
+
• Check ID: [white]{detailed_result.check_id if hasattr(detailed_result, 'check_id') and detailed_result.check_id else 'None'}[/white]
|
|
677
|
+
• Status: [{status_color}]{status_emoji} {detailed_result.status if hasattr(detailed_result, 'status') else 'Unknown'}[/{status_color}]
|
|
678
|
+
• Timestamp: [white]{detailed_result.created_at.strftime('%Y-%m-%d %H:%M:%S UTC') if hasattr(detailed_result, 'created_at') and detailed_result.created_at else 'Unknown'}[/white]"""
|
|
679
|
+
|
|
680
|
+
if hasattr(detailed_result, 'response_time') and detailed_result.response_time:
|
|
681
|
+
basic_info += f"\n• Response Time: [yellow]{detailed_result.response_time}ms[/yellow]"
|
|
622
682
|
|
|
623
|
-
#
|
|
683
|
+
# Server information
|
|
684
|
+
if hasattr(detailed_result, 'check_server') and detailed_result.check_server:
|
|
685
|
+
server = detailed_result.check_server
|
|
686
|
+
server_info = f"""• Check Server: [white]{server.id if hasattr(server, 'id') else 'Unknown'}[/white]
|
|
687
|
+
• Server IP: [white]{server.ip_address if hasattr(server, 'ip_address') else 'Unknown'}[/white]
|
|
688
|
+
• Server Country: [white]{server.country if hasattr(server, 'country') else 'Unknown'}[/white]
|
|
689
|
+
• Server Region: [white]{server.region if hasattr(server, 'region') else 'Unknown'}[/white]"""
|
|
690
|
+
basic_info += f"\n{server_info}"
|
|
691
|
+
|
|
692
|
+
# Error information
|
|
693
|
+
error_info = ""
|
|
694
|
+
if hasattr(detailed_result, 'error_message') and detailed_result.error_message:
|
|
695
|
+
error_info = f"""
|
|
696
|
+
[bold red]Error Information:[/bold red]
|
|
697
|
+
• Error: [red]{detailed_result.error_message}[/red]"""
|
|
698
|
+
|
|
699
|
+
# Metadata analysis using formatters
|
|
700
|
+
metadata_info = ""
|
|
624
701
|
if hasattr(detailed_result, 'check_metadata') and detailed_result.check_metadata:
|
|
625
|
-
|
|
626
|
-
registry = FormatterRegistry(verbose=False)
|
|
627
|
-
metadata_formatted = registry.format_metadata(detailed_result.check_metadata)
|
|
702
|
+
metadata = detailed_result.check_metadata
|
|
628
703
|
|
|
629
|
-
if
|
|
630
|
-
self.
|
|
631
|
-
|
|
704
|
+
if isinstance(metadata, dict):
|
|
705
|
+
registry = FormatterRegistry(verbose=self.verbose)
|
|
706
|
+
metadata_info = registry.format_metadata(metadata)
|
|
707
|
+
|
|
708
|
+
# Combine all sections
|
|
709
|
+
full_info = basic_info
|
|
710
|
+
if error_info:
|
|
711
|
+
full_info += error_info
|
|
712
|
+
if metadata_info:
|
|
713
|
+
full_info += metadata_info
|
|
714
|
+
|
|
715
|
+
panel = Panel(
|
|
716
|
+
full_info,
|
|
717
|
+
title=f"🔍 Result Details: {detailed_result.id if hasattr(detailed_result, 'id') else 'Unknown'}",
|
|
718
|
+
border_style="blue",
|
|
719
|
+
padding=(1, 2),
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
self.console.print(panel)
|
|
632
723
|
|
|
633
724
|
def _display_detailed_job_status(self, job_status, job_id: str):
|
|
634
725
|
"""Display detailed job status information in a rich format"""
|
|
@@ -806,7 +897,7 @@ class OnDemandChecksCommand(BaseCommand):
|
|
|
806
897
|
time.sleep(0.5) # Brief pause to show completion
|
|
807
898
|
|
|
808
899
|
# Fetch and display the actual result
|
|
809
|
-
self._fetch_and_display_job_result(job_id, job_status)
|
|
900
|
+
self._fetch_and_display_job_result(job_id, job_status, verbose=self.verbose)
|
|
810
901
|
return
|
|
811
902
|
|
|
812
903
|
elif job_status.status == 'running':
|
|
@@ -858,6 +949,12 @@ def get_output_format():
|
|
|
858
949
|
return get_config().get('output_format', 'table')
|
|
859
950
|
|
|
860
951
|
|
|
952
|
+
def get_verbose_mode():
|
|
953
|
+
"""Get verbose mode from config"""
|
|
954
|
+
from ..utils.config import get_verbose_mode as _get_verbose_mode
|
|
955
|
+
return _get_verbose_mode()
|
|
956
|
+
|
|
957
|
+
|
|
861
958
|
@run_app.command("custom")
|
|
862
959
|
def run_custom_check(
|
|
863
960
|
url: Optional[str] = typer.Option(None, "--url", "-u", help="URL to monitor (required for web, api, ssl checks)"),
|
|
@@ -885,7 +982,7 @@ def run_custom_check(
|
|
|
885
982
|
- tcp: --host required, --port optional
|
|
886
983
|
- ssl: --url or --host required
|
|
887
984
|
- synthetic/multistep: --pw-script-file or --parameters with pw_script required"""
|
|
888
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
985
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
889
986
|
on_demand_cmd.execute_custom_check(url, check_type, host, port, timeout, name, parameters, pw_script_file, from_file, not no_wait)
|
|
890
987
|
|
|
891
988
|
|
|
@@ -895,7 +992,7 @@ def run_existing_check(
|
|
|
895
992
|
no_wait: bool = typer.Option(False, "--no-wait", help="Don't wait for job completion, just queue the check and return job ID"),
|
|
896
993
|
):
|
|
897
994
|
"""Execute existing check on demand. By default, waits for job completion and shows result immediately (max 5 minutes). Use --no-wait to just queue the check."""
|
|
898
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
995
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
899
996
|
on_demand_cmd.execute_existing_check(check_id, not no_wait)
|
|
900
997
|
|
|
901
998
|
|
|
@@ -905,7 +1002,7 @@ def list_jobs(
|
|
|
905
1002
|
page_size: int = typer.Option(20, "--page-size", "-s", help="Items per page"),
|
|
906
1003
|
):
|
|
907
1004
|
"""List check jobs"""
|
|
908
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
1005
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
909
1006
|
on_demand_cmd.list_jobs(page, page_size)
|
|
910
1007
|
|
|
911
1008
|
|
|
@@ -914,5 +1011,5 @@ def get_job_status(
|
|
|
914
1011
|
job_id: str = typer.Argument(..., help="Job ID to get status for"),
|
|
915
1012
|
):
|
|
916
1013
|
"""Get job status and results. For multi-region executions, shows aggregated statistics and regional summary."""
|
|
917
|
-
on_demand_cmd = OnDemandChecksCommand(get_output_format())
|
|
1014
|
+
on_demand_cmd = OnDemandChecksCommand(get_output_format(), verbose=get_verbose_mode())
|
|
918
1015
|
on_demand_cmd.get_job_status(job_id)
|
|
@@ -196,9 +196,10 @@ def main(
|
|
|
196
196
|
if verbose:
|
|
197
197
|
console.print("[dim]Verbose mode enabled[/dim]")
|
|
198
198
|
|
|
199
|
-
# Store current output format in config temporarily for subcommands
|
|
200
|
-
from .utils.config import set_output_format as save_output_format
|
|
199
|
+
# Store current output format and verbose mode in config temporarily for subcommands
|
|
200
|
+
from .utils.config import set_output_format as save_output_format, set_verbose_mode
|
|
201
201
|
save_output_format(output)
|
|
202
|
+
set_verbose_mode(verbose)
|
|
202
203
|
|
|
203
204
|
|
|
204
205
|
def cli_entry_point():
|
|
@@ -158,6 +158,32 @@ def get_output_format() -> str:
|
|
|
158
158
|
return config.get('output_format', 'table')
|
|
159
159
|
|
|
160
160
|
|
|
161
|
+
def set_verbose_mode(verbose: bool) -> bool:
|
|
162
|
+
"""
|
|
163
|
+
Set verbose mode in configuration file
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
verbose: Verbose mode flag
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
bool: True if saved successfully, False otherwise
|
|
170
|
+
"""
|
|
171
|
+
config = get_config()
|
|
172
|
+
config['verbose'] = verbose
|
|
173
|
+
return save_config(config)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_verbose_mode() -> bool:
|
|
177
|
+
"""
|
|
178
|
+
Get verbose mode from configuration
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
bool: Verbose mode flag (default: False)
|
|
182
|
+
"""
|
|
183
|
+
config = get_config()
|
|
184
|
+
return config.get('verbose', False)
|
|
185
|
+
|
|
186
|
+
|
|
161
187
|
def validate_config() -> Dict[str, bool]:
|
|
162
188
|
"""
|
|
163
189
|
Validate current configuration
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { test, expect } = require('@playwright/test');
|
|
2
|
+
|
|
3
|
+
test('Basic Screenshot', async ({ page }) => {
|
|
4
|
+
// Navigate to the page
|
|
5
|
+
await page.goto('https://playwright.dev/');
|
|
6
|
+
|
|
7
|
+
// Wait for the page to be in a stable state (e.g., network idle)
|
|
8
|
+
await page.waitForLoadState('load');
|
|
9
|
+
|
|
10
|
+
// Take a full-page screenshot
|
|
11
|
+
await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
|
12
|
+
|
|
13
|
+
console.log('Successfully took a full-page screenshot.');
|
|
14
|
+
});
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|