diff --git a/RUN_COMMANDS.md b/RUN_COMMANDS.md index 26ea073..559f072 100644 --- a/RUN_COMMANDS.md +++ b/RUN_COMMANDS.md @@ -77,6 +77,10 @@ Token timing settings belong to each product independently. Use `pytest tests\setup -s` to run all enabled products. Each product runs in its own browser: both flags true runs session then the product's token flow in one login; otherwise only its enabled action runs. Test/report names include the product name. +Screenshot and log folders use the collected product and action, such as +`IDAS_SESSION_TOKEN_001`, `RTM_TOKEN_001`, or `RTM_SESSION_001`. +The shared HTML report for `tests\setup` uses `PXIL_SETUP_###.html`. +Existing report folders retain their original names. The session and token subfolder commands below select only products configured for session-only and token-only respectively; use the full setup command for a mixture of modes. diff --git a/tests/conftest.py b/tests/conftest.py index 64d18c5..a3d0b34 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,15 +5,15 @@ import json from tests.browser import create_chrome_driver -def get_run_id(config): +def get_run_id(config, prefix=None): - run_id = getattr(config, "_pxil_run_id", None) - if run_id: - return run_id + run_prefix = prefix or _get_run_prefix(config) + run_ids = getattr(config, "_pxil_run_ids", {}) + if run_prefix in run_ids: + return run_ids[run_prefix] base_folder = os.path.join("reports", "screenshots") os.makedirs(base_folder, exist_ok=True) - run_prefix = _get_run_prefix(config) existing = [ name for name in os.listdir(base_folder) @@ -28,10 +28,11 @@ def get_run_id(config): for name in existing if name.split("_")[-1].isdigit() ] - next_number = max(numbers) + 1 + next_number = max(numbers, default=0) + 1 run_id = f"{run_prefix}_{next_number:03d}" - config._pxil_run_id = run_id + run_ids[run_prefix] = run_id + config._pxil_run_ids = run_ids return run_id @@ -66,7 +67,7 @@ def driver(): @pytest.fixture def test_context(request): - test_id = get_run_id(request.config) + test_id = get_run_id(request.config, _setup_item_prefix(request.node)) test_name = request.node.name folder = os.path.abspath( @@ -201,9 +202,28 @@ def _build_steps_html(steps): ) +def _setup_item_prefix(item): + """Use the collected product and flow, including when -k selects a subset.""" + nodeid = item.nodeid.replace("\\", "/") + if "tests/setup/" not in nodeid: + return None + callspec = getattr(item, "callspec", None) + product_config = callspec.params.get("config") if callspec else None + if not isinstance(product_config, dict): + return None + product = product_config["product_name"].upper() + if "test_combined_setup.py" in nodeid: + return f"{product}_SESSION_TOKEN" + if "/sessions/" in nodeid: + return f"{product}_SESSION" + if "/tokens/" in nodeid: + return f"{product}_TOKEN" + return f"{product}_SETUP" + + def _get_run_prefix(config): - invocation_args = " ".join(str(arg) for arg in config.invocation_params.args).lower() + invocation_args = " ".join(str(arg) for arg in config.invocation_params.args).replace("\\", "/").lower() if "tests/setup/sessions" in invocation_args or "test_session.py" in invocation_args: return "PXIL_SESSION" @@ -211,6 +231,9 @@ def _get_run_prefix(config): if "tests/setup/tokens" in invocation_args or "test_trading_token.py" in invocation_args: return "PXIL_TOKEN" + if "tests/setup" in invocation_args or "test_combined_setup.py" in invocation_args: + return "PXIL_SETUP" + runtime_path = os.path.abspath(os.path.join("config", "runtime.json")) if os.path.exists(runtime_path): try: diff --git a/tests/test_report_naming.py b/tests/test_report_naming.py new file mode 100644 index 0000000..94f8d9b --- /dev/null +++ b/tests/test_report_naming.py @@ -0,0 +1,33 @@ +from types import SimpleNamespace + +import pytest + +from tests.conftest import _get_run_prefix, _setup_item_prefix, get_run_id + + +@pytest.mark.parametrize("path,product,expected", [ + ("tests/setup/test_combined_setup.py", "IDAS", "IDAS_SESSION_TOKEN"), + ("tests/setup/test_combined_setup.py", "RTM", "RTM_SESSION_TOKEN"), + ("tests/setup/tokens/test_trading_token.py", "RTM", "RTM_TOKEN"), + ("tests/setup/sessions/test_session.py", "RTM", "RTM_SESSION"), +]) +def test_setup_artifacts_use_collected_product_and_flow(path, product, expected): + item = SimpleNamespace(nodeid=f"{path}::test[{product}]", callspec=SimpleNamespace( + params={"config": {"product_name": product}}, + )) + assert _setup_item_prefix(item) == expected + + +@pytest.mark.parametrize("path", ["tests/setup", "tests\\setup", "tests/setup/test_combined_setup.py"]) +def test_setup_report_does_not_use_regression_config(path): + config = SimpleNamespace(invocation_params=SimpleNamespace(args=(path, "-k", "RTM"))) + assert _get_run_prefix(config) == "PXIL_SETUP" + + +def test_mixed_run_ids_are_cached_separately(tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + (tmp_path / "reports/screenshots/RTM_TOKEN_004").mkdir(parents=True) + config = SimpleNamespace() + assert get_run_id(config, "RTM_TOKEN") == "RTM_TOKEN_005" + assert get_run_id(config, "IDAS_SESSION_TOKEN") == "IDAS_SESSION_TOKEN_001" + assert get_run_id(config, "RTM_TOKEN") == "RTM_TOKEN_005"