diff --git a/README.md b/README.md index 11ff633..fb82b64 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ Note: Test id should be started from letter "T" The plugin supports dividing tests into separate, trackable steps. When reporting to testomat.io, you can view detailed information for each step including execution status, duration, and any errors that occurred. -**Important**: This plugin only supports **reporting** test steps to testomat.io during test execution. Test steps cannot be imported to testomat.io using **sync** option. +**Important**: This plugin only supports **reporting** test steps to testomat.io during test execution. Test steps cannot be imported to testomat.io using **sync** option. Steps reported for skipped and failed test by default. To enable steps reporting for passed tests use **TESTOMATIO_STEPS_PASSED** env variable. Test steps can be implemented using either decorators or context managers, giving you flexibility in how you structure your tests. @@ -233,6 +233,37 @@ def test_book_read(): assert book.read() == text ``` +**Note:** Step is registered when the step code is executed. Therefore, if test mark as skipped(not executed at all) or test code execution stops before step code is executed, step will not be attached to test: +```python +import pytest +from pytestomatio.utils.steps import step + +# Step will not be added in report +@pytest.mark.skip +def test_skipped(): + with step('Step1', 'user'): + assert True + +# Step will not be added in report +def test_exception_raised(): + raise ValueError() + with step('Step1', 'user'): + assert True + +# Step will not be added in report +def test_early_skip(): + pytest.skip() + with step('Step1', 'user'): + assert True + +# Step1 will be added in report, Step2 will not be +def test_nested_step_skip_or_exception(): + with step('Step1', 'user'): + with step('Step2', 'user'): + pytest.skip() # or AttributeError() +``` + + ### Configuration with environment variables You can use environment variable to control certain features of testomat.io diff --git a/pytestomatio/main.py b/pytestomatio/main.py index d0c2830..a274762 100644 --- a/pytestomatio/main.py +++ b/pytestomatio/main.py @@ -232,12 +232,15 @@ def pytest_runtest_makereport(item: Item, call: CallInfo): if hasattr(item, 'callspec'): request['example'] = test_item.safe_params(item.callspec.params) + if not pytest.testomatio.test_run_config.disable_steps: + step_manager = _step_managers.get(item.nodeid) + if step_manager: + if call.excinfo is not None or \ + (call.excinfo is None and pytest.testomatio.test_run_config.enable_steps_for_passed_test): + request['steps'] = step_manager.get_steps() + if not pytest.testomatio.test_run_config.disable_timestamp: request['timestamp'] = time.time() - - step_manager = _step_managers.get(item.nodeid) - if step_manager: - request['steps'] = step_manager.get_steps() if item.nodeid not in pytest.testomatio.test_run_config.status_request: pytest.testomatio.test_run_config.status_request[item.nodeid] = request diff --git a/pytestomatio/testomatio/testRunConfig.py b/pytestomatio/testomatio/testRunConfig.py index d6777a8..bb45325 100644 --- a/pytestomatio/testomatio/testRunConfig.py +++ b/pytestomatio/testomatio/testRunConfig.py @@ -15,6 +15,8 @@ def __init__(self, kind: str = 'automated'): disable_batch_upload = os.environ.get('TESTOMATIO_DISABLE_BATCH_UPLOAD') in ['True', 'true', '1'] batch_size = os.environ.get('TESTOMATIO_BATCH_SIZE', '') shared_run = os.environ.get('TESTOMATIO_SHARED_RUN') in ['True', 'true', '1'] + disable_steps = os.environ.get('TESTOMATIO_NO_STEPS') in ['True', 'true', '1'] + enable_steps_for_passed_test = os.environ.get('TESTOMATIO_STEPS_PASSED') in ['True', 'true', '1'] disable_timestamp = os.environ.get('TESTOMATIO_NO_TIMESTAMP') in ['True', 'true', '1'] update_code = os.environ.get('TESTOMATIO_UPDATE_CODE', False) in ['True', 'true', '1'] exclude_skipped = os.environ.get('TESTOMATIO_EXCLUDE_SKIPPED', False) in ['True', 'true', '1'] @@ -22,6 +24,8 @@ def __init__(self, kind: str = 'automated'): self.access_event = 'publish' if os.environ.get("TESTOMATIO_PUBLISH") else None self.test_run_id = run_id self.title = title + self.enable_steps_for_passed_test = enable_steps_for_passed_test + self.disable_steps = disable_steps self.kind = kind self.disable_batch = disable_batch_upload self.batch_size = int(batch_size) if (batch_size.isdigit() and int(batch_size) <= 100) else DEFAULT_BATCH_SIZE diff --git a/tests/test_testomatio/test_testRunConfig.py b/tests/test_testomatio/test_testRunConfig.py index 144ad6c..517701c 100644 --- a/tests/test_testomatio/test_testRunConfig.py +++ b/tests/test_testomatio/test_testRunConfig.py @@ -21,6 +21,8 @@ def test_init_default_values(self): assert config.test_run_id is None assert config.title == "test run at 2024-01-15 10:30:45" assert config.environment is None + assert config.enable_steps_for_passed_test is False + assert config.disable_steps is False assert config.kind == 'automated' assert config.disable_timestamp is False assert config.exclude_skipped is False @@ -44,6 +46,8 @@ def test_init_with_env_variables(self): 'TESTOMATIO_ENV': 'linux,browser:chrome,1920x1080', 'TESTOMATIO_LABEL': 'smoke,regression', 'TESTOMATIO_RUNGROUP_TITLE': 'Release 2.0', + 'TESTOMATIO_NO_STEPS': '1', + 'TESTOMATIO_STEPS_PASSED': '1', 'TESTOMATIO_NO_TIMESTAMP': '1', 'TESTOMATIO_JIRA_ID': 'TES-1', 'TESTOMATIO_UPDATE_CODE': '1', @@ -59,6 +63,8 @@ def test_init_with_env_variables(self): assert config.access_event == 'publish' assert config.test_run_id == 'run_12345' assert config.title == 'Custom Test Run' + assert config.enable_steps_for_passed_test is True + assert config.disable_steps is True assert config.disable_timestamp is True assert config.environment == 'linux,browser:chrome,1920x1080' assert config.exclude_skipped is True @@ -98,6 +104,38 @@ def test_init_shared_run_false_variations(self, value): assert config.shared_run_timeout is None assert config.parallel is True + @pytest.mark.parametrize('value', ['True', 'true', '1']) + def test_init_disable_steps_true_variations(self, value): + """Test different true values for TESTOMATIO_NO_STEPS""" + with patch.dict(os.environ, {'TESTOMATIO_NO_STEPS': value}, clear=True): + config = TestRunConfig() + + assert config.disable_steps is True + + @pytest.mark.parametrize('value', ['False', 'false', '0', 'anything']) + def test_init_disable_steps_false_variations(self, value): + """Test different false values TESTOMATIO_NO_STEPS""" + with patch.dict(os.environ, {'TESTOMATIO_NO_STEPS': value}, clear=True): + config = TestRunConfig() + + assert config.disable_steps is False + + @pytest.mark.parametrize('value', ['True', 'true', '1']) + def test_enable_passed_steps_run_true_variations(self, value): + """Test different true values for TESTOMATIO_STEPS_PASSED""" + with patch.dict(os.environ, {'TESTOMATIO_STEPS_PASSED': value}, clear=True): + config = TestRunConfig() + + assert config.enable_steps_for_passed_test is True + + @pytest.mark.parametrize('value', ['False', 'false', '0', 'anything']) + def test_enable_passed_steps_false_variations(self, value): + """Test different false values TESTOMATIO_STEPS_PASSED""" + with patch.dict(os.environ, {'TESTOMATIO_STEPS_PASSED': value}, clear=True): + config = TestRunConfig() + + assert config.enable_steps_for_passed_test is False + @pytest.mark.parametrize('value', ['True', 'true', '1']) def test_init_disable_timestamp_true_variations(self, value): """Test different true values for TESTOMATIO_NO_TIMESTAMP"""