[Enhancement] custom metadata support for testcases and keywords#5495
[Enhancement] custom metadata support for testcases and keywords#5495febb0e wants to merge 22 commits into
Conversation
- Add support for custom metadata tags in test cases and keywords - Include test file with examples of custom metadata usage - Enhance parsing and model handling for custom metadata - Update XML schema and output generation for metadata support
…us/robotframework into feature/custom-metadata-enhancements
- Introduced `CustomMetadata` setting in RobotSettings. - Updated parsing and lexing logic to validate custom metadata. - Enhanced command-line options to specify allowed custom metadata names. - Modified relevant classes and methods to accommodate custom metadata.
…ting documentation
…ve initialization in transformers and model classes; update tests to accommodate changes in metadata structure.
…ing names and updating documentation for command line options
…mprove validation checks, and ensure consistent initialization across settings and builders.
- Implement tests for custom metadata in the TestSuiteBuilder, covering basic filtering, keywords, special values, case sensitivity, and integration with FileSettings. - Create tests for custom metadata modifiers, including access and modification during pre-run and execution phases, complex filtering, and error handling. - Develop tests for UserKeyword custom metadata, ensuring handling of various data types, normalization, and integration. - Validate custom metadata behavior with embedded arguments, setup/teardown, and keyword binding.
|
Hello @Bouska , thank you for the valuable feedback! Typos have caused some discussion when developing this feature. Originally, the most popular opinion has been to let fail, when it has custom metadata. You would have to provide a list of all custom metadata at launch so that typos may be prevented: That approach has been altered for the opinion that metadata should be only metadata and not influence the default execution. Also, the use cases we know want to provide many custom metadata pairs. Adding them on CLI would not be feasible. I like your highlight on typo management, compatibility and least surprise. Do you have an idea how to satisfy all expectations? |
|
I really would like to see this merged as it would help us to store custom Zephyr Scale related metadata directly in the tests. |
I would go for the following: So it is a mirror on how |
|
Now that RF 7.4 is out hand the holiday season is behind us, I finally have time to review this PR. This is a pretty big change so I expect there to be quite a bit of work before we can get this merged, but we also have good time for that and hopefully can get this in for RF 7.5. Before I take a deeper look at this, I'd like to make sure @febb0e and/or others who have worked with this are available to answer questions and react to review comments. Related to that, is the PR in general ready for review or is there something you are still working with? At least the unfortunate conflicts would need to be resolved at some point. I don't know why, but GitHub doesn't show me what conflicts there are. |
…us/robotframework into feature/custom-metadata-enhancements
There was a problem hiding this comment.
Pull request overview
Adds first-class custom metadata support for Robot Framework test cases and user keywords using [CustomName] settings, with optional filtering via the new --custommetadata CLI option, and surfaces the metadata in result models and log/report outputs.
Changes:
- Extend lexer/parser/builder pipelines to recognize unknown
[Setting]tokens in test/keyword contexts asCUSTOM_METADATAand store them on models. - Add CLI plumbing (
--custommetadata) and filtering so only selected metadata keys propagate to built models and outputs. - Emit and consume custom metadata in outputs (XML
<meta>, JSON, JS model, HTML log/report) and add extensive unit/acceptance tests plus schema updates.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| utest/running/test_userkeyword_custom_metadata.py | Unit tests for UserKeyword.custom_metadata behavior and serialization. |
| utest/running/test_custom_metadata_modifiers.py | Verifies modifiers/listeners can read/write custom metadata on execution model. |
| utest/running/test_custom_metadata_builder.py | Tests builder-layer parsing and CLI filtering behavior for tests/keywords. |
| utest/running/test_builder_custom_metadata.py | Additional builder tests for edge cases (multiline, unicode, variables). |
| utest/result/test_keyword_custom_metadata.py | Tests result-model Keyword custom metadata behavior and serialization. |
| utest/reporting/test_jsmodelbuilders.py | Updates JS model expectations for added metadata fields and index shifts. |
| utest/parsing/test_custom_metadata_lexer.py | Lexer-level tests for CUSTOM_METADATA tokenization and context validation. |
| utest/model/test_testcase_custom_metadata.py | Model-level tests for TestCase.custom_metadata and copy/deepcopy semantics. |
| utest/model/test_keyword.py | Adds tests for keyword custom metadata and bind/copy behavior. |
| utest/model/test_custom_metadata_model.py | Cross-model tests ensuring consistent metadata behavior across model types. |
| utest/cli/test_custom_metadata_cli.py | Verifies --custommetadata is documented and settings propagation works. |
| src/robot/running/userkeywordrunner.py | Copies resolved keyword custom metadata into result keywords during execution. |
| src/robot/running/suiterunner.py | Copies resolved test custom metadata into result tests during execution. |
| src/robot/running/resourcemodel.py | Adds custom_metadata + has_custom_metadata for running UserKeyword and serializes it. |
| src/robot/running/model.py | Adds running TestCase.custom_metadata and has_custom_metadata. |
| src/robot/running/builder/transformers.py | Captures CustomMetadata statements into running models; applies CLI filtering. |
| src/robot/running/builder/settings.py | Adds FileSettings.custom_metadata allowlist and should_include_custom_metadata(). |
| src/robot/running/builder/parsers.py | Threads custom metadata allowlist through parsing/building pipeline. |
| src/robot/running/builder/builders.py | Adds custom_metadata parameter to suite builder construction. |
| src/robot/run.py | Documents --custommetadata and passes it into suite building. |
| src/robot/result/xmlelementhandlers.py | Allows <meta> under test/keyword and routes it to custom_metadata when applicable. |
| src/robot/result/model.py | Adds result keyword custom metadata support and includes it in to_dict(). |
| src/robot/reporting/jsmodelbuilders.py | Adds custom metadata to JS model for tests/keywords used by HTML log/report. |
| src/robot/parsing/parser/parser.py | Threads allowed_custom_metadata through get_model/get_resource_model/get_init_model. |
| src/robot/parsing/model/statements.py | Introduces CustomMetadata statement type derived from DocumentationOrMetadata. |
| src/robot/parsing/lexer/tokens.py | Adds Token.CUSTOM_METADATA. |
| src/robot/parsing/lexer/settings.py | Recognizes [CustomName] as CUSTOM_METADATA in test/keyword settings; errors in invalid contexts. |
| src/robot/parsing/lexer/lexer.py | Adds allowed_custom_metadata plumbing into lexer contexts. |
| src/robot/parsing/lexer/context.py | Passes allowlist into FileSettings-backed lexing contexts. |
| src/robot/output/xmllogger.py | Writes test/keyword custom metadata as <meta name="...">value</meta> elements. |
| src/robot/output/jsonlogger.py | Adds test custom_metadata emission to JSON output. |
| src/robot/model/testcase.py | Adds custom_metadata and has_custom_metadata to the base model TestCase. |
| src/robot/htmldata/rebot/testdata.js | Parses metadata from JS model arrays; adjusts indexes for new metadata field. |
| src/robot/htmldata/rebot/model.js | Stores metadata on Test/Keyword client-side models. |
| src/robot/htmldata/rebot/log.html | Renders custom metadata rows for tests/keywords in the log UI. |
| src/robot/conf/settings.py | Adds CustomMetadata to settings mapping and accessor. |
| src/robot/api/parsing.py | Exposes CustomMetadata in public parsing API exports. |
| doc/schema/running_suite.json | Adds custom_metadata to running-suite JSON schema. |
| doc/schema/running_json_schema.py | Adds custom_metadata fields to running schema Python models. |
| doc/schema/result_suite.json | Adds custom_metadata to result-suite JSON schema. |
| doc/schema/result_json_schema.py | Adds custom_metadata field to result schema Python models. |
| doc/schema/result.xsd | Allows <meta> under <test> and <kw> elements. |
| doc/schema/result.json | Adds custom_metadata to result JSON schema variant. |
| atest/testdata/parsing/custom_metadata_with_variables.robot | Acceptance data for variables/expressions inside custom metadata. |
| atest/testdata/parsing/custom_metadata_missing_vars.robot | Acceptance data for missing variable handling in metadata. |
| atest/testdata/parsing/custom_metadata_env_vars.robot | Acceptance data for environment variable handling in metadata. |
| atest/testdata/parsing/custom_metadata.robot | Acceptance data for broad metadata edge cases and keyword metadata. |
| atest/robot/parsing/custom_metadata.robot | Acceptance tests validating parsing and variable resolution behaviors. |
| atest/robot/output/custom_metadata_output.robot | Acceptance tests validating XML/HTML output contains custom metadata. |
| atest/robot/cli/runner/custom_metadata.robot | Acceptance tests for --custommetadata filtering behavior in robot. |
| atest/robot/cli/rebot/custom_metadata.robot | Acceptance tests for preservation/filtering in rebot workflows. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "lineno", | ||
| "_setup", | ||
| "_teardown", | ||
| "_custom_metadata", | ||
| ) |
There was a problem hiding this comment.
_custom_metadata is added to __slots__, but the actual storage used by the @setter-decorated custom_metadata attribute is _setter__custom_metadata (added automatically by SetterAwareType). The extra _custom_metadata slot (and the later self._custom_metadata = None) appears unused and can be removed to avoid confusion and unnecessary per-instance storage.
| # Validate custom metadata name pattern - allow letters, numbers, spaces, hyphens, underscores, dots, slashes | ||
| import re | ||
|
|
||
| if not re.match(r"^[a-zA-Z0-9\s\-_./]+$", inner_content): | ||
| return False |
There was a problem hiding this comment.
import re and re.match(...) are executed every time _is_custom_metadata_setting() runs. Because this code is on the hot path when lexing large files, it would be better to move the regex compilation to module scope (e.g. a precompiled pattern) and reuse it here.
| # Validate custom metadata name pattern - allow letters, numbers, spaces, hyphens, underscores, dots, slashes | ||
| import re | ||
|
|
||
| if not re.match(r"^[a-zA-Z0-9\s\-_./]+$", inner_content): | ||
| return False |
There was a problem hiding this comment.
This function imports re and runs re.match(...) on every call. Since lexing runs this for many settings lines, consider using a module-level precompiled regex/pattern to avoid repeated imports/compilation work.
| __slots__ = ( | ||
| "status", | ||
| "message", | ||
| "_start_time", | ||
| "_end_time", | ||
| "_elapsed_time", | ||
| "_custom_metadata", | ||
| ) |
There was a problem hiding this comment.
robot.result.model.TestCase inherits robot.model.testcase.TestCase, which now defines a _custom_metadata slot. Re-declaring _custom_metadata in this subclass’ __slots__ will cause a TypeError at class creation due to duplicate slot names. Remove _custom_metadata from this __slots__ (and the corresponding self._custom_metadata assignment) and rely on the base custom_metadata setter storage (_setter__custom_metadata).
| self.template = template | ||
| self.error = error | ||
| # Initialize the custom metadata setter attribute to prevent AttributeError during copy | ||
| self._setter__custom_metadata = None |
There was a problem hiding this comment.
Setting self._setter__custom_metadata = None here overrides the base model.TestCase initialization and causes the custom_metadata getter to return None (not an empty Metadata). That can break code that expects test.custom_metadata to be dict-like even when empty (e.g. dict(test.custom_metadata)). Consider removing this assignment (and relying on the base initialization) or initializing it to Metadata() instead of None.
| # Handle line continuations by replacing newlines with spaces | ||
| if node.value: | ||
| metadata_value = " ".join(node.value.split()) | ||
| else: | ||
| metadata_value = "" |
There was a problem hiding this comment.
metadata_value = " ".join(node.value.split()) collapses all whitespace and removes newlines, which loses formatting and makes multi-line metadata impossible to preserve. If the intent is only to handle continuations, consider keeping node.value as-is (it already contains the correctly joined lines) or doing a more targeted newline handling instead of split().
| # Handle line continuations by replacing newlines with spaces | ||
| if node.value: | ||
| metadata_value = " ".join(node.value.split()) | ||
| else: | ||
| metadata_value = "" |
There was a problem hiding this comment.
This whitespace handling (" ".join(node.value.split())) collapses all whitespace and strips newlines from custom metadata values, which discards intentional formatting. Using node.value directly (or only replacing the continuation newlines) would preserve the value more faithfully.

Custom Metadata Feature
Closes #4409
Overview
Introduces custom metadata feature for test cases and user keywords. The implementation allows users to define metadata for both test cases and keywords using the
[CustomName]syntax.Implementation Details
[Owner],[Requirement],[My Custom Metadata]) is now treated as custom metadata.[UndefinedSetting]) will now treat these as valid custom metadata.CLI Functionality:
--custommetadataFlag--custommetadataflag allows users to filter which custom metadata keys are considered "valid" for display and parsing in output files.Test Coverage
--custommetadataNotable Changes
Summary
This feature allows users to create tests and keywords with metadata they need. Custom metadata values support the same formatting as settings metadata (
*bold*,_italic_,`code`), variable resolution, multi-line content, etc. The--custommetadataflag provides control over output, without affecting test execution.Usage Examples
Basic Custom Metadata
Variable Resolution
Text Formatting
Inline Python Evaluation
Keyword Metadata
CLI Filtering Examples