diff --git a/LOs.csv b/LOs.csv index 83be89a3..527f96ac 100644 --- a/LOs.csv +++ b/LOs.csv @@ -125,11 +125,10 @@ LO-5.1.2.1,(K1),Recall how to define global variables and where they can be acce LO-5.1.2.2,(K1),Recall how to define suite variables and where they can be accessed,,, LO-5.1.2.3,(K1),Recall how to define test|task variables and where they can be accessed,,, LO-5.1.2.4,(K1),Recall how to define local variables and where they can be accessed,,, -LO-5.1.4.1,(K1),Recall that assignments to `@{list}` variables convert values to lists automatically,,, -LO-5.1.4.2,(K1),Recall that `@{list}` unpacks the values of a list variable when accessed,,, -LO-5.1.5.1,(K1),Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access,,, -LO-5.1.5.2,(K1),Recall that `&{dict}` unpacks to multiple key=value pairs when accessed,,, -LO-5.1.6,(K1),Recall that Robot Framework provides access to execution information via Built-In variables,,, +LO-5.1.3.1,(K1),Recall that `@{list}` unpacks the values of a list variable when accessed,,, +LO-5.1.4.1,(K1),Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access,,, +LO-5.1.4.2,(K1),Recall that `&{dict}` unpacks to multiple key=value pairs when accessed,,, +LO-5.1.5,(K1),Recall that Robot Framework provides access to execution information via Built-In variables,,, LO-5.2.1,(K2),Understand the purpose and basic concept of IF-Statements,,, LO-5.2.4,(K2),Understand the purpose and basic concept of FOR Loops,,, LO-5.2.5,(K2),Understand the purpose and basic concept of WHILE Loops,,, diff --git a/README.md b/README.md index 0cefc568..9b65bc66 100644 --- a/README.md +++ b/README.md @@ -266,18 +266,15 @@ - [`5.1.2.4 . Local Scope`](website/docs/chapter-05/01_advanced_variables.md#5124--local-scope) - LO-5.1.2.4 (K1) Recall how to define local variables and where they can be accessed - [`5.1.3 Global Variables via Command Line`](website/docs/chapter-05/01_advanced_variables.md#513-global-variables-via-command-line) -- [`5.1.4 List-Variables (Advanced)`](website/docs/chapter-05/01_advanced_variables.md#514-list-variables-advanced) - - [`5.1.4.1 Assigning List Variables`](website/docs/chapter-05/01_advanced_variables.md#5141-assigning-list-variables) - - LO-5.1.4.1 (K1) Recall that assignments to `@{list}` variables convert values to lists automatically - - [`5.1.4.2 Accessing List Variables`](website/docs/chapter-05/01_advanced_variables.md#5142-accessing-list-variables) - - LO-5.1.4.2 (K1) Recall that `@{list}` unpacks the values of a list variable when accessed -- [`5.1.5 Dict-Like`](website/docs/chapter-05/01_advanced_variables.md#515-dict-like) - - [`5.1.5.1 Assigning Dictionary Variables`](website/docs/chapter-05/01_advanced_variables.md#5151-assigning-dictionary-variables) - - LO-5.1.5.1 (K1) Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access - - [`5.1.5.2 Accessing Dictionary Variables`](website/docs/chapter-05/01_advanced_variables.md#5152-accessing-dictionary-variables) - - LO-5.1.5.2 (K1) Recall that `&{dict}` unpacks to multiple key=value pairs when accessed -- [`5.1.6 Built-In Variables`](website/docs/chapter-05/01_advanced_variables.md#516-built-in-variables) - - LO-5.1.6 (K1) Recall that Robot Framework provides access to execution information via Built-In variables + - [`5.1.3.1 Accessing List Variables`](website/docs/chapter-05/01_advanced_variables.md#5131-accessing-list-variables) + - LO-5.1.3.1 (K1) Recall that `@{list}` unpacks the values of a list variable when accessed +- [`5.1.4 Dict-Like`](website/docs/chapter-05/01_advanced_variables.md#514-dict-like) + - [`5.1.4.1 Assigning Dictionary Variables`](website/docs/chapter-05/01_advanced_variables.md#5141-assigning-dictionary-variables) + - LO-5.1.4.1 (K1) Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access + - [`5.1.4.2 Accessing Dictionary Variables`](website/docs/chapter-05/01_advanced_variables.md#5142-accessing-dictionary-variables) + - LO-5.1.4.2 (K1) Recall that `&{dict}` unpacks to multiple key=value pairs when accessed +- [`5.1.5 Built-In Variables`](website/docs/chapter-05/01_advanced_variables.md#515-built-in-variables) + - LO-5.1.5 (K1) Recall that Robot Framework provides access to execution information via Built-In variables - [`5.2 Control Structures`](website/docs/chapter-05/02_control_structures.md) - [`5.2.1 IF Statements`](website/docs/chapter-05/02_control_structures.md#521-if-statements) - LO-5.2.1 (K2) Understand the purpose and basic concept of IF-Statements diff --git a/tools/GlossaryLinker.md b/tools/GlossaryLinker.md new file mode 100644 index 00000000..114b8310 --- /dev/null +++ b/tools/GlossaryLinker.md @@ -0,0 +1,439 @@ +# Glossary Linker - Complete Guide + +Automated tool for adding glossary links throughout the Robot Framework RFCP Syllabus documentation. + +## 📚 Overview + +This toolkit consists of two scripts that work together: + +1. **`extract_from_json.py`** - Extracts glossary terms from `glossary.json` +2. **`glossary_linker.py`** - Links those terms throughout the documentation + +## ✨ Features + +- ✅ **Case-insensitive matching** - "variable files" links to "Variable File" +- ✅ **Plural/singular support** - "keywords" links to "Keyword" +- ✅ **Test|Task notation** - "Test|Task Setup" links correctly +- ✅ **Smart exclusions** - Skips headings, code blocks, LO blocks +- ✅ **Preserves casing** - Original text casing maintained in links +- ✅ **Relative paths** - Works with Docusaurus navigation + +## 🚀 Complete Workflow + +Follow these steps whenever the glossary is updated or you want to refresh links: + +### Step 1: Extract Terms from Glossary + +```bash +# Navigate to repository +cd ~/Desktop/robotframework-RFCP-syllabus + +# Extract all terms from the glossary JSON file +python3 tools/extract_from_json.py website/static/glossary/glossary.json +``` + +**Output:** +``` +Found 79 glossary terms: + + 1. Acceptance Testing + 2. Adaptation Layer + 3. Atomic Element + ... + +====================================================================== +PYTHON CODE TO ADD TO glossary_linker.py: +====================================================================== + +GLOSSARY_DATA = [ + {"term": "Acceptance Testing", "abbreviation": None}, + {"term": "Adaptation Layer", "abbreviation": None}, + ... +] +``` + +### Step 2: Update glossary_linker.py + +```bash +# Open the linker script +code tools/glossary_linker.py + +# OR use your preferred editor +nano tools/glossary_linker.py +vim tools/glossary_linker.py +``` + +**Manual steps:** +1. Scroll to the bottom of the file +2. Find the `GLOSSARY_DATA = [` section +3. **Replace the entire array** with the output from Step 1 +4. Save the file (Cmd+S or :wq) + +### Step 3: Test with Dry Run + +```bash +# Preview what will change WITHOUT modifying files +python3 tools/glossary_linker.py website/docs --dry-run +``` + +**Expected output:** +``` +Processing: website/docs +Dry run: True +Processed 31 files +Modified 0 files +Total terms linked: 189 +⚠️ DRY RUN - No files were modified +``` + +### Step 4: Apply the Links + +```bash +# Actually modify the files and create links +python3 tools/glossary_linker.py website/docs +``` + +**Output:** +``` +Processing: website/docs +Dry run: False +Processed 31 files +Modified 31 files +Total terms linked: 189 +✅ Done! +``` + +### Step 5: Verify Changes + +```bash +# Check what files were modified +git status + +# See statistics of changes +git diff --stat + +# Look for specific terms (e.g., "atomic element") +git diff website/docs/ | grep -i "atomic" + +# View changes in a specific file +git diff website/docs/chapter-03/03_user_keyword.md | head -50 +``` + +**What to look for:** +- ✅ Lowercase terms linked: `[variable files](../glossary#variable-file)` +- ✅ Plural terms linked: `[keywords](../glossary#keyword)` +- ✅ Original casing preserved in link text +- ✅ No links in headings (lines starting with `#`) +- ✅ No links in code blocks (between ` ``` `) + +### Step 6: Test Locally in Browser + +```bash +# Navigate to website directory +cd website + +# Install dependencies (first time only) +npm install + +# Start development server +npm start +``` + +**Browser opens to:** `http://localhost:3000` + +**Test the links:** +1. Navigate to any chapter (e.g., Chapter 3 → User Keywords) +2. Look for blue linked terms +3. Click on a linked term (e.g., "variable files") +4. Should navigate to glossary page and scroll to that term +5. Press Ctrl+C in terminal to stop server when done + +### Step 7: Commit Changes + +```bash +# Go back to repository root +cd .. + +# Stage all changes +git add tools/ website/docs/ + +# Commit with descriptive message +git commit -m "Update glossary links + +- Extracted 79 terms from glossary.json +- Applied case-insensitive and plural matching +- Linked 189 terms across 31 documentation files" + +# Push to your branch +git push origin glossary-links-final +``` + +### Step 8: Create Pull Request + +1. Go to GitHub: `https://github.com/robotframework/robotframework-RFCP-syllabus` +2. Click "Pull requests" → "New pull request" +3. Select your branch: `glossary-links-final` +4. Add title: "Add automated glossary linking with case-insensitive matching" +5. Add description (see template below) +6. Create pull request + +--- + +## 📝 Pull Request Description Template + +```markdown +## Summary +Adds automated glossary linking throughout the documentation using a Python script. + +## Changes +- Created `extract_from_json.py` to extract terms from `glossary.json` +- Created `glossary_linker.py` to automatically link glossary terms +- Linked 189 glossary terms across 31 documentation files + +## Features +- ✅ Case-insensitive matching ("variable files" → "Variable File") +- ✅ Plural/singular support ("keywords" → "Keyword") +- ✅ Test|Task notation support +- ✅ Preserves original text casing in links +- ✅ Excludes headings, code blocks, LO blocks + +## Testing +- [x] Dry-run completed successfully +- [x] Local build successful (`npm start`) +- [x] Links navigate correctly to glossary +- [x] No broken links detected + +## Example Changes +- `variable files` → `[variable files](../glossary#variable-file)` +- `keywords` → `[keywords](../glossary#keyword)` +- `atomic element` → `[atomic element](../glossary#atomic-element)` +``` + +--- + +## 🔄 When to Run This Workflow + +Run the complete workflow whenever: + +- ✅ **New terms are added** to `glossary.json` +- ✅ **Terms are renamed** in the glossary +- ✅ **You sync with upstream** (`git pull upstream main`) +- ✅ **Before creating a PR** (ensures links are up-to-date) +- ✅ **After major glossary changes** (like PR #72 merge) + +--- + +## 📋 Quick Reference Commands + +### One-Time Setup +```bash +# Clone the repository (if not done) +git clone https://github.com/robotframework/robotframework-RFCP-syllabus.git +cd robotframework-RFCP-syllabus + +# Install website dependencies +cd website +npm install +cd .. +``` + +### Regular Workflow +```bash +# 1. Extract terms +python3 tools/extract_from_json.py website/static/glossary/glossary.json + +# 2. Update glossary_linker.py manually (copy GLOSSARY_DATA) + +# 3. Test +python3 tools/glossary_linker.py website/docs --dry-run + +# 4. Apply +python3 tools/glossary_linker.py website/docs + +# 5. Verify +git diff website/docs/ | less + +# 6. Test locally +cd website && npm start + +# 7. Commit +git add tools/ website/docs/ +git commit -m "Update glossary links" +git push origin +``` + +--- + +## 🔧 Script Details + +### extract_from_json.py + +**Purpose:** Reads `website/static/glossary/glossary.json` and generates Python code for `GLOSSARY_DATA`. + +**Input:** JSON file with glossary terms +```json +[ + { + "term": "Atomic Element", + "aliases": [], + "abbreviation": "", + "definition": "..." + } +] +``` + +**Output:** Python code ready to paste +```python +GLOSSARY_DATA = [ + {"term": "Atomic Element", "abbreviation": None}, + ... +] +``` + +**Also creates:** `glossary_terms_extracted.json` for reference + +### glossary_linker.py + +**Purpose:** Automatically adds glossary links to all markdown documentation files. + +**Features:** +- Case-insensitive pattern matching with `re.IGNORECASE` +- Pluralization logic for common English patterns +- Regex patterns that avoid already-linked content +- Relative path generation for Docusaurus compatibility +- Section-based processing (headings, code, LO blocks, text) + +**Linking logic:** +1. Splits each file into sections (frontmatter, headings, code, LO blocks, text) +2. Only processes "text" sections +3. Searches for each glossary term (case-insensitive) +4. Links first occurrence of each term per file +5. Preserves original text casing in the link + +**Example transformations:** +```markdown + +We can use variable files to define keywords. + + +We can use [variable files](../glossary#variable-file) to define [keywords](../glossary#keyword). +``` + +--- + +## 🐛 Troubleshooting + +### Issue: "Found 0 glossary terms" + +**Cause:** Glossary file path is incorrect or file format changed + +**Solution:** +```bash +# Verify the file exists +ls -la website/static/glossary/glossary.json + +# Check the file format +head -20 website/static/glossary/glossary.json + +# Use correct path +python3 tools/extract_from_json.py website/static/glossary/glossary.json +``` + +### Issue: "No such file or directory: tools/glossary_linker.py" + +**Cause:** Running from wrong directory + +**Solution:** +```bash +# Check current directory +pwd + +# Navigate to repository root +cd ~/Desktop/robotframework-RFCP-syllabus + +# Verify you're in the right place +ls tools/ +# Should show: extract_from_json.py, glossary_linker.py, etc. +``` + +### Issue: Build fails with broken links + +**Cause:** Term in GLOSSARY_DATA doesn't exist in actual glossary + +**Solution:** +```bash +# Re-extract to get latest terms +python3 tools/extract_from_json.py website/static/glossary/glossary.json + +# Update glossary_linker.py with new output +# Re-run the linker +``` + +### Issue: npm install fails + +**Cause:** Node.js not installed or wrong version + +**Solution:** +```bash +# Check Node.js version +node --version +# Should be v18 or higher + +# Install Node.js if needed +brew install node + +# Then retry +cd website +npm install +``` + +### Issue: Unwanted terms getting linked + +**Cause:** False positives in pattern matching + +**Solution:** +Edit `glossary_linker.py` to exclude specific terms: +```python +# Add to excluded terms +excluded_terms = ['Test', 'Task'] # Add problematic terms here +``` + +--- + +## 📊 Statistics + +Current glossary coverage: +- **79 glossary terms** defined +- **31 documentation files** processed +- **189 links** created +- **100% case-insensitive** matching +- **Plural/singular** variations supported + +--- + +## 🎯 Best Practices + +1. **Always run dry-run first** - Preview changes before applying +2. **Test locally in browser** - Verify links work correctly +3. **Check git diff** - Review all changes before committing +4. **Update regularly** - Keep links in sync with glossary +5. **One term per file** - Script links each term only once per file (prevents clutter) + +--- + +## 📚 Additional Resources + +- **Glossary Table Component:** `website/src/components/Glossary/GlossaryTable.tsx` +- **Glossary Data Source:** `website/static/glossary/glossary.json` +- **Documentation Files:** `website/docs/chapter-*/` +- **Docusaurus Config:** `website/docusaurus.config.ts` + +--- + +## 🔗 Related Documentation + +- [Docusaurus Documentation](https://docusaurus.io/) +- [Robot Framework RFCP Syllabus](https://github.com/robotframework/robotframework-RFCP-syllabus) +- [PR #72 - Dynamic Glossary](https://github.com/robotframework/robotframework-RFCP-syllabus/pull/72) + +--- diff --git a/tools/extract_from_json.py b/tools/extract_from_json.py new file mode 100644 index 00000000..39cc600a --- /dev/null +++ b/tools/extract_from_json.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +""" +Extract Glossary Terms from glossary.json + +This script reads the glossary JSON file and converts it to GLOSSARY_DATA format +for use in glossary_linker.py + +Usage: + python3 extract_from_json.py website/static/glossary/glossary.json +""" + +import json +import sys +from pathlib import Path + + +def extract_from_json(json_file_path): + """Extract glossary terms from JSON file.""" + + with open(json_file_path, 'r', encoding='utf-8') as f: + glossary_items = json.load(f) + + terms = [] + + for item in glossary_items: + term_name = item.get('term', '').strip() + abbreviation = item.get('abbreviation', '').strip() + + if not term_name: + continue + + terms.append({ + 'term': term_name, + 'abbreviation': abbreviation if abbreviation else None + }) + + return terms + + +def generate_python_code(terms): + """Generate Python code for GLOSSARY_DATA.""" + + lines = ['GLOSSARY_DATA = ['] + + for term in terms: + abbr = f'"{term["abbreviation"]}"' if term['abbreviation'] else 'None' + lines.append(f' {{"term": "{term["term"]}", "abbreviation": {abbr}}},') + + lines.append(']') + + return '\n'.join(lines) + + +def main(): + if len(sys.argv) < 2: + print("Usage: python3 extract_from_json.py ") + print("\nExample:") + print(" python3 extract_from_json.py website/static/glossary/glossary.json") + sys.exit(1) + + json_path = Path(sys.argv[1]) + + if not json_path.exists(): + print(f"Error: File not found: {json_path}") + sys.exit(1) + + print(f"Extracting terms from: {json_path}") + print() + + terms = extract_from_json(json_path) + + print(f"Found {len(terms)} glossary terms:") + print() + + # Show preview + for i, term in enumerate(terms[:10], 1): + abbr_str = f" ({term['abbreviation']})" if term['abbreviation'] else "" + print(f" {i}. {term['term']}{abbr_str}") + + if len(terms) > 10: + print(f" ... and {len(terms) - 10} more") + + print() + print("="*70) + print("PYTHON CODE TO ADD TO glossary_linker.py:") + print("="*70) + print() + print(generate_python_code(terms)) + print() + + # Also save to a JSON file for reference + output_json = json_path.parent / 'glossary_terms_extracted.json' + with open(output_json, 'w', encoding='utf-8') as f: + json.dump(terms, f, indent=2, ensure_ascii=False) + + print("="*70) + print(f"Also saved to: {output_json}") + print("="*70) + + +if __name__ == '__main__': + main() diff --git a/tools/glossary_linker.py b/tools/glossary_linker.py new file mode 100644 index 00000000..87c46ed2 --- /dev/null +++ b/tools/glossary_linker.py @@ -0,0 +1,665 @@ +#!/usr/bin/env python3 +""" +Glossary Linker for Robot Framework RFCP Syllabus (v6 - Case-Insensitive + Plurals) + +This script automatically adds links to glossary terms throughout the documentation. + +NEW in v6: +- Case-insensitive matching: "variable files" links to "Variable Files" +- Smart plural/singular handling: + * Plural text → searches plural first, then singular + * Singular text → searches both singular and plural forms + +NEW in v5: +- Excludes content inside LO blocks (:::Kx[LO-x.x.x] ... :::) +- LO blocks are extracted verbatim for numbering generation + +FEATURES: +- Uses relative paths for Docusaurus compatibility +- Excludes YAML frontmatter (---...---) +- Excludes markdown headings (# ... ## ... ### ...) +- Excludes LO content blocks (:::Kx[LO-*] ... :::) +- Only links terms in actual body content/paragraphs +- Supports Test|Task notation as approved by committee +- Case-insensitive term matching +- Intelligent plural/singular matching + +This prevents glossary links from appearing in: +- Sidebar navigation (generated from headings) +- Previous/Next navigation (uses page titles) +- Table of contents +- Learning objective content blocks (used for numbering generation) +""" + +import re +import os +from pathlib import Path +from typing import Dict, List, Set, Tuple +import json + + +class GlossaryLinker: + def __init__(self, docs_path: str, use_relative_paths: bool = True): + self.docs_path = Path(docs_path) + self.use_relative_paths = use_relative_paths + self.glossary_terms = {} + self.aliases = {} + self.term_variations = {} # NEW: Store case variations and plurals + + def _pluralize(self, word: str) -> str: + """ + Simple pluralization logic for English words. + Returns the plural form of a word. + """ + # Special cases + irregular_plurals = { + 'library': 'libraries', + 'keyword': 'keywords', + 'variable': 'variables', + 'suite': 'suites', + 'task': 'tasks', + } + + word_lower = word.lower() + + # Check irregular plurals (case-insensitive) + for singular, plural in irregular_plurals.items(): + if word_lower == singular: + # Preserve original casing pattern + if word[0].isupper(): + return plural.capitalize() + return plural + + # Standard English pluralization rules + if word_lower.endswith('s') or word_lower.endswith('x') or \ + word_lower.endswith('z') or word_lower.endswith('ch') or \ + word_lower.endswith('sh'): + return word + 'es' + elif word_lower.endswith('y') and len(word) > 1 and word[-2] not in 'aeiou': + return word[:-1] + 'ies' + elif word_lower.endswith('f'): + return word[:-1] + 'ves' + elif word_lower.endswith('fe'): + return word[:-2] + 'ves' + else: + return word + 's' + + def _singularize(self, word: str) -> str: + """ + Simple singularization logic for English words. + Returns the singular form of a word (if it appears plural). + """ + irregular_plurals = { + 'libraries': 'library', + 'keywords': 'keyword', + 'variables': 'variable', + 'suites': 'suite', + 'tasks': 'task', + } + + word_lower = word.lower() + + # Check irregular plurals + for plural, singular in irregular_plurals.items(): + if word_lower == plural: + if word[0].isupper(): + return singular.capitalize() + return singular + + # Standard rules (reverse of pluralization) + if word_lower.endswith('ies') and len(word) > 3: + return word[:-3] + 'y' + elif word_lower.endswith('ves'): + if word_lower.endswith('ives'): + return word[:-3] + 'fe' + return word[:-3] + 'f' + elif word_lower.endswith('ses'): + return word[:-2] + elif word_lower.endswith('s') and not word_lower.endswith('ss'): + return word[:-1] + + return word # Already singular or unknown + + def load_glossary_terms(self, glossary_data: List[Dict]) -> None: + """ + Load glossary terms and their aliases from provided data. + Now creates case-insensitive variations and plural forms. + """ + for entry in glossary_data: + term = entry['term'] + slug = self._create_slug(term) + + # Store the main term (canonical form) + self.glossary_terms[term] = slug + + # NEW: Create variations for matching + variations = set() + + # Add the exact term + variations.add(term) + + # Add case variations (but link to canonical form) + variations.add(term.lower()) + variations.add(term.upper()) + variations.add(term.title()) + + # Add plural forms + # For multi-word terms, pluralize the last word + words = term.split() + if words: + last_word = words[-1] + plural_last = self._pluralize(last_word) + if plural_last != last_word: + plural_term = ' '.join(words[:-1] + [plural_last]) + variations.add(plural_term) + variations.add(plural_term.lower()) + variations.add(plural_term.title()) + + # Store all variations pointing to canonical term and slug + for variation in variations: + if variation not in self.term_variations: + self.term_variations[variation.lower()] = (term, slug) + + # Store abbreviations as aliases + if entry.get('abbreviation'): + abbr = entry['abbreviation'] + self.aliases[abbr] = (term, slug) + # Add case variations for abbreviations too + self.term_variations[abbr.lower()] = (term, slug) + + def _create_slug(self, term: str) -> str: + """ + Create a URL-safe slug from a term. + Matches the slugify logic in GlossaryTable.tsx: + - Convert to lowercase + - Replace non-alphanumeric chars with hyphens + - Remove leading/trailing hyphens + """ + slug = term.lower() + # Replace any non-alphanumeric character with hyphen + slug = re.sub(r'[^a-z0-9]+', '-', slug) + # Remove leading and trailing hyphens + slug = re.sub(r'(^-+|-+$)', '', slug) + return slug + + def _escape_for_regex(self, text: str) -> str: + """Escape special regex characters in text.""" + return re.escape(text) + + def _get_relative_path(self, current_file: Path) -> str: + """ + Get the glossary path for Docusaurus. + Uses absolute Docusaurus path for consistency. + """ + # For Docusaurus, always use the absolute docs path + return '/docs/glossary' + + def _split_frontmatter(self, content: str) -> Tuple[str, str]: + """ + Split YAML frontmatter from main content. + Returns (frontmatter, main_content). + """ + frontmatter = "" + main_content = content + + # Check for YAML frontmatter (---) + frontmatter_pattern = re.compile(r'^---\s*\n.*?\n---\s*\n', re.DOTALL) + match = frontmatter_pattern.match(content) + + if match: + frontmatter = match.group(0) + main_content = content[match.end():] + + return frontmatter, main_content + + def _ensure_glossary_import(self, content: str) -> str: + """ + Ensure the GlossaryTerm import is present after frontmatter. + Returns updated content with import if needed. + """ + import_statement = "import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm';\n\n" + + # Check if import already exists + if "import GlossaryTerm" in content: + return content + + # Split frontmatter and main content + frontmatter, main_content = self._split_frontmatter(content) + + # Insert import after frontmatter + return frontmatter + import_statement + main_content + + def _create_link_patterns(self, current_file: Path) -> List[Tuple]: + """ + Create regex patterns for finding and replacing glossary terms. + NOW: Case-insensitive with plural/singular support. + + Returns list of tuples: (pattern, canonical_term, slug, glossary_url) + """ + patterns = [] + + # Get the appropriate glossary URL for this file + if self.use_relative_paths: + glossary_url = self._get_relative_path(current_file) + else: + glossary_url = '/docs/glossary' + + # =================================================================== + # Handle Test|Task notation FIRST (highest priority) + # =================================================================== + test_task_mappings = [ + ('Test|Task Setup', 'Test Setup'), + ('Test|Task Teardown', 'Test Teardown'), + ('Test|Task Timeout', 'Test Timeout'), + ('Test|Task Template', 'Test Template'), + ('Test|Task Tag', 'Test Tag'), + ] + + for notation, target_term in test_task_mappings: + if target_term in self.glossary_terms: + slug = self.glossary_terms[target_term] + escaped = self._escape_for_regex(notation) + pattern = rf'(? (canonical_term, slug) + + for canonical_term, slug in self.glossary_terms.items(): + # Add the canonical term itself + terms_to_search[canonical_term] = (canonical_term, slug) + + # For multi-word terms, also search for plural of last word + words = canonical_term.split() + if len(words) > 0: + last_word = words[-1] + plural_last = self._pluralize(last_word) + + if plural_last != last_word: + # Create plural version: "Variable File" -> "Variable Files" + plural_term = ' '.join(words[:-1] + [plural_last]) if len(words) > 1 else plural_last + terms_to_search[plural_term] = (canonical_term, slug) + + # Sort by length (longest first) to match longer terms before shorter + sorted_terms = sorted(terms_to_search.keys(), key=len, reverse=True) + + # Create case-insensitive patterns for each search term + for search_term in sorted_terms: + canonical_term, slug = terms_to_search[search_term] + escaped_term = self._escape_for_regex(search_term) + + # Case-insensitive pattern + pattern = rf'(? Dict: + """Process a single markdown file.""" + stats = { + 'file': str(file_path.relative_to(self.docs_path)), + 'terms_linked': 0, + 'modified': False, + 'changes': [] + } + + try: + with open(file_path, 'r', encoding='utf-8') as f: + original_content = f.read() + + # Split frontmatter and content + frontmatter, content = self._split_frontmatter(original_content) + + # Split content into sections (headings, code, LO blocks, text) + sections = self._split_content_sections(content) + + # Get link patterns for this file + patterns = self._create_link_patterns(file_path) + + # Track which terms we've already linked (case-insensitive) + already_linked = set() + + # Process each section + processed_sections = [] + for section_type, section_content in sections: + if section_type in ['code', 'heading', 'lo_block']: + # DON'T modify code blocks, headings, or LO blocks + processed_sections.append(section_content) + else: + # Apply patterns to text sections only + modified_content = section_content + placeholders = {} # Store placeholders + placeholder_counter = 0 + + # Process each pattern + for pattern, canonical_term, slug, glossary_url in patterns: + # Find ALL case-insensitive matches + matches = list(re.finditer(pattern, modified_content, re.IGNORECASE)) + + if matches: + # Process matches in reverse order to maintain string positions + for match in reversed(matches): + matched_text = match.group(1) + + # Check if we've already linked this term (case-insensitive check) + if matched_text.lower() not in already_linked: + # Create GlossaryTerm component (preserves original casing) + # Format: matched text + # Escape quotes in the term + escaped_term = canonical_term.replace('\\', '\\\\').replace('"', '\\"') + component = f'{matched_text}' + + # Use a placeholder that won't match any pattern + placeholder = f'___GLOSSARY_PLACEHOLDER_{placeholder_counter}___' + placeholders[placeholder] = component + placeholder_counter += 1 + + # Replace with placeholder + modified_content = ( + modified_content[:match.start(1)] + + placeholder + + modified_content[match.end(1):] + ) + + stats['terms_linked'] += 1 + stats['changes'].append({ + 'term': matched_text, + 'canonical': canonical_term, + 'occurrences': 1 + }) + + # Mark as linked (case-insensitive) + already_linked.add(matched_text.lower()) + + # Replace all placeholders with actual components + for placeholder, component in placeholders.items(): + modified_content = modified_content.replace(placeholder, component) + + processed_sections.append(modified_content) + + # Reconstruct content with frontmatter + new_content = frontmatter + ''.join(processed_sections) + + # Add GlossaryTerm import if terms were linked + if stats['terms_linked'] > 0: + new_content = self._ensure_glossary_import(new_content) + + # Only write if content changed and not a dry run + if new_content != original_content and not dry_run: + with open(file_path, 'w', encoding='utf-8') as f: + f.write(new_content) + stats['modified'] = True + else: + stats['modified'] = False + + except Exception as e: + stats['error'] = str(e) + + return stats + + def _split_content_sections(self, content: str) -> List[Tuple[str, str]]: + """ + Split content into headings, code blocks, LO blocks, and text sections. + + Returns: + List of tuples: (section_type, content) + where section_type is 'heading', 'code', 'lo_block', or 'text' + """ + sections = [] + lines = content.split('\n') + + i = 0 + while i < len(lines): + line = lines[i] + + # Check for code block start (HIGHEST PRIORITY) + if line.strip().startswith('```') or line.strip().startswith('~~~'): + # Collect entire code block INCLUDING the fence lines + fence = '```' if line.strip().startswith('```') else '~~~' + code_block = [line] + i += 1 + # Collect until we find the closing fence + while i < len(lines): + code_block.append(lines[i]) + # Check if this line is a closing fence (starts with same fence marker) + if lines[i].strip().startswith(fence): + i += 1 + break + i += 1 + # Append the entire code block as one unit + sections.append(('code', '\n'.join(code_block) + '\n')) + continue + + # Check for heading (# ... ## ... ### ...) + if line.strip().startswith('#'): + # This is a heading - don't link terms here + sections.append(('heading', line + '\n')) + i += 1 + continue + + # Check for LO block start (:::Kx[LO-...) + if line.strip().startswith(':::') and 'LO-' in line: + # Collect entire LO block + lo_block = [line] + i += 1 + while i < len(lines): + lo_block.append(lines[i]) + # LO blocks end with ::: on its own line + if lines[i].strip() == ':::': + i += 1 + break + i += 1 + sections.append(('lo_block', '\n'.join(lo_block) + '\n')) + continue + + # Check for inline code, existing links, GlossaryTerm components, or :term[] directives in the line + if '`' in line or '[' in line or ' List[Tuple[str, str]]: + """ + Process a line that may contain inline code, existing links, GlossaryTerm components, or :term[] directives. + Split it into linkable and non-linkable parts. + """ + sections = [] + current_pos = 0 + + # Pattern to find inline code (`...`), existing links ([...](...) ), GlossaryTerm components, or :term[] directives + special_pattern = re.compile(r'(`[^`]+`|\[[^\]]+\]\([^\)]+\)|]*>.*?|:term\[[^\]]+\](?:\{[^}]+\})?)') + + for match in special_pattern.finditer(line): + # Add text before the special content + if match.start() > current_pos: + sections.append(('text', line[current_pos:match.start()])) + + # Add the special content (don't link inside it) + sections.append(('code', match.group(0))) + current_pos = match.end() + + # Add remaining text + if current_pos < len(line): + sections.append(('text', line[current_pos:] + '\n')) + elif line.endswith('\n'): + sections.append(('text', '\n')) + + return sections + + def process_all_markdown_files(self, dry_run: bool = False) -> Dict: + """Process all markdown files in the docs directory.""" + overall_stats = { + 'total_files': 0, + 'modified_files': 0, + 'total_terms_linked': 0, + 'files': [] + } + + # Find all .md or .mdx files + markdown_files = list(self.docs_path.glob('**/*.md')) + list(self.docs_path.glob('**/*.mdx')) + + for md_file in markdown_files: + # Skip the glossary file itself + if 'glossary' in md_file.name.lower(): + continue + + overall_stats['total_files'] += 1 + file_stats = self.process_markdown_file(md_file, dry_run) + + if file_stats.get('modified', False): + overall_stats['modified_files'] += 1 + + overall_stats['total_terms_linked'] += file_stats.get('terms_linked', 0) + overall_stats['files'].append(file_stats) + + return overall_stats + + +# =================================================================== +# GLOSSARY DATA +# =================================================================== +# This would typically be loaded from the actual glossary file, +# but for now it's hardcoded based on the syllabus content +GLOSSARY_DATA = [ + {"term": "Acceptance Testing", "abbreviation": None}, + {"term": "Adaptation Layer", "abbreviation": None}, + {"term": "Atomic Element", "abbreviation": None}, + {"term": "Automation Script", "abbreviation": None}, + {"term": "Argument", "abbreviation": None}, + {"term": "Argument Interface", "abbreviation": None}, + {"term": "Behavior-Driven Development", "abbreviation": "BDD"}, + {"term": "Behavior-Driven Specification", "abbreviation": None}, + {"term": "Built-In Variables", "abbreviation": None}, + {"term": "Command Line Interface", "abbreviation": "CLI"}, + {"term": "Composite Element", "abbreviation": None}, + {"term": "Control Structure", "abbreviation": None}, + {"term": "Data-Driven Specification", "abbreviation": None}, + {"term": "Definition Layer", "abbreviation": None}, + {"term": "Embedded Argument", "abbreviation": None}, + {"term": "End-to-End Test", "abbreviation": None}, + {"term": "Execution Artifacts", "abbreviation": None}, + {"term": "Execution Layer", "abbreviation": None}, + {"term": "Execution Model", "abbreviation": None}, + {"term": "Fail Status", "abbreviation": None}, + {"term": "FOR Loop", "abbreviation": None}, + {"term": "Free Named Argument", "abbreviation": "kwargs"}, + {"term": "Generic Test Automation Architecture", "abbreviation": "gTAA"}, + {"term": "Given / When / Then / And / But", "abbreviation": None}, + {"term": "Global Variable", "abbreviation": None}, + {"term": "Higher-Level Suite (Suite Directory)", "abbreviation": None}, + {"term": "Initialization File (__init__.robot)", "abbreviation": None}, + {"term": "Inline Comment", "abbreviation": None}, + {"term": "Inline IF", "abbreviation": None}, + {"term": "K-Level (Knowledge Level)", "abbreviation": None}, + {"term": "Keyword", "abbreviation": None}, + {"term": "Keyword Interface", "abbreviation": None}, + {"term": "Keyword-Driven Specification", "abbreviation": None}, + {"term": "Keyword Library", "abbreviation": None}, + {"term": "List Variable", "abbreviation": None}, + {"term": "Local Variable", "abbreviation": None}, + {"term": "Log File (log.html)", "abbreviation": None}, + {"term": "Mandatory Argument", "abbreviation": None}, + {"term": "Metadata (Suite Metadata)", "abbreviation": None}, + {"term": "Named-Only Argument", "abbreviation": None}, + {"term": "Named Argument", "abbreviation": None}, + {"term": "Output File (output.xml)", "abbreviation": None}, + {"term": "Optional Argument", "abbreviation": None}, + {"term": "Pass Status", "abbreviation": None}, + {"term": "Positional Argument", "abbreviation": None}, + {"term": "Positional or Named Argument", "abbreviation": None}, + {"term": "Report File (report.html)", "abbreviation": None}, + {"term": "Resource File", "abbreviation": None}, + {"term": "Return Statement (RETURN)", "abbreviation": None}, + {"term": "Return Type Hint", "abbreviation": None}, + {"term": "Robotic Process Automation", "abbreviation": "RPA"}, + {"term": "Robot Framework Foundation", "abbreviation": None}, + {"term": "Robot Framework® Certified Professional", "abbreviation": "RFCP"}, + {"term": "Root Suite", "abbreviation": None}, + {"term": "Scalar Access Syntax (${})", "abbreviation": None}, + {"term": "Scalar Variable", "abbreviation": None}, + {"term": "Skip Status", "abbreviation": None}, + {"term": "Standard Library (Robot Framework)", "abbreviation": None}, + {"term": "Suite (Test Suite / Task Suite)", "abbreviation": None}, + {"term": "Suite File", "abbreviation": None}, + {"term": "Suite Setup", "abbreviation": None}, + {"term": "Suite Teardown", "abbreviation": None}, + {"term": "Suite Variable", "abbreviation": None}, + {"term": "Synthetic Monitoring", "abbreviation": None}, + {"term": "Task", "abbreviation": None}, + {"term": "Test Setup", "abbreviation": None}, + {"term": "Test Teardown", "abbreviation": None}, + {"term": "Test Template", "abbreviation": None}, + {"term": "Test Case", "abbreviation": "Test"}, + {"term": "Test Data", "abbreviation": None}, + {"term": "Test Level", "abbreviation": None}, + {"term": "Test Tag", "abbreviation": None}, + {"term": "Test Timeout", "abbreviation": None}, + {"term": "User Keyword", "abbreviation": None}, + {"term": "Variable Number of Positional Arguments", "abbreviation": None}, + {"term": "Variable", "abbreviation": None}, + {"term": "Variable File", "abbreviation": None}, + {"term": "Variable Scope", "abbreviation": None}, + {"term": "WHILE Loop", "abbreviation": None}, +] + + +def main(): + """Main function.""" + import argparse + + parser = argparse.ArgumentParser(description='Add glossary links to RFCP Syllabus (v6: Case-insensitive + Plurals)') + parser.add_argument('docs_path', help='Path to docs directory') + parser.add_argument('--dry-run', action='store_true', help='Preview changes') + parser.add_argument('--use-absolute-paths', action='store_true', help='Use absolute paths') + parser.add_argument('--output', help='Statistics output file (JSON)') + + args = parser.parse_args() + + use_relative = not args.use_absolute_paths + linker = GlossaryLinker(args.docs_path, use_relative_paths=use_relative) + linker.load_glossary_terms(GLOSSARY_DATA) + + print(f"Processing: {args.docs_path}") + print(f"Dry run: {args.dry_run}") + print(f"Relative paths: {use_relative}") + print(f"Test|Task notation: ENABLED") + print(f"LO block exclusion: ENABLED") + print(f"Case-insensitive matching: ENABLED") + print(f"Plural/singular support: ENABLED") + print(f"Excluded files: glossary.md") + print() + + stats = linker.process_all_markdown_files(dry_run=args.dry_run) + + print(f"\nProcessed {stats['total_files']} files") + print(f"Modified {stats['modified_files']} files") + print(f"Total terms linked: {stats['total_terms_linked']}") + + if args.output: + with open(args.output, 'w') as f: + json.dump(stats, f, indent=2) + print(f"\nStatistics saved to: {args.output}") + + if args.dry_run: + print("\n⚠️ DRY RUN - No files were modified") + print("Run without --dry-run to apply changes") + + +if __name__ == '__main__': + main() diff --git a/website/docs/chapter-01/00_overview.md b/website/docs/chapter-01/00_overview.md index f5258449..4728399c 100644 --- a/website/docs/chapter-01/00_overview.md +++ b/website/docs/chapter-01/00_overview.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 1 Introduction to Robot Framework -The upcoming chapters provide a concise overview of Robot Framework, including its core structure, use cases in test automation and Robotic Process Automation (RPA), and key specification styles like keyword-driven and behavior-driven testing. You'll learn about its architecture, syntax, and how test cases and tasks are organized. Additionally, the chapters explain the open-source licensing under Apache 2.0, the role of the Robot Framework Foundation in maintaining the ecosystem, and the foundational web resources available for further exploration and contributions. \ No newline at end of file +The upcoming chapters provide a concise overview of Robot Framework, including its core structure, use cases in test automation and Robotic Process Automation (RPA), and key specification styles like keyword-driven and behavior-driven testing. You'll learn about its architecture, syntax, and how test cases and tasks are organized. Additionally, the chapters explain the open-source licensing under Apache 2.0, the role of the Robot Framework Foundation in maintaining the ecosystem, and the foundational web resources available for further exploration and contributions. diff --git a/website/docs/chapter-01/01_purpose.md b/website/docs/chapter-01/01_purpose.md index 68f8de59..acf8ff55 100644 --- a/website/docs/chapter-01/01_purpose.md +++ b/website/docs/chapter-01/01_purpose.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 1.1 Purpose / Use Cases ::::lo[Learning Objectives] @@ -11,9 +13,9 @@ Recall the two main use cases of Robot Framework :::: Robot Framework is a versatile, open-source automation framework that supports both **test automation** and **robotic process automation (RPA)**. -Initially designed for acceptance testing, it has since evolved to cover other types of testing and various automation tasks in both IT and business environments. -Its keyword-driven approach allows users to create reusable components, making it accessible even to those with minimal programming skills. -Robot Framework can be extended through a vast array of third-party or custom made keyword libraries, allowing it to automate interactions with APIs, user interfaces, databases, and many more technologies. +Initially designed for acceptance testing, it has since evolved to cover other types of testing and various automation tasks in both IT and business environments. +Its keyword-driven approach allows users to create reusable components, making it accessible even to those with minimal programming skills. +Robot Framework can be extended through a vast array of third-party or custom made keyword libraries, allowing it to automate interactions with APIs, user interfaces, databases, and many more technologies. @@ -33,29 +35,29 @@ Robot Framework is widely used at various levels of testing, primarily focusing - **System Testing**: Involves verifying the complete system’s behavior and capabilities. It often includes both functional and non-functional aspects (e.g., accessibility, security) and may use simulated components. -- **System Integration Testing**: Focuses on the interaction between the system under test and external services, as well as on the integration of multiple systems into a larger system, ensuring that all integrated components communicate and function together as expected. +- **System Integration Testing**: Focuses on the interaction between the system under test and external services, as well as on the integration of multiple systems into a larger system, ensuring that all integrated components communicate and function together as expected. - **Acceptance Testing**: Aims to validate that the system meets business requirements and is ready for deployment or release. This often includes different forms of acceptance testing (e.g., user acceptance, operational acceptance, regulatory acceptance) and is frequently written or conducted by end-users or stakeholders to confirm the system’s readiness for use. Acceptance tests, often defined by business stakeholders in approaches like Acceptance Test-Driven Development (ATDD), can be automated and executed earlier in the development process. This ensures that the solution aligns with business requirements from the start and provides immediate feedback, reducing costly changes later. -- **End-to-End Testing**: Verifies that a complete workflow or process within the system operates as intended, covering all interconnected subsystems, interfaces, and external components. End-to-end tests ensure the correct functioning of the application in real-world scenarios by simulating user interactions from start to finish. +- **End-to-End Testing**: Verifies that a complete workflow or process within the system operates as intended, covering all interconnected subsystems, interfaces, and external components. End-to-end tests ensure the correct functioning of the application in real-world scenarios by simulating user interactions from start to finish. -Robot Framework's flexibility and support for external libraries make it an excellent tool for automating these comprehensive test cases, ensuring seamless interaction between components and validating the system's behavior also in production or production-like conditions. +Robot Framework's flexibility and support for external libraries make it an excellent tool for automating these comprehensive test cases, ensuring seamless interaction between components and validating the system's behavior also in production or production-like conditions. Robot Framework is typically not used for **component testing** nor **integration testing** because its primary strength lies in higher-level testing, such as system, acceptance, and end-to-end testing, where behavior-driven and keyword-based approaches excel. Component testing requires low-level, granular tests focusing on individual units of code, often necessitating direct interaction with the codebase, mocking, or stubbing, which are better handled by unit testing frameworks like JUnit, pytest, or NUnit. Similarly, integration testing at a low level often requires precise control over service interactions, such as API stubs or protocol-level testing, which may not align with Robot Framework's abstraction-oriented design. While Robot Framework can technically handle these cases through custom libraries, its overhead and design philosophy make it less efficient compared to tools specifically tailored for low-level and tightly scoped testing tasks. ### 1.1.1.1 Synthetic Monitoring -Beyond traditional test levels, **Synthetic Monitoring**, also referred to as **Active Monitoring** or **Proactive Monitoring**, is a proactive approach that simulates user interactions with live systems at regular intervals. It detects performance issues or downtime early with the goal of detecting such failure before they affect actual users. +Beyond traditional test levels, **Synthetic Monitoring**, also referred to as **Active Monitoring** or **Proactive Monitoring**, is a proactive approach that simulates user interactions with live systems at regular intervals. It detects performance issues or downtime early with the goal of detecting such failure before they affect actual users. ## 1.1.2 Robotic Process Automation (RPA) -Robotic Process Automation (RPA) uses software bots to perform tasks and interactions normally performed by humans, without requiring changes to the underlying applications. +Robotic Process Automation (RPA) uses software bots to perform tasks and interactions normally performed by humans, without requiring changes to the underlying applications. -Robot Framework, with its keyword-driven approach, vast ecosystem of libraries, simplicity, and scalability, is widely adopted for RPA tasks. -Robot Framework allows users to automate most workflows using ready-made keyword libraries that provide a wide range of functionalities. These libraries can be combined and reused in user-defined keywords, making automation simple and efficient. For custom functionalities or more complex tasks, Robot Framework also offers the flexibility to create custom keyword libraries using Python, enabling advanced use cases and seamless integration with unique systems. +Robot Framework, with its keyword-driven approach, vast ecosystem of libraries, simplicity, and scalability, is widely adopted for RPA tasks. +Robot Framework allows users to automate most workflows using ready-made keyword libraries that provide a wide range of functionalities. These libraries can be combined and reused in user-defined keywords, making automation simple and efficient. For custom functionalities or more complex tasks, Robot Framework also offers the flexibility to create custom keyword libraries using Python, enabling advanced use cases and seamless integration with unique systems. Common use cases of RPA with Robot Framework include: @@ -63,3 +65,4 @@ Common use cases of RPA with Robot Framework include: - **Task / Process automation**: Automating tasks such as form submissions, clicks, and file operations across web or desktop applications. + diff --git a/website/docs/chapter-01/02_architecture.md b/website/docs/chapter-01/02_architecture.md index efca12c5..b5916c70 100644 --- a/website/docs/chapter-01/02_architecture.md +++ b/website/docs/chapter-01/02_architecture.md @@ -1,9 +1,11 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 1.2 Architecture of Robot Framework -Robot Framework is an open-source automation framework that allows you to build automation scripts for testing and RPA (Robotic Process Automation). -It focuses on providing a keyword-driven or behavior-driven approach, making the automation easy to understand and maintain. +Robot Framework is an open-source automation framework that allows you to build automation scripts for testing and RPA (Robotic Process Automation). +It focuses on providing a keyword-driven or behavior-driven approach, making the automation easy to understand and maintain. However, it is not a full-stack solution that encompasses all layers of automation. -Instead, it provides a flexible platform where different tools, libraries, and integrations handle specific tasks to implement a flexible automation solution. +Instead, it provides a flexible platform where different tools, libraries, and integrations handle specific tasks to implement a flexible automation solution. @@ -19,24 +21,24 @@ Recall the layers of the Generic Test Automation Architecture (gTAA) and their c :::: -The **Generic Test Automation Architecture (gTAA)** described in the ISTQB "Certified Tester Advanced Level Test Automation Engineering" offers a structured approach to test automation, dividing it into different layers for a clear separation of concerns: +The **Generic Test Automation Architecture (gTAA)** described in the ISTQB "Certified Tester Advanced Level Test Automation Engineering" offers a structured approach to test automation, dividing it into different layers for a clear separation of concerns: -- **Definition Layer**: This layer contains the "Test Data" (test cases, tasks, resource files which include user keywords and variables). -In Robot Framework, the test data is written using the defined syntax and contains keyword calls and argument values that make the test case or task definitions structured in suites. +- **Definition Layer**: This layer contains the "Test Data" (test cases, tasks, resource files which include user keywords and variables). +In Robot Framework, the test data is written using the defined syntax and contains keyword calls and argument values that make the test case or task definitions structured in suites. -- **Execution Layer**: In Robot Framework, the execution layer consists of the framework itself, including its core components and APIs. -It parses and interprets the test data syntax to build an execution model. -The execution layer is responsible for processing this execution model to execute the library keywords with their argument values, logging results, and generating reports. +- **Execution Layer**: In Robot Framework, the execution layer consists of the framework itself, including its core components and APIs. +It parses and interprets the test data syntax to build an execution model. +The execution layer is responsible for processing this execution model to execute the library keywords with their argument values, logging results, and generating reports. - **Adaptation Layer**: This layer provides the connection between Robot Framework and the system under test (SUT). -In Robot Framework, this is where the keyword libraries, which contain code responsible for interacting with different technologies and interfaces, +In Robot Framework, this is where the keyword libraries, which contain code responsible for interacting with different technologies and interfaces, such as those for UI, API, database interactions, or others, are located. These keyword libraries enable interaction with different technologies and interfaces, ensuring the automation is flexible and adaptable to various environments. Editors/IDEs that offer support for Robot Framework's syntax are tools that support or integrate in these layers. -When writing tests|tasks or keywords, the editor supports the definition layer. +When writing tests|tasks or keywords, the editor supports the definition layer. When executing or debugging tests|tasks, the editor supports the execution layer. -When writing keywords in e.g. Python for keyword libraries, the editor supports the adaptation layer. +When writing keywords in e.g. Python for keyword libraries, the editor supports the adaptation layer. Therefore also other additional extensions of Robot Framework can be categorized into these layers. {/* TODO: add a graphic here */} @@ -102,3 +104,4 @@ Robot Framework itself does not have any external dependencies, but additional t + diff --git a/website/docs/chapter-01/03_syntax.md b/website/docs/chapter-01/03_syntax.md index 7ddc9241..042286d2 100644 --- a/website/docs/chapter-01/03_syntax.md +++ b/website/docs/chapter-01/03_syntax.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 1.3 Basic Syntax & Structure @@ -19,12 +21,12 @@ Key attributes of the syntax that improves the before mentioned: - **Space-separated syntax**: Robot Framework uses two or more spaces as the primary separator (although one space is allowed as a character). A use of **FOUR (4)** spaces is recommended to ensure clarity and readability of the specification. -- **Indentation based blocks**: Code blocks like test, task or keyword bodies are defined by indentation. +- **Indentation based blocks**: Code blocks like test, task or keyword bodies are defined by indentation. This makes the structure clear and easy to follow. - **Reduced use of special characters**: Compared to programming languages the focus is on reducing special characters, making the syntax human-readable and user-friendly. -- **String first**: Unquoted strings are considered as strings, while variables need special syntax. +- **String first**: Unquoted strings are considered as strings, while variables need special syntax. - **Single spaces are valid**: Single spaces are valid as a character in most elements and values without quotation. -- **Mostly case-insensitive**: Most elements like keyword or variable names are case insensitive. +- **Mostly case-insensitive**: Most elements like keyword or variable names are case insensitive. However, some syntax, like library imports is case-sensitive. :::tip[Note] @@ -33,7 +35,7 @@ This syllabus does NOT cover other formats like Pipe-Separated ( | ) Format or R ::: -Example of test cases with their keyword calls written in Robot Framework: +Example of test cases with their keyword calls written in Robot Framework: ```robotframework *** Settings *** @@ -69,10 +71,10 @@ Create User With Admin Rights ## 1.3.1 What are Test Cases / Tasks? In Robot Framework, **Test Cases** (**Tests**) or **Tasks** are executable entities that serve a specific purpose and are organized into suites. -A **Test** is synonymous with a **Test Case**, while **Task**, technically being the same, is used in RPA mode, where the automation is not focused on testing but on automating business processes. +A **Test** is synonymous with a **Test Case**, while **Task**, technically being the same, is used in RPA mode, where the automation is not focused on testing but on automating business processes. -Tests or Tasks have a body made up of **keyword calls** and Robot Framework statements like **IF** or **VAR**, which represent the actions or steps executed during the test or task execution. -These keywords make the automation modular, maintainable, reusable, and readable. +Tests or Tasks have a body made up of **keyword calls** and Robot Framework statements like **IF** or **VAR**, which represent the actions or steps executed during the test or task execution. +These keywords make the automation modular, maintainable, reusable, and readable. @@ -81,7 +83,7 @@ These keywords make the automation modular, maintainable, reusable, and readable Robot Framework organizes tests|tasks into **Suites**, which are either files or directories. - `*.robot` files that contain test cases or tasks are suites. -- Each directory, starting from the top-level directory (the one executed by Robot Framework), and any sub-directory that contains a `*.robot` suite file, is considered a **Suite** as well. +- Each directory, starting from the top-level directory (the one executed by Robot Framework), and any sub-directory that contains a `*.robot` suite file, is considered a **Suite** as well. Suites can contain other suites, forming a hierarchical tree, which is by default alphabetically ordered. See [2.1 Suite File & Tree Structure](chapter-02/01_suitefile.md) for more details. @@ -104,14 +106,14 @@ Explain the difference between User Keywords and Library Keywords Tests or Tasks are constructed using **Keywords**, which represent specific actions or sequences of actions to be performed. -**Keywords** in Robot Framework follow the concepts used in Behavior-Driven Development (BDD) and Keyword-Driven Testing. +**Keywords** in Robot Framework follow the concepts used in Behavior-Driven Development (BDD) and Keyword-Driven Testing. **Definition**: one or more words used as a reference to a specific set of actions intended to be performed during the execution of one or more tests or tasks. There are two types of keywords in Robot Framework: -1. **User Keywords**: Written in Robot Framework syntax, they are mainly used as wrappers around sets of other keywords or to implement actions not readily available in existing library keywords. User Keywords improve readability, understandability, maintainability, and structure. These keywords always call other keywords or commands within their body, which is why they are also called **higher-level keywords**. In other literature, such keywords are also referred to as **Business Keywords** or **Composite Keywords**.

+1. **User Keywords**: Written in Robot Framework syntax, they are mainly used as wrappers around sets of other keywords or to implement actions not readily available in existing library keywords. User Keywords improve readability, understandability, maintainability, and structure. These keywords always call other keywords or commands within their body, which is why they are also called **higher-level keywords**. In other literature, such keywords are also referred to as **Business Keywords** or **Composite Keywords**.

Example: ```robot *** Keywords *** @@ -147,13 +149,14 @@ Recall the difference between Resource Files and Libraries and their artifacts While tests and tasks are organized into suites, **keywords** are organized into **Resource Files** and **Keyword Libraries**. -- **Resource Files**: Contain **User Keywords** and are also used to organize the importing of libraries and the definition of variables. These are considered to be part of the test|task data in the *Definition Layer*. -- **Keyword Libraries**: Contain **Library Keywords**, which are typically implemented in Python or other technologies and, except for the standard libraries, are not part of Robot Framework itself. They can be either custom-made or third-party libraries implemented by the Robot Framework community. These are considered to be part of the *Adaptation Layer*. +- **Resource Files**: Contain **User Keywords** and are also used to organize the importing of libraries and the definition of variables. These are considered to be part of the test|task data in the *Definition Layer*. +- **Keyword Libraries**: Contain **Library Keywords**, which are typically implemented in Python or other technologies and, except for the standard libraries, are not part of Robot Framework itself. They can be either custom-made or third-party libraries implemented by the Robot Framework community. These are considered to be part of the *Adaptation Layer*. -Central resource files and libraries allow the separation of concerns, making the automation more modular and reusable across multiple suites, tests or tasks. +Central resource files and libraries allow the separation of concerns, making the automation more modular and reusable across multiple suites, tests or tasks. The concepts of organizing are fundamental to working with Robot Framework and contribute to its flexibility and scalability in both test automation and RPA. + diff --git a/website/docs/chapter-01/04_styles.md b/website/docs/chapter-01/04_styles.md index 3a7b2a8a..4b5af0de 100644 --- a/website/docs/chapter-01/04_styles.md +++ b/website/docs/chapter-01/04_styles.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 1.4 Specification Styles @@ -11,11 +13,11 @@ Recall the three specification styles of Robot Framework :::: -Specification styles define how tests or tasks are structured, focusing on how actions and verifications are described. -While **Keyword-Driven Testing (KDT)** and **Behavior-Driven Development (BDD)** are commonly associated with testing, the principles behind these styles are adaptable to other forms of automation, such as RPA. +Specification styles define how tests or tasks are structured, focusing on how actions and verifications are described. +While **Keyword-Driven Testing (KDT)** and **Behavior-Driven Development (BDD)** are commonly associated with testing, the principles behind these styles are adaptable to other forms of automation, such as RPA. -Both styles can be mixed, even within the same test or task, but it is strongly recommended to have separate styles for separate purposes and not mix them within the same body. -One practical solution would be to define acceptance test cases that cover users' expectations in a declarative *Behavior-Driven Style*, while using keywords that are implemented in an imperative *Keyword-Driven style*. +Both styles can be mixed, even within the same test or task, but it is strongly recommended to have separate styles for separate purposes and not mix them within the same body. +One practical solution would be to define acceptance test cases that cover users' expectations in a declarative *Behavior-Driven Style*, while using keywords that are implemented in an imperative *Keyword-Driven style*. Further system level :term[test cases]{term="Test Case"}, that are not covering acceptance criteria could be written in a *Keyword-Driven style*. The approach of both styles is different in that way, @@ -26,7 +28,7 @@ where the script specifies what the automation should do to control the system. Beside these two different specification approaches how to write/formulate -your automation script and their step sequences, +your automation script and their step sequences, there is also a third specification method, **Data-Driven Specification** that can be combined with the other two styles, to define the data that is used in the automation. @@ -63,7 +65,7 @@ Verifications or assertions can be imperative, though they are often phrased as The advantage of this style lies in its **clarity** and **structure**. It provides a straightforward representation of the task flow, making it easy to understand what actions will be executed. -Separation of the executed step/keyword and its arguments/data with spaces improves the readability of tests or tasks. +Separation of the executed step/keyword and its arguments/data with spaces improves the readability of tests or tasks. Flow and data can be parsed separately by the consumer. @@ -94,7 +96,7 @@ Opening Foundation Page ``` The prefixes `Given`, `When`, `Then`, `And` and `But` are basically ignored by Robot Framework if a keyword is found matching the rest of the name. -A key difference between Robot Framework's behavior-driven style and BDD frameworks like **Cucumber** or most others is the ability in Robot Framework to use **multiple keyword layers**. +A key difference between Robot Framework's behavior-driven style and BDD frameworks like **Cucumber** or most others is the ability in Robot Framework to use **multiple keyword layers**. In other BDD frameworks the code that implements a sentence like `Given "robotframework.org" is open.` is referred to as a step definition. Step definitions are written in a programming language (typically Java, JavaScript, Ruby, or Python) and map natural language steps from a Gherkin feature file to code. Therefore there are no multiple layers of keywords that can be logged into execution protocols. @@ -121,7 +123,7 @@ It is an **imperative** style, comparable to procedural programming. It is structured, clear, and well-suited for scenarios where the steps are more technical or detailed and involve a larger number of keyword calls within a test or task. Additionally, this style is better suited for complex tasks or handling complex data, -as it enables a clear separation between keyword names and their argument values. +as it enables a clear separation between keyword names and their argument values. - **Behavior-Driven Style** emphasizes **how the system behaves** from the user's point of view, using more natural language and focusing on expected outcomes. @@ -148,19 +150,19 @@ Recall the purpose of Data-Driven Specification :::: **Data-Driven Specification** originates from **Data-Driven Testing** -and is a method where the test data and expected results are +and is a method where the test data and expected results are separated from the test script that controls the flow. While in **Robotic Process Automation (RPA)**, the data used in an automation workflow is typically acquired dynamically from an external source, in testing, the data is specifically chosen to cover different scenarios or cases. Therefore, this method of defining data combinations -statically in the suite files is normally not applicable to RPA. +statically in the suite files is normally not applicable to RPA. The purpose of **Data-Driven Testing** is to automate the same sequence of actions or scenario with different sets of input and/or expected output data. -In this style, a single user keyword, which contains the whole test logic or sequence of actions, +In this style, a single user keyword, which contains the whole test logic or sequence of actions, is executed with multiple data variations, making it highly effective for repetitive tests, where the logic stays the same but the data changes, @@ -173,6 +175,7 @@ Robot Framework offers a convenient feature for this approach through **Test Tem - **Clarity**: Keeps the test logic separate from the data, making it easier to manage large data sets. - **Scalability**: Suitable for scenarios where the same functionality needs to be tested under various conditions, such as verifying form inputs or performing calculations with different values. -See [3.4 Using Data-Driven Specification](chapter-03/04_datadriven.md) for more details and examples on Data-Driven Specification. +See [3.4 Using Data-Driven Specification](chapter-03/04_datadriven.md) for more details and examples on Data-Driven Specification. + diff --git a/website/docs/chapter-01/05_organization.md b/website/docs/chapter-01/05_organization.md index 7fd7bd9c..7f35660a 100644 --- a/website/docs/chapter-01/05_organization.md +++ b/website/docs/chapter-01/05_organization.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 1.5 Organization and Licensing @@ -36,7 +38,7 @@ List and recall the key objectives and organizational form of the Robot Framewor :::: -The **Robot Framework Foundation** (officially known as **Robot Framework ry**) is a non-profit association based in Helsinki, Finland, dedicated to promoting the use, development, and maintenance of the open-source Robot Framework. The foundation ensures that Robot Framework remains freely available and viable for both test automation and robotic process automation (RPA) in the future. +The **Robot Framework Foundation** (officially known as **Robot Framework ry**) is a non-profit association based in Helsinki, Finland, dedicated to promoting the use, development, and maintenance of the open-source Robot Framework. The foundation ensures that Robot Framework remains freely available and viable for both test automation and robotic process automation (RPA) in the future. Key objectives of the foundation include: @@ -46,7 +48,7 @@ Key objectives of the foundation include: - **Platform Maintenance**: The foundation is responsible for maintaining key infrastructure, such as the official website, GitHub repositories, and community platforms. These resources are crucial to sustaining a healthy ecosystem and fostering collaboration among users and contributors. -- **Community Support and Events**: The foundation plays a central role in organizing **RoboCon**, the annual Robot Framework User Conference, which brings together users, developers, and contributors to share knowledge and insights. Additionally, it helps to disseminate knowledge about test automation and RPA through community events and documentation efforts. +- **Community Support and Events**: The foundation plays a central role in organizing **RoboCon**, the annual Robot Framework User Conference, which brings together users, developers, and contributors to share knowledge and insights. Additionally, it helps to disseminate knowledge about test automation and RPA through community events and documentation efforts. - **Funding of Ecosystem Projects**: Whenever possible, the foundation finances open-source projects that are proposed by community members, aiming to support broader ecosystem development and innovation. @@ -75,3 +77,4 @@ These include: - **[robotframework.org](https://robotframework.org/)**: The main page providing an overview, documentation, and access to resources. - **[github.com/robotframework](https://github.com/robotframework)**: The official repository for the framework's source code and other components. + diff --git a/website/docs/chapter-02/00_overview.md b/website/docs/chapter-02/00_overview.md index 9c43a646..da0f98cf 100644 --- a/website/docs/chapter-02/00_overview.md +++ b/website/docs/chapter-02/00_overview.md @@ -1,12 +1,14 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2 Getting Started with Robot Framework This chapter introduces participants to the foundational concepts of Robot Framework. It covers the basics of how automation specifications are structured, how suites are organized, and the execution process. -Participants will learn how Robot Framework is run and explore the generated reports and logs that document test results. +Participants will learn how Robot Framework is run and explore the generated reports and logs that document test results. The chapter also provides an overview of suite structures, -the role of libraries and resource files, +the role of libraries and resource files, and how to import them. Additionally, it delves into the core syntax of Robot Framework, -focusing on how keywords are defined and used, the types of keyword arguments, -and how keyword documentation is interpreted to ensure clarity and maintainability. \ No newline at end of file +focusing on how keywords are defined and used, the types of keyword arguments, +and how keyword documentation is interpreted to ensure clarity and maintainability. diff --git a/website/docs/chapter-02/01_suitefile.md b/website/docs/chapter-02/01_suitefile.md index 65538baf..34a7c242 100644 --- a/website/docs/chapter-02/01_suitefile.md +++ b/website/docs/chapter-02/01_suitefile.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2.1 Suite File & Tree Structure @@ -18,8 +20,8 @@ The given path to Robot Framework where it starts parsing is considered the **Ro If the path to a single file is given as **Root Suite** directly to Robot Framework, only this file is parsed. If a directory path is given, starting at this location, Robot Framework will parse all `*.robot` files and directories within this path. -Robot Framework analyzes all containing files and determines if they contain test cases or tasks. If they do, they are considered **Suite Files** or **Low-Level Suites**. -All directories that either directly or indirectly contain a Suite File are considered **Suites Directories** or **Higher-Level Suites**. +Robot Framework analyzes all containing files and determines if they contain test cases or tasks. If they do, they are considered **Suite Files** or **Low-Level Suites**. +All directories that either directly or indirectly contain a Suite File are considered **Suites Directories** or **Higher-Level Suites**. The ordering of suites during execution is, by default, defined by their name and hierarchy. All files and directories, which are suites in one directory, are considered on the same level and are executed in case-insensitive alphabetical order. @@ -71,9 +73,9 @@ Recall the conditions and requirements for a file to be considered a Suite file :::: -Robot Framework parses files with the extension `.robot` and searches for test cases or tasks within these files. +Robot Framework parses files with the extension `.robot` and searches for test cases or tasks within these files. -A parsed file that contains at least one test case or task is called a **Suite File**. +A parsed file that contains at least one test case or task is called a **Suite File**. A Suite File **either** contains `*** Test Cases ***` (in Test Suites) **or** `*** Tasks ***` (in Task Suites), but it CANNOT contain both types simultaneously. @@ -96,13 +98,9 @@ These sections are recognized by their header row. The format is `***
***` with three asterisks before and after the section name and section names in **Title Case** separated by a space. The following sections are recognized by Robot Framework and are recommended to be used in the order they are listed: -- `*** Settings ***` -- `*** Variables ***` -- `*** Test Cases ***` or `*** Tasks ***` (mandatory in Suite Files) -- `*** Keywords ***` -- `*** Comments ***` - -The sections `*** Settings ***`, `*** Variables ***`, `*** Keywords ***`, and `*** Comments ***` are optional in suite files and can be omitted if not needed. +- `*** Settings ***`- `*** Variables ***`- `*** Test Cases ***` or `*** Tasks ***` (mandatory in Suite Files) +- `*** Keywords ***`- `*** Comments ***` +The sections `*** Settings ***`, `*** Variables ***`, `*** Keywords ***`, and `*** Comments ***` are optional in suite files and can be omitted if not needed. ### 2.1.2.1 Introduction to `*** Settings ***` Section @@ -124,7 +122,7 @@ Understand the concepts of suite settings and how to define them. :::: The `*** Settings ***` section is used to configure various aspects of the test|task suite. -It allows you to import keywords from external libraries (`Library`) or resource files (`Resource`), and import variables (`Variables`) from variable files (not part of this syllabus) that are needed for execution in the containing tests|tasks. +It allows you to import keywords from external libraries (`Library`) or resource files (`Resource`), and import variables (`Variables`) from variable files (not part of this syllabus) that are needed for execution in the containing tests|tasks. In this section, the suite name, that is normally derived from the file name, can be redefined with the `Name` setting and its documentation can be defined with the `Documentation` setting. @@ -144,7 +142,7 @@ Those settings are prefixed with either `Test` or `Task`, according to the type - `Test Tags`/`Task Tags` (locally `[Tags]`) define tags that are assigned to tests|tasks in the suite and can be used to filter tests|tasks for execution or for attributing information to the tests|tasks. The local setting appends or removes tags defined by the suite's default. See [4.4 Test|Task Tags and Filtering Execution](chapter-04/04_tags.md) for more information. -- `Test Template`/`Task Template` (locally `[Template]`) defines a template keyword that defines the test|task body and is typically used for Data-Driven Testing where each test has the same keywords but different argument data. The local setting overrides the suite's default. +- `Test Template`/`Task Template` (locally `[Template]`) defines a template keyword that defines the test|task body and is typically used for Data-Driven Testing where each test has the same keywords but different argument data. The local setting overrides the suite's default. Similar to test|task tags, also keyword tags can be defined in the `*** Settings ***` section with the `Keyword Tags` (locally `[Tags]`) setting, which can be used to set keyword tags to the keywords. The local setting appends or removes tags defined by the suite's default. @@ -161,10 +159,10 @@ Recall the purpose of the `*** Variables ***` section. :::: -This section is used to define suite variables that are used in the suite or its tests|tasks or inside their keywords. +This section is used to define suite variables that are used in the suite or its tests|tasks or inside their keywords. The most common use case is to define these variables as constants that contain a static value during execution. -This can either be a default value, that may be overwritten by globally defined variables via the Command Line Interface (CLI) or a constant value that is used in multiple places in the suite. +This can either be a default value, that may be overwritten by globally defined variables via the Command Line Interface (CLI) or a constant value that is used in multiple places in the suite. In some cases, these variables are also dynamically reassigned during the execution of the suite, but this is not recommended and should be avoided if possible, because this may lead to test|task runtime dependencies and errors caused by these side-effects that are hard to debug and find. @@ -194,7 +192,7 @@ A suite file must contain either a `*** Test Cases ***` or a `*** Tasks ***` sec See [2.6 Writing Test|Task and Calling Keywords](chapter-02/06_writing_test.md) for more information about the `*** Test Cases ***` or `*** Tasks ***` section. -{/* TODO maybe more references to Test Setup/Teardown or Documentation? */} +{/* TODO maybe more references to Test Setup/Teardown or Documentation? */} ### 2.1.2.4 Introduction to `*** Keywords ***` Section @@ -227,9 +225,10 @@ See [3.3.1 `*** Keywords ***` Section](chapter-03/03_user_keyword.md#331--keywor ### 2.1.2.5 Introduction to `*** Comments ***` Section -This section is used to add comments to the suite file or resource file. +This section is used to add comments to the suite file or resource file. All content in this section is ignored by Robot Framework and is not executed or parsed. + diff --git a/website/docs/chapter-02/02_suitefile_syntax.md b/website/docs/chapter-02/02_suitefile_syntax.md index 52cf3671..f82eab3f 100644 --- a/website/docs/chapter-02/02_suitefile_syntax.md +++ b/website/docs/chapter-02/02_suitefile_syntax.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2.2 Basic Suite File Syntax @@ -14,7 +16,7 @@ Understand the basic syntax of test cases and tasks. :::: -Suite files and resource files share the same syntax, however they differ in their capabilities. +Suite files and resource files share the same syntax, however they differ in their capabilities. Resource files are explained in more detail in [2.4.2 Resource Files](chapter-02/04_keyword_imports.md#242-resource-files) [3.1 Resource File Structure](chapter-03/01_resource_file.md). @@ -30,16 +32,16 @@ Understand and apply the mechanics of indentation and separation in Robot Framew :::: -As mentioned before, Robot Framework uses an indentation-based and space-separated syntax to structure keywords, test cases, and tasks. +As mentioned before, Robot Framework uses an indentation-based and space-separated syntax to structure keywords, test cases, and tasks. -**Two or more spaces** are used to separate or indent statements in Robot Framework files, while a single space is a valid character in tokens (e.g. keyword names, argument values, variables, etc.). +**Two or more spaces** are used to separate or indent statements in Robot Framework files, while a single space is a valid character in tokens (e.g. keyword names, argument values, variables, etc.). The clear recommendation for separators is to use **four spaces** or more to unambiguously make it visible to a potential reader where elements are separated or indented. A statement in Robot Framework is a logical line that contains specific data tokens, which are separated by multiple spaces (separator tokens) and typically end with a line break (end-of-line token). To create a statement spanning multiple lines, literal lines can be continued by adding `...` (three dots) and a separator token at the beginning of the next line, maintaining the same indentation level as the line being continued. -**Example 1**: A keyword call is a statement that consists of a keyword name and its arguments, which are separated by two or more spaces from the keyword name and from each other. +**Example 1**: A keyword call is a statement that consists of a keyword name and its arguments, which are separated by two or more spaces from the keyword name and from each other. An optional assignment of the return value can be possible as well. The line comments starting with a hash `#` show the tokens in the statement. @@ -72,10 +74,10 @@ Test Case Name # SEP | ASSIGNMENT | SEP | KEYWORD | EOL ``` -In the example above, the test case `Test Case Name` contains three keyword calls. +In the example above, the test case `Test Case Name` contains three keyword calls. The first keyword call `Keyword Call` has two arguments, `argument one` and `argument two`. The second keyword call even though it is split over two lines is considered one logical line and identical to the first keyword call. -The third keyword call is a keyword call that assigns the return value of the keyword `Keyword Getter Call` to the variable `${variable_assignment}`. +The third keyword call is a keyword call that assigns the return value of the keyword `Keyword Getter Call` to the variable `${variable_assignment}`. **Example 2**: In the `*** Settings ***` section, the settings are separated from their values by four or more spaces. @@ -93,7 +95,7 @@ Resource keywords.resource All elements themselves in their section are written without any indentation. -So, settings in the `*** Settings ***` section, test cases in the `*** Test Cases ***` section, +So, settings in the `*** Settings ***` section, test cases in the `*** Test Cases ***` section, and keywords in the `*** Keywords ***` section are written without any indentation. However, when defining tests|tasks and keywords, indentation is used to define their body, while their name is still un-indented, e.g., after a test case name, all subsequent lines that are part of the test case body are indented by two or more spaces. @@ -104,7 +106,7 @@ The body ends when either a new un-indented element (e.g. test case or keyword) or another section like `*** Keywords ***` starts or the end of the file is reached. -Within the body of tests|tasks and keywords, control structures like loops or conditions can be used. Their content should be indented by additional four spaces to make it clear that they are part of the control structure. However, this is not mandatory and only a recommendation to make the file more readable. +Within the body of tests|tasks and keywords, control structures like loops or conditions can be used. Their content should be indented by additional four spaces to make it clear that they are part of the control structure. However, this is not mandatory and only a recommendation to make the file more readable. While single tabulators (`\t`) as well as two or more spaces are valid separators, it is recommended to use multiple spaces for indentation and separation and avoid tabulators. @@ -214,7 +216,7 @@ Some examples are: - the `#` hash character that is used to start a comment as described above. - variables that are started by e.g. `${` (See [3.2 Variables](chapter-03/02_variables.md)) - multiple spaces that are considered as separators -- equal sign `=` that is used to assign named arguments to keywords +- equal sign `=` that is used to assign named arguments to keywords All those characters or character sequences that are interpreted as control characters can be escaped by a backslash `\`. This means that the character following the backslash is interpreted as a normal character and not as a control character. @@ -248,13 +250,11 @@ Understand the structure of a basic suite file. :::: -In the following example, two test cases are defined in a suite file. -- `Login User With Password` -- `Denied Login With Wrong Password` - +In the following example, two test cases are defined in a suite file. +- `Login User With Password`- `Denied Login With Wrong Password` Both test the login functionality of a system by calling four keywords in their bodies. -In the `*** Settings ***` section, the suite is documented, and the keywords for connecting to the server, logging in, and verifying the login are imported from a resource file. +In the `*** Settings ***` section, the suite is documented, and the keywords for connecting to the server, logging in, and verifying the login are imported from a resource file. The settings of this section are not indented, but their values are separated by four or more spaces. In the `*** Test Cases ***` section, there are two test cases defined. @@ -298,3 +298,4 @@ Denied Login With Wrong Password + diff --git a/website/docs/chapter-02/03_executing.md b/website/docs/chapter-02/03_executing.md index 9898eb93..35d315b4 100644 --- a/website/docs/chapter-02/03_executing.md +++ b/website/docs/chapter-02/03_executing.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2.3 Executing Robot ::::lo[Learning Objectives] @@ -14,8 +16,7 @@ Robot Framework comes with three executables when being installed which are desi - `robot` is the main executable that is used to execute suites. - `rebot` (not part of this syllabus) is used to post-process execution results and generate reports. -- `libdoc` (not part of this syllabus) is used to generate keyword documentation for libraries and resource files. See [2.5 Keyword Interface and Documentation](chapter-02/05_keyword_interface.md) - +- `libdoc` (not part of this syllabus) is used to generate keyword documentation for libraries and resource files. See [2.5 Keyword Interface and Documentation](chapter-02/05_keyword_interface.md) ## 2.3.1 `robot` command & help @@ -30,21 +31,21 @@ Understand how to run the `robot` command and its basic usage. :::: -The `robot` command is used to run a Robot Framework execution, which will execute suites and their containing tests|tasks. +The `robot` command is used to run a Robot Framework execution, which will execute suites and their containing tests|tasks. -At a basic level, you can run `robot` by providing the path to a suite file or suite directory containing suite files as last argument. +At a basic level, you can run `robot` by providing the path to a suite file or suite directory containing suite files as last argument. ```plaintext robot ``` -In case of the [2.2.5 Example Suite File](chapter-02/02_suitefile_syntax.md#225-example-suite-file) where a single suite file named `TestSuite.robot` is stored in a directory `robot_files`, to execute the example test suite the following command is used, if the current working directory of the terminal is the directory containing the `robot_files` directory: +In case of the [2.2.5 Example Suite File](chapter-02/02_suitefile_syntax.md#225-example-suite-file) where a single suite file named `TestSuite.robot` is stored in a directory `robot_files`, to execute the example test suite the following command is used, if the current working directory of the terminal is the directory containing the `robot_files` directory: ```plaintext > robot robot_files ``` This command starts the Robot Framework execution by first parsing all files in the given directory tree that have the extension `.robot`, -then creates an execution model and finally, executes all suites with their test cases from that model. -During execution, the results of each test case are printed to the console and at the end a summary is printed and reports are generated. +then creates an execution model and finally, executes all suites with their test cases from that model. +During execution, the results of each test case are printed to the console and at the end a summary is printed and reports are generated. Example Console Output: ```plaintext title="Console Output" @@ -69,7 +70,7 @@ Log: /path/to/log.html Report: /path/to/report.html ``` -The `robot` command can optionally be configured with additional options to control the execution behavior, such as setting output formats, specifying specific tests to run, or controlling logging levels and many more. These options are named arguments that are passed to the `robot` command BEFORE the path to the suite file or directory. To learn more about these options, you can use the help of the `robot` command like: `robot --help`. +The `robot` command can optionally be configured with additional options to control the execution behavior, such as setting output formats, specifying specific tests to run, or controlling logging levels and many more. These options are named arguments that are passed to the `robot` command BEFORE the path to the suite file or directory. To learn more about these options, you can use the help of the `robot` command like: `robot --help`. @@ -93,8 +94,8 @@ After executing a suite, Robot Framework, by default, generates three output fil `log.html` and `report.html` are generated based on the information stored in `output.xml`. -A unique feature of Robot Framework is, that it logs each keyword call and its arguments with its log outputs and timestamps, so that it is possible to have a very detailed view of the execution flow and the data that was used during the execution. -In case of a failure it is possible to see the exact keyword call that failed and the arguments that were used, which can be very helpful for debugging or reporting. Furthermore, you also get all passed keywords and even the non‑executed keywords, allowing you to trace the whole execution flow. +A unique feature of Robot Framework is, that it logs each keyword call and its arguments with its log outputs and timestamps, so that it is possible to have a very detailed view of the execution flow and the data that was used during the execution. +In case of a failure it is possible to see the exact keyword call that failed and the arguments that were used, which can be very helpful for debugging or reporting. Furthermore, you also get all passed keywords and even the non‑executed keywords, allowing you to trace the whole execution flow. @@ -112,7 +113,7 @@ Recall the four different status labels used by Robot Framework. Robot Framework uses different status labels to indicate the result of an execution: -On Suite, Test Case, Task and Keyword Level: +On Suite, Test Case, Task and Keyword Level: - **`PASS`**: Indicates that the item was successfully executed without unexpected errors. - **`FAIL`**: Shows that the item encountered an error and did not pass. - **`SKIP`**: Indicates that the item was intentionally skipped, either by tagging or during execution, typically because some condition was not met. @@ -124,7 +125,7 @@ Additional Keyword Status: **Atomic elements** like Library Keywords or Robot Framework language statements do define their own status. -**Composite elements** like suites (composed of tests|tasks), tests|tasks (composed of keywords) and User Keywords (composed of Library Keywords and Robot Framework statements) do define their status based on the status of their child elements. +**Composite elements** like suites (composed of tests|tasks), tests|tasks (composed of keywords) and User Keywords (composed of Library Keywords and Robot Framework statements) do define their status based on the status of their child elements. ### 2.3.3.1 PASS @@ -144,11 +145,11 @@ This status is used if an element was executed successfully without any errors o **Atomic elements** are `PASS` if they were executed successfully without reporting an error by raising an exception. **Composite elements** are `PASS` if all their executed body elements are pass. -E.g. in case of User Keywords this means that if all keywords or Robot Framework language statements that were directly called by that User Keyword were `PASS` the User Keyword itself is considered `PASS`. +E.g. in case of User Keywords this means that if all keywords or Robot Framework language statements that were directly called by that User Keyword were `PASS` the User Keyword itself is considered `PASS`. Library Keywords like `Run Keyword And Expect Error`, from BuiltIn Library, do `PASS` if the keyword they are internally calling does raise an error with the expected message or type. -That means that a composite element like suite, test|task or User Keyword may be `PASS` even if some of its deeper child elements are `FAIL`. +That means that a composite element like suite, test|task or User Keyword may be `PASS` even if some of its deeper child elements are `FAIL`. ### 2.3.3.2 FAIL @@ -171,7 +172,7 @@ Exceptions are teardowns, as explained in [Chapter 4: Advanced Structuring and E **Atomic elements** are `FAIL` if they were tried to be executed but raised an exception. **Composite elements** are `FAIL` if at least one of their executed direct body elements are `FAIL`. -Therefore a failure typically distributes upwards through the hierarchy of elements until it reaches the root suite. +Therefore a failure typically distributes upwards through the hierarchy of elements until it reaches the root suite. A User Keyword is `FAIL` if one of its called Library Keywords is `FAIL`. A test|task is `FAIL` if one of its directly called Keywords is `FAIL`. @@ -199,3 +200,4 @@ There are basically two kinds of logging information in Robot Framework. Log messages can be written with different levels of severity (i.e. `INFO`, `DEBUG`, `TRACE`, `WARN` or `ERROR`). Which levels are written to the log can be controlled by the log level of an execution. Further information in later chapters. + diff --git a/website/docs/chapter-02/04_keyword_imports.md b/website/docs/chapter-02/04_keyword_imports.md index ef77ee24..6b916ce9 100644 --- a/website/docs/chapter-02/04_keyword_imports.md +++ b/website/docs/chapter-02/04_keyword_imports.md @@ -1,9 +1,11 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2.4 Keyword Imports -{/* TODO: To use Keywords that are not part of BuiltIn, which is always imported invisibly, you must import keywords into the current scope. Basically Two different sources of keywords. +{/* TODO: To use Keywords that are not part of BuiltIn, which is always imported invisibly, you must import keywords into the current scope. Basically Two different sources of keywords. - Libraries, which contains low-level keywords actually implementing functionality, typically in Python. -- Resource Files, which either again import libraries or other Resource Files or they specify User Keywords. */} +- Resource Files, which either again import libraries or other Resource Files or they specify User Keywords. */} Robot Framework has a modular design that allows users to import keywords from external sources. Without importing external keywords into a suite, only the keywords from Robot Framework's BuiltIn library are available for use, due to them being imported automatically. @@ -40,8 +42,8 @@ From a user perspective there are three different kinds of libraries: Further more detailed information about the different types of libraries and are described in later chapters. {/* TODO: Do we fulfill this promise? */} -To import a library into a suite or resource file the `Library` setting is used in the `*** Settings ***` section followed by the name of the library as long as they are located in the Python module search path, which automatically happens if they are installed via `pip`. -The name of the library is case-sensitive and should be taken from the library's keyword documentation. +To import a library into a suite or resource file the `Library` setting is used in the `*** Settings ***` section followed by the name of the library as long as they are located in the Python module search path, which automatically happens if they are installed via `pip`. +The name of the library is case-sensitive and should be taken from the library's keyword documentation. By default, libraries in Robot Framework are implemented in Python and the name of the library is the name of the Python module that contains the library implementation. Alternatively, if a library is not in Python module search path, a library can be imported using the path to the Python module. See [2.4.3 Import Paths](chapter-02/04_keyword_imports.md#243-import-paths). @@ -79,9 +81,9 @@ Use resource files to import new keywords. :::: -As mentioned before resource files are used to organize and store keywords and variables that are used in multiple suites. +As mentioned before resource files are used to organize and store keywords and variables that are used in multiple suites. -They share a similar structure and the same syntax as suite files, but they do not contain test cases or tasks. +They share a similar structure and the same syntax as suite files, but they do not contain test cases or tasks. See [2.2 Basic Suite File Syntax](chapter-02/02_suitefile_syntax.md) for more information about the structure of suite files and [3.1 Resource File Structure](chapter-03/01_resource_file.md) for more details of their structure. They can contain other keyword imports, which cause the keywords from the imported libraries or resource files to be available in the suites where the resource file is imported. The same applies for variables that are defined and imported from other resource files. @@ -101,8 +103,7 @@ Resource D:/keywords/central_keywords.resource ``` See more about the structure of resource files in -[3.1 Resource File Structure](chapter-03/01_resource_file.md) -and how keywords and variables are created in the sections following that. +[3.1 Resource File Structure](chapter-03/01_resource_file.md)and how keywords and variables are created in the sections following that. @@ -124,7 +125,7 @@ If a relative path is given, the path is resolved relative to the data file that If an **absolute path** is given, the resource file or library is searched for at the given path. If a **relative path** is given, the resource file or library is searched for relative to the data file that is importing it and then relative to the Python *module search path*. -This *module search path* is defined by the Python interpreter that executes Robot Framework and can be influenced by the environment variable `PYTHONPATH` or by using the CLI-Argument `--pythonpath` when executing `robot`. +This *module search path* is defined by the Python interpreter that executes Robot Framework and can be influenced by the environment variable `PYTHONPATH` or by using the CLI-Argument `--pythonpath` when executing `robot`. For **path separators**, it is strongly recommended to always use forward slashes (`/`), and even on Windows, not to use backslashes (`\`). This is because backslashes are used as escape characters in Robot Framework, which can cause issues when used in paths. Forward slashes are supported on all operating systems when used in Robot Framework. @@ -138,3 +139,4 @@ That path needs to be defined when executing Robot Framework but can lead to mor + diff --git a/website/docs/chapter-02/05_keyword_interface.md b/website/docs/chapter-02/05_keyword_interface.md index 8a8fd3f2..a8e8ae08 100644 --- a/website/docs/chapter-02/05_keyword_interface.md +++ b/website/docs/chapter-02/05_keyword_interface.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2.5 Keyword Interface and Documentation @@ -11,9 +13,9 @@ Understand the structure of keyword interfaces and how to interpret keyword docu :::: -Library Keywords and User Keywords that are defined in a resource file should have a documentation text that describes what the keyword does and how it should be used. +Library Keywords and User Keywords that are defined in a resource file should have a documentation text that describes what the keyword does and how it should be used. -Robot Framework is capable of generating **Keyword Documentation** files that contains a library- or resource-documentation, all keywords, their argument interfaces, and their documentation texts. +Robot Framework is capable of generating **Keyword Documentation** files that contains a library- or resource-documentation, all keywords, their argument interfaces, and their documentation texts. This documentation file can be generated with the `libdoc` command and can be used to provide a reference for users who want to use the keywords. Basically all standard and external 3rd party libraries offer these Keyword Documentations as online available HTML pages. @@ -40,7 +42,7 @@ The Keyword Documentation is structured so, that it contains first the library o Each library or resource documentation can contain the following information sections for keywords: - **Name**: The name of the keyword as it is called. -- **Arguments** (opt.): The argument interface that the keyword expects/offers its types and default values. +- **Arguments** (opt.): The argument interface that the keyword expects/offers its types and default values. - **Return Type** (opt.): The type of the return value of the keyword. - (*) **Tags** (opt.): The tags that are assigned to the keyword to categorize keywords. - **Documentation** (opt.): The documentation text that describes what the keyword does and how it should be used. @@ -53,27 +55,23 @@ Their documentation has been generated by the Robot Framework tool `libdoc` whic ### 2.5.1.1 Example Keyword `Should Be Equal` [Documentation of `Should Be Equal` from `BuiltIn` library](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Should%20Be%20Equal) - `Should Be Equal` is part of the BuiltIn library and is documented as follows: ![Should Be Equal Keyword Documentation](/img/Should_Be_Equal_Docs.png) - -This keyword has 2 "Mandatory Arguments" and 6 "Optional Arguments". +This keyword has 2 "Mandatory Arguments" and 6 "Optional Arguments". All of them can be called positionally or by name. ### 2.5.1.2 Example Keyword `Set To Dictionary` [Documentation of `Set To Dictionary` from `Collections` library](https://robotframework.org/robotframework/latest/libraries/Collections.html#Set%20To%20Dictionary) - `Set To Dictionary` is part of the Collections library and is documented as follows: ![Set To Dictionary Keyword Documentation](/img/Set_To_Dictionary_part_1.png) - This keyword has one :term[Mandatory Argument] `dictionary` which can be called positionally or by name. See [Mandatory Args](../chapter-03/user_keyword). -The latter two arguments are optional and can be used depending on the style of defining keys and values the user likes most. +The latter two arguments are optional and can be used depending on the style of defining keys and values the user likes most. -The argument `key_value_pairs` is a :term[Variable Number of Positional Arguments] and can only be set by position. +The argument `key_value_pairs` is a :term[Variable Number of Positional Arguments] and can only be set by position. Therefore, if it shall be set, all preceding arguments must be set by position as well. See [2.5.2.5 Variable Number of Positional Arguments](chapter-02/05_keyword_interface.md#2525-variable-number-of-positional-arguments) for more information about this kind of argument. @@ -85,11 +83,9 @@ See [2.5.2.7 Free Named Arguments](chapter-02/05_keyword_interface.md#2527-free- ### 2.5.1.3 Example Keyword `Get Regexp Matches` [Documentation of `Get Regexp Matches` from `String` library](https://robotframework.org/robotframework/latest/libraries/String.html#Get%20Regexp%20Matches) - `Get Regexp Matches` is part of the String library and is documented as follows: ![Get Regexp Matches Keyword Documentation](/img/Get_Regexp_Matches_Docs.png) - This keyword has 2 "Mandatory Arguments" that can be called positionally or by name. The last two arguments are optional. @@ -166,11 +162,10 @@ Test Will Fail Due to Missing Args Should Be Equal One ``` -The first Test will pass, because both argument values are equal. +The first Test will pass, because both argument values are equal. The second Test will fail, because the argument values are not equal. The third Test will fail before the keyword `Should Be Equal` is actually being executed, because the keyword expects at least two arguments. The Error Message would be: `Keyword 'BuiltIn.Should Be Equal' expected 2 to 8 arguments, got 1.` - Two arguments are mandatory and the additional six arguments are optional in the `Should Be Equal` keyword. @@ -212,19 +207,15 @@ Recall the concept of keywords with embedded arguments used in Behavior-Driven S :::: -Keywords can include arguments embedded directly into their names, a feature primarily used for Behavior-Driven Development (BDD). -Embedded arguments are mandatory and must be provided in the exact position defined within the keyword name. +Keywords can include arguments embedded directly into their names, a feature primarily used for Behavior-Driven Development (BDD). +Embedded arguments are mandatory and must be provided in the exact position defined within the keyword name. -Keyword names include arguments defined using the scalar variable syntax with dollar and curly braces (`${var_name}`). +Keyword names include arguments defined using the scalar variable syntax with dollar and curly braces (`${var_name}`). This syntax explicitly defines these as arguments, distinguishing them from the rest of the keyword name. Example keyword names are: -- `"${url}" is open` -- `the user clicks the "${button}" button` -- `the page title should be ${exp_title}` -- `the url should be ${exp_url}` - -Example Test Case: +- `"${url}" is open`- `the user clicks the "${button}" button`- `the page title should be ${exp_title}`- `the url should be ${exp_url}` +Example Test Case: ```robotframework *** Test Cases *** Foundation Page should be Accessible @@ -236,8 +227,8 @@ Foundation Page should be Accessible The optional prefixes `Given`, `When`, `Then`, `And` and `But` are basically ignored by Robot Framework if a keyword is found matching the rest of the name including the embedded arguments. In the example :term[test case] some keywords are designed so that the arguments are surrounded by double quotes (`"`) for better visibility. -A mix of embedded arguments and "normal" arguments is possible to fully support BDD. -In the keyword documentation the embedded arguments are written in variable syntax with dollar-curly-braces (`${var_name}`) to indicate that they are not part of the keyword name but are arguments. +A mix of embedded arguments and "normal" arguments is possible to fully support BDD. +In the keyword documentation the embedded arguments are written in variable syntax with dollar-curly-braces (`${var_name}`) to indicate that they are not part of the keyword name but are arguments. They can also be defined using regular expressions to allow for more complex argument structures, which is not part of this syllabus. @@ -286,9 +277,9 @@ Depending on the number of keys and values, different amount of arguments are ne This key_value_pairs argument is marked with a single asterisk `*` before the argument name in the keyword documentation. -When calling this keyword, the first positional argument is assigned to `dictionary`, while all subsequent positional arguments are collected into `key_value_pairs`. +When calling this keyword, the first positional argument is assigned to `dictionary`, while all subsequent positional arguments are collected into `key_value_pairs`. Because of this behavior, no additional positional arguments can be used after these :term[Variable Number of Positional Arguments]. -As a result, any arguments following these :term[Variable Number of Positional Arguments] must be named arguments, +As a result, any arguments following these :term[Variable Number of Positional Arguments] must be named arguments, regardless of whether they are mandatory or optional arguments with a default value. @@ -342,9 +333,9 @@ These arguments are similar to the :term[Variable Number of Positional Arguments However, instead of collecting positional values, they gather all named values that are not explicitly defined as argument names. In this case all values given to the keyword as arguments, that do contain an unescaped equal sign (`=`) are considered as named arguments. -Free named arguments are marked with two asterisks `**` before the argument name in the keyword documentation. +Free named arguments are marked with two asterisks `**` before the argument name in the keyword documentation. -The example of the `Set To Dictionary` keyword also has a free named argument `** items`. +The example of the `Set To Dictionary` keyword also has a free named argument `** items`. When calling this keyword all named arguments that are not explicitly defined as argument names are collected into the `items` argument and will be available as a dictionary in the keyword implementation. @@ -403,7 +394,6 @@ Test Conversion In the first call the keyword will be called with the integer values `10` and `20` and will work as expected. The second keyword call will fail, because the second argument is not a number and cannot be converted to an integer. The error message would be: `ValueError: Argument 'y' got value 'Not_A_Number' that cannot be converted to integer.` - The advantage of using type hints is that the user get more information about what kind of values are expected and the keyword implementation can be simpler, because it can rely on the arguments being of the expected type. {/* TODO: Just to understand that they are there and that they may document how values are handled or which are allowed. */} @@ -427,7 +417,7 @@ So, a keyword can `RETURN` values to the caller as functions do in programming l If the keyword implementation offers a type hint for the return value, this is documented in the keyword documentation. Similar to the argument types, return types are optional and a more recent feature of Robot Framework and therefore not widely used, yet. -It is important to know that keywords without a return type hint are often still returning values! +It is important to know that keywords without a return type hint are often still returning values! This is typically documented in the *Documentation* part of the keyword documentation. {/* TODO: Keywords may gather information and return these to the caller of that keyword. A Documented Return Value may be present but often it is just written in the docs, due to new feature */} @@ -477,3 +467,4 @@ Should Be Equal ${x} expected ignore_case=True formatter=repr + diff --git a/website/docs/chapter-02/06_writing_test.md b/website/docs/chapter-02/06_writing_test.md index 1180f2c8..95ad0f3c 100644 --- a/website/docs/chapter-02/06_writing_test.md +++ b/website/docs/chapter-02/06_writing_test.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 2.6 Writing Test|Task and Calling Keywords ::::lo[Learning Objectives] @@ -10,18 +12,18 @@ Understand how to call imported keywords and how to structure keyword calls. :::: -A typical test case or task is a sequence of keyword calls that are executed in a specific order. -As learned before these keywords need to be imported into the suite or resource file before they can be used. -When using keywords in a test|task or User Keyword, it is important to indent the keyword calls correctly. +A typical test case or task is a sequence of keyword calls that are executed in a specific order. +As learned before these keywords need to be imported into the suite or resource file before they can be used. +When using keywords in a test|task or User Keyword, it is important to indent the keyword calls correctly. With the exception of returning values, which are described in Chapter 3, -the name of the keyword is the first element of the keyword call followed by the arguments that are separated by two or more spaces. +the name of the keyword is the first element of the keyword call followed by the arguments that are separated by two or more spaces. The following example shows different ways to call imported keywords in a test case based on the `Should Be Equal` keyword from the BuiltIn library. The keyword name should be written as defined in the keyword documentation and may have single spaces or other special characters in it. After the keyword name the arguments are set. All arguments are separated by multiple spaces from the keyword name and from each other and can also include single spaces. -Argument values are stripped from leading and trailing spaces, but spaces within the argument value are preserved. +Argument values are stripped from leading and trailing spaces, but spaces within the argument value are preserved. If an argument shall contain more than one consecutive spaces or start or end with spaces, the spaces must be escaped by a backslash `\` to prevent them from being interpreted as a part of a "multi-space-separator". @@ -78,9 +80,8 @@ Understand the concept of how to set argument values positionally. When calling keywords, arguments can often be set positionally in the order they are defined in the keyword documentation. An exception to this are :term[Named-Only Arguments]{term="Named-Only Argument"} and :term[Free Named Arguments]{term="Free Named Argument"} that can only be set by their name. -However, only using positional values can lead to poor readability as you can see in the previous example: `Mixed Positional Arguments` -Some keywords do not have an obvious order of arguments. -In these cases, calling keywords with named arguments can lead to better readability and understanding of the keyword call. +However, only using positional values can lead to poor readability as you can see in the previous example: `Mixed Positional Arguments`Some keywords do not have an obvious order of arguments. +In these cases, calling keywords with named arguments can lead to better readability and understanding of the keyword call. Using arguments positionally is very handy for arguments that are obvious and easy to understand. In the early login example the following keyword calls exists: @@ -128,11 +129,11 @@ Understand the concept of named arguments and how to set argument values by thei :::: -Keyword Calls with non-obvious arguments should use named argument calls if possible. -Also setting one optional argument but leaving the others at their default value is an indication to use named arguments. +Keyword Calls with non-obvious arguments should use named argument calls if possible. +Also setting one optional argument but leaving the others at their default value is an indication to use named arguments. Named arguments are set by their name followed by an equal sign `=` and the value of the argument. -All named arguments must be set after the positional arguments are set but can be set in any order. +All named arguments must be set after the positional arguments are set but can be set in any order. Equal signs are valid argument values and could therefore be misinterpreted as named arguments, if the text before the equal sign is an existing argument name or if :term[Free Named Arguments]{term="Free Named Argument"} are available at the called keyword. To prevent that, an equal sign in argument values can be escaped by a backslash `\`. @@ -161,12 +162,12 @@ Recall how to use embedded arguments. :::: -Embedded Arguments are mostly used in Behavior-Driven Development (BDD) using Robot Frameworks Behavior-Driven Specification style. +Embedded Arguments are mostly used in Behavior-Driven Development (BDD) using Robot Frameworks Behavior-Driven Specification style. Embedded Arguments are part of the keyword name as described in [2.5.2.3 Embedded Arguments](chapter-02/05_keyword_interface.md#2523-embedded-arguments). -When calling keywords with embedded arguments, all characters that are at the position where the embedded argument is expected are used as the argument value. +When calling keywords with embedded arguments, all characters that are at the position where the embedded argument is expected are used as the argument value. See the example in section [2.5.2.3 Embedded Arguments](chapter-02/05_keyword_interface.md#2523-embedded-arguments). -See also [2.5.2.3 Embedded Arguments](chapter-02/05_keyword_interface.md#2523-embedded-arguments) for more information about how to use embedded arguments. \ No newline at end of file +See also [2.5.2.3 Embedded Arguments](chapter-02/05_keyword_interface.md#2523-embedded-arguments) for more information about how to use embedded arguments. diff --git a/website/docs/chapter-03/00_overview.md b/website/docs/chapter-03/00_overview.md index ba078114..2c0c5c81 100644 --- a/website/docs/chapter-03/00_overview.md +++ b/website/docs/chapter-03/00_overview.md @@ -1,3 +1,6 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 3 Keyword Design, Variables, and Resource Files -This chapter introduces the essential components of Robot Framework: **Keywords**, **Variables**, and **Resource Files**. These building blocks allow users to create reusable, structured, and maintainable automation solutions. Understanding these concepts is critical for developing efficient automation in both testing and RPA contexts. +This chapter introduces the essential components of Robot Framework: **Keywords**, **Variables**, and **Resource Files**. These building blocks allow users to create reusable, structured, and maintainable automation solutions. Understanding these concepts is critical for developing efficient automation in both testing and RPA contexts. + diff --git a/website/docs/chapter-03/01_resource_file.md b/website/docs/chapter-03/01_resource_file.md index 5bbc0cea..d5c4d173 100644 --- a/website/docs/chapter-03/01_resource_file.md +++ b/website/docs/chapter-03/01_resource_file.md @@ -1,22 +1,24 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 3.1 Resource File Structure -Resource Files in Robot Framework are used to store reusable keywords, -variables, and organize imports of other resource files and libraries. +Resource Files in Robot Framework are used to store reusable keywords, +variables, and organize imports of other resource files and libraries. See [2.4.2 Resource Files](chapter-02/04_keyword_imports.md#242-resource-files) for an introduction to Resource Files. -Resource Files are typically used in many suites to share common keywords and variables across different tests|tasks. +Resource Files are typically used in many suites to share common keywords and variables across different tests|tasks. Therefore, they should be designed to be modular, reusable, and maintainable. -Keywords and variables defined in one resource file should therefore +Keywords and variables defined in one resource file should therefore be related to each other to store similar functionality or data. This relation can be based on a common purpose, a common abstraction layer, or a common context. -For example all user keywords and variables that do control -or test a specific part or dialog of an application could be stored together in one resource file. +For example all user keywords and variables that do control +or test a specific part or dialog of an application could be stored together in one resource file. Resource files are imported using the `Resource` setting in the `*** Settings ***` section so that the path to the resource file -is given as an argument to the setting. +is given as an argument to the setting. The extension for resource files shall be `.resource`. Unless the resource file is given as an absolute path, @@ -32,7 +34,7 @@ See [2.4.3 Import Paths](chapter-02/04_keyword_imports.md#243-import-paths) for See [2.1.2 Sections and Their Artifacts](chapter-02/01_suitefile.md#212-sections-and-their-artifacts) for an introduction to sections in suites. -In difference to suite files, resource files do **not** allow the `*** Test Cases ***` or `*** Tasks ***` sections. +In difference to suite files, resource files do **not** allow the `*** Test Cases ***` or `*** Tasks ***` sections. The allowed sections in recommended order are: - `*** Settings ***` to import libraries and other resource files. @@ -42,12 +44,12 @@ The allowed sections in recommended order are: Common settings are: - `Library` to import libraries. - `Resource` to import other resource files. - - `Variables` to import variable files. (Not part of this syllabus) + - `Variables` to import variable files. (Not part of this syllabus) - `Documentation` to provide documentation for the resource file. Additional settings are: - `Keyword Tags` to set tags for all keywords in the resource file. - defining and using Keyword tags is not part of this syllabus. + defining and using Keyword tags is not part of this syllabus. Other settings available in suites are not available in resource files. @@ -65,3 +67,4 @@ The allowed sections in recommended order are: + diff --git a/website/docs/chapter-03/02_variables.md b/website/docs/chapter-03/02_variables.md index 16e94e59..c50f2656 100644 --- a/website/docs/chapter-03/02_variables.md +++ b/website/docs/chapter-03/02_variables.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 3.2 Variables @@ -19,21 +21,21 @@ Recall the relevant five different ways to create and assign variables :::: -Variables in Robot Framework are used to store values that can be referenced and reused throughout suites, test cases, tasks, and keywords. +Variables in Robot Framework are used to store values that can be referenced and reused throughout suites, test cases, tasks, and keywords. They help manage dynamic data or centrally maintained data, reducing hardcoding in multiple locations and making automation flexible. Variables can be created and assigned in various ways, such as: -- Definition in the `*** Variables ***` section in suites or resource files. (see [3.2.2 `*** Variables ***` Section](chapter-03/02_variables.md#322--variables--section)) +- Definition in the `*** Variables ***` section in suites or resource files. (see [3.2.2 `*** Variables ***` Section](chapter-03/02_variables.md#322--variables--section)) - Capturing return values from keywords. (see [3.2.3 Return values from Keywords](chapter-03/02_variables.md#323-return-values-from-keywords)) - Inline assignment using the `VAR` statement. (see [3.2.4 `VAR` Statement](chapter-03/02_variables.md#324-var-statement)) -- As arguments passed to keywords. (see [3.3.5 User Keyword Arguments](chapter-03/03_user_keyword.md#335-user-keyword-arguments)) -- By the command line interface of Robot Framework. (See [5.1.3 Global Variables via Command Line](chapter-05/01_advanced_variables.md#513-global-variables-via-command-line)) +- As arguments passed to keywords. (see [3.3.5 User Keyword Arguments](chapter-03/03_user_keyword.md#335-user-keyword-arguments)) +- By the command line interface of Robot Framework. (See [5.1.3 Global Variables via Command Line](chapter-05/01_advanced_variables.md#513-global-variables-via-command-line)) - (*) By internal implementation of library keywords. -- (*) By importing variables from variable files. +- (*) By importing variables from variable files. (*) These methods are not part of this syllabus. -Beside variables created by the user, Robot Framework also supports **Built-in Variables** that are explained in the [5.1.6 Built-In Variables](chapter-05/01_advanced_variables.md#516-built-in-variables) chapter. +Beside variables created by the user, Robot Framework also supports **Built-in Variables** that are explained in the [5.1.5 Built-In Variables](chapter-05/01_advanced_variables.md#515-built-in-variables) chapter. @@ -56,7 +58,7 @@ Recall the basic syntax of variables :::: Variables in Robot Framework are defined by three attributes: -- **Prefix**: `$`, `@`, or `&` to define the access type to the variable. (`%` for environment variables) +- **Prefix**: `$`, `@`, or `&` to define the access type to the variable. (`%` for environment variables) - **Delimiter**: `{}` to enclose the variable name. - **Variable Name**: The string that addresses the variable. i.e. just the `variable_name` or more advanced access ways. @@ -76,7 +78,7 @@ These different syntactical handling methods allow the users to also create and However, these prefixes just define the access type to the variable, and the actual data stored in the variable can be of any type, including strings, numbers, lists, dictionaries, or even objects. When creating variables, different syntax is used to define the type of the variable as described in the next sections, -but when accessing the variable, the scalar variable syntax with a dollar sign `$` as the prefix is used in most cases. +but when accessing the variable, the scalar variable syntax with a dollar sign `$` as the prefix is used in most cases. More details about list-like and dictionary-like variables, and when to use `@` or `&` when accessing these variables, can be found in the [5.1 Advanced Variables](chapter-05/01_advanced_variables.md) chapter. @@ -101,12 +103,12 @@ Use the correct variable prefixes for assigning and accessing variables :::: -Variables can be defined in the `*** Variables ***` section within both suite files and resource files. +Variables can be defined in the `*** Variables ***` section within both suite files and resource files. -- Variables defined in a **suite file** are accessible throughout that specific suite, enabling consistent use across all test|tasks, and keywords executed within that suite. -- Variables defined in a **resource file**, however, are accessible in all files that import the resource file directly or indirectly by imports of other resource files. This allows for the sharing of variables across multiple suites or files while maintaining modularity and reusability. +- Variables defined in a **suite file** are accessible throughout that specific suite, enabling consistent use across all test|tasks, and keywords executed within that suite. +- Variables defined in a **resource file**, however, are accessible in all files that import the resource file directly or indirectly by imports of other resource files. This allows for the sharing of variables across multiple suites or files while maintaining modularity and reusability. -This section is evaluated before any other section in a resource or suite file, +This section is evaluated before any other section in a resource or suite file, and therefore variables defined here can be used in any other section of the file. This section is typically used to define constants or to initialize variables that may be re-assigned during execution and more globally used. @@ -120,12 +122,12 @@ Variables created in this section: - have a **suite scope** in the suite created or imported to. Because two or more spaces are used to separate elements in a row, -all values are stripped of leading and trailing spaces, identical to arguments of keyword calls (see [2.2.4 Escaping of Control Characters](chapter-02/02_suitefile_syntax.md#224-escaping-of-control-characters) to be able to define these spaces. +all values are stripped of leading and trailing spaces, identical to arguments of keyword calls (see [2.2.4 Escaping of Control Characters](chapter-02/02_suitefile_syntax.md#224-escaping-of-control-characters) to be able to define these spaces. Variable values in Robot Framework can include other variables, and their values will be concatenated at runtime when the line is executed. This means that when a variable is used within another variable's value, the final value is resolved by replacing the variables with their actual content during execution. -Variables defined in the `*** Variables ***` section are recommended to be named in uppercase to distinguish them from local variables defined in test cases or keywords. +Variables defined in the `*** Variables ***` section are recommended to be named in uppercase to distinguish them from local variables defined in test cases or keywords. ### 3.2.2.1 Scalar Variable Definition @@ -146,7 +148,7 @@ Understand how multiple lines can be used to define scalar variables :::: -Example of creating scalar variables: +Example of creating scalar variables: ```robotframework *** Variables *** ${NAME} Robot Framework @@ -183,7 +185,6 @@ ${SEARCH_URL} https://example.com/search `${SEARCH_URL}` will contain the following without any spaces or newlines: `https://example.com/search?query=robot+framework&page=1&filter=recent&lang=en&category=test-automation` - ### 3.2.2.2 Primitive Data Types ::::lo[Learning Objectives] @@ -240,7 +241,7 @@ Understand how to set and access data in list variables :::: -List variables store multiple values and are defined using the at-syntax `@{variable_name}`. +List variables store multiple values and are defined using the at-syntax `@{variable_name}`. You can define as many values as needed, with each additional value separated by multiple spaces or line continuation using the `...` syntax. @@ -321,7 +322,7 @@ In Robot Framework, values returned by keywords can be assigned to variables, enabling data to be passed between different keywords. These variables have a **local scope** in the block where they are created, -i.e., in the test|task or keyword where the assignment is made. +i.e., in the test|task or keyword where the assignment is made. If a variable has already been defined in the `*** Variables ***` section and therefore has a **suite scope**, it will just be locally overwritten/masked by the new variable with the same name. Once the block is left, the original variable with its original value is accessible again. @@ -434,7 +435,7 @@ Example use cases for the `VAR` statement: By default, variables created with the `VAR` statement have a **local scope** in the test|task, or keyword where they are defined. This means that they cannot be accessed outside that specific test|task or keyword, ensuring that variables do not interfere with other parts of the test|task suite. -However, the `VAR` statement can also be used to create variables with a broader scope, using `scope=`, such as suite-wide or global variables, when needed. +However, the `VAR` statement can also be used to create variables with a broader scope, using `scope=`, such as suite-wide or global variables, when needed. These variables can then be accessed outside of the test|task or keyword where they were originally created. For more details on this topic, refer to the section on [5.1.2 Variable Scopes](chapter-05/01_advanced_variables.md#512-variable-scopes). @@ -457,13 +458,14 @@ In Robot Framework, variables have different scopes, which define where they can - **`LOCAL` Scope**: Variables created within a test|task or keyword, by **assignment of return values**, as keyword arguments or **`VAR`** statement, are by default `LOCAL` to that specific test|task or keyword body. - They cannot be accessed outside of that block and are destroyed once the block is completed. This means that a local variable created in one test|task can neither be accessed inside the body of a called keyword nor in a subsequent test|task or other keywords. + They cannot be accessed outside of that block and are destroyed once the block is completed. This means that a local variable created in one test|task can neither be accessed inside the body of a called keyword nor in a subsequent test|task or other keywords. - **`SUITE` Scope**: Variables defined at the suite level, for example in the `*** Variables ***` section or through importing resource files, are available to all tests|tasks and keywords called within the suite. - That means that they can be accessed inside a keyword, called from a test|task of that suite even, if this variable is not created as part of the argument interface of that keyword. + That means that they can be accessed inside a keyword, called from a test|task of that suite even, if this variable is not created as part of the argument interface of that keyword. + +Examples and more details on variable scope, such as `TEST` and `GLOBAL` scope can be found in the [5.1.2 Variable Scopes](chapter-05/01_advanced_variables.md#512-variable-scopes) section. -Examples and more details on variable scope, such as `TEST` and `GLOBAL` scope can be found in the [5.1.2 Variable Scopes](chapter-05/01_advanced_variables.md#512-variable-scopes) section. diff --git a/website/docs/chapter-03/03_user_keyword.md b/website/docs/chapter-03/03_user_keyword.md index 12defdab..56689833 100644 --- a/website/docs/chapter-03/03_user_keyword.md +++ b/website/docs/chapter-03/03_user_keyword.md @@ -1,30 +1,31 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 3.3 User Keyword Definition & Arguments -User Keywords in Robot Framework allow users to create their own -keywords by combining existing keywords into reusable higher-level actions. +User Keywords in Robot Framework allow users to create their own +keywords by combining existing keywords into reusable higher-level actions. They help improve readability, maintainability, and modularity in automation by abstracting complex sequences into named actions. -User Keywords are defined syntactically very similarly to tests|tasks -and are defined in the `*** Keywords ***` section of a suite file or resource file. +User Keywords are defined syntactically very similarly to tests|tasks +and are defined in the `*** Keywords ***` section of a suite file or resource file. ## 3.3.1 `*** Keywords ***` Section -The `*** Keywords ***` section of suite and resource files +The `*** Keywords ***` section of suite and resource files is indentation-based similar to the `*** Test Cases ***` section. The user keywords defined are unindented, while their body implementation is indented by multiple spaces. See these sections for more details about -[2.2 Basic Suite File Syntax](chapter-02/02_suitefile_syntax.md) -and [2.6 Writing Test|Task and Calling Keywords](chapter-02/06_writing_test.md). +[2.2 Basic Suite File Syntax](chapter-02/02_suitefile_syntax.md)and [2.6 Writing Test|Task and Calling Keywords](chapter-02/06_writing_test.md). This section can be part of suites or resource files. While keywords defined in suites can solely be used in the suite they are defined in, keywords defined in resource files can be used in any suite that imports these resource files. -Example definition of a user keyword: +Example definition of a user keyword: ```robotframework *** Keywords *** @@ -52,7 +53,7 @@ Recall the rules how keyword names are matched. :::: -The names of User Keywords should be descriptive and clear, reflecting the purpose of the keyword. +The names of User Keywords should be descriptive and clear, reflecting the purpose of the keyword. Well-named keywords make tests more readable and easier to understand. Robot Framework supports Unicode and allows the use of special characters and even Emojis in keyword names. @@ -61,8 +62,8 @@ Also spaces and underscores will be ignored when matching keyword names. So the keywords `Login To System`, and `log_into_system` are considered identical. To identify keywords that shall be executed, Robot Framework uses a matching algorithm that is case-insensitive and ignores spaces and underscores. -- The prefixes Given, When, Then, And, and But (case-insensitive), which are used in Behavior-Driven Specification style, are removed from the called keyword name to find a match. -- If no match is found, Robot Framework tries to match the name with keywords that have embedded arguments. +- The prefixes Given, When, Then, And, and But (case-insensitive), which are used in Behavior-Driven Specification style, are removed from the called keyword name to find a match. +- If no match is found, Robot Framework tries to match the name with keywords that have embedded arguments. - If still no match is found, a full match (including possible Given, When, Then, And and But) is tried. By default, if not explicitly defined by the library developers, all Library Keywords are named in **Title Case** with capital letters at the beginning of each word, and spaces between words. @@ -86,12 +87,12 @@ Recall all available settings and their purpose for User Keywords :::: -User keywords can have similar settings as test cases, +User keywords can have similar settings as test cases, and they have the same square bracket syntax separating them from keyword calls. All available settings are listed below and explained in this section or in sections linked below. - `[Documentation]` Used for setting user keyword documentation. (see [3.3.4 User Keyword Documentation](chapter-03/03_user_keyword.md#334-user-keyword-documentation)) -- `[Arguments]` Specifies user keyword arguments to hand over values to the keyword. (see [3.3.5 User Keyword Arguments](chapter-03/03_user_keyword.md#335-user-keyword-arguments)) +- `[Arguments]` Specifies user keyword arguments to hand over values to the keyword. (see [3.3.5 User Keyword Arguments](chapter-03/03_user_keyword.md#335-user-keyword-arguments)) - `[Setup]`, `[Teardown]` Specify user keyword setup and teardown. (see [4.2 Teardowns (Suite, Test|Task, Keyword)](chapter-04/02_teardowns.md)) - `[Tags]` (*) Sets tags for the keyword, which can be used for filtering in documentation and attribution for post-processing results. - `[Timeout]` (*) Sets the possible user keyword timeout. @@ -115,7 +116,7 @@ Recall the significance of the first logical line and in keyword documentation f Each keyword can have a `[Documentation]` setting to provide a description of the keyword's purpose and usage. -The first logical line, until the first empty row, is used as the *short documentation* of the keyword in the `log.html` test protocol. +The first logical line, until the first empty row, is used as the *short documentation* of the keyword in the `log.html` test protocol. Proper documentation helps maintain clarity, especially in larger projects. It is a good practice to document what the keyword does, @@ -157,9 +158,9 @@ Understand the purpose and syntax of the [Arguments] setting in User Keywords. User Keywords can accept arguments, which make them more dynamic and reusable in various contexts. The `[Arguments]` setting is used to define the arguments a user keyword expects. -See also [2.5.2 Keyword Arguments](chapter-02/05_keyword_interface.md#252-keyword-arguments) for an introduction to argument kinds. +See also [2.5.2 Keyword Arguments](chapter-02/05_keyword_interface.md#252-keyword-arguments) for an introduction to argument kinds. -Arguments are defined by `[Arguments]` followed by the argument names separated by multiple spaces in the syntax of scalar variables. +Arguments are defined by `[Arguments]` followed by the argument names separated by multiple spaces in the syntax of scalar variables. Since Robot Framework 7.3 User Keywords can define argument types like `string`, `number`, etc., as described in the [2.5.2.8 Argument Types](chapter-02/05_keyword_interface.md#2528-argument-types) section. @@ -182,7 +183,7 @@ Define User Keywords with mandatory arguments. :::: -Arguments defined as scalar variable (`${arg}`) without a default value are mandatory and must be provided when calling the keyword. +Arguments defined as scalar variable (`${arg}`) without a default value are mandatory and must be provided when calling the keyword. Example that defines a keyword with two arguments: ```robotframework @@ -197,9 +198,9 @@ Verify File Contains Should Contain ${server_log} ${expected_content} ``` -All variables defined in the `[Arguments]` are local to the keyword body and do not exist outside of the keyword. +All variables defined in the `[Arguments]` are local to the keyword body and do not exist outside of the keyword. -This keyword may be called in a test case like this: +This keyword may be called in a test case like this: ```robotframework *** Test Cases *** Check Server Log @@ -227,8 +228,8 @@ Define User Keywords with optional arguments. :::: -Optional arguments are defined by assigning default values to them in the `[Arguments]` setting. -All optional arguments must be defined after all mandatory arguments. +Optional arguments are defined by assigning default values to them in the `[Arguments]` setting. +All optional arguments must be defined after all mandatory arguments. Default values are assigned using an equal sign (`=`), followed by the default value without any spaces, such as `${ignore_case}=True`, @@ -291,11 +292,9 @@ The file '${file_name}' should contain '${expected_content}' Should Contain ${file_content} ${expected_content} ``` -When this keyword is called, the placeholders `${file_name}` -and `${expected_content}` are replaced by the actual values provided in the keyword call. +When this keyword is called, the placeholders `${file_name}`and `${expected_content}` are replaced by the actual values provided in the keyword call. For instance, in the following example, -`${file_name}` is replaced with `server.log` -and `${expected_content}` with `Successfully started`: +`${file_name}` is replaced with `server.log`and `${expected_content}` with `Successfully started`: ```robotframework *** Test Cases *** @@ -380,7 +379,7 @@ This allows test execution to pass data between different keywords. It can return one or more values. If more than one value is returned, they can either be assigned -to multiple variables or stored as a list in a single variable. +to multiple variables or stored as a list in a single variable. Example: ```robotframework @@ -454,3 +453,4 @@ Keyword Conventions should contain agreements on: + diff --git a/website/docs/chapter-03/04_datadriven.md b/website/docs/chapter-03/04_datadriven.md index 42e8d370..cfc5c708 100644 --- a/website/docs/chapter-03/04_datadriven.md +++ b/website/docs/chapter-03/04_datadriven.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 3.4 Using Data-Driven Specification @@ -11,7 +13,7 @@ Understand the basic concept and syntax of Data-Driven Specification :::: -The **Data-Driven Specification** style in Robot Framework separates test|task logic from data, enabling tests|tasks to be executed with multiple data sets efficiently. This approach involves using a single higher-level keyword to represent the entire workflow, while the test data is defined as rows of input and expected output values. +The **Data-Driven Specification** style in Robot Framework separates test|task logic from data, enabling tests|tasks to be executed with multiple data sets efficiently. This approach involves using a single higher-level keyword to represent the entire workflow, while the test data is defined as rows of input and expected output values. ## 3.4.1 Test|Task Templates @@ -74,7 +76,7 @@ Empty Password ${VALID USER} ${EMPTY} The advantage of this approach is that each test|task is executed separately with its own name and data set. Each test|task appears in the statistics and reports. -Single tests|tasks can be filtered and re-executed or tagged, like the test case `Empty User Name and Password`. +Single tests|tasks can be filtered and re-executed or tagged, like the test case `Empty User Name and Password`. It is possible to add header names to the data columns in the line of `*** Test Cases ***` or `*** Tasks ***` to describe the data columns to improve readability. @@ -94,7 +96,7 @@ Recall the syntax and properties of named test|task with multiple data rows A slightly different approach is to define multiple data rows for a single test|task. This is still possible with a single template defined in the `*** Settings ***` section, but in this case it would also make sense to define the template locally for each test|task with the `[Template]` setting. -With this approach, it is possible to define different scenarios in the same suite file, which can be useful for testing different aspects of the same functionality. +With this approach, it is possible to define different scenarios in the same suite file, which can be useful for testing different aspects of the same functionality. ```robotframework *** Test Cases *** @@ -120,7 +122,7 @@ This approach creates only a single tests|tasks for multiple data rows in the lo However, this approach has also its drawbacks: -- Test|task setup and teardown are executed only once for all data rows of one test|task. +- Test|task setup and teardown are executed only once for all data rows of one test|task. If there is a setup and teardown needed for each data row, a keyword setup or teardown is needed. - The test|task name is not unique for each data row, which can make it harder to understand the failing data row in the logs. - Filtering and re-execution of some or single data rows is not possible. @@ -129,3 +131,4 @@ However, this approach has also its drawbacks: + diff --git a/website/docs/chapter-03/05_advanced_importing.md b/website/docs/chapter-03/05_advanced_importing.md index be27581e..5bc96161 100644 --- a/website/docs/chapter-03/05_advanced_importing.md +++ b/website/docs/chapter-03/05_advanced_importing.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 3.5 Advanced Importing of Keywords and Naming Conflicts @@ -11,15 +13,15 @@ Recall that naming conflicts can arise from the import of multiple resource file :::: -As stated before, it is possible to organize imports and available keywords in Robot Framework by using Resource Files. -By default, all keywords or variables created or imported in a resource file are available to those suites and files that are importing that higher-level resource file. +As stated before, it is possible to organize imports and available keywords in Robot Framework by using Resource Files. +By default, all keywords or variables created or imported in a resource file are available to those suites and files that are importing that higher-level resource file. This can lead to complex import hierarchies or the importing of libraries multiple times, which should be avoided. -Due to this mechanism, the number of keywords available to a suite can be quite large, and naming conflicts, especially with keywords from third-party keyword libraries, can occur. These conflicts need to be resolved. +Due to this mechanism, the number of keywords available to a suite can be quite large, and naming conflicts, especially with keywords from third-party keyword libraries, can occur. These conflicts need to be resolved. -Some keyword libraries have the option to be configured to change their behavior, which may also change the available keywords they offer. +Some keyword libraries have the option to be configured to change their behavior, which may also change the available keywords they offer. @@ -36,14 +38,7 @@ Understand how transitive imports of resource files and libraries work. :::: Let's assume the following libraries and resource files shall be used: -- **Library** `A` -- **Library** `B` -- **Library** `Operating System` -- **Resource** `tech_keywordsA.resource` -- **Resource** `tech_keywordsB.resource` -- **Resource** `variables.resource` -- **Resource** `functional_keywords.resource` - +- **Library** `A`- **Library** `B`- **Library** `Operating System`- **Resource** `tech_keywordsA.resource`- **Resource** `tech_keywordsB.resource`- **Resource** `variables.resource`- **Resource** `functional_keywords.resource` The respective files could look like this: **tech_keywordsA.resource:** @@ -73,7 +68,7 @@ Resource tech_keywordsB.resource Resource functional_keywords.resource ``` -In this case, the suite `suite.robot` has access to all keywords from all keyword libraries, as well as all variables and user keywords from all resource files. +In this case, the suite `suite.robot` has access to all keywords from all keyword libraries, as well as all variables and user keywords from all resource files. With this transitive importing it is possible to organize user keywords and imports of libraries in a hierarchical way. It shall be avoided to create circular imports, where `A.resource` imports `B.resource` and `B.resource` imports `A.resource`. @@ -104,8 +99,8 @@ This is typically global behavior like internal timeouts, connection settings to If this is possible, the library documentation will have an `Importing` section directly before the list of keywords. -Library importing arguments are used in the same way as keyword calls with arguments. -If possible, it is recommended to set the arguments as named arguments to make usage more readable and future-proof. +Library importing arguments are used in the same way as keyword calls with arguments. +If possible, it is recommended to set the arguments as named arguments to make usage more readable and future-proof. These arguments follow the Library path or name, separated by multiple spaces. Example with the [Telnet library](https://robotframework.org/robotframework/latest/libraries/Telnet.html#Importing): @@ -117,8 +112,7 @@ Library Telnet newline=LF encoding=ISO-8859-1 Another example that cannot be used without configuration is the Remote library. Remote libraries are libraries that are connected remotely via a network connection. -So the actual library is running as a server, and the library `Remote` -is connecting as a client and connects the keywords of the server to Robot Framework. +So the actual library is running as a server, and the library `Remote`is connecting as a client and connects the keywords of the server to Robot Framework. Therefore, it needs the server's address and port to connect to. Because there may be more than one Remote Library, we need to define the used library name as well. ```robotframework @@ -146,14 +140,13 @@ Explain how naming conflicts can happen and how to mitigate them. :::: Naming conflicts can occur when two or more keywords have the same name. -If a proper IDE is used, that can be detected, and users can be warned after they have created a duplicate user keyword name. +If a proper IDE is used, that can be detected, and users can be warned after they have created a duplicate user keyword name. Project teams may not have this influence over imported third-party libraries that have the same keyword names. Due to the fact that keywords from library and resource files are imported in the scope of the importing suite, it may be unavoidable to have naming conflicts. One example of these kinds of conflicts is the two libraries -[`Telnet`](https://robotframework.org/robotframework/latest/libraries/Telnet.html) -and [`SSHLibrary`](https://marketsquare.github.io/SSHLibrary/SSHLibrary.html), +[`Telnet`](https://robotframework.org/robotframework/latest/libraries/Telnet.html)and [`SSHLibrary`](https://marketsquare.github.io/SSHLibrary/SSHLibrary.html), which at the current time both have multiple keywords with the same name. This is because they both work with network connections and have similar functionality. Keywords like `Open Connection`, `Login`, `Read`, `Close Connection`, and many more are common. @@ -194,3 +187,4 @@ Using Remote Libraries DeviceAPI.Verify Contact 15 1 ``` + diff --git a/website/docs/chapter-04/00_overview.md b/website/docs/chapter-04/00_overview.md index def9ade0..4a377a52 100644 --- a/website/docs/chapter-04/00_overview.md +++ b/website/docs/chapter-04/00_overview.md @@ -1,7 +1,9 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 4 Advanced Structuring and Execution -As a Robot Framework automation project expands, the increasing number of tests|tasks adds complexity to the project. +As a Robot Framework automation project expands, the increasing number of tests|tasks adds complexity to the project. This chapter explores advanced structuring and execution techniques to effectively manage this complexity and control the execution flow. We will cover methods for error handling and cleaning up after failed tests|tasks using **Teardowns**, as well as preparing individual or multiple suites and tests|tasks for execution with **Setups**. -Additionally, filtering subsets of tests|tasks based on tags will be discussed, which is essential for managing test|task execution efficiently. \ No newline at end of file +Additionally, filtering subsets of tests|tasks based on tags will be discussed, which is essential for managing test|task execution efficiently. diff --git a/website/docs/chapter-04/01_setups.md b/website/docs/chapter-04/01_setups.md index b7a8f18e..7b73c9dd 100644 --- a/website/docs/chapter-04/01_setups.md +++ b/website/docs/chapter-04/01_setups.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 4.1 Setups (Suite, Test|Task, Keyword) @@ -19,13 +21,13 @@ Recall the different levels where a Setup can be defined Setups in Robot Framework are used to prepare the environment or system for execution or to verify that the requirements/preconditions needed for execution are met. -They can be defined at the suite, test|task, or keyword level and are executed before the respective scope begins execution. +They can be defined at the suite, test|task, or keyword level and are executed before the respective scope begins execution. -A **Setup** is a single keyword with potential argument values that is called before all other keywords; or before tests|tasks in Suite Setup. +A **Setup** is a single keyword with potential argument values that is called before all other keywords; or before tests|tasks in Suite Setup. Examples of typical use cases for Setups are: - Establishing connections to databases or services. -- Initializing test data or configurations. +- Initializing test data or configurations. - Setting the system under test to a known state. - Logging into applications or systems. - Navigating to the feature under test. @@ -97,7 +99,7 @@ Understand when Test|Task Setup is executed and used A **Test|Task Setup** is executed before a single test|task runs. It is used to prepare the specific conditions required for that test|task. -You can define a default Test|Task Setup in the `*** Settings ***` section of the suite using the `Test Setup`|`Task Setup` setting. +You can define a default Test|Task Setup in the `*** Settings ***` section of the suite using the `Test Setup`|`Task Setup` setting. This setup will be applied to all tests|tasks within the suite unless overridden and executed before each test|task. Individual tests|tasks can override the default setup by specifying their own `[Setup]` setting within the test|task. @@ -115,7 +117,7 @@ To disable the setup for a specific test|task, you can set `[Setup] NONE`, wh - Executing preparation steps to navigate to the automated task or feature under test. - Distinguishing phases of a test|task in *setup* (aka *preparation* or *precondition checking*), *steps*, and *teardown* (aka *clean up* or *postconditions*). -Example of defining a default Test|Task Setup in the suite settings and overriding it on a test case: +Example of defining a default Test|Task Setup in the suite settings and overriding it on a test case: ```robotframework *** Settings *** @@ -152,7 +154,7 @@ Recall key characteristics and syntax of Keyword Setup :::: -A **Keyword Setup** is executed before the body of a user keyword is executed. +A **Keyword Setup** is executed before the body of a user keyword is executed. It allows for preparation steps specific to that keyword or ensures that the keyword's requirements are met before execution. **Key characteristics of Keyword Setup:** @@ -163,7 +165,7 @@ It allows for preparation steps specific to that keyword or ensures that the key **Typical use cases:** - Opening connections or files needed by the keyword. -- Initializing variables or data structures. +- Initializing variables or data structures. - Ensuring preconditions specific to the keyword are met. Example of defining a Keyword Setup: @@ -178,3 +180,4 @@ Process Data + diff --git a/website/docs/chapter-04/02_teardowns.md b/website/docs/chapter-04/02_teardowns.md index eefb7e72..43d8ec93 100644 --- a/website/docs/chapter-04/02_teardowns.md +++ b/website/docs/chapter-04/02_teardowns.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 4.2 Teardowns (Suite, Test|Task, Keyword) @@ -17,14 +19,14 @@ Recall the typical use cases for using Teardowns :::: -In automation, tests|tasks are typically executed in a linear sequence. -This linear execution can lead to issues when a preceding test|task fails, potentially affecting subsequent tests|tasks due to an unclean state of the system under test or the automated environment. -To prevent such issues, Robot Framework provides the **Teardown** functionality, which can be defined at the suite, test|task, or keyword level. +In automation, tests|tasks are typically executed in a linear sequence. +This linear execution can lead to issues when a preceding test|task fails, potentially affecting subsequent tests|tasks due to an unclean state of the system under test or the automated environment. +To prevent such issues, Robot Framework provides the **Teardown** functionality, which can be defined at the suite, test|task, or keyword level. -As mentioned before, a failure resulting in a keyword with the status `FAIL` will cause Robot Framework not to execute all subsequent keywords of the current test|task. +As mentioned before, a failure resulting in a keyword with the status `FAIL` will cause Robot Framework not to execute all subsequent keywords of the current test|task. These not-executed keywords will receive the status `NOT RUN`. -A **Teardown** is a single keyword call with potential argument values that is executed after the child suites, test|tasks, and keywords have completed execution, regardless of the outcome, even if previously executed elements have failed. +A **Teardown** is a single keyword call with potential argument values that is executed after the child suites, test|tasks, and keywords have completed execution, regardless of the outcome, even if previously executed elements have failed. It ensures that necessary cleanup actions are performed, maintaining the integrity of the environment for subsequent executions. **Typical use cases for Teardowns include:** @@ -58,7 +60,7 @@ Understand when Suite Teardown is executed and used A **Suite Teardown** is executed after all tests|tasks and all child suites in a suite have been executed. -The Suite Teardown is executed regardless of the outcome of the tests|tasks within the suite, even if the suite setup fails. +The Suite Teardown is executed regardless of the outcome of the tests|tasks within the suite, even if the suite setup fails. **Key characteristics of Suite Teardown:** - Suite Teardown is a single keyword call with potential argument values. @@ -100,7 +102,7 @@ Understand when Test|Task Teardown is executed and used A **Test|Task Teardown** is executed after a single test|task body has been executed. It is used for cleaning up actions specific to that test|task. -The Test|Task Teardown is executed regardless of the test|task's outcome, even if the test|task's setup fails. +The Test|Task Teardown is executed regardless of the test|task's outcome, even if the test|task's setup fails. In Robot Framework, you can define a default Test|Task Teardown in the `*** Settings ***` section of the suite using the `Test Teardown`|`Task Teardown` setting. This default teardown will be applied to all tests|tasks within the suite unless overridden. @@ -113,14 +115,14 @@ It is recommended to define the local `[Teardown]` setting as the last line of t **Key characteristics of Test|Task Teardown:** - Test|Task Teardown is a single keyword call with potential argument values. - Executed after the test|task has been executed, regardless of its status. -- Runs even if the Test|Task Setup fails. +- Runs even if the Test|Task Setup fails. - If the Test|Task Teardown fails, the test|task is marked as failed in reports and logs. - All keywords within the Test|Task Teardown are executed, even if one of them fails. - Can be set globally for all tests|tasks in a suite and overridden locally. **Typical use cases:** - Logging out of an application after a test|task completes. -- Deleting test data created during the test|task. +- Deleting test data created during the test|task. - Restoring configurations altered during the test|task. - Distinguishing phases of a test|task in *setup* (aka *preparation* or *precondition checking*), *steps*, and *teardown* (aka *clean up* or *postconditions*). @@ -164,7 +166,7 @@ Recall key characteristics, benefits, and syntax of Keyword Teardown :::: -A **Keyword Teardown** is executed after a user keyword body has been executed. +A **Keyword Teardown** is executed after a user keyword body has been executed. It allows for cleanup actions specific to that keyword, ensuring that any resources used within the keyword are properly released independently of failed child keyword calls. @@ -178,7 +180,7 @@ For better readability, it should be written as the last line of a keyword. **Typical use cases:** - Closing temporary files or connections opened within the keyword. -- Resetting variables or states altered during keyword execution. +- Resetting variables or states altered during keyword execution. - Logging additional information after keyword execution. Example of defining a Keyword Teardown: @@ -194,3 +196,4 @@ Process Data + diff --git a/website/docs/chapter-04/03_init_files.md b/website/docs/chapter-04/03_init_files.md index 2a6d59db..8816d3f5 100644 --- a/website/docs/chapter-04/03_init_files.md +++ b/website/docs/chapter-04/03_init_files.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 4.3 Initialization Files @@ -11,7 +13,7 @@ Recall how to define Initialization Files and its purpose :::: -As Robot Framework automation projects grow, organizing tests|tasks into directories becomes essential for managing complexity and maintaining a clear structure. +As Robot Framework automation projects grow, organizing tests|tasks into directories becomes essential for managing complexity and maintaining a clear structure. When suites are created from directories, these directories can contain multiple suites and tests|tasks, forming a hierarchical suite structure. However, directories alone cannot hold suite-level settings or information. To address this, Robot Framework uses **initialization files**, which allow you to define suite-level settings for directories. @@ -24,7 +26,7 @@ This file can contain suite-level settings that apply to the directory suite. ## 4.3.1 Purpose of Initialization Files Initialization files enable you to: -- Define `Suite Setup` and `Suite Teardown` keywords for the directory suite. +- Define `Suite Setup` and `Suite Teardown` keywords for the directory suite. - Set the name of the suite with the `Name` setting if it should be different from the directory name. - Specify suite-level settings such as `Documentation` and `Metadata`. - Set default `Test Setup`, `Test Teardown`, `Test Tags`, and `Test Timeout` for all tests|tasks within the directory (these can be overridden/extended in lower-level suites or tests|tasks). @@ -45,8 +47,8 @@ Understand the execution order of Suite Setup and Suite Teardown in Initializati As previously explained, **Suite Setup** and **Suite Teardown** are used to prepare and clean up the environment before and after a suite's execution. Initialization files provide a centralized place to define these setups and teardowns for all sub-suites and their tests|tasks within a directory structure. -Thus, it is possible to define one Suite Setup that is executed at the very start of the execution before any other Suite Setup, Test|Task Setup, and Test|Task is executed. -The Suite Teardown of an initialization file is executed after all sub-suites in the directory and their tests|tasks have been completed. +Thus, it is possible to define one Suite Setup that is executed at the very start of the execution before any other Suite Setup, Test|Task Setup, and Test|Task is executed. +The Suite Teardown of an initialization file is executed after all sub-suites in the directory and their tests|tasks have been completed. @@ -62,29 +64,29 @@ Recall the allowed sections and their content in Initialization Files :::: -Initialization files have the same structure and syntax as regular suite files but with some limitations. +Initialization files have the same structure and syntax as regular suite files but with some limitations. The following sections are allowed in initialization files: - **`*** Settings ***` Section (required)**: - `Name`: Set a custom name for the suite directory. - `Documentation`: Provide documentation for the suite. - `Metadata`: Add metadata to the suite. - - `Suite Setup`: Define a keyword to be executed before any tests|tasks or child suites. + - `Suite Setup`: Define a keyword to be executed before any tests|tasks or child suites. - `Suite Teardown`: Define a keyword to be executed after all tests|tasks and child suites have completed. - `Test Setup`|`Task Setup`: Set a default setup keyword for all tests|tasks in the suite (can be overridden in lower-level suites or tests|tasks). - `Test Teardown`|`Task Teardown`: Set a default teardown keyword for all tests|tasks in the suite (can be overridden in lower-level suites or tests|tasks). - `Test Timeout`|`Task Timeout`: Define a default timeout for all tests|tasks in the suite (can be overridden in lower-level suites or tests|tasks). - `Test Tags`|`Task Tags`: Assign tags to all tests|tasks in the suite (applied recursively to all lower-level suites and tests|tasks and can be extended or reduced there). - - `Library`, `Resource`, `Variables`: Import necessary libraries, resource files, or variable files. + - `Library`, `Resource`, `Variables`: Import necessary libraries, resource files, or variable files. - `Keyword Tags`: Assign tags to all keywords in the local `*** Keywords ***` section. - **`*** Variables ***` Section (optional)**: - Define variables that are available to the initialization file. + Define variables that are available to the initialization file. - **`*** Keywords ***` Section (optional)**: - Define keywords that are available to the initialization file for Suite Setup, Suite Teardown, Test Setup, or Test Teardown. + Define keywords that are available to the initialization file for Suite Setup, Suite Teardown, Test Setup, or Test Teardown. - **`*** Comments ***` Section (optional)**: @@ -125,3 +127,4 @@ Cleanup Environment + diff --git a/website/docs/chapter-04/04_tags.md b/website/docs/chapter-04/04_tags.md index 51159270..014dc3f9 100644 --- a/website/docs/chapter-04/04_tags.md +++ b/website/docs/chapter-04/04_tags.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 4.4 Test|Task Tags and Filtering Execution @@ -11,10 +13,10 @@ Recall the purpose of Test|Task Tags in Robot Framework :::: -In Robot Framework, **tags** offer a simple yet powerful mechanism for classifying and controlling the execution of tests|tasks. -Tags are free-form text labels that can be assigned to tests|tasks to provide metadata, enable flexible test selection, and organize test results. +In Robot Framework, **tags** offer a simple yet powerful mechanism for classifying and controlling the execution of tests|tasks. +Tags are free-form text labels that can be assigned to tests|tasks to provide metadata, enable flexible test selection, and organize test results. -Tags are also used to create a statistical summary of the test|task results in the execution protocols. +Tags are also used to create a statistical summary of the test|task results in the execution protocols. **Important Note**: Tags are case-insensitive in Robot Framework, but the first appearance of a tag in a test|task is used as the tag name in reports and logs in its current case. @@ -70,7 +72,7 @@ Tags can be assigned to tests|tasks in several ways: This test|task will have a tag `environment:production`. -4. **By Keyword `Set Tags` or `Remove Tags`** to dynamically assign or remove tags during test|task execution: +4. **By Keyword `Set Tags` or `Remove Tags`** to dynamically assign or remove tags during test|task execution: See [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Set%20Tags) library documentation for more information. @@ -162,3 +164,4 @@ Using own tags with this prefix may lead to unexpected behavior in test executio + diff --git a/website/docs/chapter-04/05_skip.md b/website/docs/chapter-04/05_skip.md index b4b54f4b..89d802fa 100644 --- a/website/docs/chapter-04/05_skip.md +++ b/website/docs/chapter-04/05_skip.md @@ -1,3 +1,5 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 4.5 SKIP Test|Task Status @@ -17,12 +19,12 @@ Recall the different ways to skip tests|tasks in Robot Framework :::: -In addition to `PASS` and `FAIL`, Robot Framework introduces the `SKIP` status to indicate that a test|task was explicitly skipped **during** execution. The `SKIP` status is useful when certain tests|tasks should not be executed, for example, due to unfulfilled preconditions, incomplete test logic, or unsupported environments. Skipped tests|tasks appear in logs and reports, clearly marked as skipped. +In addition to `PASS` and `FAIL`, Robot Framework introduces the `SKIP` status to indicate that a test|task was explicitly skipped **during** execution. The `SKIP` status is useful when certain tests|tasks should not be executed, for example, due to unfulfilled preconditions, incomplete test logic, or unsupported environments. Skipped tests|tasks appear in logs and reports, clearly marked as skipped. **Reasons to Use SKIP** - **Temporary Exclusion of Tests|Tasks**: To prevent tests|tasks with known issues from running until the issue is resolved. -- **Conditional Execution**: To skip tests|tasks dynamically based on runtime conditions, e.g., if a Suite Setup detects an issue. +- **Conditional Execution**: To skip tests|tasks dynamically based on runtime conditions, e.g., if a Suite Setup detects an issue. - **Unsupported Scenarios**: To mark tests|tasks as skipped in environments where they cannot run, while still ensuring they are logged as such. @@ -56,10 +58,10 @@ Therefore skip is better for documenting that a specific test|task was not execu ## 4.5.2 Skipping Dynamically During Execution -Tests|tasks can be skipped dynamically within their execution with the `Skip` keyword based on runtime conditions. +Tests|tasks can be skipped dynamically within their execution with the `Skip` keyword based on runtime conditions. The `Skip` keyword does stop the execution of a test|task and mark it as skipped with a custom message. -If a Test|Task Teardown exists, it will be executed. +If a Test|Task Teardown exists, it will be executed. ## 4.5.3 Automatically Skipping Failed Tests @@ -73,3 +75,4 @@ Tests|tasks can be automatically marked as skipped if they fail: - **Reserved Tag `robot:skip-on-failure`**: Tag tests|tasks to skip automatically on failure. + diff --git a/website/docs/chapter-05/00_overview.md b/website/docs/chapter-05/00_overview.md index be5fba10..4013433d 100644 --- a/website/docs/chapter-05/00_overview.md +++ b/website/docs/chapter-05/00_overview.md @@ -2,4 +2,4 @@ This chapter introduces more advanced constructs of Robot Framework. These topics are often not needed for simple automation cases but can be very useful in more complex situations. -Although it is not expected that Robot Framework Certified Professionals will be able to use them, it is important to be aware of the possibilities and to understand the basic concepts. \ No newline at end of file +Although it is not expected that Robot Framework Certified Professionals will be able to use them, it is important to be aware of the possibilities and to understand the basic concepts. diff --git a/website/docs/chapter-05/01_advanced_variables.md b/website/docs/chapter-05/01_advanced_variables.md index 133198ba..2e6c8cf1 100644 --- a/website/docs/chapter-05/01_advanced_variables.md +++ b/website/docs/chapter-05/01_advanced_variables.md @@ -1,14 +1,16 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 5.1 Advanced Variables -Variables in Robot Framework, and in programming languages in general, can be more complex and can store various types of data. +Variables in Robot Framework, and in programming languages in general, can be more complex and can store various types of data. Robot Framework also offers multiple ways to create different kinds of values and types. However, the built-in language support is limited to the basic [3.2.2.2 Primitive Data Types](chapter-03/02_variables.md#3222-primitive-data-types), [3.2.2.3 List Variable Definition](chapter-03/02_variables.md#3223-list-variable-definition), and [3.2.2.4 Dictionary Variable Definition](chapter-03/02_variables.md#3224-dictionary-variable-definition). -This chapter provides more advanced knowledge about the different variable scopes, lists, dictionaries, their syntax, and some background on the most important Built-In Variables. +This chapter provides more advanced knowledge about the different variable scopes, lists, dictionaries, their syntax, and some background on the most important Built-In Variables. -Understanding the **priority** and **scope** of variables in Robot Framework is crucial for effective test automation. +Understanding the **priority** and **scope** of variables in Robot Framework is crucial for effective test automation. Variables can be defined in multiple places and ways, and their availability and precedence depend on where and how they are created. @@ -28,16 +30,16 @@ Understand the difference between statically defined and dynamically created var Variables can originate from various sources, and when variables with the same name exist, Robot Framework resolves them based on their priority. -Several factors influence variable priority in Robot Framework: the type of variable, the time of (re-)definition, and the variable’s scope. +Several factors influence variable priority in Robot Framework: the type of variable, the time of (re-)definition, and the variable’s scope. In general, there are two types of variables regarding how they are created: - Statically defined or imported variables (e.g., in the `*** Variables ***` section, command-line options, imported resource files) -- Dynamically created variables during Robot Framework execution (e.g., using the `VAR` syntax, assignment of return values from keywords or keyword arguments) +- Dynamically created variables during Robot Framework execution (e.g., using the `VAR` syntax, assignment of return values from keywords or keyword arguments) Built-in variables cannot generally be sorted into one of these categories, as some are predefined globally while others are created during execution with a `SUITE` or `TEST` scope. Examples: -- `${TEST_NAME}` is dynamically set during execution to the name of the currently running test case. +- `${TEST_NAME}` is dynamically set during execution to the name of the currently running test case. - `${OUTPUT_DIR}` is statically defined before the execution and contains the directory where `output.xml`, `log.html` and `report.html` are written. - `${LOG_LEVEL}` is by default set statically via command line options or `INFO` as default, but can be changed, with the keyword `Set Log Level` during exection. @@ -61,9 +63,9 @@ In descending order, the priority is as follows: 1. **Global Command-Line Variables**: Variables defined via command-line options like `--variable` or `--variablefile` have the highest priority. See [5.1.3 Global Variables via Command Line](chapter-05/01_advanced_variables.md#513-global-variables-via-command-line) for more details. -2. **`*** Variables ***` Section**: Variables defined in the `*** Variables ***` section of a suite are set before any resource file from the `*** Settings ***` section is imported. See [3.2.2 `*** Variables ***` Section](chapter-03/02_variables.md#322--variables--section) for more details. +2. **`*** Variables ***` Section**: Variables defined in the `*** Variables ***` section of a suite are set before any resource file from the `*** Settings ***` section is imported. See [3.2.2 `*** Variables ***` Section](chapter-03/02_variables.md#322--variables--section) for more details. -3. **Resource Files**: Variables from resource files are imported in the order they are specified in the `*** Settings ***` section. See [2.4.2 Resource Files](chapter-02/04_keyword_imports.md#242-resource-files) for more details. +3. **Resource Files**: Variables from resource files are imported in the order they are specified in the `*** Settings ***` section. See [2.4.2 Resource Files](chapter-02/04_keyword_imports.md#242-resource-files) for more details. Within a resource file, the same order applies: variables defined in the `*** Variables ***` section of a resource file have higher priority than variables imported from other resource files. @@ -89,7 +91,7 @@ The rule of thumb here is: **"Last one wins!"** The scope of a variable defines its lifetime and availability. As long as a variable is in scope, the last definition takes precedence over the previous ones. -For example, a local variable defined as a [3.3.5 User Keyword Arguments](chapter-03/03_user_keyword.md#335-user-keyword-arguments) has a higher priority than a suite variable defined in the `*** Variables ***` section of the suite file. +For example, a local variable defined as a [3.3.5 User Keyword Arguments](chapter-03/03_user_keyword.md#335-user-keyword-arguments) has a higher priority than a suite variable defined in the `*** Variables ***` section of the suite file. However, once the keyword body scope is exited, the suite variable is back in scope with higher priority and the local variable is no longer existent. @@ -122,17 +124,17 @@ Recall how to define global variables and where they can be accessed - **Definition**: Variables accessible everywhere during the test execution. - **Creation**: - Set from the command line using `--variable` or `--variablefile` options. (static) - - Created during execution using the `VAR` syntax with the `scope=GLOBAL` argument. (dynamic) + - Created during execution using the `VAR` syntax with the `scope=GLOBAL` argument. (dynamic) - **Usage**: Ideal for configuration parameters that need to be consistent across the entire test run. -Because global variables set via the command line have the highest priority, they can override other variables defined in the suite or resource files. +Because global variables set via the command line have the highest priority, they can override other variables defined in the suite or resource files. The most common use case for global variables is to define environment-specific or execution configurations, such as URLs, credentials, browser types, API keys, or similar data. See [5.1.3 Global Variables via Command Line](chapter-05/01_advanced_variables.md#513-global-variables-via-command-line) for more details. **Recommendation**: -Global variables should always be defined using uppercase letters, like `${GLOBAL_VARIABLE}`, to distinguish them from local variables. -Every global variable should have a corresponding default value defined either in a `*** Variables ***` section or imported from variable files, so that editors and IDEs can provide auto-completion and static code analysis. +Global variables should always be defined using uppercase letters, like `${GLOBAL_VARIABLE}`, to distinguish them from local variables. +Every global variable should have a corresponding default value defined either in a `*** Variables ***` section or imported from variable files, so that editors and IDEs can provide auto-completion and static code analysis. ### 5.1.2.2 . Suite Scope @@ -147,7 +149,7 @@ Recall how to define suite variables and where they can be accessed :::: -- **Definition**: Variables accessible within the test suite where they are defined, including all its tests|tasks and keywords. +- **Definition**: Variables accessible within the test suite where they are defined, including all its tests|tasks and keywords. - **Creation**: - Defined in the `*** Variables ***` section of the suite file. (static) - Imported from resource or variable files. (static) @@ -163,7 +165,7 @@ If a variable is defined in the `*** Variables ***` section of a suite file and If a global variable is defined using the command line, and a suite-level variable with the same name is dynamically defined, the suite variable now shadows the global variable and has higher priority as long as the suite is in scope. Once the suite is finished or a sub-suite is executed, the global variable returns to scope with higher priority. **Recommendation**: -Suite variables should be defined using uppercase letters, like `${SUITE_VARIABLE}`, to distinguish them from local variables. These variables should be defined in the `*** Variables ***` section of the suite file, even if they are dynamically overwritten during execution, so they are visible in the editor or IDE and can be used for auto-completion and static code analysis. +Suite variables should be defined using uppercase letters, like `${SUITE_VARIABLE}`, to distinguish them from local variables. These variables should be defined in the `*** Variables ***` section of the suite file, even if they are dynamically overwritten during execution, so they are visible in the editor or IDE and can be used for auto-completion and static code analysis. ### 5.1.2.3 . Test|Task Scope @@ -177,12 +179,12 @@ Recall how to define test|task variables and where they can be accessed :::: -- **Definition**: Variables accessible within a single test|task and within all keywords it calls. +- **Definition**: Variables accessible within a single test|task and within all keywords it calls. - **Creation**: - Created during test execution using the `VAR` syntax with the `scope=TEST` or `scope=TASK` argument. (dynamic) - **Usage**: Appropriate for data that is specific to a single test|task. -Test|Task variables cannot be created in suite setup or teardown, nor can they be imported. Test|Task scope variables are not available in other tests|tasks, even within the same suite. +Test|Task variables cannot be created in suite setup or teardown, nor can they be imported. Test|Task scope variables are not available in other tests|tasks, even within the same suite. They can only be created dynamically, so they have higher priority than suite or global variables while in scope. Once a test|task is finished, the variables are no longer available. If they have shadowed a suite or global variable, that variable returns to scope. @@ -207,7 +209,7 @@ Recall how to define local variables and where they can be accessed - **Creation**: - Variables assigned by keyword return values. - Variables defined using the `VAR` syntax (optional: with `scope=LOCAL`) within a keyword or test|task. - - Keyword arguments. + - Keyword arguments. - **Usage**: Commonly used to temporarily store data and pass it to other keywords. Local variables are the most commonly used variables in Robot Framework and have the fewest side effects. They should be preferred over other variable scopes unless there is an explicit need to share data across scope boundaries. @@ -260,8 +262,7 @@ Only scalar string values are supported. robot -v "hello:Hello world" . ``` -- Multiple Variables: `${name}` == `Robot` (str), `${version}` == `4.0` (str), `${patch}` == `${EMPTY}` - ```shell +- Multiple Variables: `${name}` == `Robot` (str), `${version}` == `4.0` (str), `${patch}` == `${EMPTY}` ```shell robot -v "name:Robot Framework" -v version:4.0 -v patch: . ``` @@ -285,7 +286,7 @@ Recall that assignments to `@{list}` variables convert values to lists automatic :::: -Using the at-syntax (`@{}`) is required to define a list variable with `VAR` syntax or in the `*** Variables ***` section, but it is optional when assigning return values, which are list-like, from keywords to a variable. +Using the at-syntax (`@{}`) is required to define a list variable with `VAR` syntax or in the `*** Variables ***` section, but it is optional when assigning return values, which are list-like, from keywords to a variable. Example: @@ -298,17 +299,17 @@ Test List Variables Both assignments will contain a list if the keyword returns a list of values. -However, if a keyword returns something other than a list but still list-like, it will be assigned without changes to the scalar variable `${trainers}` and will be converted to a list when using the at-syntax, as in `@{participants}`. +However, if a keyword returns something other than a list but still list-like, it will be assigned without changes to the scalar variable `${trainers}` and will be converted to a list when using the at-syntax, as in `@{participants}`. List-like values can include Tuples, Sets, Dictionary Keys, or generator functions. As long as a value is iterable, it can be assigned to a list variable using the at-syntax to ensure it is a list after assignment. **Note**: Strings are iterable in Python; however, they are explicitly **NOT** converted to a list when assigned to a list variable to prevent mistakes. -### 5.1.4.2 Accessing List Variables +### 5.1.3.1 Accessing List Variables ::::lo[Learning Objectives] -:::K1[LO-5.1.4.2] +:::K1[LO-5.1.3.1] Recall that `@{list}` unpacks the values of a list variable when accessed @@ -342,17 +343,17 @@ This is particularly needed when using FOR-Loops. See [5.2.4 FOR Loops](chapter- -## 5.1.5 Dict-Like +## 5.1.4 Dict-Like As explained in the `*** Variables ***` section under [3.2.2.4 Dictionary Variable Definition](chapter-03/02_variables.md#3224-dictionary-variable-definition), Robot Framework natively supports creating dictionaries. However, the ampersand-syntax `&{var}` has different meanings when assigning values and when accessing values. -### 5.1.5.1 Assigning Dictionary Variables +### 5.1.4.1 Assigning Dictionary Variables ::::lo[Learning Objectives] -:::K1[LO-5.1.5.1] +:::K1[LO-5.1.4.1] Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access @@ -374,11 +375,11 @@ Test Dictionary Variables In the following example, the first assignment to `&{participant}` causes an automatic conversion to a Robot Framework Dictionary, also known as DotDict. These special dictionary types can be accessed using dot-access like `${participant.name}` or `${participant.age}`, instead of the usual dictionary access like `${trainer}[name]` or `${trainer}[age]`. -### 5.1.5.2 Accessing Dictionary Variables +### 5.1.4.2 Accessing Dictionary Variables ::::lo[Learning Objectives] -:::K1[LO-5.1.5.2] +:::K1[LO-5.1.4.2] Recall that `&{dict}` unpacks to multiple key=value pairs when accessed @@ -411,16 +412,16 @@ Log Participant Log ${name} is ${age} years old ``` -Instead of calling the keyword `Log Participant` with two arguments, it is possible to use the unpacked dictionary variables `&{participant_one}` and `&{participant_two}` to call the keyword with two named arguments. +Instead of calling the keyword `Log Participant` with two arguments, it is possible to use the unpacked dictionary variables `&{participant_one}` and `&{participant_two}` to call the keyword with two named arguments. The dictionary keys act as the argument names and the values as the argument values. -## 5.1.6 Built-In Variables +## 5.1.5 Built-In Variables ::::lo[Learning Objectives] -:::K1[LO-5.1.6] +:::K1[LO-5.1.5] Recall that Robot Framework provides access to execution information via Built-In variables @@ -428,7 +429,7 @@ Recall that Robot Framework provides access to execution information via Built-I :::: -Robot Framework has a set of built-in variables that can be used in test cases, keywords, and other places. Some examples are: +Robot Framework has a set of built-in variables that can be used in test cases, keywords, and other places. Some examples are: | Variable | Description | |--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -455,3 +456,4 @@ These variables can be used in test cases, keywords, and other places to access + diff --git a/website/docs/chapter-05/02_control_structures.md b/website/docs/chapter-05/02_control_structures.md index 8d660524..3ef76181 100644 --- a/website/docs/chapter-05/02_control_structures.md +++ b/website/docs/chapter-05/02_control_structures.md @@ -1,7 +1,9 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # 5.2 Control Structures -Robot Framework is a Turing-complete language and supports all common control structures, including IF-Statements, FOR-Loops, WHILE-Loops and more. +Robot Framework is a Turing-complete language and supports all common control structures, including IF-Statements, FOR-Loops, WHILE-Loops and more. While it is not expected that RFCPs can write complex control structures, they should understand their purpose. In some cases, it is necessary to use control structures to handle different cases, iterate over a list of values, or execute an action until a condition is met. @@ -19,12 +21,12 @@ Understand the purpose and basic concept of IF-Statements :::: -The `IF` / `ELSE IF` / `ELSE` syntax in Robot Framework is used to control the flow of test|task execution by allowing certain keywords to run only when specific conditions are met. -This is achieved by evaluating conditions written as Python expressions, enabling dynamic decision-making within your tests|tasks. +The `IF` / `ELSE IF` / `ELSE` syntax in Robot Framework is used to control the flow of test|task execution by allowing certain keywords to run only when specific conditions are met. +This is achieved by evaluating conditions written as Python expressions, enabling dynamic decision-making within your tests|tasks. The `IF` statement begins with the `IF` token and ends with an `END`, enclosing the keywords executed when the condition is true. An optional `ELSE` or `ELSE IF` can specify alternative actions when the initial condition is false. -This structure enhances the flexibility and responsiveness of your tests|tasks, allowing them to adapt based on variables and outcomes encountered during execution. +This structure enhances the flexibility and responsiveness of your tests|tasks, allowing them to adapt based on variables and outcomes encountered during execution. ### 5.2.1.1 Basic IF Syntax @@ -46,7 +48,7 @@ Check Status END ``` -It executes the `Log` keyword if `${status}` is the string `SUCCESS`. +It executes the `Log` keyword if `${status}` is the string `SUCCESS`. ## 5.2.2 IF/ELSE Structure @@ -76,7 +78,7 @@ Evaluate Score ## 5.2.3 Inline IF Statement -For single conditional keywords, the simplified inline IF statement can be used. +For single conditional keywords, the simplified inline IF statement can be used. ```robotframework title="Structure" IF [arguments] @@ -107,7 +109,7 @@ Understand the purpose and basic concept of FOR Loops The `FOR` loop in Robot Framework repeats a set of keywords multiple times, iterating over a sequence of values. This allows you to perform the same actions for different items without duplicating code, enhancing the efficiency and readability of your keyword logic. -Robot Framework has four types of FOR loops; this chapter focuses on the basic `FOR-IN` loop. +Robot Framework has four types of FOR loops; this chapter focuses on the basic `FOR-IN` loop. - `FOR-IN` is used to iterate over a list of values. The other types are `FOR-IN-RANGE`, `FOR-IN-ENUMERATE`, and `FOR-IN-ZIP`, which are more advanced and less commonly required. @@ -115,7 +117,7 @@ The other types are `FOR-IN-RANGE`, `FOR-IN-ENUMERATE`, and `FOR-IN-ZIP`, which - `FOR-IN-ENUMERATE` iterates over a list of values and their indexes. - `FOR-IN-ZIP` iterates over multiple lists simultaneously. -The `FOR` loop begins with the `FOR` token, followed by a loop variable, the `IN` token, and the iterable variable or list of values. +The `FOR` loop begins with the `FOR` token, followed by a loop variable, the `IN` token, and the iterable variable or list of values. The loop variable takes on each value in the sequence one at a time, executing the enclosed keywords for each value. @@ -130,7 +132,7 @@ FOR ${loop_variable} IN ... END ``` -Since ` ... ` can be the same as an unpacked list like `@{values}`, this is the most common way to use the FOR loop. +Since ` ... ` can be the same as an unpacked list like `@{values}`, this is the most common way to use the FOR loop. ```robotframework title="Structure" FOR ${loop_variable} IN @{iterable_values} @@ -298,3 +300,4 @@ Get Older Participants END RETURN ${older_participants} ``` + diff --git a/website/docs/example-exam/Example-exam.mdx b/website/docs/example-exam/Example-exam.mdx index f2e196fe..60c1cbea 100644 --- a/website/docs/example-exam/Example-exam.mdx +++ b/website/docs/example-exam/Example-exam.mdx @@ -1,7 +1,10 @@ +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + import Quiz from '@site/src/components/Quiz/Quiz'; # Example Questions -This example exam should give you the oportunity to check you knowledge and to get an impression what kind of questions may be asked in the real examination for RFCP®. +This example exam should give you the oportunity to check you knowledge and to get an impression what kind of questions may be asked in the real examination for RFCP®. + diff --git a/website/docs/learning_objectives.md b/website/docs/learning_objectives.md index e0832b25..c3d94eab 100644 --- a/website/docs/learning_objectives.md +++ b/website/docs/learning_objectives.md @@ -127,11 +127,10 @@ | [`LO-5.1.2.2`](chapter-05/01_advanced_variables.md#5122--suite-scope) | K1 | Recall how to define suite variables and where they can be accessed | | [`LO-5.1.2.3`](chapter-05/01_advanced_variables.md#5123--testtask-scope) | K1 | Recall how to define test\|task variables and where they can be accessed | | [`LO-5.1.2.4`](chapter-05/01_advanced_variables.md#5124--local-scope) | K1 | Recall how to define local variables and where they can be accessed | -| [`LO-5.1.4.1`](chapter-05/01_advanced_variables.md#5141-assigning-list-variables) | K1 | Recall that assignments to `@{list}` variables convert values to lists automatically | -| [`LO-5.1.4.2`](chapter-05/01_advanced_variables.md#5142-accessing-list-variables) | K1 | Recall that `@{list}` unpacks the values of a list variable when accessed | -| [`LO-5.1.5.1`](chapter-05/01_advanced_variables.md#5151-assigning-dictionary-variables) | K1 | Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access | -| [`LO-5.1.5.2`](chapter-05/01_advanced_variables.md#5152-accessing-dictionary-variables) | K1 | Recall that `&{dict}` unpacks to multiple key=value pairs when accessed | -| [`LO-5.1.6`](chapter-05/01_advanced_variables.md#516-built-in-variables) | K1 | Recall that Robot Framework provides access to execution information via Built-In variables | +| [`LO-5.1.3.1`](chapter-05/01_advanced_variables.md#5131-accessing-list-variables) | K1 | Recall that `@{list}` unpacks the values of a list variable when accessed | +| [`LO-5.1.4.1`](chapter-05/01_advanced_variables.md#5141-assigning-dictionary-variables) | K1 | Recall that assignments to `&{dict}` variables automatically convert values to Robot Framework Dictionaries and enable dot-access | +| [`LO-5.1.4.2`](chapter-05/01_advanced_variables.md#5142-accessing-dictionary-variables) | K1 | Recall that `&{dict}` unpacks to multiple key=value pairs when accessed | +| [`LO-5.1.5`](chapter-05/01_advanced_variables.md#515-built-in-variables) | K1 | Recall that Robot Framework provides access to execution information via Built-In variables | | [`LO-5.2.1`](chapter-05/02_control_structures.md#521-if-statements) | K2 | Understand the purpose and basic concept of IF-Statements | | [`LO-5.2.4`](chapter-05/02_control_structures.md#524-for-loops) | K2 | Understand the purpose and basic concept of FOR Loops | | [`LO-5.2.5`](chapter-05/02_control_structures.md#525-while-loops) | K2 | Understand the purpose and basic concept of WHILE Loops | diff --git a/website/docs/overview.md b/website/docs/overview.md index 7f4df546..e69df6a0 100644 --- a/website/docs/overview.md +++ b/website/docs/overview.md @@ -2,6 +2,8 @@ sidebar_position: 1 --- +import GlossaryTerm from '@site/src/components/Glossary/GlossaryTerm'; + # Introduction @@ -9,7 +11,7 @@ sidebar_position: 1 ## 0.1 About the Syllabus This syllabus serves as both a guidance document for participants and a requirement specification for Accredited Training Providers -preparing candidates for the "Robot Framework® Certified Professional" (RFCP®) exam. +preparing candidates for the "Robot Framework® Certified Professional" (RFCP®) exam. It outlines the structure, learning objectives, and knowledge areas essential for certification. This syllabus is not a training manual, tutorial, or comprehensive learning resource but instead defines the scope of knowledge @@ -34,13 +36,13 @@ but the specific teaching methods, order and pace may be adapted by the instruct ## 0.2 About "Robot Framework® Certified Professional" -The Robot Framework® Certified Professional (RFCP®) certification represents the foundational level of expertise in Robot Framework. It provides participants with a strong understanding of the core principles, syntax, and basic control structures needed to develop effective automation scripts. +The Robot Framework® Certified Professional (RFCP®) certification represents the foundational level of expertise in Robot Framework. It provides participants with a strong understanding of the core principles, syntax, and basic control structures needed to develop effective automation scripts. While the RFCP® includes an introduction to advanced features such as FOR-Loops and IF statements, the focus is primarily on awareness rather than in-depth mastery, leaving detailed exploration of these topics to the more advanced future certification levels. -RFCP® concentrates on essential concepts such as keyword-driven automation, script execution, and integrating external libraries. +RFCP® concentrates on essential concepts such as keyword-driven automation, script execution, and integrating external libraries. It is designed for those seeking proficiency in Robot Framework’s core functionalities while gaining an overview of its broader capabilities. This certification does not require or teach domain-specific automation knowledge, such as web, API, or database automation. @@ -54,9 +56,9 @@ Upon completing this course, participants will achieve the following capabilitie - **Develop and maintain stable automation scripts**: Learn how to create automation scripts that are robust, easy to maintain, and adaptable to different scenarios. -- **Develop user keywords and build keyword repositories for reuse**: Understand how to create reusable keywords and build keyword repositories to improve efficiency and maintainability in automation projects. +- **Develop user keywords and build keyword repositories for reuse**: Understand how to create reusable keywords and build keyword repositories to improve efficiency and maintainability in automation projects. -- **Write documentation**: Learn best practices for documenting keywords, suites and tests or tasks to ensure clarity and ease of use for future script maintenance or collaboration. +- **Write documentation**: Learn best practices for documenting keywords, suites and tests or tasks to ensure clarity and ease of use for future script maintenance or collaboration. - **Integrate external automation libraries**: Leverage external libraries to enable Robot Framework® to interact with a wide range of technologies, such as APIs, user interfaces (Web, Mobile, others), databases, and many more. @@ -74,7 +76,6 @@ The learning objectives (LOs) are a critical component of this syllabus, as they define what participants are expected to know and be able to do by the end of the course. To ensure a clear understanding of these objectives, we apply Knowledge Levels (K-Levels) as a framework for assessing learning progress. These levels are based on Bloom's Taxonomy of Educational Objectives. See [Bloom's taxonomy](https://en.wikipedia.org/wiki/Bloom%27s_taxonomy) - - **K1 (Remember)**: Basic knowledge of terminology and facts. At this level, participants are expected to recall essential terms, concepts, and definitions. - **K2 (Understand)**: Comprehension of concepts. Participants should demonstrate an understanding of the principles behind Robot Framework, such as its mechanics, syntax and architecture. @@ -87,7 +88,7 @@ Throughout this syllabus, participants will progress through these knowledge lev ## 0.5 About Accredited Training Providers -Accredited Training Providers are organizations officially accredited by the Robot Framework Foundation to offer certified training programs for a specific certification level. +Accredited Training Providers are organizations officially accredited by the Robot Framework Foundation to offer certified training programs for a specific certification level. These partners shall deliver high-quality, structured courses designed to prepare candidates for the Robot Framework® Certified Professional (RFCP®) exam and other future Robot Framework certifications. All training providers are members of the Robot Framework Foundation, @@ -144,4 +145,4 @@ Special recognition is given to **Gerwin Laagland**, **Simon Meggle**, and **Fra **Acknowledgment** -The creation of the "Robot Framework Certified Professional®" syllabus stands as a testament to the dedication and generosity of its contributors. Most of the work has been done pro bono, reflecting a deep commitment to the principles of open-source collaboration and knowledge sharing. Each contributor—from those who meticulously reviewed and refined the content to those who laid its very foundation—has left a lasting impact. Their combined efforts have ensured that this document serves as a meaningful and accessible resource. We extend our heartfelt gratitude to everyone involved for their invaluable contributions. \ No newline at end of file +The creation of the "Robot Framework Certified Professional®" syllabus stands as a testament to the dedication and generosity of its contributors. Most of the work has been done pro bono, reflecting a deep commitment to the principles of open-source collaboration and knowledge sharing. Each contributor—from those who meticulously reviewed and refined the content to those who laid its very foundation—has left a lasting impact. Their combined efforts have ensured that this document serves as a meaningful and accessible resource. We extend our heartfelt gratitude to everyone involved for their invaluable contributions. diff --git a/website/src/components/Glossary/GlossaryTerm.module.css b/website/src/components/Glossary/GlossaryTerm.module.css new file mode 100644 index 00000000..c6f7a489 --- /dev/null +++ b/website/src/components/Glossary/GlossaryTerm.module.css @@ -0,0 +1,43 @@ +.glossaryTerm { + position: relative; + display: inline; +} + +.glossaryLink { + color: var(--ifm-color-primary); + text-decoration: none; + border-bottom: 1px dotted var(--ifm-color-primary); + cursor: help; +} + +.glossaryLink:hover { + color: var(--ifm-color-primary-dark); + border-bottom: 1px solid var(--ifm-color-primary-dark); +} + +.tooltip { + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + margin-bottom: 8px; + padding: 6px 12px; + background-color: var(--ifm-color-emphasis-700); + color: var(--ifm-font-color-base-inverse); + border-radius: 4px; + font-size: 0.875rem; + white-space: nowrap; + z-index: 1000; + pointer-events: none; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +} + +.tooltip::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + border: 6px solid transparent; + border-top-color: var(--ifm-color-emphasis-700); +} diff --git a/website/src/components/Glossary/GlossaryTerm.tsx b/website/src/components/Glossary/GlossaryTerm.tsx new file mode 100644 index 00000000..b16b7620 --- /dev/null +++ b/website/src/components/Glossary/GlossaryTerm.tsx @@ -0,0 +1,44 @@ +import React, { useState } from 'react'; +import Link from '@docusaurus/Link'; +import styles from './GlossaryTerm.module.css'; + +interface GlossaryTermProps { + children: React.ReactNode; + term: string; +} + +const GlossaryTerm: React.FC = ({ children, term }) => { + const [showTooltip, setShowTooltip] = useState(false); + + // Create slug from term (matches GlossaryTable.tsx slugify logic) + const slugify = (text: string): string => + text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-+|-+$)/g, ''); + + const slug = slugify(term); + const glossaryUrl = `/docs/glossary#${slug}`; + + return ( + setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > + + {children} + + {showTooltip && ( + + Click to view definition in glossary + + )} + + ); +}; + +export default GlossaryTerm;