From 80df81494347fa5dd2c7cdba8f8e02adc8d5688b Mon Sep 17 00:00:00 2001 From: "pavel.butuzov" Date: Mon, 14 Sep 2026 10:29:25 +0300 Subject: [PATCH] feat: TMS-41085: add the "workItemId" annotation. --- testit-adapter-behave/README.md | 8 +++++--- .../src/testit_adapter_behave/models/tags.py | 1 + .../src/testit_adapter_behave/scenario_parser.py | 5 ++++- .../src/testit_adapter_behave/tags_parser.py | 8 +++++++- testit-adapter-nose/README.md | 8 +++++--- testit-adapter-pytest/README.md | 8 +++++--- testit-adapter-robotframework/README.md | 3 ++- testit-python-commons/src/testit.py | 4 ++++ .../src/testit_python_commons/decorators.py | 15 ++++++++++++++- .../src/testit_python_commons/dynamic_methods.py | 12 ++++++++++++ 10 files changed, 59 insertions(+), 13 deletions(-) diff --git a/testit-adapter-behave/README.md b/testit-adapter-behave/README.md index 50542bd3..bfe07d2e 100644 --- a/testit-adapter-behave/README.md +++ b/testit-adapter-behave/README.md @@ -110,7 +110,8 @@ Use tags to specify information about autotest. Description of tags: -- `WorkItemIds` - a method that links autotests with manual tests. Receives the array of manual tests' IDs +- `WorkItemId` - a method that links an autotest with a manual test. Receives a single globalId +- `WorkItemIds` - deprecated, use `WorkItemId` instead - `DisplayName` - internal autotest name (used in Test IT) - `ExternalId` - unique internal autotest ID (used in Test IT) - `Title` - autotest name specified in the autotest card. If not specified, the name from the displayName method is used @@ -126,7 +127,8 @@ If you want to insert a space in the tags, use the "\\_" character combination. Description of methods: -- `testit.addWorkItemIds` - a dynamic method that links autotests with manual tests. Receives the array of manual tests' IDs +- `testit.addWorkItemId` - a dynamic method that links an autotest with a manual test. Receives a single globalId +- `testit.addWorkItemIds` - deprecated, use `testit.addWorkItemId` instead - `testit.addDisplayName` - a dynamic method for adding internal autotest name (used in Test IT) - `testit.addExternalId` - a dynamic method for adding unique internal autotest ID (used in Test IT) - `testit.addTitle` - a dynamic method for adding autotest name specified in the autotest card. If not specified, the name from the displayName method is used @@ -193,7 +195,7 @@ Feature: Sample @ExternalId=failed_with_all_annotations @DisplayName=Failed_test_with_all_annotations - @WorkItemIds=123 + @WorkItemId=123 @Title=Title_in_the_autotest_card @Description=Test_with_all_annotations @Tags=Tag1,Tag2 diff --git a/testit-adapter-behave/src/testit_adapter_behave/models/tags.py b/testit-adapter-behave/src/testit_adapter_behave/models/tags.py index df0715a8..64420560 100644 --- a/testit-adapter-behave/src/testit_adapter_behave/models/tags.py +++ b/testit-adapter-behave/src/testit_adapter_behave/models/tags.py @@ -4,6 +4,7 @@ class TagType: LINKS = 'Links=' TITLE = 'Title=' WORK_ITEM_IDS = 'WorkItemIds=' + WORK_ITEM_ID = 'WorkItemId=' DESCRIPTION = 'Description=' LABELS = 'Labels=' TAGS = 'Tags=' diff --git a/testit-adapter-behave/src/testit_adapter_behave/scenario_parser.py b/testit-adapter-behave/src/testit_adapter_behave/scenario_parser.py index fcdc85b6..cf71c161 100644 --- a/testit-adapter-behave/src/testit_adapter_behave/scenario_parser.py +++ b/testit-adapter-behave/src/testit_adapter_behave/scenario_parser.py @@ -86,10 +86,13 @@ def parse_scenario(scenario): if TagType.CLASSNAME in tags: executable_test['classname'] = tags[TagType.CLASSNAME] - if TagType.WORK_ITEM_IDS in tags: + if TagType.WORK_ITEM_IDS in tags and tags[TagType.WORK_ITEM_IDS]: # TODO: Fix in python-commons to "workItemIds" executable_test['workItemsID'] = tags[TagType.WORK_ITEM_IDS] + if TagType.WORK_ITEM_ID in tags and tags[TagType.WORK_ITEM_ID]: + executable_test['workItemsID'] = [tags[TagType.WORK_ITEM_ID]] + if TagType.LAYER in tags and tags[TagType.LAYER]: executable_test['layer'] = tags[TagType.LAYER] diff --git a/testit-adapter-behave/src/testit_adapter_behave/tags_parser.py b/testit-adapter-behave/src/testit_adapter_behave/tags_parser.py index 9781c6cd..91cab3ce 100644 --- a/testit-adapter-behave/src/testit_adapter_behave/tags_parser.py +++ b/testit-adapter-behave/src/testit_adapter_behave/tags_parser.py @@ -1,6 +1,7 @@ from .models.label import get_label_model from .models.tags import TagType from .models.url_link import get_url_to_link_model, get_dict_to_link_model +import logging def parse_test_tags(tags): @@ -10,6 +11,7 @@ def parse_test_tags(tags): TagType.LINKS: [], TagType.TITLE: None, TagType.WORK_ITEM_IDS: [], + TagType.WORK_ITEM_ID: None, TagType.DESCRIPTION: None, TagType.LABELS: [], TagType.TAGS: [], @@ -32,10 +34,14 @@ def parse_test_tags(tags): elif TagType.TITLE in tag: parsed_tags[TagType.TITLE] = __parse_space_in_tag(tag[len(TagType.TITLE):]) - elif TagType.WORK_ITEM_IDS in tag: + elif tag.startswith(TagType.WORK_ITEM_IDS): + logging.warning('WorkItemIds is deprecated. Use WorkItemId with a single globalId instead.') parsed_tags[TagType.WORK_ITEM_IDS].extend( __parse_massive(tag[len(TagType.WORK_ITEM_IDS):])) + elif tag.startswith(TagType.WORK_ITEM_ID): + parsed_tags[TagType.WORK_ITEM_ID] = __parse_space_in_tag(tag[len(TagType.WORK_ITEM_ID):]) + elif TagType.DESCRIPTION in tag: parsed_tags[TagType.DESCRIPTION] = __parse_space_in_tag(tag[len(TagType.DESCRIPTION):]) diff --git a/testit-adapter-nose/README.md b/testit-adapter-nose/README.md index 0fb70f1d..9a519374 100644 --- a/testit-adapter-nose/README.md +++ b/testit-adapter-nose/README.md @@ -94,7 +94,8 @@ Decorators can be used to specify information about autotest. Description of decorators: -- `testit.workItemIds` - a method that links autotests with manual tests. Receives the array of manual tests' IDs +- `testit.workItemId` - a method that links an autotest with a manual test. Receives a single globalId +- `testit.workItemIds` - deprecated, use `testit.workItemId` instead - `testit.displayName` - internal autotest name (used in Test IT) - `testit.externalId` - unique internal autotest ID (used in Test IT) - `testit.title` - autotest name specified in the autotest card. If not specified, the name from the displayName method is used @@ -111,7 +112,8 @@ All decorators support the use of parameterization attributes Description of methods: -- `testit.addWorkItemIds` - a dynamic method that links autotests with manual tests. Receives the array of manual tests' IDs +- `testit.addWorkItemId` - a dynamic method that links an autotest with a manual test. Receives a single globalId +- `testit.addWorkItemIds` - deprecated, use `testit.addWorkItemId` instead - `testit.addDisplayName` - a dynamic method for adding internal autotest name (used in Test IT) - `testit.addExternalId` - a dynamic method for adding unique internal autotest ID (used in Test IT) - `testit.addTitle` - a dynamic method for adding autotest name specified in the autotest card. If not specified, the name from the displayName method is used @@ -189,7 +191,7 @@ import testit from nose2.tools import params @params(1, 2, 3) -@testit.workItemIds(627) +@testit.workItemId(627) @testit.externalId('param {num}') @testit.displayName('param {num}') @testit.title('Test with params') diff --git a/testit-adapter-pytest/README.md b/testit-adapter-pytest/README.md index ab0be0bf..422218bb 100644 --- a/testit-adapter-pytest/README.md +++ b/testit-adapter-pytest/README.md @@ -106,7 +106,8 @@ Decorators can be used to specify information about autotest. Description of decorators: -- `testit.workItemIds` - a method that links autotests with manual tests. Receives the array of manual tests' IDs +- `testit.workItemId` - a method that links an autotest with a manual test. Receives a single globalId +- `testit.workItemIds` - deprecated, use `testit.workItemId` instead - `testit.displayName` - internal autotest name (used in Test IT) - `testit.externalId` - unique internal autotest ID (used in Test IT) - `testit.title` - autotest name specified in the autotest card. If not specified, the name from the displayName method is used @@ -123,7 +124,8 @@ All decorators support the use of parameterization attributes Description of methods: -- `testit.addWorkItemIds` - a dynamic method that links autotests with manual tests. Receives the array of manual tests' IDs +- `testit.addWorkItemId` - a dynamic method that links an autotest with a manual test. Receives a single globalId +- `testit.addWorkItemIds` - deprecated, use `testit.addWorkItemId` instead - `testit.addDisplayName` - a dynamic method for adding internal autotest name (used in Test IT) - `testit.addExternalId` - a dynamic method for adding unique internal autotest ID (used in Test IT) - `testit.addTitle` - a dynamic method for adding autotest name specified in the autotest card. If not specified, the name from the displayName method is used @@ -220,7 +222,7 @@ import pytest import testit -@testit.workItemIds(627) +@testit.workItemId(627) @testit.displayName('Simple autotest 1 - {name}') @testit.externalId('Simple_autotest1_{name}') @testit.title('Authorization') diff --git a/testit-adapter-robotframework/README.md b/testit-adapter-robotframework/README.md index 860c0e0f..ddb03934 100644 --- a/testit-adapter-robotframework/README.md +++ b/testit-adapter-robotframework/README.md @@ -116,7 +116,8 @@ Description of scenario methods: - `Add Message` - information about autotest in the autotest result Description of methods: -- `testit.addWorkItemIds` - a dynamic method that links autotests with manual tests. Receives the array of manual tests' IDs +- `testit.addWorkItemId` - a dynamic method that links an autotest with a manual test. Receives a single globalId +- `testit.addWorkItemIds` - deprecated, use `testit.addWorkItemId` instead - `testit.addDisplayName` - a dynamic method for adding internal autotest name (used in Test IT) - `testit.addExternalId` - a dynamic method for adding unique internal autotest ID (used in Test IT) - `testit.addTitle` - a dynamic method for adding autotest name specified in the autotest card. If not specified, the name from the displayName method is used diff --git a/testit-python-commons/src/testit.py b/testit-python-commons/src/testit.py index 55b2949d..8b3f10df 100644 --- a/testit-python-commons/src/testit.py +++ b/testit-python-commons/src/testit.py @@ -12,6 +12,7 @@ nameSpace, title, workItemID, + workItemId, workItemIds ) from testit_python_commons.dynamic_methods import ( @@ -19,6 +20,7 @@ addLink, addLinks, addMessage, + addWorkItemId, addWorkItemIds, addDisplayName, addNameSpace, @@ -43,6 +45,7 @@ 'nameSpace', 'className', 'workItemID', + 'workItemId', 'workItemIds', 'title', 'description', @@ -57,6 +60,7 @@ 'addAttachments', 'message', 'addMessage', + 'addWorkItemId', 'addWorkItemIds', 'addDisplayName', 'addNameSpace', diff --git a/testit-python-commons/src/testit_python_commons/decorators.py b/testit-python-commons/src/testit_python_commons/decorators.py index 0d1ac353..31e99a06 100644 --- a/testit-python-commons/src/testit_python_commons/decorators.py +++ b/testit-python-commons/src/testit_python_commons/decorators.py @@ -37,7 +37,7 @@ async def async_wrapper(*args, **kwargs): return function -@Utils.deprecated('Use "workItemIds" instead.') +@Utils.deprecated('Use "workItemId" instead.') @adapter_logger def workItemID(*test_workitems_id: int or str): # noqa: N802 def outer(function): @@ -49,6 +49,19 @@ def outer(function): return outer +@adapter_logger +def workItemId(globalId: int or str): # noqa: N802 + """ + specifies a method that links an autotest with a manual test. Receives a single globalId + """ + def outer(function): + function.test_workitems_id = [str(globalId)] + return inner(function) + + return outer + + +@Utils.deprecated('Use "workItemId" instead.') @adapter_logger def workItemIds(*test_workitems_id: int or str): # noqa: N802 """ diff --git a/testit-python-commons/src/testit_python_commons/dynamic_methods.py b/testit-python-commons/src/testit_python_commons/dynamic_methods.py index 8a616c70..4a988d93 100644 --- a/testit-python-commons/src/testit_python_commons/dynamic_methods.py +++ b/testit-python-commons/src/testit_python_commons/dynamic_methods.py @@ -130,6 +130,7 @@ def __add_attachments_to_test(data, is_text: bool = False, name: str = None): logging.warning(f'({data}) is not path!') +@Utils.deprecated('Use "addWorkItemId" instead.') @adapter_logger def addWorkItemIds(*test_work_item_ids: int or str): # noqa: N802 """ @@ -142,6 +143,17 @@ def addWorkItemIds(*test_work_item_ids: int or str): # noqa: N802 TmsPluginManager.get_plugin_manager().hook.add_work_item_id(test_work_item_id=str(test_work_item_id)) +@adapter_logger +def addWorkItemId(globalId: int or str): # noqa: N802 + """ + a dynamic method that links an autotest with a manual test. Receives a single globalId + """ + if not hasattr(TmsPluginManager.get_plugin_manager().hook, 'add_work_item_id'): + return + + TmsPluginManager.get_plugin_manager().hook.add_work_item_id(test_work_item_id=str(globalId)) + + @adapter_logger def addDisplayName(test_display_name: str): # noqa: N802 """